X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fixgbe%2Fbase%2Fixgbe_x550.c;h=0bbaa55ba1b692e108f7388b0cc3b3c6052da70e;hb=9115326d99f0f03c163b04d6379bd3b8969db6c0;hp=48077aec24a2680db408775798e09f6e69784dab;hpb=da431fd14d00af94deab1e1c078f8417a3732e1f;p=dpdk.git diff --git a/drivers/net/ixgbe/base/ixgbe_x550.c b/drivers/net/ixgbe/base/ixgbe_x550.c index 48077aec24..0bbaa55ba1 100644 --- a/drivers/net/ixgbe/base/ixgbe_x550.c +++ b/drivers/net/ixgbe/base/ixgbe_x550.c @@ -39,6 +39,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "ixgbe_phy.h" STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed); +static s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *, u32 mask); +static void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *, u32 mask); /** * ixgbe_init_ops_X550 - Inits func ptrs and MAC type @@ -80,9 +82,14 @@ 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) { + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_10G_T: hw->mac.ops.led_on = ixgbe_led_on_t_X550em; hw->mac.ops.led_off = ixgbe_led_off_t_X550em; + break; + default: + break; } return ret_val; } @@ -97,7 +104,7 @@ s32 ixgbe_init_ops_X550(struct ixgbe_hw *hw) **/ STATIC s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) { - return ixgbe_read_i2c_combined_unlocked(hw, IXGBE_CS4227, reg, value); + return hw->link.ops.read_link_unlocked(hw, hw->link.addr, reg, value); } /** @@ -110,133 +117,7 @@ STATIC s32 ixgbe_read_cs4227(struct ixgbe_hw *hw, u16 reg, u16 *value) **/ 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 - * - * Performs a diagnostic on the CS4227 chip. Returns an error if it is - * not operating correctly. - * This function assumes that the caller has acquired the proper semaphore. - **/ -STATIC s32 ixgbe_get_cs4227_status(struct ixgbe_hw *hw) -{ - s32 status; - u16 value = 0; - u16 reg_slice, reg_val; - u8 retry; - - /* Check register reads. */ - 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. - * While we are at it, set the LINE side to 10G SR, which is - * what it needs to be regardless of the actual link. - */ - if (value != IXGBE_CS4227_SCRATCH_VALUE) { - reg_slice = IXGBE_CS4227_LINE_SPARE22_MSB; - reg_val = IXGBE_CS4227_SPEED_10G; - status = ixgbe_write_cs4227(hw, reg_slice, reg_val); - if (status != IXGBE_SUCCESS) - return status; - - 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_SPARE22_MSB + (1 << 12); - reg_val = IXGBE_CS4227_SPEED_10G; - 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; + return hw->link.ops.write_link_unlocked(hw, hw->link.addr, reg, value); } /** @@ -281,13 +162,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; @@ -322,7 +207,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; } @@ -333,29 +240,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); } /** @@ -384,22 +337,36 @@ STATIC void ixgbe_setup_mux_ctl(struct ixgbe_hw *hw) STATIC s32 ixgbe_identify_phy_x550em(struct ixgbe_hw *hw) { switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_A_SFP: + hw->phy.phy_semaphore_mask = IXGBE_GSSR_TOKEN_SM; + if (hw->bus.lan_id) + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY1_SM; + else + hw->phy.phy_semaphore_mask |= IXGBE_GSSR_PHY0_SM; + return ixgbe_identify_module_generic(hw); case IXGBE_DEV_ID_X550EM_X_SFP: /* set up for CS4227 usage */ hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM; ixgbe_setup_mux_ctl(hw); ixgbe_check_cs4227(hw); + /* Fallthrough */ + case IXGBE_DEV_ID_X550EM_A_SFP_N: return ixgbe_identify_module_generic(hw); break; case IXGBE_DEV_ID_X550EM_X_KX4: hw->phy.type = ixgbe_phy_x550em_kx4; break; case IXGBE_DEV_ID_X550EM_X_KR: + case IXGBE_DEV_ID_X550EM_A_KR: + case IXGBE_DEV_ID_X550EM_A_KR_L: hw->phy.type = ixgbe_phy_x550em_kr; break; case IXGBE_DEV_ID_X550EM_X_1G_T: case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + case IXGBE_DEV_ID_X550EM_A_10G_T: return ixgbe_identify_phy_generic(hw); default: break; @@ -421,6 +388,68 @@ STATIC s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr, return IXGBE_NOT_IMPLEMENTED; } +/** + * ixgbe_read_i2c_combined_generic - Perform I2C read combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to read from + * @reg: I2C device register to read from + * @val: pointer to location to receive read value + * + * Returns an error code on error. + **/ +static s32 ixgbe_read_i2c_combined_generic(struct ixgbe_hw *hw, u8 addr, + u16 reg, u16 *val) +{ + return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, true); +} + +/** + * ixgbe_read_i2c_combined_generic_unlocked - Do I2C read combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to read from + * @reg: I2C device register to read from + * @val: pointer to location to receive read value + * + * Returns an error code on error. + **/ +static s32 +ixgbe_read_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, u8 addr, + u16 reg, u16 *val) +{ + return ixgbe_read_i2c_combined_generic_int(hw, addr, reg, val, false); +} + +/** + * ixgbe_write_i2c_combined_generic - Perform I2C write combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to write to + * @reg: I2C device register to write to + * @val: value to write + * + * Returns an error code on error. + **/ +static s32 ixgbe_write_i2c_combined_generic(struct ixgbe_hw *hw, + u8 addr, u16 reg, u16 val) +{ + return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, true); +} + +/** + * ixgbe_write_i2c_combined_generic_unlocked - Do I2C write combined operation + * @hw: pointer to the hardware structure + * @addr: I2C bus address to write to + * @reg: I2C device register to write to + * @val: value to write + * + * Returns an error code on error. + **/ +static s32 +ixgbe_write_i2c_combined_generic_unlocked(struct ixgbe_hw *hw, + u8 addr, u16 reg, u16 val) +{ + return ixgbe_write_i2c_combined_generic_int(hw, addr, reg, val, false); +} + /** * ixgbe_init_ops_X550EM - Inits func ptrs and MAC type * @hw: pointer to hardware structure @@ -433,6 +462,7 @@ s32 ixgbe_init_ops_X550EM(struct ixgbe_hw *hw) struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_eeprom_info *eeprom = &hw->eeprom; struct ixgbe_phy_info *phy = &hw->phy; + struct ixgbe_link_info *link = &hw->link; s32 ret_val; DEBUGFUNC("ixgbe_init_ops_X550EM"); @@ -468,8 +498,26 @@ 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; + link->ops.read_link = ixgbe_read_i2c_combined_generic; + link->ops.read_link_unlocked = + ixgbe_read_i2c_combined_generic_unlocked; + link->ops.write_link = ixgbe_write_i2c_combined_generic; + link->ops.write_link_unlocked = + ixgbe_write_i2c_combined_generic_unlocked; + link->addr = IXGBE_CS4227; + } + if (hw->mac.type == ixgbe_mac_X550EM_a) { + mac->ops.read_iosf_sb_reg = ixgbe_read_iosf_sb_reg_x550a; + mac->ops.write_iosf_sb_reg = ixgbe_write_iosf_sb_reg_x550a; + mac->ops.acquire_swfw_sync = ixgbe_acquire_swfw_sync_X550a; + mac->ops.release_swfw_sync = ixgbe_release_swfw_sync_X550a; + } + 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; @@ -482,8 +530,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; @@ -686,7 +732,6 @@ s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee) u16 autoneg_eee_reg; u32 link_reg; s32 status; - u32 fuse; DEBUGFUNC("ixgbe_setup_eee_X550"); @@ -695,7 +740,7 @@ s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee) if (enable_eee) { eeer |= (IXGBE_EEER_TX_LPI_EN | IXGBE_EEER_RX_LPI_EN); - if (hw->device_id == IXGBE_DEV_ID_X550T) { + if (hw->mac.type == ixgbe_mac_X550) { /* Advertise EEE capability */ hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_eee_reg); @@ -707,9 +752,10 @@ s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee) hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_eee_reg); } else if (hw->device_id == IXGBE_DEV_ID_X550EM_X_KR) { - /* Not supported on first revision. */ - fuse = IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)); - if (!(fuse & IXGBE_FUSES0_REV1)) + /* Not supported on first revision of X550EM_x. */ + if ((hw->mac.type == ixgbe_mac_X550EM_x) && + !(IXGBE_FUSES0_REV_MASK & + IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))) return IXGBE_SUCCESS; status = ixgbe_read_iosf_sb_reg_x550(hw, @@ -733,7 +779,7 @@ s32 ixgbe_setup_eee_X550(struct ixgbe_hw *hw, bool enable_eee) } else { eeer &= ~(IXGBE_EEER_TX_LPI_EN | IXGBE_EEER_RX_LPI_EN); - if (hw->device_id == IXGBE_DEV_ID_X550T) { + if (hw->mac.type == ixgbe_mac_X550) { /* Disable advertised EEE capability */ hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_EEE_ADVT, IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_eee_reg); @@ -948,6 +994,126 @@ out: return ret; } +/** + * ixgbe_get_phy_token - Get the token for shared phy access + * @hw: Pointer to hardware structure + */ + +s32 ixgbe_get_phy_token(struct ixgbe_hw *hw) +{ + struct ixgbe_hic_phy_token_req token_cmd; + s32 status; + + token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; + token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; + token_cmd.hdr.cmd_or_resp.cmd_resv = 0; + token_cmd.port_number = hw->bus.lan_id; + token_cmd.command_type = FW_PHY_TOKEN_REQ; + token_cmd.pad = 0; + status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd, + sizeof(token_cmd), + IXGBE_HI_COMMAND_TIMEOUT, + true); + if (status) + return status; + if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK) + return IXGBE_SUCCESS; + if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY) + return IXGBE_ERR_FW_RESP_INVALID; + + return IXGBE_ERR_TOKEN_RETRY; +} + +/** + * ixgbe_put_phy_token - Put the token for shared phy access + * @hw: Pointer to hardware structure + */ + +s32 ixgbe_put_phy_token(struct ixgbe_hw *hw) +{ + struct ixgbe_hic_phy_token_req token_cmd; + s32 status; + + token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD; + token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN; + token_cmd.hdr.cmd_or_resp.cmd_resv = 0; + token_cmd.port_number = hw->bus.lan_id; + token_cmd.command_type = FW_PHY_TOKEN_REL; + token_cmd.pad = 0; + status = ixgbe_host_interface_command(hw, (u32 *)&token_cmd, + sizeof(token_cmd), + IXGBE_HI_COMMAND_TIMEOUT, + true); + if (status) + return status; + if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK) + return IXGBE_SUCCESS; + return IXGBE_ERR_FW_RESP_INVALID; +} + +/** + * ixgbe_write_iosf_sb_reg_x550a - Writes a value to specified register + * of the IOSF device + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 3 bit device type + * @data: Data to write to the register + **/ +s32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 data) +{ + struct ixgbe_hic_internal_phy_req write_cmd; + s32 status; + UNREFERENCED_1PARAMETER(device_type); + + write_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; + write_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN; + write_cmd.port_number = hw->bus.lan_id; + write_cmd.command_type = FW_INT_PHY_REQ_WRITE; + write_cmd.address = (u16)reg_addr; + write_cmd.rsv1 = 0; + write_cmd.write_data = data; + write_cmd.pad = 0; + + status = ixgbe_host_interface_command(hw, (u32 *)&write_cmd, + sizeof(write_cmd), IXGBE_HI_COMMAND_TIMEOUT, false); + + return status; +} + +/** + * ixgbe_read_iosf_sb_reg_x550a - Writes a value to specified register + * of the IOSF device. + * @hw: pointer to hardware structure + * @reg_addr: 32 bit PHY register to write + * @device_type: 3 bit device type + * @data: Pointer to read data from the register + **/ +s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr, + u32 device_type, u32 *data) +{ + struct ixgbe_hic_internal_phy_req read_cmd; + s32 status; + UNREFERENCED_1PARAMETER(device_type); + + read_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD; + read_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN; + read_cmd.port_number = hw->bus.lan_id; + read_cmd.command_type = FW_INT_PHY_REQ_READ; + read_cmd.address = (u16)reg_addr; + read_cmd.rsv1 = 0; + read_cmd.write_data = 0; + read_cmd.pad = 0; + + status = ixgbe_host_interface_command(hw, (u32 *)&read_cmd, + sizeof(read_cmd), IXGBE_HI_COMMAND_TIMEOUT, true); + + /* Extract the register value from the response. */ + *data = ((struct ixgbe_hic_internal_phy_resp *)&read_cmd)->read_data; + + return status; +} + /** * ixgbe_disable_mdd_X550 * @hw: pointer to hardware structure @@ -1107,13 +1273,22 @@ enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw) switch (hw->device_id) { case IXGBE_DEV_ID_X550EM_X_KR: case IXGBE_DEV_ID_X550EM_X_KX4: + case IXGBE_DEV_ID_X550EM_A_KR: + case IXGBE_DEV_ID_X550EM_A_KR_L: media_type = ixgbe_media_type_backplane; break; case IXGBE_DEV_ID_X550EM_X_SFP: + case IXGBE_DEV_ID_X550EM_A_SFP: + case IXGBE_DEV_ID_X550EM_A_SFP_N: + case IXGBE_DEV_ID_X550EM_A_QSFP: + case IXGBE_DEV_ID_X550EM_A_QSFP_N: media_type = ixgbe_media_type_fiber; break; case IXGBE_DEV_ID_X550EM_X_1G_T: case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + case IXGBE_DEV_ID_X550EM_A_10G_T: media_type = ixgbe_media_type_copper; break; default: @@ -1318,7 +1493,7 @@ STATIC s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc) IXGBE_MDIO_GLOBAL_ALARM_1_INT))) return status; - /* High temperature failure alarm triggered */ + /* Global alarm triggered */ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_ALARM_1, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®); @@ -1331,6 +1506,21 @@ STATIC s32 ixgbe_get_lasi_ext_t_x550em(struct ixgbe_hw *hw, bool *lsc) /* power down the PHY in case the PHY FW didn't already */ ixgbe_set_copper_phy_power(hw, false); return IXGBE_ERR_OVERTEMP; + } else if (reg & IXGBE_MDIO_GLOBAL_ALM_1_DEV_FAULT) { + /* device fault alarm triggered */ + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_FAULT_MSG, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + ®); + + if (status != IXGBE_SUCCESS) + return status; + + /* if device fault was due to high temp alarm handle and exit */ + if (reg == IXGBE_MDIO_GLOBAL_FAULT_MSG_HI_TMP) { + /* power down the PHY in case the PHY FW didn't */ + ixgbe_set_copper_phy_power(hw, false); + return IXGBE_ERR_OVERTEMP; + } } /* Vendor alarm 2 triggered */ @@ -1388,7 +1578,7 @@ STATIC s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw) if (status != IXGBE_SUCCESS) return status; - /* Enables high temperature failure alarm */ + /* Enable high temperature failure and global fault alarms */ status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, ®); @@ -1396,7 +1586,8 @@ STATIC s32 ixgbe_enable_lasi_ext_t_x550em(struct ixgbe_hw *hw) if (status != IXGBE_SUCCESS) return status; - reg |= IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN; + reg |= (IXGBE_MDIO_GLOBAL_INT_HI_TEMP_EN | + IXGBE_MDIO_GLOBAL_INT_DEV_FAULT_EN); status = hw->phy.ops.write_reg(hw, IXGBE_MDIO_GLOBAL_INT_MASK, IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, @@ -1491,7 +1682,6 @@ STATIC s32 ixgbe_setup_kr_speed_x550em(struct ixgbe_hw *hw, s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) { struct ixgbe_phy_info *phy = &hw->phy; - ixgbe_link_speed speed; s32 ret_val; DEBUGFUNC("ixgbe_init_phy_ops_X550em"); @@ -1506,14 +1696,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; } @@ -1530,7 +1712,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; @@ -1548,18 +1730,13 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) /* If internal link mode is XFI, then setup iXFI internal link, * else setup KR now. */ - if (!(phy->nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { - phy->ops.setup_internal_link = + phy->ops.setup_internal_link = ixgbe_setup_internal_phy_t_x550em; - } else { - speed = IXGBE_LINK_SPEED_10GB_FULL | - IXGBE_LINK_SPEED_1GB_FULL; - ret_val = ixgbe_setup_kr_speed_x550em(hw, speed); - } - /* setup SW LPLU only for first revision */ - if (!(IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, - IXGBE_FUSES0_GROUP(0)))) + /* setup SW LPLU only for first revision of X550EM_x */ + if ((hw->mac.type == ixgbe_mac_X550EM_x) && + !(IXGBE_FUSES0_REV_MASK & + 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; @@ -1571,6 +1748,31 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) return ret_val; } +/** + * ixgbe_set_mdio_speed - Set MDIO clock speed + * @hw: pointer to hardware structure + */ +static void ixgbe_set_mdio_speed(struct ixgbe_hw *hw) +{ + u32 hlreg0; + + switch (hw->device_id) { + case IXGBE_DEV_ID_X550EM_X_10G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T: + case IXGBE_DEV_ID_X550EM_A_1G_T_L: + case IXGBE_DEV_ID_X550EM_A_10G_T: + case IXGBE_DEV_ID_X550EM_A_SFP: + case IXGBE_DEV_ID_X550EM_A_QSFP: + /* Config MDIO clock speed before the first MDIO PHY access */ + hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0); + hlreg0 &= ~IXGBE_HLREG0_MDCSPD; + IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0); + break; + default: + break; + } +} + /** * ixgbe_reset_hw_X550em - Perform hardware reset * @hw: pointer to hardware structure @@ -1585,7 +1787,6 @@ 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"); @@ -1598,9 +1799,9 @@ s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw) /* flush pending Tx transactions */ ixgbe_clear_tx_pending(hw); - /* PHY ops must be identified and initialized prior to reset */ + ixgbe_set_mdio_speed(hw); - /* Identify PHY and related function pointers */ + /* PHY ops must be identified and initialized prior to reset */ status = hw->phy.ops.init(hw); if (status == IXGBE_ERR_SFP_NOT_SUPPORTED) @@ -1677,12 +1878,7 @@ 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); - } + ixgbe_set_mdio_speed(hw); if (hw->device_id == IXGBE_DEV_ID_X550EM_X_SFP) ixgbe_setup_mux_ctl(hw); @@ -1744,43 +1940,6 @@ s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw) return ixgbe_setup_kr_speed_x550em(hw, hw->phy.autoneg_advertised); } -/** - * ixgbe_setup_kx4_x550em - Configure the KX4 PHY. - * @hw: pointer to hardware structure - * - * Configures the integrated KX4 PHY. - **/ -s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw) -{ - 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); - - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_ENABLE; - - /* Advertise 10G support. */ - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX4; - - /* Advertise 1G support. */ - if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) - reg_val |= IXGBE_KX4_LINK_CNTL_1_TETH_AN_CAP_KX; - - /* 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); - - return status; -} - /** * ixgbe_setup_mac_link_sfp_x550em - Setup internal/external the PHY for SFP * @hw: pointer to hardware structure @@ -1809,81 +1968,67 @@ s32 ixgbe_setup_mac_link_sfp_x550em(struct ixgbe_hw *hw, if (ret_val != IXGBE_SUCCESS) return ret_val; - /* 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); + 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 = hw->link.ops.write_link(hw, hw->link.addr, 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); + reg_slice = IXGBE_CS4227_LINE_SPARE24_LSB + + (hw->bus.lan_id << 12); + reg_val = (IXGBE_CS4227_EDC_MODE_SR << 1) | 0x1; + ret_val = hw->link.ops.write_link(hw, hw->link.addr, 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) ? + /* 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); + ret_val = hw->link.ops.write_link(hw, hw->link.addr, 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); + 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 = hw->link.ops.write_link(hw, hw->link.addr, reg_slice, + reg_val); - /* 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)) + /* 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 = hw->link.ops.write_link(hw, hw->link.addr, reg_slice, + reg_val); + } return ret_val; } /** - * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode. + * ixgbe_setup_ixfi_x550em_x - MAC specific iXFI configuration * @hw: pointer to hardware structure - * @speed: the link speed to force * - * Configures the integrated KR PHY to use iXFI mode. Used to connect an - * internal and external PHY at a specific speed, without autonegotiation. + * iXfI configuration needed for ixgbe_mac_X550EM_x devices. **/ -STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) +STATIC s32 ixgbe_setup_ixfi_x550em_x(struct ixgbe_hw *hw) { s32 status; u32 reg_val; - /* Disable AN and force speed to 10G Serial. */ - status = ixgbe_read_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); - if (status != IXGBE_SUCCESS) - return status; - - reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; - reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; - - /* Select forced link speed for internal PHY. */ - switch (*speed) { - case IXGBE_LINK_SPEED_10GB_FULL: - reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; - break; - case IXGBE_LINK_SPEED_1GB_FULL: - reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; - break; - default: - /* Other link speeds are not supported by internal KR PHY. */ - return IXGBE_ERR_LINK_SETUP; - } - - status = ixgbe_write_iosf_sb_reg_x550(hw, - IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), - IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); - if (status != IXGBE_SUCCESS) - return status; - /* Disable training protocol FSM. */ status = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KRM_RX_TRN_LINKUP_CTRL(hw->bus.lan_id), @@ -1938,9 +2083,58 @@ STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) status = ixgbe_write_iosf_sb_reg_x550(hw, IXGBE_KRM_TX_COEFF_CTRL_1(hw->bus.lan_id), IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); + return status; +} + +/** + * ixgbe_setup_ixfi_x550em - Configure the KR PHY for iXFI mode. + * @hw: pointer to hardware structure + * @speed: the link speed to force + * + * Configures the integrated KR PHY to use iXFI mode. Used to connect an + * internal and external PHY at a specific speed, without autonegotiation. + **/ +STATIC s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed) +{ + s32 status; + u32 reg_val; + + /* Disable AN and force speed to 10G Serial. */ + status = ixgbe_read_iosf_sb_reg_x550(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, ®_val); + if (status != IXGBE_SUCCESS) + return status; + + reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_AN_ENABLE; + reg_val &= ~IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_MASK; + + /* Select forced link speed for internal PHY. */ + switch (*speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_10G; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + reg_val |= IXGBE_KRM_LINK_CTRL_1_TETH_FORCE_SPEED_1G; + break; + default: + /* Other link speeds are not supported by internal KR PHY. */ + return IXGBE_ERR_LINK_SETUP; + } + + status = ixgbe_write_iosf_sb_reg_x550(hw, + IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), + IXGBE_SB_IOSF_TARGET_KR_PHY, reg_val); if (status != IXGBE_SUCCESS) return status; + /* Additional configuration needed for x550em_x */ + if (hw->mac.type == ixgbe_mac_X550EM_x) { + status = ixgbe_setup_ixfi_x550em_x(hw); + if (status != IXGBE_SUCCESS) + return status; + } + /* Toggle port SW reset by AN reset. */ status = ixgbe_read_iosf_sb_reg_x550(hw, IXGBE_KRM_LINK_CTRL_1(hw->bus.lan_id), @@ -2009,43 +2203,50 @@ s32 ixgbe_setup_internal_phy_t_x550em(struct ixgbe_hw *hw) if (hw->mac.ops.get_media_type(hw) != ixgbe_media_type_copper) return IXGBE_ERR_CONFIG; - /* 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 (!(hw->phy.nw_mng_if_sel & IXGBE_NW_MNG_IF_SEL_INT_PHY_MODE)) { + /* If link is down, 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_up) - return IXGBE_SUCCESS; + 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; + 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; + /* If link is still down - no setup is required 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; + /* clear everything but the speed and duplex bits */ + speed &= IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK; - switch (speed) { - case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL: - force_speed = IXGBE_LINK_SPEED_10GB_FULL; - break; - case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL: - force_speed = IXGBE_LINK_SPEED_1GB_FULL; - break; - default: - /* Internal PHY does not support anything else */ - return IXGBE_ERR_INVALID_LINK_SETTINGS; - } + switch (speed) { + case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL: + force_speed = IXGBE_LINK_SPEED_10GB_FULL; + break; + case IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL: + force_speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + default: + /* Internal PHY does not support anything else */ + return IXGBE_ERR_INVALID_LINK_SETTINGS; + } - return ixgbe_setup_ixfi_x550em(hw, &force_speed); + return ixgbe_setup_ixfi_x550em(hw, &force_speed); + } else { + speed = IXGBE_LINK_SPEED_10GB_FULL | + IXGBE_LINK_SPEED_1GB_FULL; + return ixgbe_setup_kr_speed_x550em(hw, speed); + } } /** @@ -2760,7 +2961,9 @@ s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) bool link_up; /* SW LPLU not required on later HW revisions. */ - if (IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))) + if ((hw->mac.type == ixgbe_mac_X550EM_x) && + (IXGBE_FUSES0_REV_MASK & + IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)))) return IXGBE_SUCCESS; /* If blocked by MNG FW, then don't restart AN */ @@ -3028,6 +3231,59 @@ void ixgbe_release_swfw_sync_X550em(struct ixgbe_hw *hw, u32 mask) ixgbe_release_swfw_sync_X540(hw, mask); } +/** + * ixgbe_acquire_swfw_sync_X550a - Acquire SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to acquire + * + * Acquires the SWFW semaphore and get the shared phy token as needed + */ +static s32 ixgbe_acquire_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask) +{ + u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; + int retries = FW_PHY_TOKEN_RETRIES; + s32 status = IXGBE_SUCCESS; + + DEBUGFUNC("ixgbe_acquire_swfw_sync_X550a"); + + while (--retries) { + if (hmask) + status = ixgbe_acquire_swfw_sync_X540(hw, hmask); + if (status) + break; + if (!(mask & IXGBE_GSSR_TOKEN_SM)) + break; + status = ixgbe_get_phy_token(hw); + if (status != IXGBE_ERR_TOKEN_RETRY) + break; + if (hmask) + ixgbe_release_swfw_sync_X540(hw, hmask); + msec_delay(FW_PHY_TOKEN_DELAY); + } + + return status; +} + +/** + * ixgbe_release_swfw_sync_X550a - Release SWFW semaphore + * @hw: pointer to hardware structure + * @mask: Mask to specify which semaphore to release + * + * Releases the SWFW semaphore and puts the shared phy token as needed + */ +static void ixgbe_release_swfw_sync_X550a(struct ixgbe_hw *hw, u32 mask) +{ + u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM; + + DEBUGFUNC("ixgbe_release_swfw_sync_X550a"); + + if (mask & IXGBE_GSSR_TOKEN_SM) + ixgbe_put_phy_token(hw); + + if (hmask) + ixgbe_release_swfw_sync_X540(hw, hmask); +} + /** * ixgbe_handle_lasi_ext_t_x550em - Handle external Base T PHY interrupt * @hw: pointer to hardware structure @@ -3207,3 +3463,4 @@ s32 ixgbe_led_off_t_X550em(struct ixgbe_hw *hw, u32 led_idx) return IXGBE_SUCCESS; } +