Commit a8627f44 authored by Chris Wright's avatar Chris Wright Committed by Greg Kroah-Hartman

[PATCH] sis900 kernel oops fix

Backport of fix described below.

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

  Fix bug #4223.

  OK, 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.

  Anyway, 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
  before register_netdevice.

  Since the netdev name is not available before register_netdev, I've
  changed the relevant printk's to use pci_name instead.  Note that
  one of those printk's may be called after register_netdev as well.
Signed-off-by: default avatarChris Wright <chrisw@osdl.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e0e4e66b
...@@ -236,7 +236,7 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de ...@@ -236,7 +236,7 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de
signature = (u16) read_eeprom(ioaddr, EEPROMSignature); signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) { if (signature == 0xffff || signature == 0x0000) {
printk (KERN_INFO "%s: Error EERPOM read %x\n", printk (KERN_INFO "%s: Error EERPOM read %x\n",
net_dev->name, signature); pci_name(pci_dev), signature);
return 0; return 0;
} }
...@@ -268,7 +268,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev, ...@@ -268,7 +268,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev,
if (!isa_bridge) if (!isa_bridge)
isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge); isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0018, isa_bridge);
if (!isa_bridge) { if (!isa_bridge) {
printk("%s: Can not find ISA bridge\n", net_dev->name); printk("%s: Can not find ISA bridge\n", pci_name(pci_dev));
return 0; return 0;
} }
pci_read_config_byte(isa_bridge, 0x48, &reg); pci_read_config_byte(isa_bridge, 0x48, &reg);
...@@ -456,10 +456,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ...@@ -456,10 +456,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
net_dev->tx_timeout = sis900_tx_timeout; net_dev->tx_timeout = sis900_tx_timeout;
net_dev->watchdog_timeo = TX_TIMEOUT; net_dev->watchdog_timeo = TX_TIMEOUT;
net_dev->ethtool_ops = &sis900_ethtool_ops; net_dev->ethtool_ops = &sis900_ethtool_ops;
ret = register_netdev(net_dev);
if (ret)
goto err_unmap_rx;
/* Get Mac address according to the chip revision */ /* Get Mac address according to the chip revision */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision);
...@@ -476,7 +472,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ...@@ -476,7 +472,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
if (ret == 0) { if (ret == 0) {
ret = -ENODEV; ret = -ENODEV;
goto err_out_unregister; goto err_unmap_rx;
} }
/* 630ET : set the mii access mode as software-mode */ /* 630ET : set the mii access mode as software-mode */
...@@ -486,7 +482,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ...@@ -486,7 +482,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
/* probe for mii transceiver */ /* probe for mii transceiver */
if (sis900_mii_probe(net_dev) == 0) { if (sis900_mii_probe(net_dev) == 0) {
ret = -ENODEV; ret = -ENODEV;
goto err_out_unregister; goto err_unmap_rx;
} }
/* save our host bridge revision */ /* save our host bridge revision */
...@@ -496,6 +492,10 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ...@@ -496,6 +492,10 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
pci_dev_put(dev); pci_dev_put(dev);
} }
ret = register_netdev(net_dev);
if (ret)
goto err_unmap_rx;
/* print some information about our NIC */ /* print some information about our NIC */
printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name, printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
card_name, ioaddr, net_dev->irq); card_name, ioaddr, net_dev->irq);
...@@ -505,8 +505,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ...@@ -505,8 +505,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
return 0; return 0;
err_out_unregister:
unregister_netdev(net_dev);
err_unmap_rx: err_unmap_rx:
pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring, pci_free_consistent(pci_dev, RX_TOTAL_SIZE, sis_priv->rx_ring,
sis_priv->rx_ring_dma); sis_priv->rx_ring_dma);
...@@ -533,6 +531,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, ...@@ -533,6 +531,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
static int __init sis900_mii_probe(struct net_device * net_dev) static int __init sis900_mii_probe(struct net_device * net_dev)
{ {
struct sis900_private * sis_priv = net_dev->priv; struct sis900_private * sis_priv = net_dev->priv;
const char *dev_name = pci_name(sis_priv->pci_dev);
u16 poll_bit = MII_STAT_LINK, status = 0; u16 poll_bit = MII_STAT_LINK, status = 0;
unsigned long timeout = jiffies + 5 * HZ; unsigned long timeout = jiffies + 5 * HZ;
int phy_addr; int phy_addr;
...@@ -582,21 +581,20 @@ static int __init sis900_mii_probe(struct net_device * net_dev) ...@@ -582,21 +581,20 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
mii_phy->phy_types = mii_phy->phy_types =
(mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME; (mii_status & (MII_STAT_CAN_TX_FDX | MII_STAT_CAN_TX)) ? LAN : HOME;
printk(KERN_INFO "%s: %s transceiver found at address %d.\n", printk(KERN_INFO "%s: %s transceiver found at address %d.\n",
net_dev->name, mii_chip_table[i].name, dev_name, mii_chip_table[i].name,
phy_addr); phy_addr);
break; break;
} }
if( !mii_chip_table[i].phy_id1 ) { if( !mii_chip_table[i].phy_id1 ) {
printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n", printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
net_dev->name, phy_addr); dev_name, phy_addr);
mii_phy->phy_types = UNKNOWN; mii_phy->phy_types = UNKNOWN;
} }
} }
if (sis_priv->mii == NULL) { if (sis_priv->mii == NULL) {
printk(KERN_INFO "%s: No MII transceivers found!\n", printk(KERN_INFO "%s: No MII transceivers found!\n", dev_name);
net_dev->name);
return 0; return 0;
} }
...@@ -621,7 +619,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev) ...@@ -621,7 +619,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit); poll_bit ^= (mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS) & poll_bit);
if (time_after_eq(jiffies, timeout)) { if (time_after_eq(jiffies, timeout)) {
printk(KERN_WARNING "%s: reset phy and link down now\n", printk(KERN_WARNING "%s: reset phy and link down now\n",
net_dev->name); dev_name);
return -ETIME; return -ETIME;
} }
} }
...@@ -691,7 +689,7 @@ static u16 sis900_default_phy(struct net_device * net_dev) ...@@ -691,7 +689,7 @@ static u16 sis900_default_phy(struct net_device * net_dev)
sis_priv->mii = default_phy; sis_priv->mii = default_phy;
sis_priv->cur_phy = default_phy->phy_addr; sis_priv->cur_phy = default_phy->phy_addr;
printk(KERN_INFO "%s: Using transceiver found at address %d as default\n", printk(KERN_INFO "%s: Using transceiver found at address %d as default\n",
net_dev->name,sis_priv->cur_phy); pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
} }
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL); status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment