X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fixgbe%2Fbase%2Fixgbe_x550.c;h=6514a0f67784d9f3b8b45eb68264bae5193a037a;hb=1a92547a395447871c089db5ef9152688010f050;hp=8d8a5bf5e73d78e0db3a09e1323a6d9d7f605a32;hpb=5a9c0187086140cd945bdf338bf2925139eb1a38;p=dpdk.git diff --git a/drivers/net/ixgbe/base/ixgbe_x550.c b/drivers/net/ixgbe/base/ixgbe_x550.c index 8d8a5bf5e7..6514a0f677 100644 --- a/drivers/net/ixgbe/base/ixgbe_x550.c +++ b/drivers/net/ixgbe/base/ixgbe_x550.c @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "ixgbe_common.h" #include "ixgbe_phy.h" +STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed); /** * ixgbe_init_ops_X550 - Inits func ptrs and MAC type @@ -79,6 +80,10 @@ s32 ixgbe_init_ops_X550(struct ixgbe_hw *hw) mac->ops.mdd_event = ixgbe_mdd_event_X550; mac->ops.restore_mdd_vf = ixgbe_restore_mdd_vf_X550; mac->ops.disable_rx = ixgbe_disable_rx_x550; + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + hw->mac.ops.led_on = ixgbe_led_on_t_X550em; + hw->mac.ops.led_off = ixgbe_led_off_t_X550em; + } return ret_val; } @@ -108,115 +113,6 @@ STATIC s32 ixgbe_write_cs4227(struct ixgbe_hw *hw, u16 reg, u16 value) return ixgbe_write_i2c_combined_unlocked(hw, IXGBE_CS4227, reg, value); } -/** - * ixgbe_get_cs4227_status - Return CS4227 status - * @hw: pointer to hardware structure - * - * Returns error if CS4227 not successfully initialized - **/ -STATIC s32 ixgbe_get_cs4227_status(struct ixgbe_hw *hw) -{ - s32 status; - u16 value = 0; - u16 reg_slice, reg_val; - u8 retry; - - for (retry = 0; retry < IXGBE_CS4227_RETRIES; ++retry) { - status = ixgbe_read_cs4227(hw, IXGBE_CS4227_GLOBAL_ID_LSB, - &value); - if (status != IXGBE_SUCCESS) - return status; - if (value == IXGBE_CS4227_GLOBAL_ID_VALUE) - break; - msec_delay(IXGBE_CS4227_CHECK_DELAY); - } - if (value != IXGBE_CS4227_GLOBAL_ID_VALUE) - return IXGBE_ERR_PHY; - - status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value); - if (status != IXGBE_SUCCESS) - return status; - - /* If this is the first time after power-on, check the ucode. - * Otherwise, this will disrupt link on all ports. Because we - * can only do this the first time, we must check all ports, - * not just our own. - */ - if (value != IXGBE_CS4227_SCRATCH_VALUE) { - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB; - reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - status = ixgbe_write_cs4227(hw, reg_slice, reg_val); - if (status != IXGBE_SUCCESS) - return status; - - reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB; - reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; - status = ixgbe_write_cs4227(hw, reg_slice, reg_val); - if (status != IXGBE_SUCCESS) - return status; - - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (1 << 12); - reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - status = ixgbe_write_cs4227(hw, reg_slice, reg_val); - if (status != IXGBE_SUCCESS) - return status; - - reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (1 << 12); - reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; - status = ixgbe_write_cs4227(hw, reg_slice, reg_val); - if (status != IXGBE_SUCCESS) - return status; - - msec_delay(10); - } - - /* Verify that the ucode is operational on all ports. */ - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB; - reg_val = 0xFFFF; - status = ixgbe_read_cs4227(hw, reg_slice, ®_val); - if (status != IXGBE_SUCCESS) - return status; - if (reg_val != 0) - return IXGBE_ERR_PHY; - - reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB; - reg_val = 0xFFFF; - status = ixgbe_read_cs4227(hw, reg_slice, ®_val); - if (status != IXGBE_SUCCESS) - return status; - if (reg_val != 0) - return IXGBE_ERR_PHY; - - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (1 << 12); - reg_val = 0xFFFF; - status = ixgbe_read_cs4227(hw, reg_slice, ®_val); - if (status != IXGBE_SUCCESS) - return status; - if (reg_val != 0) - return IXGBE_ERR_PHY; - - reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (1 << 12); - reg_val = 0xFFFF; - status = ixgbe_read_cs4227(hw, reg_slice, ®_val); - if (status != IXGBE_SUCCESS) - return status; - if (reg_val != 0) - return IXGBE_ERR_PHY; - - /* Set scratch indicating that the diagnostic was successful. */ - status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH, - IXGBE_CS4227_SCRATCH_VALUE); - if (status != IXGBE_SUCCESS) - return status; - status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value); - if (status != IXGBE_SUCCESS) - return status; - if (value != IXGBE_CS4227_SCRATCH_VALUE) - return IXGBE_ERR_PHY; - - return IXGBE_SUCCESS; -} - /** * ixgbe_read_pe - Read register from port expander * @hw: pointer to hardware structure @@ -259,13 +155,17 @@ STATIC s32 ixgbe_write_pe(struct ixgbe_hw *hw, u8 reg, u8 value) * ixgbe_reset_cs4227 - Reset CS4227 using port expander * @hw: pointer to hardware structure * + * This function assumes that the caller has acquired the proper semaphore. * Returns error code **/ STATIC s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw) { s32 status; + u32 retry; + u16 value; u8 reg; + /* Trigger hard reset. */ status = ixgbe_read_pe(hw, IXGBE_PE_OUTPUT, ®); if (status != IXGBE_SUCCESS) return status; @@ -300,7 +200,29 @@ STATIC s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw) if (status != IXGBE_SUCCESS) return status; + /* Wait for the reset to complete. */ msec_delay(IXGBE_CS4227_RESET_DELAY); + for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) { + status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EFUSE_STATUS, + &value); + if (status == IXGBE_SUCCESS && + value == IXGBE_CS4227_EEPROM_LOAD_OK) + break; + msec_delay(IXGBE_CS4227_CHECK_DELAY); + } + if (retry == IXGBE_CS4227_RETRIES) { + ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, + "CS4227 reset did not complete."); + return IXGBE_ERR_PHY; + } + + status = ixgbe_read_cs4227(hw, IXGBE_CS4227_EEPROM_STATUS, &value); + if (status != IXGBE_SUCCESS || + !(value & IXGBE_CS4227_EEPROM_LOAD_OK)) { + ERROR_REPORT1(IXGBE_ERROR_INVALID_STATE, + "CS4227 EEPROM did not load successfully."); + return IXGBE_ERR_PHY; + } return IXGBE_SUCCESS; } @@ -311,29 +233,75 @@ STATIC s32 ixgbe_reset_cs4227(struct ixgbe_hw *hw) **/ STATIC void ixgbe_check_cs4227(struct ixgbe_hw *hw) { + s32 status = IXGBE_SUCCESS; u32 swfw_mask = hw->phy.phy_semaphore_mask; - s32 status; + u16 value = 0; u8 retry; for (retry = 0; retry < IXGBE_CS4227_RETRIES; retry++) { status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); if (status != IXGBE_SUCCESS) { ERROR_REPORT2(IXGBE_ERROR_CAUTION, - "semaphore failed with %d\n", status); - return; + "semaphore failed with %d", status); + msec_delay(IXGBE_CS4227_CHECK_DELAY); + continue; } - status = ixgbe_get_cs4227_status(hw); - if (status == IXGBE_SUCCESS) { - hw->mac.ops.release_swfw_sync(hw, swfw_mask); - msec_delay(hw->eeprom.semaphore_delay); + + /* Get status of reset flow. */ + status = ixgbe_read_cs4227(hw, IXGBE_CS4227_SCRATCH, &value); + + if (status == IXGBE_SUCCESS && + value == IXGBE_CS4227_RESET_COMPLETE) + goto out; + + if (status != IXGBE_SUCCESS || + value != IXGBE_CS4227_RESET_PENDING) + break; + + /* Reset is pending. Wait and check again. */ + hw->mac.ops.release_swfw_sync(hw, swfw_mask); + msec_delay(IXGBE_CS4227_CHECK_DELAY); + } + + /* If still pending, assume other instance failed. */ + if (retry == IXGBE_CS4227_RETRIES) { + status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); + if (status != IXGBE_SUCCESS) { + ERROR_REPORT2(IXGBE_ERROR_CAUTION, + "semaphore failed with %d", status); return; } - ixgbe_reset_cs4227(hw); - hw->mac.ops.release_swfw_sync(hw, swfw_mask); - msec_delay(hw->eeprom.semaphore_delay); } - ERROR_REPORT2(IXGBE_ERROR_CAUTION, - "Unable to initialize CS4227, err=%d\n", status); + + /* Reset the CS4227. */ + status = ixgbe_reset_cs4227(hw); + if (status != IXGBE_SUCCESS) { + ERROR_REPORT2(IXGBE_ERROR_INVALID_STATE, + "CS4227 reset failed: %d", status); + goto out; + } + + /* Reset takes so long, temporarily release semaphore in case the + * other driver instance is waiting for the reset indication. + */ + ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH, + IXGBE_CS4227_RESET_PENDING); + hw->mac.ops.release_swfw_sync(hw, swfw_mask); + msec_delay(10); + status = hw->mac.ops.acquire_swfw_sync(hw, swfw_mask); + if (status != IXGBE_SUCCESS) { + ERROR_REPORT2(IXGBE_ERROR_CAUTION, + "semaphore failed with %d", status); + return; + } + + /* Record completion for next time. */ + status = ixgbe_write_cs4227(hw, IXGBE_CS4227_SCRATCH, + IXGBE_CS4227_RESET_COMPLETE); + +out: + hw->mac.ops.release_swfw_sync(hw, swfw_mask); + msec_delay(hw->eeprom.semaphore_delay); } /** @@ -446,8 +414,13 @@ s32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw) hw->bus.type = ixgbe_bus_type_internal; mac->ops.get_bus_info = ixgbe_get_bus_info_X550em; - mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; - mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; + if (hw->mac.type == ixgbe_mac_X550EM_x) { + mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550; + mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550; + mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em; + mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em; + } + mac->ops.get_media_type = ixgbe_get_media_type_X550em; mac->ops.setup_sfp = ixgbe_setup_sfp_modules_X550em; mac->ops.get_link_capabilities = ixgbe_get_link_capabilities_X550em; @@ -460,8 +433,6 @@ s32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw) else mac->ops.setup_fc = ixgbe_setup_fc_X550em; - mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550em; - mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550em; if (hw->device_id != IXGBE_DEV_ID_X550EM_X_KR) mac->ops.setup_eee = NULL; @@ -1484,14 +1455,6 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) * to determine internal PHY mode. */ phy->nw_mng_if_sel = IXGBE_READ_REG(hw, IXGBE_NW_MNG_IF_SEL); - - /* If internal PHY mode is KR, then initialize KR link */ - if (phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE) { - speed = IXGBE_LINK_SPEED_10GB_FULL | - IXGBE_LINK_SPEED_1GB_FULL; - ret_val = ixgbe_setup_kr_speed_x550em(hw, speed); - } - phy->ops.identify_sfp = ixgbe_identify_sfp_module_X550em; } @@ -1508,7 +1471,7 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) /* Set functions pointers based on phy type */ switch (hw->phy.type) { case ixgbe_phy_x550em_kx4: - phy->ops.setup_link = ixgbe_setup_kx4_x550em; + phy->ops.setup_link = NULL; phy->ops.read_reg = ixgbe_read_phy_reg_x550em; phy->ops.write_reg = ixgbe_write_phy_reg_x550em; break; @@ -1535,7 +1498,11 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) ret_val = ixgbe_setup_kr_speed_x550em(hw, speed); } - phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em; + /* setup SW LPLU only for first revision */ + if (!(IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, + IXGBE_FUSES0_GROUP(0)))) + phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em; + phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em; phy->ops.reset = ixgbe_reset_phy_t_X550em; break; @@ -1559,6 +1526,7 @@ s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) s32 status; u32 ctrl = 0; u32 i; + u32 hlreg0; bool link_up = false; DEBUGFUNC("ixgbe_reset_hw_X550em"); @@ -1650,6 +1618,12 @@ mac_reset_top: hw->mac.num_rar_entries = 128; hw->mac.ops.init_rx_addrs(hw); + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_10G_T) { + /* Config MDIO clock speed. */ + hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); + hlreg0 &= ~IXGBE_HLREG0_MDCSPD; + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); + } if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) ixgbe_setup_mux_ctl(hw); @@ -1712,40 +1686,81 @@ s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) } /** - * ixgbe_setup_kx4_x550em - Configure the KX4 PHY. + * ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP * @hw: pointer to hardware structure * - * Configures the integrated KX4 PHY. + * Configure the external PHY and the integrated KR PHY for SFP support. **/ -s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) +s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, + ixgbe_link_speed speed, + bool autoneg_wait_to_complete) { - s32 status; - u32 reg_val; - - status = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1, - IXGBE_SB_IOSF_TARGET_KX4_PCS, ®_val); - if (status) - return status; - - reg_val &= ~(IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4 | - IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX); + s32 ret_val; + u16 reg_slice, reg_val; + bool setup_linear = false; + UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_ENABLE; + /* Check if SFP module is supported and linear */ + ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); - /* Advertise 10G support. */ - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4; + /* If no SFP module present, then return success. Return success since + * there is no reason to configure CS4227 and SFP not present error is + * not excepted in the setup MAC link flow. + */ + if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) + return IXGBE_SUCCESS; - /* Advertise 1G support. */ - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX; + if (ret_val != IXGBE_SUCCESS) + return ret_val; - /* Restart auto-negotiation. */ - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_RESTART; - status = ixgbe_write_iosf_sb_reg_x550(hw, IXGBE_KX4_LINK_CNTL_1, - IXGBE_SB_IOSF_TARGET_KX4_PCS, reg_val); + if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { + /* Configure CS4227 LINE side to 10G SR. */ + reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB + + (hw->bus.lan_id << 12); + reg_val = IXGBE_CS4227_SPEED_10G; + ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, + reg_val); + + reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + + (hw->bus.lan_id << 12); + reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; + ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, + reg_val); + + /* Configure CS4227 for HOST connection rate then type. */ + reg_slice = IXGBE_CS4227_HOST_SPARE22_MSB + + (hw->bus.lan_id << 12); + reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ? + IXGBE_CS4227_SPEED_10G : IXGBE_CS4227_SPEED_1G; + ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, + reg_val); + + reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + + (hw->bus.lan_id << 12); + if (setup_linear) + reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; + else + reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; + ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, + reg_val); - return status; + /* Setup XFI internal link. */ + ret_val = ixgbe_setup_ixfi_x550em(hw, &speed); + } else { + /* Configure internal PHY for KR/KX. */ + ixgbe_setup_kr_speed_x550em(hw, speed); + + /* Configure CS4227 LINE side to proper mode. */ + reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + + (hw->bus.lan_id << 12); + if (setup_linear) + reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; + else + reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; + ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, + reg_val); + } + return ret_val; } /** @@ -1862,66 +1877,35 @@ STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) } /** - * ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP - * @hw: pointer to hardware structure + * ixgbe_ext_phy_t_x550em_get_link - Get ext phy link status + * @hw: address of hardware structure + * @link_up: address of boolean to indicate link status * - * Configure the external PHY and the integrated KR PHY for SFP support. - **/ -s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, - ixgbe_link_speed speed, - bool autoneg_wait_to_complete) + * Returns error code if unable to get link status. + */ +STATIC s32 ixgbe_ext_phy_t_x550em_get_link(struct ixgbe_hw *hw, bool *link_up) { - s32 ret_val; - u16 reg_slice, reg_val; - bool setup_linear = false; - UNREFERENCED_1PARAMETER(autoneg_wait_to_complete); - - /* Check if SFP module is supported and linear */ - ret_val = ixgbe_supported_sfp_modules_X550em(hw, &setup_linear); + u32 ret; + u16 autoneg_status; - /* If no SFP module present, then return success. Return success since - * there is no reason to configure CS4227 and SFP not present error is - * not excepted in the setup MAC link flow. - */ - if (ret_val == IXGBE_ERR_SFP_NOT_PRESENT) - return IXGBE_SUCCESS; + *link_up = false; - if (ret_val != IXGBE_SUCCESS) - return ret_val; - - /* Configure CS4227 for LINE connection rate then type. */ - reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB + (hw->bus.lan_id << 12); - reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 0 : 0x8000; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); + /* read this twice back to back to indicate current status */ + ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_status); + if (ret != IXGBE_SUCCESS) + return ret; - reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + (hw->bus.lan_id << 12); - if (setup_linear) - reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; - else - reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); - - /* Configure CS4227 for HOST connection rate then type. */ - reg_slice = IXGBE_CS4227_HOST_SPARE22_MSB + (hw->bus.lan_id << 12); - reg_val = (speed & IXGBE_LINK_SPEED_10GB_FULL) ? 0 : 0x8000; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); - - reg_slice = IXGBE_CS4227_HOST_SPARE24_LSB + (hw->bus.lan_id << 12); - if (setup_linear) - reg_val = (IXGBE_CS4227_EDC_MODE_CX1 << 1) | 0x1; - else - reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; - ret_val = ixgbe_write_i2c_combined(hw, IXGBE_CS4227, reg_slice, - reg_val); + ret = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_status); + if (ret != IXGBE_SUCCESS) + return ret; - /* If internal link mode is XFI, then setup XFI internal link. */ - if (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) - ret_val = ixgbe_setup_ixfi_x550em(hw, &speed); + *link_up = !!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS); - return ret_val; + return IXGBE_SUCCESS; } /** @@ -1938,33 +1922,34 @@ s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, */ s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw) { - u32 status; - u16 autoneg_status, speed; ixgbe_link_speed force_speed; + bool link_up; + u32 status; + u16 speed; if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) return IXGBE_ERR_CONFIG; - /* read this twice back to back to indicate current status */ - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_status); - if (status != IXGBE_SUCCESS) - return status; - - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_status); + /* If link is not up, then there is no setup necessary so return */ + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); if (status != IXGBE_SUCCESS) return status; - /* If link is not up, then there is no setup necessary so return */ - if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS)) + if (!link_up) return IXGBE_SUCCESS; status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT, IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &speed); + if (status != IXGBE_SUCCESS) + return status; + + /* If link is not still up, then no setup is necessary so return */ + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); + if (status != IXGBE_SUCCESS) + return status; + if (!link_up) + return IXGBE_SUCCESS; /* clear everything but the speed and duplex bits */ speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK; @@ -2689,19 +2674,21 @@ void ixgbe_disable_rx_x550(struct ixgbe_hw *hw) **/ s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) { - u16 autoneg_status, an_10g_cntl_reg, autoneg_reg, speed; + u16 an_10g_cntl_reg, autoneg_reg, speed; s32 status; ixgbe_link_speed lcd_speed; u32 save_autoneg; + bool link_up; + + /* SW LPLU not required on later HW revisions. */ + if (IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))) + return IXGBE_SUCCESS; /* If blocked by MNG FW, then don't restart AN */ if (ixgbe_check_reset_blocked(hw)) return IXGBE_SUCCESS; - status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS, - IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_status); - + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); if (status != IXGBE_SUCCESS) return status; @@ -2713,8 +2700,7 @@ s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) /* If link is down, LPLU disabled in NVM, WoL disabled, or manageability * disabled, then force link down by entering low power mode. */ - if (!(autoneg_status & IXGBE_MDIO_AUTO_NEG_LINK_STATUS) || - !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) || + if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) || !(hw->wol_enabled || ixgbe_mng_present(hw))) return ixgbe_set_copper_phy_power(hw, FALSE); @@ -2735,6 +2721,11 @@ s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) if (status != IXGBE_SUCCESS) return status; + /* If no link now, speed is invalid so take link down */ + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); + if (status != IXGBE_SUCCESS) + return ixgbe_set_copper_phy_power(hw, false); + /* clear everything but the speed bits */ speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK; @@ -2748,7 +2739,7 @@ s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) /* Clear AN completed indication */ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM, IXGBE_MDIO_AUTO_NEG_DEV_TYPE, - &autoneg_status); + &autoneg_reg); if (status != IXGBE_SUCCESS) return status; @@ -2874,7 +2865,7 @@ s32 ixgbe_setup_fc_X550em(struct ixgbe_hw *hw) goto out; } - if (hw->phy.media_type == ixgbe_media_type_backplane) { + if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { ret_val = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); @@ -2890,9 +2881,8 @@ s32 ixgbe_setup_fc_X550em(struct ixgbe_hw *hw) IXGBE_KRM_AN_CNTL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); - /* Not all devices fully support AN. */ - if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) - hw->fc.disable_fc_autoneg = true; + /* This device does not fully support AN. */ + hw->fc.disable_fc_autoneg = true; } out: @@ -3090,3 +3080,51 @@ s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw) /* Configure Link Status Alarm and Temperature Threshold interrupts */ return ixgbe_enable_lasi_ext_t_x550em(hw); } + +/** + * ixgbe_led_on_t_X550em - Turns on the software controllable LEDs. + * @hw: pointer to hardware structure + * @led_idx: led number to turn on + **/ +s32 ixgbe_led_on_t_X550em(struct ixgbe_hw *hw, u32 led_idx) +{ + u16 phy_data; + + DEBUGFUNC("ixgbe_led_on_t_X550em"); + + if (led_idx >= IXGBE_X557_MAX_LED_INDEX) + return IXGBE_ERR_PARAM; + + /* To turn on the LED, set mode to ON. */ + ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data); + phy_data |= IXGBE_X557_LED_MANUAL_SET_MASK; + ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data); + + return IXGBE_SUCCESS; +} + +/** + * ixgbe_led_off_t_X550em - Turns off the software controllable LEDs. + * @hw: pointer to hardware structure + * @led_idx: led number to turn off + **/ +s32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx) +{ + u16 phy_data; + + DEBUGFUNC("ixgbe_led_off_t_X550em"); + + if (led_idx >= IXGBE_X557_MAX_LED_INDEX) + return IXGBE_ERR_PARAM; + + /* To turn on the LED, set mode to ON. */ + ixgbe_read_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, &phy_data); + phy_data &= ~IXGBE_X557_LED_MANUAL_SET_MASK; + ixgbe_write_phy_reg(hw, IXGBE_X557_LED_PROVISIONING + led_idx, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, phy_data); + + return IXGBE_SUCCESS; +}