Commit 71b2f5a8 authored by Manfred Spraul's avatar Manfred Spraul Committed by Jeff Garzik

drivers/net/natsemi.c: stop abusing netdev_device_{de,a}ttach

parent a5953cb3
...@@ -124,6 +124,8 @@ ...@@ -124,6 +124,8 @@
* create a function for rx refill (Manfred Spraul) * create a function for rx refill (Manfred Spraul)
* combine drain_ring and init_ring (Manfred Spraul) * combine drain_ring and init_ring (Manfred Spraul)
* oom handling (Manfred Spraul) * oom handling (Manfred Spraul)
* hands_off instead of playing with netif_device_{de,a}ttach
(Manfred Spraul)
TODO: TODO:
* big endian support with CFG:BEM instead of cpu_to_le32 * big endian support with CFG:BEM instead of cpu_to_le32
...@@ -648,6 +650,7 @@ struct netdev_private { ...@@ -648,6 +650,7 @@ struct netdev_private {
unsigned int cur_tx, dirty_tx; unsigned int cur_tx, dirty_tx;
unsigned int rx_buf_sz; /* Based on MTU+slack. */ unsigned int rx_buf_sz; /* Based on MTU+slack. */
int oom; int oom;
int hands_off; /* Do not touch the nic registers */
/* These values are keep track of the transceiver/media in use. */ /* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex; unsigned int full_duplex;
/* Rx filter. */ /* Rx filter. */
...@@ -791,6 +794,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, ...@@ -791,6 +794,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np->iosize = iosize; np->iosize = iosize;
spin_lock_init(&np->lock); spin_lock_init(&np->lock);
np->msg_enable = debug; np->msg_enable = debug;
np->hands_off = 0;
/* Reset the chip to erase previous misconfiguration. */ /* Reset the chip to erase previous misconfiguration. */
natsemi_reload_eeprom(dev); natsemi_reload_eeprom(dev);
...@@ -1396,7 +1400,7 @@ static void tx_timeout(struct net_device *dev) ...@@ -1396,7 +1400,7 @@ static void tx_timeout(struct net_device *dev)
disable_irq(dev->irq); disable_irq(dev->irq);
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
if (netif_device_present(dev)) { if (!np->hands_off) {
if (netif_msg_tx_err(np)) if (netif_msg_tx_err(np))
printk(KERN_WARNING printk(KERN_WARNING
"%s: Transmit timed out, status %#08x," "%s: Transmit timed out, status %#08x,"
...@@ -1409,7 +1413,7 @@ static void tx_timeout(struct net_device *dev) ...@@ -1409,7 +1413,7 @@ static void tx_timeout(struct net_device *dev)
init_registers(dev); init_registers(dev);
} else { } else {
printk(KERN_WARNING printk(KERN_WARNING
"%s: tx_timeout while in suspended state?\n", "%s: tx_timeout while in hands_off state?\n",
dev->name); dev->name);
} }
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
...@@ -1584,7 +1588,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -1584,7 +1588,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
if (netif_device_present(dev)) { if (!np->hands_off) {
np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len); np->tx_ring[entry].cmd_status = cpu_to_le32(DescOwn | skb->len);
/* StrongARM: Explicitly cache flush np->tx_ring and /* StrongARM: Explicitly cache flush np->tx_ring and
* skb->data,skb->len. */ * skb->data,skb->len. */
...@@ -1663,15 +1667,15 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) ...@@ -1663,15 +1667,15 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
int boguscnt = max_interrupt_work; int boguscnt = max_interrupt_work;
if (!netif_device_present(dev)) if (np->hands_off)
return; return;
do { do {
/* Reading automatically acknowledges all int sources. */ /* Reading automatically acknowledges all int sources. */
u32 intr_status = readl(ioaddr + IntrStatus); u32 intr_status = readl(ioaddr + IntrStatus);
if (netif_msg_intr(np)) if (netif_msg_intr(np))
printk(KERN_DEBUG "%s: Interrupt, status %#08x.\n", printk(KERN_DEBUG "%s: Interrupt, status %#08x, mask %#08x.\n",
dev->name, intr_status); dev->name, intr_status, readl(ioaddr + IntrMask));
if (intr_status == 0) if (intr_status == 0)
break; break;
...@@ -1863,7 +1867,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) ...@@ -1863,7 +1867,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
/* The chip only need report frame silently dropped. */ /* The chip only need report frame silently dropped. */
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
if (netif_running(dev) && netif_device_present(dev)) if (netif_running(dev) && !np->hands_off)
__get_stats(dev); __get_stats(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
...@@ -1951,7 +1955,7 @@ static void set_rx_mode(struct net_device *dev) ...@@ -1951,7 +1955,7 @@ static void set_rx_mode(struct net_device *dev)
{ {
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
if (netif_device_present(dev)) if (!np->hands_off)
__set_rx_mode(dev); __set_rx_mode(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
} }
...@@ -2478,9 +2482,6 @@ static int netdev_close(struct net_device *dev) ...@@ -2478,9 +2482,6 @@ static int netdev_close(struct net_device *dev)
long ioaddr = dev->base_addr; long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv; struct netdev_private *np = dev->priv;
netif_stop_queue(dev);
netif_carrier_off(dev);
if (netif_msg_ifdown(np)) if (netif_msg_ifdown(np))
printk(KERN_DEBUG printk(KERN_DEBUG
"%s: Shutting down ethercard, status was %#04x.\n", "%s: Shutting down ethercard, status was %#04x.\n",
...@@ -2491,13 +2492,31 @@ static int netdev_close(struct net_device *dev) ...@@ -2491,13 +2492,31 @@ static int netdev_close(struct net_device *dev)
dev->name, np->cur_tx, np->dirty_tx, dev->name, np->cur_tx, np->dirty_tx,
np->cur_rx, np->dirty_rx); np->cur_rx, np->dirty_rx);
del_timer_sync(&np->timer); /*
* FIXME: what if someone tries to close a device
* that is suspended?
* Should we reenable the nic to switch to
* the final WOL settings?
*/
del_timer_sync(&np->timer);
disable_irq(dev->irq); disable_irq(dev->irq);
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
/* Disable interrupts, and flush posted writes */
/* Disable and clear interrupts */
writel(0, ioaddr + IntrEnable); writel(0, ioaddr + IntrEnable);
readl(ioaddr + IntrEnable);
np->hands_off = 1;
spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
free_irq(dev->irq, dev);
/* Interrupt disabled, interrupt handler released,
* queue stopped, timer deleted, rtnl_lock held
* All async codepaths that access the driver are disabled.
*/
spin_lock_irq(&np->lock);
np->hands_off = 0;
readl(ioaddr + IntrMask); readl(ioaddr + IntrMask);
readw(ioaddr + MIntrStatus); readw(ioaddr + MIntrStatus);
...@@ -2510,19 +2529,9 @@ static int netdev_close(struct net_device *dev) ...@@ -2510,19 +2529,9 @@ static int netdev_close(struct net_device *dev)
__get_stats(dev); __get_stats(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
/* race: shared irq and as most nics the DP83815
* reports _all_ interrupt conditions in IntrStatus, even
* disabled ones.
* packet received after disable_irq, but before stop_rxtx
* --> race. intr_handler would restart the rx process.
* netif_device_{de,a}tach around {enable,free}_irq.
*/
netif_device_detach(dev);
enable_irq(dev->irq);
free_irq(dev->irq, dev);
netif_device_attach(dev);
/* clear the carrier last - an interrupt could reenable it otherwise */ /* clear the carrier last - an interrupt could reenable it otherwise */
netif_carrier_off(dev); netif_carrier_off(dev);
netif_stop_queue(dev);
dump_ring(dev); dump_ring(dev);
drain_ring(dev); drain_ring(dev);
...@@ -2591,9 +2600,9 @@ static int natsemi_suspend (struct pci_dev *pdev, u32 state) ...@@ -2591,9 +2600,9 @@ static int natsemi_suspend (struct pci_dev *pdev, u32 state)
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
writel(0, ioaddr + IntrEnable); writel(0, ioaddr + IntrEnable);
np->hands_off = 1;
natsemi_stop_rxtx(dev); natsemi_stop_rxtx(dev);
netif_stop_queue(dev); netif_stop_queue(dev);
netif_device_detach(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
enable_irq(dev->irq); enable_irq(dev->irq);
...@@ -2617,9 +2626,8 @@ static int natsemi_suspend (struct pci_dev *pdev, u32 state) ...@@ -2617,9 +2626,8 @@ static int natsemi_suspend (struct pci_dev *pdev, u32 state)
writel(np->SavedClkRun, ioaddr + ClkRun); writel(np->SavedClkRun, ioaddr + ClkRun);
} }
} }
} else {
netif_device_detach(dev);
} }
netif_device_detach(dev);
rtnl_unlock(); rtnl_unlock();
return 0; return 0;
} }
...@@ -2634,20 +2642,23 @@ static int natsemi_resume (struct pci_dev *pdev) ...@@ -2634,20 +2642,23 @@ static int natsemi_resume (struct pci_dev *pdev)
if (netif_device_present(dev)) if (netif_device_present(dev))
goto out; goto out;
if (netif_running(dev)) { if (netif_running(dev)) {
BUG_ON(!np->hands_off);
pci_enable_device(pdev); pci_enable_device(pdev);
/* pci_power_on(pdev); */ /* pci_power_on(pdev); */
natsemi_reset(dev); natsemi_reset(dev);
init_ring(dev); init_ring(dev);
disable_irq(dev->irq);
spin_lock_irq(&np->lock); spin_lock_irq(&np->lock);
np->hands_off = 0;
init_registers(dev); init_registers(dev);
netif_device_attach(dev); netif_device_attach(dev);
spin_unlock_irq(&np->lock); spin_unlock_irq(&np->lock);
enable_irq(dev->irq);
mod_timer(&np->timer, jiffies + 1*HZ); mod_timer(&np->timer, jiffies + 1*HZ);
} else {
netif_device_attach(dev);
} }
netif_device_attach(dev);
out: out:
rtnl_unlock(); rtnl_unlock();
return 0; return 0;
......
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