Commit e0236ad9 authored by Bruce Allan's avatar Bruce Allan Committed by Jeff Kirsher

e1000e: Tx hang on I218 when linked at 100Half and slow response at 10Mbps

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: default avatarBruce Allan <bruce.w.allan@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent ce345e08
......@@ -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;
......@@ -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;
......
......@@ -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
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment