diff options
Diffstat (limited to 'drivers/net/ethernet/intel/e1000e/netdev.c')
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/netdev.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 4fa6f9f7d199..27107a927455 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6481,8 +6481,10 @@ static void e1000e_s0ix_entry_flow(struct e1000_adapter *adapter) static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; + bool firmware_bug = false; u32 mac_data; u16 phy_data; + u32 i = 0; if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { /* Request ME unconfigure the device from S0ix */ @@ -6490,6 +6492,28 @@ static void e1000e_s0ix_exit_flow(struct e1000_adapter *adapter) mac_data &= ~E1000_H2ME_START_DPG; mac_data |= E1000_H2ME_EXIT_DPG; ew32(H2ME, mac_data); + + /* Poll up to 2.5 seconds for ME to unconfigure DPG. + * If this takes more than 1 second, show a warning indicating a + * firmware bug + */ + while (!(er32(EXFWSM) & E1000_EXFWSM_DPG_EXIT_DONE)) { + if (i > 100 && !firmware_bug) + firmware_bug = true; + + if (i++ == 250) { + e_dbg("Timeout (firmware bug): %d msec\n", + i * 10); + break; + } + + usleep_range(10000, 11000); + } + if (firmware_bug) + e_warn("DPG_EXIT_DONE took %d msec. This is a firmware bug\n", + i * 10); + else + e_dbg("DPG_EXIT_DONE cleared after %d msec\n", i * 10); } else { /* Request driver unconfigure the device from S0ix */ |