r8169: fix broken ring index handling in suspend/resume
authorFrancois Romieu <romieu@fr.zoreil.com>
Wed, 22 Feb 2006 23:47:58 +0000 (00:47 +0100)
committerFrancois Romieu <romieu@fr.zoreil.com>
Thu, 23 Feb 2006 22:06:07 +0000 (23:06 +0100)
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>
drivers/net/r8169.c

index 6e1018448eea9b00a21215d3b284933ffab836a1..999fd6cef77eebc17de2e20e7be5098f4ec39ce3 100644 (file)
@@ -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,