diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2006-02-22 23:47:58 (GMT) |
---|---|---|
committer | Francois Romieu <romieu@fr.zoreil.com> | 2006-02-23 22:06:07 (GMT) |
commit | 5d06a99f543e734ceb53bbc9e550537be97f0c49 (patch) | |
tree | 7b8112f808f59ecde35b3de9900b1221e9aeb162 | |
parent | 791917deb63c6d8beb3f347ea0911371deff1624 (diff) | |
download | linux-5d06a99f543e734ceb53bbc9e550537be97f0c49.tar.xz |
r8169: fix broken ring index handling in suspend/resume
rtl8169_hw_start() requires that the descriptor ring indexes be
set to zero. Let a deferred invocation of rtl8169_reset_task()
handle it. Enabling a few power management bits will not hurt
either.
suspend/resume is issued with irq on: the spinlock do not need
to save the irq flag.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
-rw-r--r-- | drivers/net/r8169.c | 102 |
1 files changed, 59 insertions, 43 deletions
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 6e10184..999fd6c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -287,6 +287,12 @@ enum RTL8169_register_content { TxInterFrameGapShift = 24, TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + /* Config1 register p.24 */ + PMEnable = (1 << 0), /* Power Management Enable */ + + /* Config5 register p.27 */ + PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ + /* TBICSR p.28 */ TBIReset = 0x80000000, TBILoopback = 0x40000000, @@ -1442,6 +1448,11 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, } tp->chipset = i; + RTL_W8(Cfg9346, Cfg9346_Unlock); + RTL_W8(Config1, RTL_R8(Config1) | PMEnable); + RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); + RTL_W8(Cfg9346, Cfg9346_Lock); + *ioaddr_out = ioaddr; *dev_out = dev; out: @@ -1612,49 +1623,6 @@ rtl8169_remove_one(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } -#ifdef CONFIG_PM - -static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = netdev_priv(dev); - void __iomem *ioaddr = tp->mmio_addr; - unsigned long flags; - - if (!netif_running(dev)) - return 0; - - netif_device_detach(dev); - netif_stop_queue(dev); - spin_lock_irqsave(&tp->lock, flags); - - /* Disable interrupts, stop Rx and Tx */ - RTL_W16(IntrMask, 0); - RTL_W8(ChipCmd, 0); - - /* Update the error counts. */ - tp->stats.rx_missed_errors += RTL_R32(RxMissed); - RTL_W32(RxMissed, 0); - spin_unlock_irqrestore(&tp->lock, flags); - - return 0; -} - -static int rtl8169_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (!netif_running(dev)) - return 0; - - netif_device_attach(dev); - rtl8169_hw_start(dev); - - return 0; -} - -#endif /* CONFIG_PM */ - static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, struct net_device *dev) { @@ -2700,6 +2668,54 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) return &tp->stats; } +#ifdef CONFIG_PM + +static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + + if (!netif_running(dev)) + goto out; + + netif_device_detach(dev); + netif_stop_queue(dev); + + spin_lock_irq(&tp->lock); + + rtl8169_asic_down(ioaddr); + + tp->stats.rx_missed_errors += RTL_R32(RxMissed); + RTL_W32(RxMissed, 0); + + spin_unlock_irq(&tp->lock); + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); +out: + return 0; +} + +static int rtl8169_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (!netif_running(dev)) + goto out; + + netif_device_attach(dev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + rtl8169_schedule_work(dev, rtl8169_reset_task); +out: + return 0; +} + +#endif /* CONFIG_PM */ + static struct pci_driver rtl8169_pci_driver = { .name = MODULENAME, .id_table = rtl8169_pci_tbl, |