CHROMIUM: r8169: transition to D0 state at shutdown
authorSameer Nanda <snanda@chromium.org>
Sat, 26 May 2012 00:37:27 +0000 (17:37 -0700)
committerOlof Johansson <olof@lixom.net>
Fri, 1 Jun 2012 06:56:26 +0000 (23:56 -0700)
With runtime PM, if the ethernet cable is disconnected, the device is
transitioned to D3 state to conserve energy. If the system is shutdown
in this state, any register accesses in rtl_shutdown are dropped on
the floor.

This patch transitions the device back to D0 state in rtl_shutdown if
the device was runtime PM suspended. In addition, since runtime PM
also mucks around with WOL options, the saved WOL options are also
restored in rtl_shutdown.

BUG=chrome-os-partner:7026
TEST=Don't have a good black box test case. It can be tested by
modifying the driver to verify that register accesses in
rtl_shutdown go through with the cable disconnected.

Change-Id: Ic08f2c3fed22a4b1a876dc3816565156b464ec78
Signed-off-by: Sameer Nanda <snanda@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/15832
Reviewed-by: Olof Johansson <olofj@chromium.org>
Reviewed-by: Todd Broch <tbroch@chromium.org>
drivers/net/ethernet/realtek/r8169.c

index 3e3497e..3fabaf9 100644 (file)
@@ -704,6 +704,7 @@ struct rtl8169_private {
        u16 cp_cmd;
 
        u16 event_slow;
+       bool runtime_suspended;
 
        struct mdio_ops {
                void (*write)(void __iomem *, int, int);
@@ -5724,6 +5725,7 @@ static int rtl_open(struct net_device *dev)
        rtl_unlock_work(tp);
 
        tp->saved_wolopts = 0;
+       tp->runtime_suspended = false;
        pm_runtime_put_noidle(&pdev->dev);
 
        rtl8169_check_link_status(dev, tp, ioaddr);
@@ -5852,6 +5854,7 @@ static int rtl8169_runtime_suspend(struct device *device)
        rtl_lock_work(tp);
        tp->saved_wolopts = __rtl8169_get_wol(tp);
        __rtl8169_set_wol(tp, WAKE_ANY);
+       tp->runtime_suspended = true;
        rtl_unlock_work(tp);
 
        rtl8169_net_suspend(dev);
@@ -5871,6 +5874,7 @@ static int rtl8169_runtime_resume(struct device *device)
        rtl_lock_work(tp);
        __rtl8169_set_wol(tp, tp->saved_wolopts);
        tp->saved_wolopts = 0;
+       tp->runtime_suspended = false;
        rtl_unlock_work(tp);
 
        rtl8169_init_phy(dev, tp);
@@ -5938,6 +5942,10 @@ static void rtl_shutdown(struct pci_dev *pdev)
 
        pm_runtime_get_sync(d);
 
+       /* Get the device back to D0 state if it was runtime suspended. */
+       if (tp->runtime_suspended)
+               pci_set_power_state(pdev, PCI_D0);
+
        rtl8169_net_suspend(dev);
 
        /* Restore original MAC address */
@@ -5945,6 +5953,10 @@ static void rtl_shutdown(struct pci_dev *pdev)
 
        rtl8169_hw_reset(tp);
 
+       /* Restore WOL flags if they were messed around with. */
+       if (tp->saved_wolopts)
+               __rtl8169_set_wol(tp, tp->saved_wolopts);
+
        if (system_state == SYSTEM_POWER_OFF) {
                if (__rtl8169_get_wol(tp) & WAKE_ANY) {
                        rtl_wol_suspend_quirk(tp);