Skip to content

Commit

Permalink
e1000e: Tx hang on I218 when linked at 100Half and slow response at 1…
Browse files Browse the repository at this point in the history
…0Mbps

Tx hang is an unintended consequence of another workaround that is in the
EEPROM for an issue with the firmware at 10Mbps when K1 (a power mode of
the MAC-PHY interconnect) is enabled.  The issue is resolved by setting
appropriate Tx re-transmission timeouts in the PHY and associated K1 entry
times in the MAC to allow enough transmissions to occur without triggering
a Tx hang.  A similar change is needed when linked at 10Mbps to improve
latency.

Signed-off-by: Bruce Allan <[email protected]>
Tested-by: Jeff Pieper <[email protected]>
Signed-off-by: Jeff Kirsher <[email protected]>
  • Loading branch information
bwallan authored and Jeff Kirsher committed Jul 28, 2013
1 parent ce345e0 commit e0236ad
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 7 deletions.
49 changes: 42 additions & 7 deletions drivers/net/ethernet/intel/e1000e/ich8lan.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,29 +793,31 @@ static s32 e1000_set_eee_pchlan(struct e1000_hw *hw)
* When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications
* preventing further DMA write requests. Workaround the issue by disabling
* the de-assertion of the clock request when in 1Gpbs mode.
* Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link
* speeds in order to avoid Tx hangs.
**/
static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
{
u32 fextnvm6 = er32(FEXTNVM6);
u32 status = er32(STATUS);
s32 ret_val = 0;
u16 reg;

if (link && (er32(STATUS) & E1000_STATUS_SPEED_1000)) {
u16 kmrn_reg;

if (link && (status & E1000_STATUS_SPEED_1000)) {
ret_val = hw->phy.ops.acquire(hw);
if (ret_val)
return ret_val;

ret_val =
e1000e_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG,
&kmrn_reg);
&reg);
if (ret_val)
goto release;

ret_val =
e1000e_write_kmrn_reg_locked(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
kmrn_reg &
reg &
~E1000_KMRNCTRLSTA_K1_ENABLE);
if (ret_val)
goto release;
Expand All @@ -827,12 +829,45 @@ static s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link)
ret_val =
e1000e_write_kmrn_reg_locked(hw,
E1000_KMRNCTRLSTA_K1_CONFIG,
kmrn_reg);
reg);
release:
hw->phy.ops.release(hw);
} else {
/* clear FEXTNVM6 bit 8 on link down or 10/100 */
ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK);
fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK;

if (!link || ((status & E1000_STATUS_SPEED_100) &&
(status & E1000_STATUS_FD)))
goto update_fextnvm6;

ret_val = e1e_rphy(hw, I217_INBAND_CTRL, &reg);
if (ret_val)
return ret_val;

/* Clear link status transmit timeout */
reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK;

if (status & E1000_STATUS_SPEED_100) {
/* Set inband Tx timeout to 5x10us for 100Half */
reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;

/* Do not extend the K1 entry latency for 100Half */
fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
} else {
/* Set inband Tx timeout to 50x10us for 10Full/Half */
reg |= 50 <<
I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT;

/* Extend the K1 entry latency for 10 Mbps */
fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION;
}

ret_val = e1e_wphy(hw, I217_INBAND_CTRL, reg);
if (ret_val)
return ret_val;

update_fextnvm6:
ew32(FEXTNVM6, fextnvm6);
}

return ret_val;
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/ethernet/intel/e1000e/ich8lan.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
#define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3

#define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100
#define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200

#define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL

Expand Down Expand Up @@ -197,6 +198,11 @@

#define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in ms */

/* Inband Control */
#define I217_INBAND_CTRL PHY_REG(770, 18)
#define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK 0x3F00
#define I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT 8

/* PHY Low Power Idle Control */
#define I82579_LPI_CTRL PHY_REG(772, 20)
#define I82579_LPI_CTRL_100_ENABLE 0x2000
Expand Down

0 comments on commit e0236ad

Please sign in to comment.