Commit 5d06a99f authored by Francois Romieu's avatar Francois Romieu

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: default avatarFrancois Romieu <romieu@fr.zoreil.com>
parent 791917de
......@@ -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,
......
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