From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id E35EAA04B7; Wed, 14 Oct 2020 08:00:33 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id EB0631DC5D; Wed, 14 Oct 2020 07:54:32 +0200 (CEST) Received: from smtpbgeu1.qq.com (smtpbgeu1.qq.com [52.59.177.22]) by dpdk.org (Postfix) with ESMTP id 081861DC3F for ; Wed, 14 Oct 2020 07:54:26 +0200 (CEST) X-QQ-mid: bizesmtp28t1602654860tj8kqgk0 Received: from localhost.localdomain.com (unknown [183.129.236.74]) by esmtp10.qq.com (ESMTP) with id ; Wed, 14 Oct 2020 13:54:20 +0800 (CST) X-QQ-SSF: 01400000000000C0C000B00A0000000 X-QQ-FEAT: JefCW0AU9/i1W/b9u4lajqRmEOiXztuypr26axT4A/ev7RpVf1N2YuuZ8Nrsv DlPPTXnz379lqptfZ4DHBQKmmXEiHV8UFqoMvdhhIctRwL4OVgR9tNvl0BjgFuwkWDhm/1K h/FqgqrvIIbJU/9Pm7iEFkT8ZqGcAdILExRt0/vMskwHq6veEtGjrZ19/OBw5hdDSN1LVx6 soJcBAQ6/7cDWKhKJHqUqOeLjJ6d7P3wphmFOFVAWBQL5p0ReOqgoWXRTUJqb6sm4+lBKr0 HUJeJ4xMH5h9FbuyH3TKy7JZU0eNIGtkqvD5gzav1BLkp22o6tzB8TsODQvRkCWs1UmvUax 4ZvpYsx X-QQ-GoodBg: 2 From: Jiawen Wu To: dev@dpdk.org Cc: Jiawen Wu Date: Wed, 14 Oct 2020 13:54:36 +0800 Message-Id: <20201014055517.1214386-16-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.18.4 In-Reply-To: <20201014055517.1214386-1-jiawenwu@trustnetic.com> References: <20201014055517.1214386-1-jiawenwu@trustnetic.com> X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybgforeign:qybgforeign6 X-QQ-Bgrelay: 1 Subject: [dpdk-dev] [PATCH v3 15/56] net/txgbe: add link status change X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add ethdev link interrupt handler, MAC setup link and check link status and get capabilities. Signed-off-by: Jiawen Wu --- drivers/net/txgbe/base/txgbe_eeprom.h | 3 + drivers/net/txgbe/base/txgbe_hw.c | 498 +++++++++++++++++++++++++- drivers/net/txgbe/base/txgbe_hw.h | 15 + drivers/net/txgbe/base/txgbe_phy.c | 312 ++++++++++++++++ drivers/net/txgbe/base/txgbe_phy.h | 12 + drivers/net/txgbe/base/txgbe_regs.h | 10 +- drivers/net/txgbe/base/txgbe_type.h | 21 ++ drivers/net/txgbe/txgbe_ethdev.c | 148 +++++++- drivers/net/txgbe/txgbe_ethdev.h | 8 +- 9 files changed, 1017 insertions(+), 10 deletions(-) diff --git a/drivers/net/txgbe/base/txgbe_eeprom.h b/drivers/net/txgbe/base/txgbe_eeprom.h index 25d03421c..26cf08495 100644 --- a/drivers/net/txgbe/base/txgbe_eeprom.h +++ b/drivers/net/txgbe/base/txgbe_eeprom.h @@ -24,6 +24,9 @@ #define TXGBE_ISCSI_BOOT_CONFIG 0x07 #define TXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1 +#define TXGBE_FW_LESM_PARAMETERS_PTR 0x2 +#define TXGBE_FW_LESM_STATE_1 0x1 +#define TXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */ s32 txgbe_init_eeprom_params(struct txgbe_hw *hw); s32 txgbe_calc_eeprom_checksum(struct txgbe_hw *hw); diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index 31f8688d4..5b346746e 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -12,6 +12,10 @@ #define TXGBE_RAPTOR_MAX_RX_QUEUES 128 #define TXGBE_RAPTOR_RAR_ENTRIES 128 +static s32 txgbe_setup_copper_link_raptor(struct txgbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete); + /** * txgbe_init_hw - Generic hardware initialization * @hw: pointer to hardware structure @@ -93,6 +97,117 @@ s32 txgbe_validate_mac_addr(u8 *mac_addr) return status; } +/** + * txgbe_need_crosstalk_fix - Determine if we need to do cross talk fix + * @hw: pointer to hardware structure + * + * Contains the logic to identify if we need to verify link for the + * crosstalk fix + **/ +static bool txgbe_need_crosstalk_fix(struct txgbe_hw *hw) +{ + /* Does FW say we need the fix */ + if (!hw->need_crosstalk_fix) + return false; + + /* Only consider SFP+ PHYs i.e. media type fiber */ + switch (hw->phy.media_type) { + case txgbe_media_type_fiber: + case txgbe_media_type_fiber_qsfp: + break; + default: + return false; + } + + return true; +} + +/** + * txgbe_check_mac_link - Determine link and speed status + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true when link is up + * @link_up_wait_to_complete: bool used to wait for link up or not + * + * Reads the links register to determine if link is up and the current speed + **/ +s32 txgbe_check_mac_link(struct txgbe_hw *hw, u32 *speed, + bool *link_up, bool link_up_wait_to_complete) +{ + u32 links_reg, links_orig; + u32 i; + + DEBUGFUNC("txgbe_check_mac_link"); + + /* If Crosstalk fix enabled do the sanity check of making sure + * the SFP+ cage is full. + */ + if (txgbe_need_crosstalk_fix(hw)) { + u32 sfp_cage_full; + + switch (hw->mac.type) { + case txgbe_mac_raptor: + sfp_cage_full = !rd32m(hw, TXGBE_GPIODATA, + TXGBE_GPIOBIT_2); + break; + default: + /* sanity check - No SFP+ devices here */ + sfp_cage_full = false; + break; + } + + if (!sfp_cage_full) { + *link_up = false; + *speed = TXGBE_LINK_SPEED_UNKNOWN; + return 0; + } + } + + /* clear the old state */ + links_orig = rd32(hw, TXGBE_PORTSTAT); + + links_reg = rd32(hw, TXGBE_PORTSTAT); + + if (links_orig != links_reg) { + DEBUGOUT("LINKS changed from %08X to %08X\n", + links_orig, links_reg); + } + + if (link_up_wait_to_complete) { + for (i = 0; i < hw->mac.max_link_up_time; i++) { + if (!(links_reg & TXGBE_PORTSTAT_UP)) { + *link_up = false; + } else { + *link_up = true; + break; + } + msec_delay(100); + links_reg = rd32(hw, TXGBE_PORTSTAT); + } + } else { + if (links_reg & TXGBE_PORTSTAT_UP) + *link_up = true; + else + *link_up = false; + } + + switch (links_reg & TXGBE_PORTSTAT_BW_MASK) { + case TXGBE_PORTSTAT_BW_10G: + *speed = TXGBE_LINK_SPEED_10GB_FULL; + break; + case TXGBE_PORTSTAT_BW_1G: + *speed = TXGBE_LINK_SPEED_1GB_FULL; + break; + case TXGBE_PORTSTAT_BW_100M: + *speed = TXGBE_LINK_SPEED_100M_FULL; + break; + default: + *speed = TXGBE_LINK_SPEED_UNKNOWN; + } + + return 0; +} + /** * txgbe_clear_tx_pending - Clear pending TX work from the PCIe fifo * @hw: pointer to the hardware structure @@ -232,7 +347,8 @@ void txgbe_init_mac_link_ops(struct txgbe_hw *hw) struct txgbe_mac_info *mac = &hw->mac; DEBUGFUNC("txgbe_init_mac_link_ops"); - RTE_SET_USED(mac); + + mac->setup_link = txgbe_setup_mac_link; } /** @@ -246,6 +362,7 @@ void txgbe_init_mac_link_ops(struct txgbe_hw *hw) **/ s32 txgbe_init_phy_raptor(struct txgbe_hw *hw) { + struct txgbe_mac_info *mac = &hw->mac; struct txgbe_phy_info *phy = &hw->phy; s32 err = 0; @@ -267,6 +384,23 @@ s32 txgbe_init_phy_raptor(struct txgbe_hw *hw) /* Setup function pointers based on detected SFP module and speeds */ txgbe_init_mac_link_ops(hw); + /* If copper media, overwrite with copper function pointers */ + if (phy->media_type == txgbe_media_type_copper) { + mac->setup_link = txgbe_setup_copper_link_raptor; + mac->get_link_capabilities = + txgbe_get_copper_link_capabilities; + } + + /* Set necessary function pointers based on PHY type */ + switch (hw->phy.type) { + case txgbe_phy_tn: + phy->setup_link = txgbe_setup_phy_link_tnx; + phy->check_link = txgbe_check_phy_link_tnx; + break; + default: + break; + } + init_phy_ops_out: return err; } @@ -297,6 +431,8 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) phy->write_reg = txgbe_write_phy_reg; phy->read_reg_mdi = txgbe_read_phy_reg_mdi; phy->write_reg_mdi = txgbe_write_phy_reg_mdi; + phy->setup_link = txgbe_setup_phy_link; + phy->setup_link_speed = txgbe_setup_phy_link_speed; phy->read_i2c_byte = txgbe_read_i2c_byte; phy->write_i2c_byte = txgbe_write_i2c_byte; phy->read_i2c_eeprom = txgbe_read_i2c_eeprom; @@ -307,6 +443,10 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) mac->init_hw = txgbe_init_hw; mac->reset_hw = txgbe_reset_hw; + /* Link */ + mac->get_link_capabilities = txgbe_get_link_capabilities_raptor; + mac->check_link = txgbe_check_mac_link; + /* EEPROM */ rom->init_params = txgbe_init_eeprom_params; rom->read16 = txgbe_ee_read16; @@ -328,6 +468,289 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) return 0; } +/** + * txgbe_get_link_capabilities_raptor - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: true when autoneg or autotry is enabled + * + * Determines the link capabilities by reading the AUTOC register. + **/ +s32 txgbe_get_link_capabilities_raptor(struct txgbe_hw *hw, + u32 *speed, + bool *autoneg) +{ + s32 status = 0; + u32 autoc = 0; + + DEBUGFUNC("txgbe_get_link_capabilities_raptor"); + + /* Check if 1G SFP module. */ + if (hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_cu_core1 || + hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_lx_core1 || + hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core0 || + hw->phy.sfp_type == txgbe_sfp_type_1g_sx_core1) { + *speed = TXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + return 0; + } + + /* + * Determine link capabilities based on the stored value of AUTOC, + * which represents EEPROM defaults. If AUTOC value has not + * been stored, use the current register values. + */ + if (hw->mac.orig_link_settings_stored) + autoc = hw->mac.orig_autoc; + else + autoc = hw->mac.autoc_read(hw); + + switch (autoc & TXGBE_AUTOC_LMS_MASK) { + case TXGBE_AUTOC_LMS_1G_LINK_NO_AN: + *speed = TXGBE_LINK_SPEED_1GB_FULL; + *autoneg = false; + break; + + case TXGBE_AUTOC_LMS_10G_LINK_NO_AN: + *speed = TXGBE_LINK_SPEED_10GB_FULL; + *autoneg = false; + break; + + case TXGBE_AUTOC_LMS_1G_AN: + *speed = TXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + case TXGBE_AUTOC_LMS_10G: + *speed = TXGBE_LINK_SPEED_10GB_FULL; + *autoneg = false; + break; + + case TXGBE_AUTOC_LMS_KX4_KX_KR: + case TXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN: + *speed = TXGBE_LINK_SPEED_UNKNOWN; + if (autoc & TXGBE_AUTOC_KR_SUPP) + *speed |= TXGBE_LINK_SPEED_10GB_FULL; + if (autoc & TXGBE_AUTOC_KX4_SUPP) + *speed |= TXGBE_LINK_SPEED_10GB_FULL; + if (autoc & TXGBE_AUTOC_KX_SUPP) + *speed |= TXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + case TXGBE_AUTOC_LMS_KX4_KX_KR_SGMII: + *speed = TXGBE_LINK_SPEED_100M_FULL; + if (autoc & TXGBE_AUTOC_KR_SUPP) + *speed |= TXGBE_LINK_SPEED_10GB_FULL; + if (autoc & TXGBE_AUTOC_KX4_SUPP) + *speed |= TXGBE_LINK_SPEED_10GB_FULL; + if (autoc & TXGBE_AUTOC_KX_SUPP) + *speed |= TXGBE_LINK_SPEED_1GB_FULL; + *autoneg = true; + break; + + case TXGBE_AUTOC_LMS_SGMII_1G_100M: + *speed = TXGBE_LINK_SPEED_1GB_FULL | + TXGBE_LINK_SPEED_100M_FULL | + TXGBE_LINK_SPEED_10M_FULL; + *autoneg = false; + break; + + default: + return TXGBE_ERR_LINK_SETUP; + } + + return status; +} + +/** + * txgbe_start_mac_link_raptor - Setup MAC link settings + * @hw: pointer to hardware structure + * @autoneg_wait_to_complete: true when waiting for completion is needed + * + * Configures link settings based on values in the txgbe_hw struct. + * Restarts the link. Performs autonegotiation if needed. + **/ +s32 txgbe_start_mac_link_raptor(struct txgbe_hw *hw, + bool autoneg_wait_to_complete) +{ + s32 status = 0; + bool got_lock = false; + + DEBUGFUNC("txgbe_start_mac_link_raptor"); + + UNREFERENCED_PARAMETER(autoneg_wait_to_complete); + + /* reset_pipeline requires us to hold this lock as it writes to + * AUTOC. + */ + if (txgbe_verify_lesm_fw_enabled_raptor(hw)) { + status = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + if (status != 0) + goto out; + + got_lock = true; + } + + /* Restart link */ + txgbe_reset_pipeline_raptor(hw); + + if (got_lock) + hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + + /* Add delay to filter out noises during initial link setup */ + msec_delay(50); + +out: + return status; +} + +/** + * txgbe_setup_mac_link - Set MAC link speed + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg_wait_to_complete: true when waiting for completion is needed + * + * Set the link speed in the AUTOC register and restarts link. + **/ +s32 txgbe_setup_mac_link(struct txgbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete) +{ + bool autoneg = false; + s32 status = 0; + + u64 autoc = hw->mac.autoc_read(hw); + u64 pma_pmd_10gs = autoc & TXGBE_AUTOC_10GS_PMA_PMD_MASK; + u64 pma_pmd_1g = autoc & TXGBE_AUTOC_1G_PMA_PMD_MASK; + u64 link_mode = autoc & TXGBE_AUTOC_LMS_MASK; + u64 current_autoc = autoc; + u64 orig_autoc = 0; + u32 links_reg; + u32 i; + u32 link_capabilities = TXGBE_LINK_SPEED_UNKNOWN; + + DEBUGFUNC("txgbe_setup_mac_link"); + + /* Check to see if speed passed in is supported. */ + status = hw->mac.get_link_capabilities(hw, + &link_capabilities, &autoneg); + if (status) + return status; + + speed &= link_capabilities; + if (speed == TXGBE_LINK_SPEED_UNKNOWN) + return TXGBE_ERR_LINK_SETUP; + + /* Use stored value (EEPROM defaults) of AUTOC to find KR/KX4 support*/ + if (hw->mac.orig_link_settings_stored) + orig_autoc = hw->mac.orig_autoc; + else + orig_autoc = autoc; + + link_mode = autoc & TXGBE_AUTOC_LMS_MASK; + pma_pmd_1g = autoc & TXGBE_AUTOC_1G_PMA_PMD_MASK; + + if (link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR || + link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || + link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { + /* Set KX4/KX/KR support according to speed requested */ + autoc &= ~(TXGBE_AUTOC_KX_SUPP | + TXGBE_AUTOC_KX4_SUPP | + TXGBE_AUTOC_KR_SUPP); + if (speed & TXGBE_LINK_SPEED_10GB_FULL) { + if (orig_autoc & TXGBE_AUTOC_KX4_SUPP) + autoc |= TXGBE_AUTOC_KX4_SUPP; + if ((orig_autoc & TXGBE_AUTOC_KR_SUPP) && + !hw->phy.smart_speed_active) + autoc |= TXGBE_AUTOC_KR_SUPP; + } + if (speed & TXGBE_LINK_SPEED_1GB_FULL) + autoc |= TXGBE_AUTOC_KX_SUPP; + } else if ((pma_pmd_1g == TXGBE_AUTOC_1G_SFI) && + (link_mode == TXGBE_AUTOC_LMS_1G_LINK_NO_AN || + link_mode == TXGBE_AUTOC_LMS_1G_AN)) { + /* Switch from 1G SFI to 10G SFI if requested */ + if (speed == TXGBE_LINK_SPEED_10GB_FULL && + pma_pmd_10gs == TXGBE_AUTOC_10GS_SFI) { + autoc &= ~TXGBE_AUTOC_LMS_MASK; + autoc |= TXGBE_AUTOC_LMS_10G; + } + } else if ((pma_pmd_10gs == TXGBE_AUTOC_10GS_SFI) && + (link_mode == TXGBE_AUTOC_LMS_10G)) { + /* Switch from 10G SFI to 1G SFI if requested */ + if (speed == TXGBE_LINK_SPEED_1GB_FULL && + pma_pmd_1g == TXGBE_AUTOC_1G_SFI) { + autoc &= ~TXGBE_AUTOC_LMS_MASK; + if (autoneg || hw->phy.type == txgbe_phy_qsfp_intel) + autoc |= TXGBE_AUTOC_LMS_1G_AN; + else + autoc |= TXGBE_AUTOC_LMS_1G_LINK_NO_AN; + } + } + + if (autoc == current_autoc) + return status; + + autoc &= ~TXGBE_AUTOC_SPEED_MASK; + autoc |= TXGBE_AUTOC_SPEED(speed); + autoc |= (autoneg ? TXGBE_AUTOC_AUTONEG : 0); + + /* Restart link */ + hw->mac.autoc_write(hw, autoc); + + /* Only poll for autoneg to complete if specified to do so */ + if (autoneg_wait_to_complete) { + if (link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR || + link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN || + link_mode == TXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) { + links_reg = 0; /*Just in case Autoneg time=0*/ + for (i = 0; i < TXGBE_AUTO_NEG_TIME; i++) { + links_reg = rd32(hw, TXGBE_PORTSTAT); + if (links_reg & TXGBE_PORTSTAT_UP) + break; + msec_delay(100); + } + if (!(links_reg & TXGBE_PORTSTAT_UP)) { + status = TXGBE_ERR_AUTONEG_NOT_COMPLETE; + DEBUGOUT("Autoneg did not complete.\n"); + } + } + } + + /* Add delay to filter out noises during initial link setup */ + msec_delay(50); + + return status; +} + +/** + * txgbe_setup_copper_link_raptor - Set the PHY autoneg advertised field + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg_wait_to_complete: true if waiting is needed to complete + * + * Restarts link on PHY and MAC based on settings passed in. + **/ +static s32 txgbe_setup_copper_link_raptor(struct txgbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete) +{ + s32 status; + + DEBUGFUNC("txgbe_setup_copper_link_raptor"); + + /* Setup the PHY according to input speed */ + status = hw->phy.setup_link_speed(hw, speed, + autoneg_wait_to_complete); + /* Set up MAC */ + txgbe_start_mac_link_raptor(hw, autoneg_wait_to_complete); + + return status; +} + static int txgbe_check_flash_load(struct txgbe_hw *hw, u32 check_bit) { @@ -481,3 +904,76 @@ s32 txgbe_reset_hw(struct txgbe_hw *hw) return status; } +/** + * txgbe_verify_lesm_fw_enabled_raptor - Checks LESM FW module state. + * @hw: pointer to hardware structure + * + * Returns true if the LESM FW module is present and enabled. Otherwise + * returns false. Smart Speed must be disabled if LESM FW module is enabled. + **/ +bool txgbe_verify_lesm_fw_enabled_raptor(struct txgbe_hw *hw) +{ + bool lesm_enabled = false; + u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; + s32 status; + + DEBUGFUNC("txgbe_verify_lesm_fw_enabled_raptor"); + + /* get the offset to the Firmware Module block */ + status = hw->rom.read16(hw, TXGBE_FW_PTR, &fw_offset); + + if (status != 0 || fw_offset == 0 || fw_offset == 0xFFFF) + goto out; + + /* get the offset to the LESM Parameters block */ + status = hw->rom.read16(hw, (fw_offset + + TXGBE_FW_LESM_PARAMETERS_PTR), + &fw_lesm_param_offset); + + if (status != 0 || + fw_lesm_param_offset == 0 || fw_lesm_param_offset == 0xFFFF) + goto out; + + /* get the LESM state word */ + status = hw->rom.read16(hw, (fw_lesm_param_offset + + TXGBE_FW_LESM_STATE_1), + &fw_lesm_state); + + if (status == 0 && (fw_lesm_state & TXGBE_FW_LESM_STATE_ENABLED)) + lesm_enabled = true; + +out: + lesm_enabled = false; + return lesm_enabled; +} + +/** + * txgbe_reset_pipeline_raptor - perform pipeline reset + * + * @hw: pointer to hardware structure + * + * Reset pipeline by asserting Restart_AN together with LMS change to ensure + * full pipeline reset. This function assumes the SW/FW lock is held. + **/ +s32 txgbe_reset_pipeline_raptor(struct txgbe_hw *hw) +{ + s32 err = 0; + u64 autoc; + + autoc = hw->mac.autoc_read(hw); + + /* Enable link if disabled in NVM */ + if (autoc & TXGBE_AUTOC_LINK_DIA_MASK) + autoc &= ~TXGBE_AUTOC_LINK_DIA_MASK; + + autoc |= TXGBE_AUTOC_AN_RESTART; + /* Write AUTOC register with toggled LMS[2] bit and Restart_AN */ + hw->mac.autoc_write(hw, autoc ^ TXGBE_AUTOC_LMS_AN); + + /* Write AUTOC register with original LMS field and Restart_AN */ + hw->mac.autoc_write(hw, autoc); + txgbe_flush(hw); + + return err; +} + diff --git a/drivers/net/txgbe/base/txgbe_hw.h b/drivers/net/txgbe/base/txgbe_hw.h index 22a54da37..506e4b13a 100644 --- a/drivers/net/txgbe/base/txgbe_hw.h +++ b/drivers/net/txgbe/base/txgbe_hw.h @@ -12,11 +12,26 @@ s32 txgbe_init_hw(struct txgbe_hw *hw); void txgbe_set_lan_id_multi_port(struct txgbe_hw *hw); s32 txgbe_validate_mac_addr(u8 *mac_addr); + +s32 txgbe_check_mac_link(struct txgbe_hw *hw, + u32 *speed, + bool *link_up, bool link_up_wait_to_complete); + void txgbe_clear_tx_pending(struct txgbe_hw *hw); + +s32 txgbe_reset_pipeline_raptor(struct txgbe_hw *hw); + s32 txgbe_init_shared_code(struct txgbe_hw *hw); s32 txgbe_set_mac_type(struct txgbe_hw *hw); s32 txgbe_init_ops_pf(struct txgbe_hw *hw); +s32 txgbe_get_link_capabilities_raptor(struct txgbe_hw *hw, + u32 *speed, bool *autoneg); +s32 txgbe_start_mac_link_raptor(struct txgbe_hw *hw, + bool autoneg_wait_to_complete); +s32 txgbe_setup_mac_link(struct txgbe_hw *hw, u32 speed, + bool autoneg_wait_to_complete); void txgbe_init_mac_link_ops(struct txgbe_hw *hw); s32 txgbe_reset_hw(struct txgbe_hw *hw); s32 txgbe_init_phy_raptor(struct txgbe_hw *hw); +bool txgbe_verify_lesm_fw_enabled_raptor(struct txgbe_hw *hw); #endif /* _TXGBE_HW_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_phy.c b/drivers/net/txgbe/base/txgbe_phy.c index 347641ce9..8dd0fc1b5 100644 --- a/drivers/net/txgbe/base/txgbe_phy.c +++ b/drivers/net/txgbe/base/txgbe_phy.c @@ -425,6 +425,318 @@ s32 txgbe_write_phy_reg(struct txgbe_hw *hw, u32 reg_addr, return err; } + +/** + * txgbe_setup_phy_link - Set and restart auto-neg + * @hw: pointer to hardware structure + * + * Restart auto-negotiation and PHY and waits for completion. + **/ +s32 txgbe_setup_phy_link(struct txgbe_hw *hw) +{ + s32 err = 0; + u16 autoneg_reg = TXGBE_MII_AUTONEG_REG; + bool autoneg = false; + u32 speed; + + DEBUGFUNC("txgbe_setup_phy_link"); + + txgbe_get_copper_link_capabilities(hw, &speed, &autoneg); + + /* Set or unset auto-negotiation 10G advertisement */ + hw->phy.read_reg(hw, TXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + TXGBE_MD_DEV_AUTO_NEG, + &autoneg_reg); + + autoneg_reg &= ~TXGBE_MII_10GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10GB_FULL) && + (speed & TXGBE_LINK_SPEED_10GB_FULL)) + autoneg_reg |= TXGBE_MII_10GBASE_T_ADVERTISE; + + hw->phy.write_reg(hw, TXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + TXGBE_MD_DEV_AUTO_NEG, + autoneg_reg); + + hw->phy.read_reg(hw, TXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, + TXGBE_MD_DEV_AUTO_NEG, + &autoneg_reg); + + /* Set or unset auto-negotiation 5G advertisement */ + autoneg_reg &= ~TXGBE_MII_5GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_5GB_FULL) && + (speed & TXGBE_LINK_SPEED_5GB_FULL)) + autoneg_reg |= TXGBE_MII_5GBASE_T_ADVERTISE; + + /* Set or unset auto-negotiation 2.5G advertisement */ + autoneg_reg &= ~TXGBE_MII_2_5GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & + TXGBE_LINK_SPEED_2_5GB_FULL) && + (speed & TXGBE_LINK_SPEED_2_5GB_FULL)) + autoneg_reg |= TXGBE_MII_2_5GBASE_T_ADVERTISE; + /* Set or unset auto-negotiation 1G advertisement */ + autoneg_reg &= ~TXGBE_MII_1GBASE_T_ADVERTISE; + if ((hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_1GB_FULL) && + (speed & TXGBE_LINK_SPEED_1GB_FULL)) + autoneg_reg |= TXGBE_MII_1GBASE_T_ADVERTISE; + + hw->phy.write_reg(hw, TXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, + TXGBE_MD_DEV_AUTO_NEG, + autoneg_reg); + + /* Set or unset auto-negotiation 100M advertisement */ + hw->phy.read_reg(hw, TXGBE_MII_AUTONEG_ADVERTISE_REG, + TXGBE_MD_DEV_AUTO_NEG, + &autoneg_reg); + + autoneg_reg &= ~(TXGBE_MII_100BASE_T_ADVERTISE | + TXGBE_MII_100BASE_T_ADVERTISE_HALF); + if ((hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_100M_FULL) && + (speed & TXGBE_LINK_SPEED_100M_FULL)) + autoneg_reg |= TXGBE_MII_100BASE_T_ADVERTISE; + + hw->phy.write_reg(hw, TXGBE_MII_AUTONEG_ADVERTISE_REG, + TXGBE_MD_DEV_AUTO_NEG, + autoneg_reg); + + /* Blocked by MNG FW so don't reset PHY */ + if (txgbe_check_reset_blocked(hw)) + return err; + + /* Restart PHY auto-negotiation. */ + hw->phy.read_reg(hw, TXGBE_MD_AUTO_NEG_CONTROL, + TXGBE_MD_DEV_AUTO_NEG, &autoneg_reg); + + autoneg_reg |= TXGBE_MII_RESTART; + + hw->phy.write_reg(hw, TXGBE_MD_AUTO_NEG_CONTROL, + TXGBE_MD_DEV_AUTO_NEG, autoneg_reg); + + return err; +} + +/** + * txgbe_setup_phy_link_speed - Sets the auto advertised capabilities + * @hw: pointer to hardware structure + * @speed: new link speed + * @autoneg_wait_to_complete: unused + **/ +s32 txgbe_setup_phy_link_speed(struct txgbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete) +{ + UNREFERENCED_PARAMETER(autoneg_wait_to_complete); + + DEBUGFUNC("txgbe_setup_phy_link_speed"); + + /* + * Clear autoneg_advertised and set new values based on input link + * speed. + */ + hw->phy.autoneg_advertised = 0; + + if (speed & TXGBE_LINK_SPEED_10GB_FULL) + hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_10GB_FULL; + + if (speed & TXGBE_LINK_SPEED_5GB_FULL) + hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_5GB_FULL; + + if (speed & TXGBE_LINK_SPEED_2_5GB_FULL) + hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_2_5GB_FULL; + + if (speed & TXGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_1GB_FULL; + + if (speed & TXGBE_LINK_SPEED_100M_FULL) + hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_100M_FULL; + + if (speed & TXGBE_LINK_SPEED_10M_FULL) + hw->phy.autoneg_advertised |= TXGBE_LINK_SPEED_10M_FULL; + + /* Setup link based on the new speed settings */ + hw->phy.setup_link(hw); + + return 0; +} + +/** + * txgbe_get_copper_speeds_supported - Get copper link speeds from phy + * @hw: pointer to hardware structure + * + * Determines the supported link capabilities by reading the PHY auto + * negotiation register. + **/ +static s32 txgbe_get_copper_speeds_supported(struct txgbe_hw *hw) +{ + s32 err; + u16 speed_ability; + + err = hw->phy.read_reg(hw, TXGBE_MD_PHY_SPEED_ABILITY, + TXGBE_MD_DEV_PMA_PMD, + &speed_ability); + if (err) + return err; + + if (speed_ability & TXGBE_MD_PHY_SPEED_10G) + hw->phy.speeds_supported |= TXGBE_LINK_SPEED_10GB_FULL; + if (speed_ability & TXGBE_MD_PHY_SPEED_1G) + hw->phy.speeds_supported |= TXGBE_LINK_SPEED_1GB_FULL; + if (speed_ability & TXGBE_MD_PHY_SPEED_100M) + hw->phy.speeds_supported |= TXGBE_LINK_SPEED_100M_FULL; + + return err; +} + +/** + * txgbe_get_copper_link_capabilities - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + **/ +s32 txgbe_get_copper_link_capabilities(struct txgbe_hw *hw, + u32 *speed, + bool *autoneg) +{ + s32 err = 0; + + DEBUGFUNC("txgbe_get_copper_link_capabilities"); + + *autoneg = true; + if (!hw->phy.speeds_supported) + err = txgbe_get_copper_speeds_supported(hw); + + *speed = hw->phy.speeds_supported; + return err; +} + +/** + * txgbe_check_phy_link_tnx - Determine link and speed status + * @hw: pointer to hardware structure + * @speed: current link speed + * @link_up: true is link is up, false otherwise + * + * Reads the VS1 register to determine if link is up and the current speed for + * the PHY. + **/ +s32 txgbe_check_phy_link_tnx(struct txgbe_hw *hw, u32 *speed, + bool *link_up) +{ + s32 err = 0; + u32 time_out; + u32 max_time_out = 10; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + + DEBUGFUNC("txgbe_check_phy_link_tnx"); + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = TXGBE_LINK_SPEED_10GB_FULL; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + for (time_out = 0; time_out < max_time_out; time_out++) { + usec_delay(10); + err = hw->phy.read_reg(hw, + TXGBE_MD_VENDOR_SPECIFIC_1_STATUS, + TXGBE_MD_DEV_VENDOR_1, + &phy_data); + phy_link = phy_data & TXGBE_MD_VENDOR_SPECIFIC_1_LINK_STATUS; + phy_speed = phy_data & + TXGBE_MD_VENDOR_SPECIFIC_1_SPEED_STATUS; + if (phy_link == TXGBE_MD_VENDOR_SPECIFIC_1_LINK_STATUS) { + *link_up = true; + if (phy_speed == + TXGBE_MD_VENDOR_SPECIFIC_1_SPEED_STATUS) + *speed = TXGBE_LINK_SPEED_1GB_FULL; + break; + } + } + + return err; +} + +/** + * txgbe_setup_phy_link_tnx - Set and restart auto-neg + * @hw: pointer to hardware structure + * + * Restart auto-negotiation and PHY and waits for completion. + **/ +s32 txgbe_setup_phy_link_tnx(struct txgbe_hw *hw) +{ + s32 err = 0; + u16 autoneg_reg = TXGBE_MII_AUTONEG_REG; + bool autoneg = false; + u32 speed; + + DEBUGFUNC("txgbe_setup_phy_link_tnx"); + + txgbe_get_copper_link_capabilities(hw, &speed, &autoneg); + + if (speed & TXGBE_LINK_SPEED_10GB_FULL) { + /* Set or unset auto-negotiation 10G advertisement */ + hw->phy.read_reg(hw, TXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + TXGBE_MD_DEV_AUTO_NEG, + &autoneg_reg); + + autoneg_reg &= ~TXGBE_MII_10GBASE_T_ADVERTISE; + if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_10GB_FULL) + autoneg_reg |= TXGBE_MII_10GBASE_T_ADVERTISE; + + hw->phy.write_reg(hw, TXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + TXGBE_MD_DEV_AUTO_NEG, + autoneg_reg); + } + + if (speed & TXGBE_LINK_SPEED_1GB_FULL) { + /* Set or unset auto-negotiation 1G advertisement */ + hw->phy.read_reg(hw, TXGBE_MII_AUTONEG_XNP_TX_REG, + TXGBE_MD_DEV_AUTO_NEG, + &autoneg_reg); + + autoneg_reg &= ~TXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; + if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_1GB_FULL) + autoneg_reg |= TXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX; + + hw->phy.write_reg(hw, TXGBE_MII_AUTONEG_XNP_TX_REG, + TXGBE_MD_DEV_AUTO_NEG, + autoneg_reg); + } + + if (speed & TXGBE_LINK_SPEED_100M_FULL) { + /* Set or unset auto-negotiation 100M advertisement */ + hw->phy.read_reg(hw, TXGBE_MII_AUTONEG_ADVERTISE_REG, + TXGBE_MD_DEV_AUTO_NEG, + &autoneg_reg); + + autoneg_reg &= ~TXGBE_MII_100BASE_T_ADVERTISE; + if (hw->phy.autoneg_advertised & TXGBE_LINK_SPEED_100M_FULL) + autoneg_reg |= TXGBE_MII_100BASE_T_ADVERTISE; + + hw->phy.write_reg(hw, TXGBE_MII_AUTONEG_ADVERTISE_REG, + TXGBE_MD_DEV_AUTO_NEG, + autoneg_reg); + } + + /* Blocked by MNG FW so don't reset PHY */ + if (txgbe_check_reset_blocked(hw)) + return err; + + /* Restart PHY auto-negotiation. */ + hw->phy.read_reg(hw, TXGBE_MD_AUTO_NEG_CONTROL, + TXGBE_MD_DEV_AUTO_NEG, &autoneg_reg); + + autoneg_reg |= TXGBE_MII_RESTART; + + hw->phy.write_reg(hw, TXGBE_MD_AUTO_NEG_CONTROL, + TXGBE_MD_DEV_AUTO_NEG, autoneg_reg); + + return err; +} + /** * txgbe_identify_module - Identifies module type * @hw: pointer to hardware structure diff --git a/drivers/net/txgbe/base/txgbe_phy.h b/drivers/net/txgbe/base/txgbe_phy.h index 750934e06..9f9b52a03 100644 --- a/drivers/net/txgbe/base/txgbe_phy.h +++ b/drivers/net/txgbe/base/txgbe_phy.h @@ -336,9 +336,21 @@ s32 txgbe_read_phy_reg(struct txgbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data); s32 txgbe_write_phy_reg(struct txgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data); +s32 txgbe_setup_phy_link(struct txgbe_hw *hw); +s32 txgbe_setup_phy_link_speed(struct txgbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete); +s32 txgbe_get_copper_link_capabilities(struct txgbe_hw *hw, + u32 *speed, + bool *autoneg); s32 txgbe_check_reset_blocked(struct txgbe_hw *hw); /* PHY specific */ +s32 txgbe_check_phy_link_tnx(struct txgbe_hw *hw, + u32 *speed, + bool *link_up); +s32 txgbe_setup_phy_link_tnx(struct txgbe_hw *hw); + s32 txgbe_identify_module(struct txgbe_hw *hw); s32 txgbe_identify_sfp_module(struct txgbe_hw *hw); s32 txgbe_identify_qsfp_module(struct txgbe_hw *hw); diff --git a/drivers/net/txgbe/base/txgbe_regs.h b/drivers/net/txgbe/base/txgbe_regs.h index 9acbd3b7b..607e1df29 100644 --- a/drivers/net/txgbe/base/txgbe_regs.h +++ b/drivers/net/txgbe/base/txgbe_regs.h @@ -52,7 +52,7 @@ #define TXGBE_AUTOC_1G_KX_BX LS64(1, 9, 0x7) #define TXGBE_AUTOC_AN_RESTART MS64(12, 0x1) #define TXGBE_AUTOC_LMS_MASK MS64(13, 0x7) -#define TXGBE_AUTOC_LMS_10Gs LS64(3, 13, 0x7) +#define TXGBE_AUTOC_LMS_10G LS64(3, 13, 0x7) #define TXGBE_AUTOC_LMS_KX4_KX_KR LS64(4, 13, 0x7) #define TXGBE_AUTOC_LMS_SGMII_1G_100M LS64(5, 13, 0x7) #define TXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN LS64(6, 13, 0x7) @@ -79,10 +79,10 @@ #define TXGBE_AUTOC_KX_SUPP MS64(30, 0x1) #define TXGBE_AUTOC_KX4_SUPP MS64(31, 0x1) -#define TXGBE_AUTOC_10Gs_PMA_PMD_MASK MS64(48, 0x3) /* serial */ -#define TXGBE_AUTOC_10Gs_KR LS64(0, 48, 0x3) -#define TXGBE_AUTOC_10Gs_XFI LS64(1, 48, 0x3) -#define TXGBE_AUTOC_10Gs_SFI LS64(2, 48, 0x3) +#define TXGBE_AUTOC_10GS_PMA_PMD_MASK MS64(48, 0x3) /* serial */ +#define TXGBE_AUTOC_10GS_KR LS64(0, 48, 0x3) +#define TXGBE_AUTOC_10GS_XFI LS64(1, 48, 0x3) +#define TXGBE_AUTOC_10GS_SFI LS64(2, 48, 0x3) #define TXGBE_AUTOC_LINK_DIA_MASK MS64(60, 0x7) #define TXGBE_AUTOC_LINK_DIA_D3_MASK LS64(5, 60, 0x7) diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index 01af0c9af..459f2b8b8 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -6,6 +6,7 @@ #define _TXGBE_TYPE_H_ #define TXGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ +#define TXGBE_AUTO_NEG_TIME 45 /* 4.5 Seconds */ #define TXGBE_ALIGN 128 /* as intel did */ @@ -100,6 +101,15 @@ enum txgbe_media_type { txgbe_media_type_virtual }; + +/* Smart Speed Settings */ +#define TXGBE_SMARTSPEED_MAX_RETRIES 3 +enum txgbe_smart_speed { + txgbe_smart_speed_auto = 0, + txgbe_smart_speed_on, + txgbe_smart_speed_off +}; + /* PCI bus types */ enum txgbe_bus_type { txgbe_bus_type_unknown = 0, @@ -307,6 +317,7 @@ struct txgbe_mac_info { u32 max_rx_queues; u8 san_mac_rar_index; + bool get_link_status; u64 orig_autoc; /* cached value of AUTOC */ bool orig_link_settings_stored; bool autotry_restart; @@ -360,6 +371,10 @@ struct txgbe_phy_info { u32 media_type; u32 phy_semaphore_mask; bool reset_disable; + u32 autoneg_advertised; + u32 speeds_supported; + enum txgbe_smart_speed smart_speed; + bool smart_speed_active; bool multispeed_fiber; bool qsfp_shared_i2c_bus; u32 nw_mng_if_sel; @@ -402,9 +417,15 @@ struct txgbe_hw { u16 subsystem_vendor_id; bool allow_unsupported_sfp; + bool need_crosstalk_fix; uint64_t isb_dma; void IOMEM *isb_mem; + enum txgbe_link_status { + TXGBE_LINK_STATUS_NONE = 0, + TXGBE_LINK_STATUS_KX, + TXGBE_LINK_STATUS_KX4 + } link_status; enum txgbe_reset_type { TXGBE_LAN_RESET = 0, TXGBE_SW_RESET, diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c index 5e866461f..15f83d36b 100644 --- a/drivers/net/txgbe/txgbe_ethdev.c +++ b/drivers/net/txgbe/txgbe_ethdev.c @@ -20,7 +20,11 @@ #include "txgbe_ethdev.h" #include "txgbe_rxtx.h" +static int txgbe_dev_set_link_up(struct rte_eth_dev *dev); +static int txgbe_dev_set_link_down(struct rte_eth_dev *dev); static int txgbe_dev_close(struct rte_eth_dev *dev); +static int txgbe_dev_link_update(struct rte_eth_dev *dev, + int wait_to_complete); static void txgbe_dev_link_status_print(struct rte_eth_dev *dev); static int txgbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev, uint8_t on); @@ -507,6 +511,46 @@ txgbe_dev_phy_intr_setup(struct rte_eth_dev *dev) intr->mask_misc |= TXGBE_ICRMISC_GPIO; } +/* + * Set device link up: enable tx. + */ +static int +txgbe_dev_set_link_up(struct rte_eth_dev *dev) +{ + struct txgbe_hw *hw = TXGBE_DEV_HW(dev); + + if (hw->phy.media_type == txgbe_media_type_copper) { + /* Turn on the copper */ + hw->phy.set_phy_power(hw, true); + } else { + /* Turn on the laser */ + hw->mac.enable_tx_laser(hw); + txgbe_dev_link_update(dev, 0); + } + + return 0; +} + +/* + * Set device link down: disable tx. + */ +static int +txgbe_dev_set_link_down(struct rte_eth_dev *dev) +{ + struct txgbe_hw *hw = TXGBE_DEV_HW(dev); + + if (hw->phy.media_type == txgbe_media_type_copper) { + /* Turn off the copper */ + hw->phy.set_phy_power(hw, false); + } else { + /* Turn off the laser */ + hw->mac.disable_tx_laser(hw); + txgbe_dev_link_update(dev, 0); + } + + return 0; +} + /* * Reset and stop device. */ @@ -613,12 +657,108 @@ txgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) return 0; } +void +txgbe_dev_setup_link_alarm_handler(void *param) +{ + struct rte_eth_dev *dev = (struct rte_eth_dev *)param; + struct txgbe_hw *hw = TXGBE_DEV_HW(dev); + struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev); + u32 speed; + bool autoneg = false; + + speed = hw->phy.autoneg_advertised; + if (!speed) + hw->mac.get_link_capabilities(hw, &speed, &autoneg); + + hw->mac.setup_link(hw, speed, true); + + intr->flags &= ~TXGBE_FLAG_NEED_LINK_CONFIG; +} + +/* return 0 means link status changed, -1 means not changed */ +int +txgbe_dev_link_update_share(struct rte_eth_dev *dev, + int wait_to_complete) +{ + struct txgbe_hw *hw = TXGBE_DEV_HW(dev); + struct rte_eth_link link; + u32 link_speed = TXGBE_LINK_SPEED_UNKNOWN; + struct txgbe_interrupt *intr = TXGBE_DEV_INTR(dev); + bool link_up; + int err; + int wait = 1; + + memset(&link, 0, sizeof(link)); + link.link_status = ETH_LINK_DOWN; + link.link_speed = ETH_SPEED_NUM_NONE; + link.link_duplex = ETH_LINK_HALF_DUPLEX; + link.link_autoneg = ETH_LINK_AUTONEG; + + hw->mac.get_link_status = true; + + if (intr->flags & TXGBE_FLAG_NEED_LINK_CONFIG) + return rte_eth_linkstatus_set(dev, &link); + + /* check if it needs to wait to complete, if lsc interrupt is enabled */ + if (wait_to_complete == 0 || dev->data->dev_conf.intr_conf.lsc != 0) + wait = 0; + + err = hw->mac.check_link(hw, &link_speed, &link_up, wait); + + if (err != 0) { + link.link_speed = ETH_SPEED_NUM_100M; + link.link_duplex = ETH_LINK_FULL_DUPLEX; + return rte_eth_linkstatus_set(dev, &link); + } + + if (link_up == 0) { + if (hw->phy.media_type == txgbe_media_type_fiber) { + intr->flags |= TXGBE_FLAG_NEED_LINK_CONFIG; + rte_eal_alarm_set(10, + txgbe_dev_setup_link_alarm_handler, dev); + } + return rte_eth_linkstatus_set(dev, &link); + } + + intr->flags &= ~TXGBE_FLAG_NEED_LINK_CONFIG; + link.link_status = ETH_LINK_UP; + link.link_duplex = ETH_LINK_FULL_DUPLEX; + + switch (link_speed) { + default: + case TXGBE_LINK_SPEED_UNKNOWN: + link.link_duplex = ETH_LINK_FULL_DUPLEX; + link.link_speed = ETH_SPEED_NUM_100M; + break; + + case TXGBE_LINK_SPEED_100M_FULL: + link.link_speed = ETH_SPEED_NUM_100M; + break; + + case TXGBE_LINK_SPEED_1GB_FULL: + link.link_speed = ETH_SPEED_NUM_1G; + break; + + case TXGBE_LINK_SPEED_2_5GB_FULL: + link.link_speed = ETH_SPEED_NUM_2_5G; + break; + + case TXGBE_LINK_SPEED_5GB_FULL: + link.link_speed = ETH_SPEED_NUM_5G; + break; + + case TXGBE_LINK_SPEED_10GB_FULL: + link.link_speed = ETH_SPEED_NUM_10G; + break; + } + + return rte_eth_linkstatus_set(dev, &link); +} + static int txgbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete) { - RTE_SET_USED(dev); - RTE_SET_USED(wait_to_complete); - return 0; + return txgbe_dev_link_update_share(dev, wait_to_complete); } /** @@ -1004,6 +1144,8 @@ txgbe_configure_msix(struct rte_eth_dev *dev) static const struct eth_dev_ops txgbe_eth_dev_ops = { .dev_configure = txgbe_dev_configure, .dev_infos_get = txgbe_dev_info_get, + .dev_set_link_up = txgbe_dev_set_link_up, + .dev_set_link_down = txgbe_dev_set_link_down, }; RTE_PMD_REGISTER_PCI(net_txgbe, rte_txgbe_pmd); diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h index 8dd6c36c2..ec8eaaf19 100644 --- a/drivers/net/txgbe/txgbe_ethdev.h +++ b/drivers/net/txgbe/txgbe_ethdev.h @@ -58,7 +58,7 @@ struct txgbe_adapter { }; #define TXGBE_DEV_ADAPTER(dev) \ - ((struct txgbe_adapter *)(dev)->data->dev_private) + ((struct txgbe_adapter *)(dev)->data->dev_private) #define TXGBE_DEV_HW(dev) \ (&((struct txgbe_adapter *)(dev)->data->dev_private)->hw) @@ -69,6 +69,10 @@ struct txgbe_adapter { void txgbe_set_ivar_map(struct txgbe_hw *hw, int8_t direction, uint8_t queue, uint8_t msix_vector); +int +txgbe_dev_link_update_share(struct rte_eth_dev *dev, + int wait_to_complete); + #define TXGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */ #define TXGBE_LINK_UP_CHECK_TIMEOUT 1000 /* ms */ #define TXGBE_VMDQ_NUM_UC_MAC 4096 /* Maximum nb. of UC MAC addr. */ @@ -86,4 +90,6 @@ void txgbe_set_ivar_map(struct txgbe_hw *hw, int8_t direction, #define TXGBE_DEFAULT_TX_HTHRESH 0 #define TXGBE_DEFAULT_TX_WTHRESH 0 +void txgbe_dev_setup_link_alarm_handler(void *param); + #endif /* _TXGBE_ETHDEV_H_ */ -- 2.18.4