diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2006-02-22 18:47:58 -0500 |
---|---|---|
committer | Francois Romieu <romieu@fr.zoreil.com> | 2006-02-23 17:06:07 -0500 |
commit | 5d06a99f543e734ceb53bbc9e550537be97f0c49 (patch) | |
tree | 7b8112f808f59ecde35b3de9900b1221e9aeb162 | |
parent | 791917deb63c6d8beb3f347ea0911371deff1624 (diff) |
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 6e1018448eea..999fd6cef77e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -287,6 +287,12 @@ enum RTL8169_register_content { | |||
287 | TxInterFrameGapShift = 24, | 287 | TxInterFrameGapShift = 24, |
288 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ | 288 | TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ |
289 | 289 | ||
290 | /* Config1 register p.24 */ | ||
291 | PMEnable = (1 << 0), /* Power Management Enable */ | ||
292 | |||
293 | /* Config5 register p.27 */ | ||
294 | PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */ | ||
295 | |||
290 | /* TBICSR p.28 */ | 296 | /* TBICSR p.28 */ |
291 | TBIReset = 0x80000000, | 297 | TBIReset = 0x80000000, |
292 | TBILoopback = 0x40000000, | 298 | TBILoopback = 0x40000000, |
@@ -1442,6 +1448,11 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out, | |||
1442 | } | 1448 | } |
1443 | tp->chipset = i; | 1449 | tp->chipset = i; |
1444 | 1450 | ||
1451 | RTL_W8(Cfg9346, Cfg9346_Unlock); | ||
1452 | RTL_W8(Config1, RTL_R8(Config1) | PMEnable); | ||
1453 | RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); | ||
1454 | RTL_W8(Cfg9346, Cfg9346_Lock); | ||
1455 | |||
1445 | *ioaddr_out = ioaddr; | 1456 | *ioaddr_out = ioaddr; |
1446 | *dev_out = dev; | 1457 | *dev_out = dev; |
1447 | out: | 1458 | out: |
@@ -1612,49 +1623,6 @@ rtl8169_remove_one(struct pci_dev *pdev) | |||
1612 | pci_set_drvdata(pdev, NULL); | 1623 | pci_set_drvdata(pdev, NULL); |
1613 | } | 1624 | } |
1614 | 1625 | ||
1615 | #ifdef CONFIG_PM | ||
1616 | |||
1617 | static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1618 | { | ||
1619 | struct net_device *dev = pci_get_drvdata(pdev); | ||
1620 | struct rtl8169_private *tp = netdev_priv(dev); | ||
1621 | void __iomem *ioaddr = tp->mmio_addr; | ||
1622 | unsigned long flags; | ||
1623 | |||
1624 | if (!netif_running(dev)) | ||
1625 | return 0; | ||
1626 | |||
1627 | netif_device_detach(dev); | ||
1628 | netif_stop_queue(dev); | ||
1629 | spin_lock_irqsave(&tp->lock, flags); | ||
1630 | |||
1631 | /* Disable interrupts, stop Rx and Tx */ | ||
1632 | RTL_W16(IntrMask, 0); | ||
1633 | RTL_W8(ChipCmd, 0); | ||
1634 | |||
1635 | /* Update the error counts. */ | ||
1636 | tp->stats.rx_missed_errors += RTL_R32(RxMissed); | ||
1637 | RTL_W32(RxMissed, 0); | ||
1638 | spin_unlock_irqrestore(&tp->lock, flags); | ||
1639 | |||
1640 | return 0; | ||
1641 | } | ||
1642 | |||
1643 | static int rtl8169_resume(struct pci_dev *pdev) | ||
1644 | { | ||
1645 | struct net_device *dev = pci_get_drvdata(pdev); | ||
1646 | |||
1647 | if (!netif_running(dev)) | ||
1648 | return 0; | ||
1649 | |||
1650 | netif_device_attach(dev); | ||
1651 | rtl8169_hw_start(dev); | ||
1652 | |||
1653 | return 0; | ||
1654 | } | ||
1655 | |||
1656 | #endif /* CONFIG_PM */ | ||
1657 | |||
1658 | static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, | 1626 | static void rtl8169_set_rxbufsize(struct rtl8169_private *tp, |
1659 | struct net_device *dev) | 1627 | struct net_device *dev) |
1660 | { | 1628 | { |
@@ -2700,6 +2668,54 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev) | |||
2700 | return &tp->stats; | 2668 | return &tp->stats; |
2701 | } | 2669 | } |
2702 | 2670 | ||
2671 | #ifdef CONFIG_PM | ||
2672 | |||
2673 | static int rtl8169_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2674 | { | ||
2675 | struct net_device *dev = pci_get_drvdata(pdev); | ||
2676 | struct rtl8169_private *tp = netdev_priv(dev); | ||
2677 | void __iomem *ioaddr = tp->mmio_addr; | ||
2678 | |||
2679 | if (!netif_running(dev)) | ||
2680 | goto out; | ||
2681 | |||
2682 | netif_device_detach(dev); | ||
2683 | netif_stop_queue(dev); | ||
2684 | |||
2685 | spin_lock_irq(&tp->lock); | ||
2686 | |||
2687 | rtl8169_asic_down(ioaddr); | ||
2688 | |||
2689 | tp->stats.rx_missed_errors += RTL_R32(RxMissed); | ||
2690 | RTL_W32(RxMissed, 0); | ||
2691 | |||
2692 | spin_unlock_irq(&tp->lock); | ||
2693 | |||
2694 | pci_save_state(pdev); | ||
2695 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
2696 | out: | ||
2697 | return 0; | ||
2698 | } | ||
2699 | |||
2700 | static int rtl8169_resume(struct pci_dev *pdev) | ||
2701 | { | ||
2702 | struct net_device *dev = pci_get_drvdata(pdev); | ||
2703 | |||
2704 | if (!netif_running(dev)) | ||
2705 | goto out; | ||
2706 | |||
2707 | netif_device_attach(dev); | ||
2708 | |||
2709 | pci_set_power_state(pdev, PCI_D0); | ||
2710 | pci_restore_state(pdev); | ||
2711 | |||
2712 | rtl8169_schedule_work(dev, rtl8169_reset_task); | ||
2713 | out: | ||
2714 | return 0; | ||
2715 | } | ||
2716 | |||
2717 | #endif /* CONFIG_PM */ | ||
2718 | |||
2703 | static struct pci_driver rtl8169_pci_driver = { | 2719 | static struct pci_driver rtl8169_pci_driver = { |
2704 | .name = MODULENAME, | 2720 | .name = MODULENAME, |
2705 | .id_table = rtl8169_pci_tbl, | 2721 | .id_table = rtl8169_pci_tbl, |