e1000e: PCIm function state support
authorVitaly Lifshits <vitaly.lifshits@intel.com>
Tue, 25 Jun 2019 14:39:11 +0000 (17:39 +0300)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 28 Jun 2019 23:00:28 +0000 (16:00 -0700)
Due to commit: 5d8682588605 ("[misc] mei: me: allow runtime
pm for platform with D0i3")
When disconnecting the cable and reconnecting it the NIC
enters DMoff state. This caused wrong link indication
and duplex mismatch. This bug is described in:
https://bugzilla.redhat.com/show_bug.cgi?id=1689436

Checking PCIm function state and performing PHY reset after a
timeout in watchdog task solves this issue.

Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
Acked-by: Sasha Neftin <sasha.neftin@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/netdev.c

index fd550dee498200502f0940ffb1dd88daa12b22b8..63c3c79380a1b6975f789c7d65410a0537ba752e 100644 (file)
 #define E1000_STATUS_PHYRA      0x00000400      /* PHY Reset Asserted */
 #define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000      /* Master Req status */
 
+/* PCIm function state */
+#define E1000_STATUS_PCIM_STATE        0x40000000
+
 #define HALF_DUPLEX 1
 #define FULL_DUPLEX 2
 
index b5fed6177ad6215fc087a26dd9c4f4f65a8af941..e4baa13b3cda95c123c2a8eaeda396f0de3583e7 100644 (file)
@@ -5161,8 +5161,9 @@ static void e1000_watchdog_task(struct work_struct *work)
        struct e1000_mac_info *mac = &adapter->hw.mac;
        struct e1000_phy_info *phy = &adapter->hw.phy;
        struct e1000_ring *tx_ring = adapter->tx_ring;
+       u32 dmoff_exit_timeout = 100, tries = 0;
        struct e1000_hw *hw = &adapter->hw;
-       u32 link, tctl;
+       u32 link, tctl, pcim_state;
 
        if (test_bit(__E1000_DOWN, &adapter->state))
                return;
@@ -5187,6 +5188,21 @@ static void e1000_watchdog_task(struct work_struct *work)
                        /* Cancel scheduled suspend requests. */
                        pm_runtime_resume(netdev->dev.parent);
 
+                       /* Checking if MAC is in DMoff state*/
+                       pcim_state = er32(STATUS);
+                       while (pcim_state & E1000_STATUS_PCIM_STATE) {
+                               if (tries++ == dmoff_exit_timeout) {
+                                       e_dbg("Error in exiting dmoff\n");
+                                       break;
+                               }
+                               usleep_range(10000, 20000);
+                               pcim_state = er32(STATUS);
+
+                               /* Checking if MAC exited DMoff state */
+                               if (!(pcim_state & E1000_STATUS_PCIM_STATE))
+                                       e1000_phy_hw_reset(&adapter->hw);
+                       }
+
                        /* update snapshot of PHY registers on LSC */
                        e1000_phy_read_status(adapter);
                        mac->ops.get_link_up_info(&adapter->hw,