Skip to content

Commit

Permalink
r8169: fix broken ring index handling in suspend/resume
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Francois Romieu committed Feb 23, 2006
1 parent 791917d commit 5d06a99
Showing 1 changed file with 59 additions and 43 deletions.
102 changes: 59 additions & 43 deletions drivers/net/r8169.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 5d06a99

Please sign in to comment.