diff options
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/if_em_hw.c | 209 | ||||
-rw-r--r-- | sys/dev/pci/if_em_hw.h | 15 |
2 files changed, 182 insertions, 42 deletions
diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 1c6f662c5d2..120729cdec3 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.69 2012/05/17 10:45:17 jsg Exp $ */ +/* $OpenBSD: if_em_hw.c,v 1.70 2012/11/26 01:17:41 jsg Exp $ */ /* * if_em_hw.c Shared functions for accessing and configuring the MAC */ @@ -159,7 +159,6 @@ static void em_release_eeprom(struct em_hw *); static void em_standby_eeprom(struct em_hw *); static int32_t em_set_vco_speed(struct em_hw *); static int32_t em_polarity_reversal_workaround(struct em_hw *); -static void em_pch2lan_disable_hw_config(struct em_hw *, boolean_t); static int32_t em_set_phy_mode(struct em_hw *); static int32_t em_host_if_read_cookie(struct em_hw *, uint8_t *); static uint8_t em_calculate_mng_checksum(char *, uint32_t); @@ -168,10 +167,12 @@ static int32_t em_configure_kmrn_for_1000(struct em_hw *); static int32_t em_set_pciex_completion_timeout(struct em_hw *hw); static int32_t em_set_mdio_slow_mode_hv(struct em_hw *); int32_t em_hv_phy_workarounds_ich8lan(struct em_hw *); +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_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, uint16_t *, boolean_t); int32_t em_access_phy_debug_regs_hv(struct em_hw *, uint32_t, @@ -182,7 +183,9 @@ int32_t em_oem_bits_config_pchlan(struct em_hw *, boolean_t); void em_power_up_serdes_link_82575(struct em_hw *); int32_t em_get_pcs_speed_and_duplex_82575(struct em_hw *, uint16_t *, uint16_t *); -int32_t em_set_eee_i350(struct em_hw *); +int32_t em_set_eee_i350(struct em_hw *); +int32_t em_set_eee_pchlan(struct em_hw *); + /* IGP cable length table */ static const uint16_t @@ -565,6 +568,7 @@ em_set_mac_type(struct em_hw *hw) case E1000_DEV_ID_PCH_D_HV_DC: case E1000_DEV_ID_PCH_D_HV_DM: hw->mac_type = em_pchlan; + hw->eee_enable = 1; break; case E1000_DEV_ID_PCH2_LV_LM: case E1000_DEV_ID_PCH2_LV_V: @@ -848,16 +852,26 @@ em_reset_hw(struct em_hw *hw) * the external PHY is reset. */ ctrl |= E1000_CTRL_PHY_RST; - + /* + * Gate automatic PHY configuration by hardware on + * non-managed 82579 + */ if ((hw->mac_type == em_pch2lan) && !(E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID)) { - em_pch2lan_disable_hw_config(hw, TRUE); + em_gate_hw_phy_config_ich8lan(hw, TRUE); } } em_get_software_flag(hw); E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); msec_delay(5); - break; + + /* Ungate automatic PHY configuration on non-managed 82579 */ + if (hw->mac_type == em_pch2lan && !hw->phy_reset_disable && + !(E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID)) { + msec_delay(10); + em_gate_hw_phy_config_ich8lan(hw, FALSE); + } + break; default: E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST)); break; @@ -870,7 +884,7 @@ em_reset_hw(struct em_hw *hw) return ret_val; } else if (hw->mac_type == em_pch2lan) { - ret_val = em_set_mdio_slow_mode_hv(hw); + ret_val = em_lv_phy_workarounds_ich8lan(hw); if (ret_val) return ret_val; } @@ -1173,8 +1187,9 @@ em_init_hw(struct em_hw *hw) msec_delay(50); } + /* Gate automatic PHY configuration on non-managed 82579 */ if (hw->mac_type == em_pch2lan) - em_pch2lan_disable_hw_config(hw, TRUE); + em_gate_hw_phy_config_ich8lan(hw, TRUE); /* * Reset the PHY before any acccess to it. Doing so, @@ -1185,9 +1200,10 @@ em_init_hw(struct em_hw *hw) */ em_phy_reset(hw); + /* Ungate automatic PHY configuration on non-managed 82579 */ if (hw->mac_type == em_pch2lan && (fwsm & E1000_FWSM_FW_VALID) == 0) - em_pch2lan_disable_hw_config(hw, FALSE); + em_gate_hw_phy_config_ich8lan(hw, FALSE); /* Set MDIO slow mode before any other MDIO access */ ret_val = em_set_mdio_slow_mode_hv(hw); @@ -3681,6 +3697,13 @@ em_check_for_link(struct em_hw *hw) */ em_check_downshift(hw); + /* Enable/Disable EEE after link up */ + if (hw->mac_type == em_pch2lan) { + ret_val = em_set_eee_pchlan(hw); + if (ret_val) + return ret_val; + } + /* * If we are on 82544 or 82543 silicon and * speed/duplex are forced to 10H or 10F, then we @@ -4901,16 +4924,18 @@ em_oem_bits_config_pchlan(struct em_hw *hw, boolean_t d0_state) uint16_t oem_reg; uint16_t swfw = E1000_SWFW_PHY0_SM; - if (hw->mac_type != em_pchlan) + if ((hw->mac_type != em_pchlan) && (hw->mac_type != em_pch2lan)) return ret_val; ret_val = em_swfw_sync_acquire(hw, swfw); if (ret_val) return ret_val; - mac_reg = E1000_READ_REG(hw, EXTCNF_CTRL); - if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) - goto out; + if (hw->mac_type != em_pch2lan) { + mac_reg = E1000_READ_REG(hw, EXTCNF_CTRL); + if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) + goto out; + } mac_reg = E1000_READ_REG(hw, FEXTNVM); if (!(mac_reg & FEXTNVM_SW_CONFIG_ICH8M)) @@ -4930,16 +4955,20 @@ em_oem_bits_config_pchlan(struct em_hw *hw, boolean_t d0_state) if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) oem_reg |= HV_OEM_BITS_LPLU; + /* Restart auto-neg to activate the bits */ + if (!em_check_phy_reset_block(hw)) + oem_reg |= HV_OEM_BITS_RESTART_AN; + } else { - if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE) + if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE | + E1000_PHY_CTRL_NOND0A_GBE_DISABLE)) oem_reg |= HV_OEM_BITS_GBE_DIS; - if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU) + if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU | + E1000_PHY_CTRL_NOND0A_LPLU)) oem_reg |= HV_OEM_BITS_LPLU; } - /* Restart auto-neg to activate the bits */ - if (!em_check_phy_reset_block(hw)) - oem_reg |= HV_OEM_BITS_RESTART_AN; + ret_val = em_write_phy_reg(hw, HV_OEM_BITS, oem_reg); out: @@ -4996,9 +5025,9 @@ em_phy_reset(struct em_hw *hw) /* Allow time for h/w to get to a quiescent state after reset */ msec_delay(10); - if (hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2) + if (hw->phy_type == em_phy_igp || hw->phy_type == em_phy_igp_2) { em_phy_init_script(hw); - else if (hw->mac_type == em_pchlan) { + } else if (hw->mac_type == em_pchlan) { ret_val = em_hv_phy_workarounds_ich8lan(hw); if (ret_val) return ret_val; @@ -5006,11 +5035,21 @@ em_phy_reset(struct em_hw *hw) ret_val = em_oem_bits_config_pchlan(hw, TRUE); if (ret_val) return ret_val; - } - else if (hw->mac_type == em_pch2lan) { - ret_val = em_set_mdio_slow_mode_hv(hw); + + } else if (hw->mac_type == em_pch2lan) { + ret_val = em_lv_phy_workarounds_ich8lan(hw); + if (ret_val) + return ret_val; + + ret_val = em_oem_bits_config_pchlan(hw, TRUE); if (ret_val) return ret_val; + + /* Ungate automatic PHY configuration on non-managed 82579 */ + if (!(E1000_READ_REG(hw, FWSM) & E1000_FWSM_FW_VALID)) { + msec_delay(10); + em_gate_hw_phy_config_ich8lan(hw, FALSE); + } } return E1000_SUCCESS; @@ -8577,24 +8616,6 @@ em_polarity_reversal_workaround(struct em_hw *hw) return E1000_SUCCESS; } -/* - * Set whether the PHY self-configures itself in hardware - */ -static void em_pch2lan_disable_hw_config(struct em_hw *hw, boolean_t sc) -{ - uint32_t ctrl_ext; - DEBUGFUNC("em_pch2lan_disable_hw_config"); - - ctrl_ext = E1000_READ_REG(hw, CTRL_EXT); - - if (sc) - ctrl_ext |= E1000_CTRL_EXT_SDP3_DATA; - else - ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA; - - E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); -} - /****************************************************************************** * * Disables PCI-Express master access. @@ -10140,6 +10161,34 @@ em_k1_workaround_lv(struct em_hw *hw) } /*************************************************************************** + * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware + * @hw: pointer to the HW structure + * @gate: boolean set to TRUE to gate, FALSE to ungate + * + * Gate/ungate the automatic PHY configuration via hardware; perform + * the configuration via software instead. + ***************************************************************************/ +void +em_gate_hw_phy_config_ich8lan(struct em_hw *hw, boolean_t gate) +{ + uint32_t extcnf_ctrl; + + DEBUGFUNC("em_gate_hw_phy_config_ich8lan"); + + if (hw->mac_type != em_pch2lan) + return; + + extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL); + + if (gate) + extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; + else + extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG; + + E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl); +} + +/*************************************************************************** * Configure K1 power state * * Configure the K1 power state based on the provided parameter. @@ -10189,6 +10238,51 @@ out: return ret_val; } +/*************************************************************************** + * em_lv_phy_workarounds_ich8lan - A series of Phy workarounds to be + * done after every PHY reset. + ***************************************************************************/ +int32_t +em_lv_phy_workarounds_ich8lan(struct em_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint16_t swfw; + + DEBUGFUNC("e1000_lv_phy_workarounds_ich8lan"); + + if (hw->mac_type != em_pch2lan) + goto out; + + /* Set MDIO slow mode before any other MDIO access */ + ret_val = em_set_mdio_slow_mode_hv(hw); + + swfw = E1000_SWFW_PHY0_SM; + ret_val = em_swfw_sync_acquire(hw, swfw); + if (ret_val) + goto out; + ret_val = em_write_phy_reg(hw, I82579_EMI_ADDR, + I82579_MSE_THRESHOLD); + if (ret_val) + goto release; + /* set MSE higher to enable link to stay up when noise is high */ + ret_val = em_write_phy_reg(hw, I82579_EMI_DATA, + 0x0034); + if (ret_val) + goto release; + ret_val = em_write_phy_reg(hw, I82579_EMI_ADDR, + I82579_MSE_LINK_DOWN); + if (ret_val) + goto release; + /* drop link after 5 times MSE threshold was reached */ + ret_val = em_write_phy_reg(hw, I82579_EMI_DATA, + 0x0005); +release: + em_swfw_sync_release(hw, swfw); + +out: + return ret_val; +} + int32_t em_set_eee_i350(struct em_hw *hw) { @@ -10217,3 +10311,36 @@ em_set_eee_i350(struct em_hw *hw) out: return ret_val; } + +/*************************************************************************** + * em_set_eee_pchlan - Enable/disable EEE support + * @hw: pointer to the HW structure + * + * Enable/disable EEE based on setting in dev_spec structure. The bits in + * the LPI Control register will remain set only if/when link is up. + ***************************************************************************/ +int32_t +em_set_eee_pchlan(struct em_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint16_t phy_reg; + + DEBUGFUNC("em_set_eee_pchlan"); + + if (hw->phy_type != em_phy_82579) + goto out; + + ret_val = em_read_phy_reg(hw, I82579_LPI_CTRL, &phy_reg); + if (ret_val) + goto out; + + if (hw->eee_enable) + phy_reg &= ~I82579_LPI_CTRL_ENABLE_MASK; + else + phy_reg |= I82579_LPI_CTRL_ENABLE_MASK; + + ret_val = em_write_phy_reg(hw, I82579_LPI_CTRL, phy_reg); +out: + return ret_val; +} + diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index 286dcea4840..f6a43de34d1 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.53 2012/05/17 10:45:17 jsg Exp $ */ +/* $OpenBSD: if_em_hw.h,v 1.54 2012/11/26 01:17:41 jsg Exp $ */ /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */ /* if_em_hw.h @@ -2586,6 +2586,7 @@ struct em_host_command_info { #define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000 #define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001 #define E1000_EXTCNF_CTRL_SWFLAG 0x00000020 +#define E1000_EXTCNF_CTRL_GATE_PHY_CFG 0x00000080 /* PBA constants */ #define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */ @@ -3678,6 +3679,18 @@ union ich8_hws_flash_regacc { #define HV_M_STATUS_SPEED_1000 0x0200 #define HV_M_STATUS_LINK_UP 0x0040 +/* PHY Low Power Idle Control */ +#define I82579_LPI_CTRL PHY_REG(772, 20) +#define I82579_LPI_CTRL_ENABLE_MASK 0x6000 +#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80 + +/* EMI Registers */ +#define I82579_EMI_ADDR 0x10 +#define I82579_EMI_DATA 0x11 +#define I82579_LPI_UPDATE_TIMER 0x4805 /* in 40ns units + 40 ns base value */ +#define I82579_MSE_THRESHOLD 0x084F /* Mean Square Error Threshold */ +#define I82579_MSE_LINK_DOWN 0x2411 /* MSE count before dropping link */ + #define PHY_UPPER_SHIFT 21 #define BM_PHY_REG(page, reg) \ (((reg) & MAX_PHY_REG_ADDRESS) |\ |