diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2011-06-10 12:46:36 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2011-06-10 12:46:36 +0000 |
commit | ede3ae71faaa64d8a260366efbfa6669a1a8898a (patch) | |
tree | 19da36ebabdeb9dfc35c109712cf84715463ca39 /sys/dev/pci/ixgbe_phy.c | |
parent | 1067402c5d83af16fa9c9f95adef20db70eff0e3 (diff) |
Monster update of ix(4). This brings ix(4) close to what is currently
in FreeBSD. This seems to fix a lot of problems on 82599 based cards
including the VLAN problems and the corrupted receives.
Putting this in now to work on it in tree since a few additional things
need to be merged. Tested by myself, deraadt@ and jsg@ on both 98er and
99er cards.
OK jsg@, deraadt@
Diffstat (limited to 'sys/dev/pci/ixgbe_phy.c')
-rw-r--r-- | sys/dev/pci/ixgbe_phy.c | 247 |
1 files changed, 185 insertions, 62 deletions
diff --git a/sys/dev/pci/ixgbe_phy.c b/sys/dev/pci/ixgbe_phy.c index c859aef86f1..7bfcd7ff9b7 100644 --- a/sys/dev/pci/ixgbe_phy.c +++ b/sys/dev/pci/ixgbe_phy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ixgbe_phy.c,v 1.5 2010/09/21 00:29:29 claudio Exp $ */ +/* $OpenBSD: ixgbe_phy.c,v 1.6 2011/06/10 12:46:35 claudio Exp $ */ /****************************************************************************** @@ -75,7 +75,7 @@ int32_t ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw) phy->ops.i2c_bus_clear = &ixgbe_i2c_bus_clear; phy->ops.identify_sfp = &ixgbe_identify_sfp_module_generic; phy->sfp_type = ixgbe_sfp_type_unknown; - + phy->ops.check_overtemp = &ixgbe_tn_check_overtemp; return IXGBE_SUCCESS; } @@ -105,9 +105,8 @@ int32_t ixgbe_identify_phy_generic(struct ixgbe_hw *hw) IXGBE_MDIO_PMA_PMD_DEV_TYPE, &ext_ability); if (ext_ability & - IXGBE_MDIO_PHY_10GBASET_ABILITY || - ext_ability & - IXGBE_MDIO_PHY_1000BASET_ABILITY) + (IXGBE_MDIO_PHY_10GBASET_ABILITY | + IXGBE_MDIO_PHY_1000BASET_ABILITY)) hw->phy.type = ixgbe_phy_cu_unknown; else @@ -119,6 +118,7 @@ int32_t ixgbe_identify_phy_generic(struct ixgbe_hw *hw) break; } } + /* clear value if nothing found */ if (status != IXGBE_SUCCESS) hw->phy.addr = 0; } else { @@ -221,6 +221,11 @@ int32_t ixgbe_reset_phy_generic(struct ixgbe_hw *hw) if (status != IXGBE_SUCCESS || hw->phy.type == ixgbe_phy_none) goto out; + /* Don't reset PHY if it's shut down due to overtemp. */ + if (!hw->phy.reset_if_overtemp && + (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) + goto out; + /* * Perform soft PHY reset to the PHY_XS. * This will cause a soft reset to the PHY @@ -229,13 +234,19 @@ int32_t ixgbe_reset_phy_generic(struct ixgbe_hw *hw) IXGBE_MDIO_PHY_XS_DEV_TYPE, IXGBE_MDIO_PHY_XS_RESET); - /* Poll for reset bit to self-clear indicating reset is complete */ - for (i = 0; i < 500; i++) { - msec_delay(1); + /* + * Poll for reset bit to self-clear indicating reset is complete. + * Some PHYs could take up to 3 seconds to complete and need about + * 1.7 usec delay after the reset is complete. + */ + for (i = 0; i < 30; i++) { + msec_delay(100); hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, IXGBE_MDIO_PHY_XS_DEV_TYPE, &ctrl); - if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) + if (!(ctrl & IXGBE_MDIO_PHY_XS_RESET)) { + usec_delay(2); break; + } } if (ctrl & IXGBE_MDIO_PHY_XS_RESET) { @@ -289,9 +300,8 @@ int32_t ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, uint32_t reg_addr, command = IXGBE_READ_REG(hw, IXGBE_MSCA); - if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) { + if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) break; - } } if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) { @@ -438,10 +448,10 @@ int32_t ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, uint32_t reg_addr, } /** - * ixgbe_setup_phy_link_generic - Set and restart autoneg - * @hw: pointer to hardware structure + * ixgbe_setup_phy_link_generic - Set and restart autoneg + * @hw: pointer to hardware structure * - * Restart autonegotiation and PHY and waits for completion. + * Restart autonegotiation and PHY and waits for completion. **/ int32_t ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) { @@ -520,12 +530,15 @@ int32_t ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) &autoneg_reg); autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; - if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) + if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { break; + } } - if (time_out == max_time_out) + if (time_out == max_time_out) { status = IXGBE_ERR_LINK_SETUP; + DEBUGOUT("ixgbe_setup_phy_link_generic: time out"); + } return status; } @@ -727,8 +740,9 @@ int32_t ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) &autoneg_reg); autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE; - if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) + if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) { break; + } } if (time_out == max_time_out) { @@ -739,7 +753,6 @@ int32_t ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) return status; } - /** * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version * @hw: pointer to hardware structure @@ -757,7 +770,6 @@ int32_t ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, return status; } - /** * ixgbe_get_phy_firmware_version_generic - Gets the PHY Firmware Version * @hw: pointer to hardware structure @@ -888,6 +900,7 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) uint8_t comp_codes_10g = 0; uint8_t oui_bytes[3] = {0, 0, 0}; uint8_t cable_tech = 0; + uint8_t cable_spec = 0; uint16_t enforce_sfp = 0; if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_fiber) { @@ -900,15 +913,10 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, &identifier); - if (status == IXGBE_ERR_SFP_NOT_PRESENT || status == IXGBE_ERR_I2C) { - status = IXGBE_ERR_SFP_NOT_PRESENT; - hw->phy.sfp_type = ixgbe_sfp_type_not_present; - if (hw->phy.type != ixgbe_phy_nl) { - hw->phy.id = 0; - hw->phy.type = ixgbe_phy_unknown; - } - goto out; - } + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; /* LAN ID is needed for sfp_type determination */ hw->mac.ops.set_lan_id(hw); @@ -917,15 +925,31 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) hw->phy.type = ixgbe_phy_sfp_unsupported; status = IXGBE_ERR_SFP_NOT_SUPPORTED; } else { - hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES, - &comp_codes_1g); - hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, - &comp_codes_10g); - hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_CABLE_TECHNOLOGY, - &cable_tech); - - DEBUGOUT3("SFP+ capa codes 1G %x 10G %x cable %x\n", - comp_codes_1g, comp_codes_10g, cable_tech); + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_1GBE_COMP_CODES, + &comp_codes_1g); + + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; + + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_10GBE_COMP_CODES, + &comp_codes_10g); + + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; + status = hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_CABLE_TECHNOLOGY, + &cable_tech); + + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; /* ID Module * ========= @@ -936,6 +960,10 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) * 4 SFP_DA_CORE1 - 82599-specific * 5 SFP_SR/LR_CORE0 - 82599-specific * 6 SFP_SR/LR_CORE1 - 82599-specific + * 7 SFP_act_lmt_DA_CORE0 - 82599-specific + * 8 SFP_act_lmt_DA_CORE1 - 82599-specific + * 9 SFP_1g_cu_CORE0 - 82599-specific + * 10 SFP_1g_cu_CORE1 - 82599-specific */ if (hw->mac.type == ixgbe_mac_82598EB) { if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) @@ -949,29 +977,48 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) else hw->phy.sfp_type = ixgbe_sfp_type_unknown; } else if (hw->mac.type == ixgbe_mac_82599EB) { - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) + if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { if (hw->bus.lan_id == 0) hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core0; else hw->phy.sfp_type = ixgbe_sfp_type_da_cu_core1; - else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) + } else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) { + hw->phy.ops.read_i2c_eeprom( + hw, IXGBE_SFF_CABLE_SPEC_COMP, + &cable_spec); + if (cable_spec & + IXGBE_SFF_DA_SPEC_ACTIVE_LIMITING) { + if (hw->bus.lan_id == 0) + hw->phy.sfp_type = + ixgbe_sfp_type_da_act_lmt_core0; + else + hw->phy.sfp_type = + ixgbe_sfp_type_da_act_lmt_core1; + } else { + hw->phy.sfp_type = + ixgbe_sfp_type_unknown; + } + } else if (comp_codes_10g & + (IXGBE_SFF_10GBASESR_CAPABLE | + IXGBE_SFF_10GBASELR_CAPABLE)) { if (hw->bus.lan_id == 0) hw->phy.sfp_type = ixgbe_sfp_type_srlr_core0; else hw->phy.sfp_type = ixgbe_sfp_type_srlr_core1; - else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) + } else if (comp_codes_1g & IXGBE_SFF_1GBASET_CAPABLE) { if (hw->bus.lan_id == 0) hw->phy.sfp_type = - ixgbe_sfp_type_srlr_core0; + ixgbe_sfp_type_1g_cu_core0; else hw->phy.sfp_type = - ixgbe_sfp_type_srlr_core1; - else + ixgbe_sfp_type_1g_cu_core1; + } else { hw->phy.sfp_type = ixgbe_sfp_type_unknown; + } } if (hw->phy.sfp_type != stored_sfp_type) @@ -988,28 +1035,49 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) /* Determine PHY vendor */ if (hw->phy.type != ixgbe_phy_nl) { hw->phy.id = identifier; - hw->phy.ops.read_i2c_eeprom(hw, + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE0, &oui_bytes[0]); - hw->phy.ops.read_i2c_eeprom(hw, + + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; + + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE1, &oui_bytes[1]); - hw->phy.ops.read_i2c_eeprom(hw, + + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; + + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_VENDOR_OUI_BYTE2, &oui_bytes[2]); + if (status == IXGBE_ERR_SWFW_SYNC || + status == IXGBE_ERR_I2C || + status == IXGBE_ERR_SFP_NOT_PRESENT) + goto err_read_i2c_eeprom; + vendor_oui = - ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | - (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | - (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); + ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | + (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | + (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); switch (vendor_oui) { case IXGBE_SFF_VENDOR_OUI_TYCO: if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) - hw->phy.type = ixgbe_phy_tw_tyco; + hw->phy.type = + ixgbe_phy_sfp_passive_tyco; break; case IXGBE_SFF_VENDOR_OUI_FTL: - hw->phy.type = ixgbe_phy_sfp_ftl; + if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) + hw->phy.type = ixgbe_phy_sfp_ftl_active; + else + hw->phy.type = ixgbe_phy_sfp_ftl; break; case IXGBE_SFF_VENDOR_OUI_AVAGO: hw->phy.type = ixgbe_phy_sfp_avago; @@ -1019,21 +1087,28 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) break; default: if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) - hw->phy.type = ixgbe_phy_tw_unknown; + hw->phy.type = + ixgbe_phy_sfp_passive_unknown; + else if (cable_tech & IXGBE_SFF_DA_ACTIVE_CABLE) + hw->phy.type = + ixgbe_phy_sfp_active_unknown; else hw->phy.type = ixgbe_phy_sfp_unknown; break; } } - /* All passive DA cables are supported */ - if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE) { + /* Allow any DA cable vendor */ + if (cable_tech & (IXGBE_SFF_DA_PASSIVE_CABLE | + IXGBE_SFF_DA_ACTIVE_CABLE)) { status = IXGBE_SUCCESS; goto out; } - /* 1G SFP modules are not supported */ - if (comp_codes_10g == 0) { + /* Verify supported 1G SFP modules */ + if (comp_codes_10g == 0 && + !(hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0)) { hw->phy.type = ixgbe_phy_sfp_unsupported; status = IXGBE_ERR_SFP_NOT_SUPPORTED; goto out; @@ -1048,7 +1123,9 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) /* unimplemented even in the intel driver */ /* ixgbe_get_device_caps(hw, &enforce_sfp); */ enforce_sfp = IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP; - if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP)) { + if (!(enforce_sfp & IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP) && + !((hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core0) || + (hw->phy.sfp_type == ixgbe_sfp_type_1g_cu_core1))) { /* Make sure we're a supported PHY type */ if (hw->phy.type == ixgbe_phy_sfp_intel) { status = IXGBE_SUCCESS; @@ -1065,6 +1142,14 @@ int32_t ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) out: return status; + +err_read_i2c_eeprom: + hw->phy.sfp_type = ixgbe_sfp_type_not_present; + if (hw->phy.type != ixgbe_phy_nl) { + hw->phy.id = 0; + hw->phy.type = ixgbe_phy_unknown; + } + return IXGBE_ERR_SFP_NOT_PRESENT; } /** @@ -1081,6 +1166,7 @@ int32_t ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, uint16_t *data_offset) { uint16_t sfp_id; + uint16_t sfp_type = hw->phy.sfp_type; if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) return IXGBE_ERR_SFP_NOT_SUPPORTED; @@ -1092,6 +1178,17 @@ int32_t ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) return IXGBE_ERR_SFP_NOT_SUPPORTED; + /* + * Limiting active cables and 1G Phys must be initialized as + * SR modules + */ + if (sfp_type == ixgbe_sfp_type_da_act_lmt_core0 || + sfp_type == ixgbe_sfp_type_1g_cu_core0) + sfp_type = ixgbe_sfp_type_srlr_core0; + else if (sfp_type == ixgbe_sfp_type_da_act_lmt_core1 || + sfp_type == ixgbe_sfp_type_1g_cu_core1) + sfp_type = ixgbe_sfp_type_srlr_core1; + /* Read offset to PHY init contents */ hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); @@ -1108,7 +1205,7 @@ int32_t ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, hw->eeprom.ops.read(hw, *list_offset, &sfp_id); while (sfp_id != IXGBE_PHY_INIT_END_NL) { - if (sfp_id == hw->phy.sfp_type) { + if (sfp_id == sfp_type) { (*list_offset)++; hw->eeprom.ops.read(hw, *list_offset, data_offset); if ((!*data_offset) || (*data_offset == 0xFFFF)) { @@ -1135,9 +1232,10 @@ int32_t ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); (*list_offset) += 2; hw->eeprom.ops.read(hw, *list_offset, data_offset); - } else if (sfp_id == IXGBE_PHY_INIT_END_NL) + } else if (sfp_id == IXGBE_PHY_INIT_END_NL) { + DEBUGOUT("No matching SFP+ module found\n"); return IXGBE_ERR_SFP_NOT_SUPPORTED; - + } return IXGBE_SUCCESS; } @@ -1196,7 +1294,6 @@ int32_t ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, uint8_t byte_offset, else swfw_mask = IXGBE_GSSR_PHY0_SM; - do { if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != IXGBE_SUCCESS) { status = IXGBE_ERR_SWFW_SYNC; @@ -1401,7 +1498,7 @@ int32_t ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, uint8_t *data) for (i = 7; i >= 0; i--) { status = ixgbe_clock_in_i2c_bit(hw, &bit); - *data |= bit<<i; + *data |= bit << i; if (status != IXGBE_SUCCESS) break; @@ -1670,3 +1767,29 @@ void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw) /* Put the i2c bus back to default state */ ixgbe_i2c_stop(hw); } + +/** + * ixgbe_tn_check_overtemp - Checks if an overtemp occured. + * @hw: pointer to hardware structure + * + * Checks if the LASI temp alarm status was triggered due to overtemp + **/ +int32_t ixgbe_tn_check_overtemp(struct ixgbe_hw *hw) +{ + int32_t status = IXGBE_SUCCESS; + uint16_t phy_data = 0; + + if (hw->device_id != IXGBE_DEV_ID_82599_T3_LOM) + goto out; + + /* Check that the LASI temp alarm status was triggered */ + hw->phy.ops.read_reg(hw, IXGBE_TN_LASI_STATUS_REG, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_data); + + if (!(phy_data & IXGBE_TN_LASI_STATUS_TEMP_ALARM)) + goto out; + + status = IXGBE_ERR_OVERTEMP; +out: + return status; +} |