From: Herbert Xu Fix bug #4223. This happened because we got preempted before sis900_mii_probe finished setting the sis_priv->mii. Theoretically this can happen with SMP as well but I suppose the number of SMP machines with sis900 is fairly small. The fix is to make sure that sis900_mii_probe is done before the device can be opened. This patch does it by moving the setup after register_netdevice into the netdev init function. Signed-off-by: Herbert Xu Signed-off-by: Andrew Morton --- 25-akpm/drivers/net/sis900.c | 94 ++++++++++++++++++++++--------------------- 1 files changed, 50 insertions(+), 44 deletions(-) diff -puN drivers/net/sis900.c~sis900-oops-fix drivers/net/sis900.c --- 25/drivers/net/sis900.c~sis900-oops-fix Fri Feb 18 16:32:58 2005 +++ 25-akpm/drivers/net/sis900.c Fri Feb 18 16:32:58 2005 @@ -373,6 +373,55 @@ static int __devinit sis96x_get_mac_addr return 0; } +static int __devinit sis900_init_netdev(struct net_device *net_dev) +{ + struct sis900_private *sis_priv = netdev_priv(net_dev); + struct pci_dev *pci_dev = sis_priv->pci_dev; + long ioaddr = net_dev->base_addr; + struct pci_dev *dev; + int ret; + + /* Get Mac address according to the chip revision */ + pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev)); + if (netif_msg_probe(sis_priv)) + printk(KERN_DEBUG "%s: detected revision %2.2x, " + "trying to get MAC address...\n", + net_dev->name, sis_priv->chipset_rev); + + if (sis_priv->chipset_rev == SIS630E_900_REV) + ret = sis630e_get_mac_addr(pci_dev, net_dev); + else if ((sis_priv->chipset_rev > 0x81) && (sis_priv->chipset_rev <= 0x90)) + ret = sis635_get_mac_addr(pci_dev, net_dev); + else if (sis_priv->chipset_rev == SIS96x_900_REV) + ret = sis96x_get_mac_addr(pci_dev, net_dev); + else + ret = sis900_get_mac_addr(pci_dev, net_dev); + + if (ret == 0) { + printk(KERN_WARNING "%s: Cannot read MAC address.\n", net_dev->name); + return -ENODEV; + } + + /* 630ET : set the mii access mode as software-mode */ + if (sis_priv->chipset_rev == SIS630ET_900_REV) + outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr); + + /* probe for mii transceiver */ + if (sis900_mii_probe(net_dev) == 0) { + printk(KERN_WARNING "%s: Error probing MII device.\n", net_dev->name); + return -ENODEV; + } + + /* save our host bridge revision */ + dev = pci_get_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, NULL); + if (dev) { + pci_read_config_byte(dev, PCI_CLASS_REVISION, &sis_priv->host_bridge_rev); + pci_dev_put(dev); + } + + return 0; +} + /** * sis900_probe - Probe for sis900 device * @pci_dev: the sis900 pci device @@ -389,7 +438,6 @@ static int __devinit sis900_probe(struct { struct sis900_private *sis_priv; struct net_device *net_dev; - struct pci_dev *dev; dma_addr_t ring_dma; void *ring_space; long ioaddr; @@ -463,6 +511,7 @@ static int __devinit sis900_probe(struct net_dev->tx_timeout = sis900_tx_timeout; net_dev->watchdog_timeo = TX_TIMEOUT; net_dev->ethtool_ops = &sis900_ethtool_ops; + net_dev->init = &sis900_init_netdev; if (sis900_debug > 0) sis_priv->msg_enable = sis900_debug; @@ -472,47 +521,6 @@ static int __devinit sis900_probe(struct ret = register_netdev(net_dev); if (ret) goto err_unmap_rx; - - /* Get Mac address according to the chip revision */ - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &(sis_priv->chipset_rev)); - if(netif_msg_probe(sis_priv)) - printk(KERN_DEBUG "%s: detected revision %2.2x, " - "trying to get MAC address...\n", - net_dev->name, sis_priv->chipset_rev); - - ret = 0; - if (sis_priv->chipset_rev == SIS630E_900_REV) - ret = sis630e_get_mac_addr(pci_dev, net_dev); - else if ((sis_priv->chipset_rev > 0x81) && (sis_priv->chipset_rev <= 0x90) ) - ret = sis635_get_mac_addr(pci_dev, net_dev); - else if (sis_priv->chipset_rev == SIS96x_900_REV) - ret = sis96x_get_mac_addr(pci_dev, net_dev); - else - ret = sis900_get_mac_addr(pci_dev, net_dev); - - if (ret == 0) { - printk(KERN_WARNING "%s: Cannot read MAC address.\n", net_dev->name); - ret = -ENODEV; - goto err_out_unregister; - } - - /* 630ET : set the mii access mode as software-mode */ - if (sis_priv->chipset_rev == SIS630ET_900_REV) - outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr); - - /* probe for mii transceiver */ - if (sis900_mii_probe(net_dev) == 0) { - printk(KERN_WARNING "%s: Error probing MII device.\n", net_dev->name); - ret = -ENODEV; - goto err_out_unregister; - } - - /* save our host bridge revision */ - dev = pci_get_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, NULL); - if (dev) { - pci_read_config_byte(dev, PCI_CLASS_REVISION, &sis_priv->host_bridge_rev); - pci_dev_put(dev); - } /* print some information about our NIC */ printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, @@ -523,8 +531,6 @@ static int __devinit sis900_probe(struct return 0; - err_out_unregister: - unregister_netdev(net_dev); err_unmap_rx: pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring, sis_priv->rx_ring_dma); _