Skip to content

Commit

Permalink
e1000e: disable K1 at 1000Mbps for 82577/82578
Browse files Browse the repository at this point in the history
This workaround is required for an issue in hardware where noise on the
interconnect between the MAC and PHY could be generated by a lower power
mode (K1) at 1000Mbps resulting in bad packets.  Disable K1 while at 1000
Mbps but keep it enabled for 10/100Mbps and when the cable is disconnected.

Signed-off-by: Bruce Allan <bruce.w.allan@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Bruce Allan authored and David S. Miller committed Jul 4, 2009
1 parent 906e8d9 commit 7d3cabb
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 7 deletions.
4 changes: 4 additions & 0 deletions drivers/net/e1000e/hw.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ enum e1e_registers {
E1000_SWSM = 0x05B50, /* SW Semaphore */
E1000_FWSM = 0x05B54, /* FW Semaphore */
E1000_SWSM2 = 0x05B58, /* Driver-only SW semaphore */
E1000_CRC_OFFSET = 0x05F50, /* CRC Offset register */
E1000_HICR = 0x08F00, /* Host Interface Control */
};

Expand Down Expand Up @@ -302,6 +303,9 @@ enum e1e_registers {
#define E1000_KMRNCTRLSTA_REN 0x00200000
#define E1000_KMRNCTRLSTA_DIAG_OFFSET 0x3 /* Kumeran Diagnostic */
#define E1000_KMRNCTRLSTA_DIAG_NELPBK 0x1000 /* Nearend Loopback mode */
#define E1000_KMRNCTRLSTA_K1_CONFIG 0x7
#define E1000_KMRNCTRLSTA_K1_ENABLE 0x140E
#define E1000_KMRNCTRLSTA_K1_DISABLE 0x1400

#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10
#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY Special Control */
Expand Down
107 changes: 106 additions & 1 deletion drivers/net/e1000e/ich8lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,95 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
return 0;
}

/**
* e1000_check_for_copper_link_ich8lan - Check for link (Copper)
* @hw: pointer to the HW structure
*
* Checks to see of the link status of the hardware has changed. If a
* change in link status has been detected, then we read the PHY registers
* to get the current speed/duplex if link exists.
**/
static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val;
bool link;

/*
* We only want to go out to the PHY registers to see if Auto-Neg
* has completed and/or if our link status has changed. The
* get_link_status flag is set upon receiving a Link Status
* Change or Rx Sequence Error interrupt.
*/
if (!mac->get_link_status) {
ret_val = 0;
goto out;
}

if (hw->mac.type == e1000_pchlan) {
ret_val = e1000e_write_kmrn_reg(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
E1000_KMRNCTRLSTA_K1_ENABLE);
if (ret_val)
goto out;
}

/*
* First we want to see if the MII Status Register reports
* link. If so, then we want to get the current speed/duplex
* of the PHY.
*/
ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
if (ret_val)
goto out;

if (!link)
goto out; /* No link detected */

mac->get_link_status = false;

if (hw->phy.type == e1000_phy_82578) {
ret_val = e1000_link_stall_workaround_hv(hw);
if (ret_val)
goto out;
}

/*
* Check if there was DownShift, must be checked
* immediately after link-up
*/
e1000e_check_downshift(hw);

/*
* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
*/
if (!mac->autoneg) {
ret_val = -E1000_ERR_CONFIG;
goto out;
}

/*
* Auto-Neg is enabled. Auto Speed Detection takes care
* of MAC speed/duplex configuration. So we only need to
* configure Collision Distance in the MAC.
*/
e1000e_config_collision_dist(hw);

/*
* Configure Flow Control now that Auto-Neg has completed.
* First, we need to restore the desired flow control
* settings because we may have had to re-autoneg with a
* different link partner.
*/
ret_val = e1000e_config_fc_after_link_up(hw);
if (ret_val)
hw_dbg(hw, "Error configuring flow control\n");

out:
return ret_val;
}

static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
Expand Down Expand Up @@ -2224,6 +2313,14 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
}
}

/*
* For PCH, this write will make sure that any noise
* will be detected as a CRC error and be dropped rather than show up
* as a bad packet to the DMA engine.
*/
if (hw->mac.type == e1000_pchlan)
ew32(CRC_OFFSET, 0x65656565);

ew32(IMC, 0xffffffff);
icr = er32(ICR);

Expand Down Expand Up @@ -2538,6 +2635,14 @@ static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
if (ret_val)
return ret_val;

if ((hw->mac.type == e1000_pchlan) && (*speed == SPEED_1000)) {
ret_val = e1000e_write_kmrn_reg(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
E1000_KMRNCTRLSTA_K1_DISABLE);
if (ret_val)
return ret_val;
}

if ((hw->mac.type == e1000_ich8lan) &&
(hw->phy.type == e1000_phy_igp_3) &&
(*speed == SPEED_1000)) {
Expand Down Expand Up @@ -2984,7 +3089,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
static struct e1000_mac_operations ich8_mac_ops = {
.id_led_init = e1000e_id_led_init,
.check_mng_mode = e1000_check_mng_mode_ich8lan,
.check_for_link = e1000e_check_for_copper_link,
.check_for_link = e1000_check_for_copper_link_ich8lan,
/* cleanup_led dependent on mac type */
.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan,
.get_bus_info = e1000_get_bus_info_ich8lan,
Expand Down
6 changes: 0 additions & 6 deletions drivers/net/e1000e/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,6 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)

mac->get_link_status = 0;

if (hw->phy.type == e1000_phy_82578) {
ret_val = e1000_link_stall_workaround_hv(hw);
if (ret_val)
return ret_val;
}

/*
* Check if there was DownShift, must be checked
* immediately after link-up
Expand Down

0 comments on commit 7d3cabb

Please sign in to comment.