diff options
author | Bruce Allan <bruce.w.allan@intel.com> | 2011-05-13 03:19:48 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-06-09 23:31:49 -0400 |
commit | 99730e4c13c8344b02dd96108945b48d28c14c25 (patch) | |
tree | 36ae5f5c6bf0804f45dfb387931f88d11f7bc400 /drivers/net/e1000e | |
parent | d9b24135b972ccdd5f5174fba06c730e895e6daf (diff) |
e1000e: 82579 intermittently disabled during S0->Sx
When repeatedly cycling Sx->S0 states with the network cable unplugged,
the 82579 PHY may not initialize as expected and may require a full power
cycle to recover functionality to the device. Workaround this by testing
access of the PHY registers after resuming; if that returns unexpected
results toggle the LANPHYPC signal to power cycle the PHY.
This is implemented in the new function e1000_resume_workarounds_pchlan()
which calls another new function, e1000_toggle_lanphypc_value_ich8lan(),
which has been created to reduce code duplication (same functionality
required by a previous workaround). Also, e1000e_disable_gig_wol_ich8lan
is now e1000_suspend_workarounds_ich8lan to better reflect what it does.
Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/e1000e')
-rw-r--r-- | drivers/net/e1000e/e1000.h | 3 | ||||
-rw-r--r-- | drivers/net/e1000e/ich8lan.c | 86 | ||||
-rw-r--r-- | drivers/net/e1000e/netdev.c | 5 |
3 files changed, 79 insertions, 15 deletions
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index 9549879e66a0..f8cd56a1ade0 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h | |||
@@ -533,7 +533,8 @@ extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, | |||
533 | bool state); | 533 | bool state); |
534 | extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); | 534 | extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); |
535 | extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); | 535 | extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); |
536 | extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); | 536 | extern void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw); |
537 | extern void e1000_resume_workarounds_pchlan(struct e1000_hw *hw); | ||
537 | extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); | 538 | extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); |
538 | extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); | 539 | extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); |
539 | extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw); | 540 | extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw); |
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index 3369d1f6a39c..dcd5db5e34e5 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c | |||
@@ -275,6 +275,19 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) | |||
275 | #define ew16flash(reg,val) __ew16flash(hw, (reg), (val)) | 275 | #define ew16flash(reg,val) __ew16flash(hw, (reg), (val)) |
276 | #define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) | 276 | #define ew32flash(reg,val) __ew32flash(hw, (reg), (val)) |
277 | 277 | ||
278 | static void e1000_toggle_lanphypc_value_ich8lan(struct e1000_hw *hw) | ||
279 | { | ||
280 | u32 ctrl; | ||
281 | |||
282 | ctrl = er32(CTRL); | ||
283 | ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; | ||
284 | ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; | ||
285 | ew32(CTRL, ctrl); | ||
286 | udelay(10); | ||
287 | ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; | ||
288 | ew32(CTRL, ctrl); | ||
289 | } | ||
290 | |||
278 | /** | 291 | /** |
279 | * e1000_init_phy_params_pchlan - Initialize PHY function pointers | 292 | * e1000_init_phy_params_pchlan - Initialize PHY function pointers |
280 | * @hw: pointer to the HW structure | 293 | * @hw: pointer to the HW structure |
@@ -284,7 +297,7 @@ static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) | |||
284 | static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) | 297 | static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) |
285 | { | 298 | { |
286 | struct e1000_phy_info *phy = &hw->phy; | 299 | struct e1000_phy_info *phy = &hw->phy; |
287 | u32 ctrl, fwsm; | 300 | u32 fwsm; |
288 | s32 ret_val = 0; | 301 | s32 ret_val = 0; |
289 | 302 | ||
290 | phy->addr = 1; | 303 | phy->addr = 1; |
@@ -308,13 +321,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) | |||
308 | */ | 321 | */ |
309 | fwsm = er32(FWSM); | 322 | fwsm = er32(FWSM); |
310 | if (!(fwsm & E1000_ICH_FWSM_FW_VALID) && !e1000_check_reset_block(hw)) { | 323 | if (!(fwsm & E1000_ICH_FWSM_FW_VALID) && !e1000_check_reset_block(hw)) { |
311 | ctrl = er32(CTRL); | 324 | e1000_toggle_lanphypc_value_ich8lan(hw); |
312 | ctrl |= E1000_CTRL_LANPHYPC_OVERRIDE; | ||
313 | ctrl &= ~E1000_CTRL_LANPHYPC_VALUE; | ||
314 | ew32(CTRL, ctrl); | ||
315 | udelay(10); | ||
316 | ctrl &= ~E1000_CTRL_LANPHYPC_OVERRIDE; | ||
317 | ew32(CTRL, ctrl); | ||
318 | msleep(50); | 325 | msleep(50); |
319 | 326 | ||
320 | /* | 327 | /* |
@@ -3586,17 +3593,16 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) | |||
3586 | } | 3593 | } |
3587 | 3594 | ||
3588 | /** | 3595 | /** |
3589 | * e1000e_disable_gig_wol_ich8lan - disable gig during WoL | 3596 | * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx |
3590 | * @hw: pointer to the HW structure | 3597 | * @hw: pointer to the HW structure |
3591 | * | 3598 | * |
3592 | * During S0 to Sx transition, it is possible the link remains at gig | 3599 | * During S0 to Sx transition, it is possible the link remains at gig |
3593 | * instead of negotiating to a lower speed. Before going to Sx, set | 3600 | * instead of negotiating to a lower speed. Before going to Sx, set |
3594 | * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation | 3601 | * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation |
3595 | * to a lower speed. | 3602 | * to a lower speed. For PCH and newer parts, the OEM bits PHY register |
3596 | * | 3603 | * (LED, GbE disable and LPLU configurations) also needs to be written. |
3597 | * Should only be called for applicable parts. | ||
3598 | **/ | 3604 | **/ |
3599 | void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) | 3605 | void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) |
3600 | { | 3606 | { |
3601 | u32 phy_ctrl; | 3607 | u32 phy_ctrl; |
3602 | s32 ret_val; | 3608 | s32 ret_val; |
@@ -3616,6 +3622,60 @@ void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) | |||
3616 | } | 3622 | } |
3617 | 3623 | ||
3618 | /** | 3624 | /** |
3625 | * e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0 | ||
3626 | * @hw: pointer to the HW structure | ||
3627 | * | ||
3628 | * During Sx to S0 transitions on non-managed devices or managed devices | ||
3629 | * on which PHY resets are not blocked, if the PHY registers cannot be | ||
3630 | * accessed properly by the s/w toggle the LANPHYPC value to power cycle | ||
3631 | * the PHY. | ||
3632 | **/ | ||
3633 | void e1000_resume_workarounds_pchlan(struct e1000_hw *hw) | ||
3634 | { | ||
3635 | u32 fwsm; | ||
3636 | |||
3637 | if (hw->mac.type != e1000_pch2lan) | ||
3638 | return; | ||
3639 | |||
3640 | fwsm = er32(FWSM); | ||
3641 | if (!(fwsm & E1000_ICH_FWSM_FW_VALID) || !e1000_check_reset_block(hw)) { | ||
3642 | u16 phy_id1, phy_id2; | ||
3643 | s32 ret_val; | ||
3644 | |||
3645 | ret_val = hw->phy.ops.acquire(hw); | ||
3646 | if (ret_val) { | ||
3647 | e_dbg("Failed to acquire PHY semaphore in resume\n"); | ||
3648 | return; | ||
3649 | } | ||
3650 | |||
3651 | /* Test access to the PHY registers by reading the ID regs */ | ||
3652 | ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID1, &phy_id1); | ||
3653 | if (ret_val) | ||
3654 | goto release; | ||
3655 | ret_val = hw->phy.ops.read_reg_locked(hw, PHY_ID2, &phy_id2); | ||
3656 | if (ret_val) | ||
3657 | goto release; | ||
3658 | |||
3659 | if (hw->phy.id == ((u32)(phy_id1 << 16) | | ||
3660 | (u32)(phy_id2 & PHY_REVISION_MASK))) | ||
3661 | goto release; | ||
3662 | |||
3663 | e1000_toggle_lanphypc_value_ich8lan(hw); | ||
3664 | |||
3665 | hw->phy.ops.release(hw); | ||
3666 | msleep(50); | ||
3667 | e1000_phy_hw_reset(hw); | ||
3668 | msleep(50); | ||
3669 | return; | ||
3670 | } | ||
3671 | |||
3672 | release: | ||
3673 | hw->phy.ops.release(hw); | ||
3674 | |||
3675 | return; | ||
3676 | } | ||
3677 | |||
3678 | /** | ||
3619 | * e1000_cleanup_led_ich8lan - Restore the default LED operation | 3679 | * e1000_cleanup_led_ich8lan - Restore the default LED operation |
3620 | * @hw: pointer to the HW structure | 3680 | * @hw: pointer to the HW structure |
3621 | * | 3681 | * |
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 888bd9cc2710..c4a23c7ac170 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c | |||
@@ -5278,7 +5278,7 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake, | |||
5278 | } | 5278 | } |
5279 | 5279 | ||
5280 | if (adapter->flags & FLAG_IS_ICH) | 5280 | if (adapter->flags & FLAG_IS_ICH) |
5281 | e1000e_disable_gig_wol_ich8lan(&adapter->hw); | 5281 | e1000_suspend_workarounds_ich8lan(&adapter->hw); |
5282 | 5282 | ||
5283 | /* Allow time for pending master requests to run */ | 5283 | /* Allow time for pending master requests to run */ |
5284 | e1000e_disable_pcie_master(&adapter->hw); | 5284 | e1000e_disable_pcie_master(&adapter->hw); |
@@ -5429,6 +5429,9 @@ static int __e1000_resume(struct pci_dev *pdev) | |||
5429 | return err; | 5429 | return err; |
5430 | } | 5430 | } |
5431 | 5431 | ||
5432 | if (hw->mac.type == e1000_pch2lan) | ||
5433 | e1000_resume_workarounds_pchlan(&adapter->hw); | ||
5434 | |||
5432 | e1000e_power_up_phy(adapter); | 5435 | e1000e_power_up_phy(adapter); |
5433 | 5436 | ||
5434 | /* report the system wakeup cause from S3/S4 */ | 5437 | /* report the system wakeup cause from S3/S4 */ |