diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2014-11-05 15:30:18 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2014-11-05 15:30:18 +0000 |
commit | bcdf5c2efe76d9f4aa2866937338df4094947a85 (patch) | |
tree | ae9aaf270197f543b0245dcee20015308d04b379 /sys/dev | |
parent | 6b6a9200ed3ae933c414ea1ed6e76a44124843f7 (diff) |
Implement yet another workaround for the k1 em(4)'s. This time for
the i218 which is used in many modern laptops like the X240. This
seems to stop the watchdog timeouts triggered by heavy traffic on
such systems.
Tested by myself, phessler, blambert and Donovan Watteau
OK deraadt, brad
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_em_hw.c | 91 | ||||
-rw-r--r-- | sys/dev/pci/if_em_hw.h | 16 |
2 files changed, 103 insertions, 4 deletions
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 02543e928f5..6c1e170661f 100644 --- a/sys/dev/pci/if_em_hw.c +++ b/sys/dev/pci/if_em_hw.c @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.c,v 1.80 2014/07/22 13:12:11 mpi Exp $ */ +/* $OpenBSD: if_em_hw.c,v 1.81 2014/11/05 15:30:17 claudio Exp $ */ /* * if_em_hw.c Shared functions for accessing and configuring the MAC */ @@ -163,6 +163,7 @@ int32_t em_lv_phy_workarounds_ich8lan(struct em_hw *); int32_t em_link_stall_workaround_hv(struct em_hw *); int32_t em_k1_gig_workaround_hv(struct em_hw *, boolean_t); int32_t em_k1_workaround_lv(struct em_hw *); +int32_t em_k1_workaround_lpt_lp(struct em_hw *, boolean_t); int32_t em_configure_k1_ich8lan(struct em_hw *, boolean_t); void em_gate_hw_phy_config_ich8lan(struct em_hw *, boolean_t); int32_t em_access_phy_wakeup_reg_bm(struct em_hw *, uint32_t, @@ -3709,6 +3710,16 @@ em_check_for_link(struct em_hw *hw) if (ret_val) return ret_val; } + /* Work-around I218 hang issue */ + if ((hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || + (hw->device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || + (hw->device_id == E1000_DEV_ID_PCH_I218_LM3) || + (hw->device_id == E1000_DEV_ID_PCH_I218_V3)) { + ret_val = em_k1_workaround_lpt_lp(hw, + hw->icp_xxxx_is_link_up); + if (ret_val) + return ret_val; + } /* * Check if there was DownShift, must be checked @@ -10186,6 +10197,84 @@ em_k1_workaround_lv(struct em_hw *hw) return E1000_SUCCESS; } +/** + * em_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP + * + * 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 1Gbps mode. + * Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link + * speeds in order to avoid Tx hangs. + **/ +int32_t +em_k1_workaround_lpt_lp(struct em_hw *hw, boolean_t link) +{ + uint32_t fextnvm6 = E1000_READ_REG(hw, FEXTNVM6); + uint32_t status = E1000_READ_REG(hw, STATUS); + int32_t ret_val = E1000_SUCCESS; + uint16_t reg; + + if (link && (status & E1000_STATUS_SPEED_1000)) { + ret_val = em_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_K1_CONFIG, + ®); + if (ret_val) + return ret_val; + + ret_val = em_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_K1_CONFIG, + reg & ~E1000_KMRNCTRLSTA_K1_ENABLE); + if (ret_val) + return ret_val; + + usec_delay(10); + + E1000_WRITE_REG(hw, FEXTNVM6, + fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK); + + ret_val = em_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_K1_CONFIG, + reg); + } else { + /* clear FEXTNVM6 bit 8 on link down or 10/100 */ + fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK; + + if (!link || ((status & E1000_STATUS_SPEED_100) && + (status & E1000_STATUS_FD))) + goto update_fextnvm6; + + ret_val = em_read_phy_reg(hw, I217_INBAND_CTRL, ®); + 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 = em_write_phy_reg(hw, I217_INBAND_CTRL, reg); + if (ret_val) + return ret_val; + +update_fextnvm6: + E1000_WRITE_REG(hw, FEXTNVM6, fextnvm6); + } + + return ret_val; + +} + + /*************************************************************************** * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware * @hw: pointer to the HW structure diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index 5e5f9d5cd75..49ede9a9baa 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -31,7 +31,7 @@ *******************************************************************************/ -/* $OpenBSD: if_em_hw.h,v 1.60 2014/03/10 04:09:53 jsg Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.61 2014/11/05 15:30:17 claudio Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -987,8 +987,9 @@ struct em_ffvt_entry { #define E1000_MDIC 0x00020 /* MDI Control - RW */ #define E1000_MDICNFG 0x00E04 /* MDI Config - RW */ #define E1000_SCTL 0x00024 /* SerDes Control - RW */ -#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */ +#define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ +#define E1000_FEXTNVM6 0x00010 /* Future Extended NVM 6 - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ #define E1000_FCT 0x00030 /* Flow Control Type - RW */ @@ -1215,8 +1216,9 @@ struct em_ffvt_entry { #define E1000_82542_FLA E1000_FLA #define E1000_82542_MDIC E1000_MDIC #define E1000_82542_SCTL E1000_SCTL -#define E1000_82542_FEXTNVM4 E1000_FEXTNVM4 #define E1000_82542_FEXTNVM E1000_FEXTNVM +#define E1000_82542_FEXTNVM4 E1000_FEXTNVM4 +#define E1000_82542_FEXTNVM6 E1000_FEXTNVM6 #define E1000_82542_FCAL E1000_FCAL #define E1000_82542_FCAH E1000_FCAH #define E1000_82542_FCT E1000_FCT @@ -1430,6 +1432,9 @@ struct em_ffvt_entry { #define E1000_FEXTNVM4_BEACON_DURATION_8USEC 0x7 #define E1000_FEXTNVM4_BEACON_DURATION_16USEC 0x3 +#define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100 +#define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200 + /* Statistics counters collected by the MAC */ struct em_hw_stats { uint64_t crcerrs; @@ -3720,6 +3725,11 @@ union ich8_hws_flash_regacc { #define HV_M_STATUS_SPEED_1000 0x0200 #define HV_M_STATUS_LINK_UP 0x0040 +/* 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_ENABLE_MASK 0x6000 |