aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/e1000e
diff options
context:
space:
mode:
authorBruce Allan <bruce.w.allan@intel.com>2011-05-13 03:19:48 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2011-06-09 23:31:49 -0400
commit99730e4c13c8344b02dd96108945b48d28c14c25 (patch)
tree36ae5f5c6bf0804f45dfb387931f88d11f7bc400 /drivers/net/e1000e
parentd9b24135b972ccdd5f5174fba06c730e895e6daf (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.h3
-rw-r--r--drivers/net/e1000e/ich8lan.c86
-rw-r--r--drivers/net/e1000e/netdev.c5
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);
534extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw); 534extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
535extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw); 535extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
536extern void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw); 536extern void e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw);
537extern void e1000_resume_workarounds_pchlan(struct e1000_hw *hw);
537extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable); 538extern s32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable);
538extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); 539extern s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable);
539extern void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw); 540extern 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
278static 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)
284static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 297static 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 **/
3599void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw) 3605void 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 **/
3633void 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
3672release:
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 */