r8169: Fix runtime power management
I noticed that one of the post-2.6.36 patches broke runtime PM of the r8169 on my MSI Wind test machine in such a way that the link was not brought up after reconnecting the network cable. In the process of debugging the issue I realized that we only should invoke the runtime PM functions in rtl8169_check_link_status() when link change is reported and if we do so, the problem goes away. Moreover, this allows rtl8169_runtime_idle() to be simplified quite a bit. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Francois Romieu <romieu@fr.zoreil.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6934d33556
commit
e4fbce740f
1 changed files with 16 additions and 10 deletions
|
@ -744,26 +744,36 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
|
|||
mdio_write(ioaddr, MII_BMCR, val & 0xffff);
|
||||
}
|
||||
|
||||
static void rtl8169_check_link_status(struct net_device *dev,
|
||||
static void __rtl8169_check_link_status(struct net_device *dev,
|
||||
struct rtl8169_private *tp,
|
||||
void __iomem *ioaddr)
|
||||
void __iomem *ioaddr,
|
||||
bool pm)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
if (tp->link_ok(ioaddr)) {
|
||||
/* This is to cancel a scheduled suspend if there's one. */
|
||||
pm_request_resume(&tp->pci_dev->dev);
|
||||
if (pm)
|
||||
pm_request_resume(&tp->pci_dev->dev);
|
||||
netif_carrier_on(dev);
|
||||
netif_info(tp, ifup, dev, "link up\n");
|
||||
} else {
|
||||
netif_carrier_off(dev);
|
||||
netif_info(tp, ifdown, dev, "link down\n");
|
||||
pm_schedule_suspend(&tp->pci_dev->dev, 100);
|
||||
if (pm)
|
||||
pm_schedule_suspend(&tp->pci_dev->dev, 100);
|
||||
}
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
}
|
||||
|
||||
static void rtl8169_check_link_status(struct net_device *dev,
|
||||
struct rtl8169_private *tp,
|
||||
void __iomem *ioaddr)
|
||||
{
|
||||
__rtl8169_check_link_status(dev, tp, ioaddr, false);
|
||||
}
|
||||
|
||||
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
|
||||
|
||||
static u32 __rtl8169_get_wol(struct rtl8169_private *tp)
|
||||
|
@ -4600,7 +4610,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
|
|||
}
|
||||
|
||||
if (status & LinkChg)
|
||||
rtl8169_check_link_status(dev, tp, ioaddr);
|
||||
__rtl8169_check_link_status(dev, tp, ioaddr, true);
|
||||
|
||||
/* We need to see the lastest version of tp->intr_mask to
|
||||
* avoid ignoring an MSI interrupt and having to wait for
|
||||
|
@ -4890,11 +4900,7 @@ static int rtl8169_runtime_idle(struct device *device)
|
|||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct rtl8169_private *tp = netdev_priv(dev);
|
||||
|
||||
if (!tp->TxDescArray)
|
||||
return 0;
|
||||
|
||||
rtl8169_check_link_status(dev, tp, tp->mmio_addr);
|
||||
return -EBUSY;
|
||||
return tp->TxDescArray ? -EBUSY : 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops rtl8169_pm_ops = {
|
||||
|
|
Loading…
Reference in a new issue