From: Herbert Xu <herbert@gondor.apana.org.au>

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 <herbert@gondor.apana.org.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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);
_