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 E71C1A04B7; Wed, 14 Oct 2020 08:12:38 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 7016E1DC1D; Wed, 14 Oct 2020 07:55:28 +0200 (CEST) Received: from smtpbgsg2.qq.com (smtpbgsg2.qq.com [54.254.200.128]) by dpdk.org (Postfix) with ESMTP id 7CCCF1DCD8 for ; Wed, 14 Oct 2020 07:55:01 +0200 (CEST) X-QQ-mid: bizesmtp28t1602654897t5wiceop Received: from localhost.localdomain.com (unknown [183.129.236.74]) by esmtp10.qq.com (ESMTP) with id ; Wed, 14 Oct 2020 13:54:56 +0800 (CST) X-QQ-SSF: 01400000000000C0C000B00A0000000 X-QQ-FEAT: evoCpQyf+dgLgI4K4TSK/Tn5LxblR6wnVxb7xWGY56Tvz3TJF85VxtKx3ldtz hukVJ8NqS7w/F8PKNHq+ANorR9UNbOAninD6Q7wsVcuq62tdvLZa0f6J1MViVa5r/lVlmKP Z32glPHL4xatcczIIutPhjAHJXmqL9N7v436PfiB+Mwz62LACIQ+lWCJGW0VbtAY1hzo22u dRjzfi0ow9fXF4VkQe5Qj9ej3ZYrYElyDECU9MtV6EP3wG5e5nPeXzI+BVCNrBBiWUVm/SQ NE0BqjJyUDyW7nAa/gV5tV/TAKnP+kCdRu4jOpimFciENYH//m2MY4du+5+XGwYR5yS0YFc i5yhH4ENng1xHdheZw= X-QQ-GoodBg: 2 From: Jiawen Wu To: dev@dpdk.org Cc: Jiawen Wu Date: Wed, 14 Oct 2020 13:55:05 +0800 Message-Id: <20201014055517.1214386-45-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:qybgforeign7 X-QQ-Bgrelay: 1 Subject: [dpdk-dev] [PATCH v3 44/56] net/txgbe: add flow control support 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 flow control support. Signed-off-by: Jiawen Wu --- doc/guides/nics/features/txgbe.ini | 1 + doc/guides/nics/txgbe.rst | 1 + drivers/net/txgbe/base/txgbe_hw.c | 425 ++++++++++++++++++++++++++++ drivers/net/txgbe/base/txgbe_hw.h | 6 + drivers/net/txgbe/base/txgbe_type.h | 22 ++ drivers/net/txgbe/txgbe_ethdev.c | 122 +++++++- drivers/net/txgbe/txgbe_ethdev.h | 7 + 7 files changed, 583 insertions(+), 1 deletion(-) diff --git a/doc/guides/nics/features/txgbe.ini b/doc/guides/nics/features/txgbe.ini index 6cbc3a65a..f69785787 100644 --- a/doc/guides/nics/features/txgbe.ini +++ b/doc/guides/nics/features/txgbe.ini @@ -22,6 +22,7 @@ VMDq = Y SR-IOV = Y DCB = Y VLAN filter = Y +Flow control = Y Rate limitation = Y CRC offload = P VLAN offload = P diff --git a/doc/guides/nics/txgbe.rst b/doc/guides/nics/txgbe.rst index 54aebee78..95919478b 100644 --- a/doc/guides/nics/txgbe.rst +++ b/doc/guides/nics/txgbe.rst @@ -20,6 +20,7 @@ Features - Port hardware statistics - Jumbo frames - Link state information +- Link flow control - Interrupt mode for RX - Scattered and gather for TX and RX - DCB diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index e4c6c2d64..7a6c30999 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -25,6 +25,211 @@ static s32 txgbe_mta_vector(struct txgbe_hw *hw, u8 *mc_addr); static s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw, u16 *san_mac_offset); +/** + * txgbe_device_supports_autoneg_fc - Check if device supports autonegotiation + * of flow control + * @hw: pointer to hardware structure + * + * This function returns true if the device supports flow control + * autonegotiation, and false if it does not. + * + **/ +bool txgbe_device_supports_autoneg_fc(struct txgbe_hw *hw) +{ + bool supported = false; + u32 speed; + bool link_up; + + DEBUGFUNC("txgbe_device_supports_autoneg_fc"); + + switch (hw->phy.media_type) { + case txgbe_media_type_fiber_qsfp: + case txgbe_media_type_fiber: + hw->mac.check_link(hw, &speed, &link_up, false); + /* if link is down, assume supported */ + if (link_up) + supported = speed == TXGBE_LINK_SPEED_1GB_FULL ? + true : false; + else + supported = true; + + break; + case txgbe_media_type_backplane: + supported = true; + break; + case txgbe_media_type_copper: + /* only some copper devices support flow control autoneg */ + switch (hw->device_id) { + case TXGBE_DEV_ID_RAPTOR_XAUI: + case TXGBE_DEV_ID_RAPTOR_SGMII: + supported = true; + break; + default: + supported = false; + } + default: + break; + } + + if (!supported) + DEBUGOUT("Device %x does not support flow control autoneg", + hw->device_id); + return supported; +} + +/** + * txgbe_setup_fc - Set up flow control + * @hw: pointer to hardware structure + * + * Called at init time to set up flow control. + **/ +s32 txgbe_setup_fc(struct txgbe_hw *hw) +{ + s32 err = 0; + u32 reg = 0; + u16 reg_cu = 0; + u32 value = 0; + u64 reg_bp = 0; + bool locked = false; + + DEBUGFUNC("txgbe_setup_fc"); + + /* Validate the requested mode */ + if (hw->fc.strict_ieee && hw->fc.requested_mode == txgbe_fc_rx_pause) { + DEBUGOUT("txgbe_fc_rx_pause not valid in strict IEEE mode\n"); + err = TXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* + * 10gig parts do not have a word in the EEPROM to determine the + * default flow control setting, so we explicitly set it to full. + */ + if (hw->fc.requested_mode == txgbe_fc_default) + hw->fc.requested_mode = txgbe_fc_full; + + /* + * Set up the 1G and 10G flow control advertisement registers so the + * HW will be able to do fc autoneg once the cable is plugged in. If + * we link at 10G, the 1G advertisement is harmless and vice versa. + */ + switch (hw->phy.media_type) { + case txgbe_media_type_backplane: + /* some MAC's need RMW protection on AUTOC */ + err = hw->mac.prot_autoc_read(hw, &locked, ®_bp); + if (err != 0) + goto out; + + /* fall through - only backplane uses autoc */ + case txgbe_media_type_fiber_qsfp: + case txgbe_media_type_fiber: + case txgbe_media_type_copper: + hw->phy.read_reg(hw, TXGBE_MD_AUTO_NEG_ADVT, + TXGBE_MD_DEV_AUTO_NEG, ®_cu); + break; + default: + break; + } + + /* + * The possible values of fc.requested_mode are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.requested_mode) { + case txgbe_fc_none: + /* Flow control completely disabled by software override. */ + reg &= ~(SR_MII_MMD_AN_ADV_PAUSE_SYM | + SR_MII_MMD_AN_ADV_PAUSE_ASM); + if (hw->phy.media_type == txgbe_media_type_backplane) + reg_bp &= ~(TXGBE_AUTOC_SYM_PAUSE | + TXGBE_AUTOC_ASM_PAUSE); + else if (hw->phy.media_type == txgbe_media_type_copper) + reg_cu &= ~(TXGBE_TAF_SYM_PAUSE | TXGBE_TAF_ASM_PAUSE); + break; + case txgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + reg |= SR_MII_MMD_AN_ADV_PAUSE_ASM; + reg &= ~SR_MII_MMD_AN_ADV_PAUSE_SYM; + if (hw->phy.media_type == txgbe_media_type_backplane) { + reg_bp |= TXGBE_AUTOC_ASM_PAUSE; + reg_bp &= ~TXGBE_AUTOC_SYM_PAUSE; + } else if (hw->phy.media_type == txgbe_media_type_copper) { + reg_cu |= TXGBE_TAF_ASM_PAUSE; + reg_cu &= ~TXGBE_TAF_SYM_PAUSE; + } + reg |= SR_MII_MMD_AN_ADV_PAUSE_ASM; + reg_bp |= SR_AN_MMD_ADV_REG1_PAUSE_ASM; + break; + case txgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE, as such we fall + * through to the fc_full statement. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + case txgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + reg |= SR_MII_MMD_AN_ADV_PAUSE_SYM | + SR_MII_MMD_AN_ADV_PAUSE_ASM; + if (hw->phy.media_type == txgbe_media_type_backplane) + reg_bp |= TXGBE_AUTOC_SYM_PAUSE | + TXGBE_AUTOC_ASM_PAUSE; + else if (hw->phy.media_type == txgbe_media_type_copper) + reg_cu |= TXGBE_TAF_SYM_PAUSE | TXGBE_TAF_ASM_PAUSE; + reg |= SR_MII_MMD_AN_ADV_PAUSE_SYM | + SR_MII_MMD_AN_ADV_PAUSE_ASM; + reg_bp |= SR_AN_MMD_ADV_REG1_PAUSE_SYM | + SR_AN_MMD_ADV_REG1_PAUSE_ASM; + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + err = TXGBE_ERR_CONFIG; + goto out; + } + + /* + * Enable auto-negotiation between the MAC & PHY; + * the MAC will advertise clause 37 flow control. + */ + value = rd32_epcs(hw, SR_MII_MMD_AN_ADV); + value = (value & ~(SR_MII_MMD_AN_ADV_PAUSE_ASM | + SR_MII_MMD_AN_ADV_PAUSE_SYM)) | reg; + wr32_epcs(hw, SR_MII_MMD_AN_ADV, value); + + /* + * AUTOC restart handles negotiation of 1G and 10G on backplane + * and copper. There is no need to set the PCS1GCTL register. + * + */ + if (hw->phy.media_type == txgbe_media_type_backplane) { + value = rd32_epcs(hw, SR_AN_MMD_ADV_REG1); + value = (value & ~(SR_AN_MMD_ADV_REG1_PAUSE_ASM | + SR_AN_MMD_ADV_REG1_PAUSE_SYM)) | + reg_bp; + wr32_epcs(hw, SR_AN_MMD_ADV_REG1, value); + } else if ((hw->phy.media_type == txgbe_media_type_copper) && + (txgbe_device_supports_autoneg_fc(hw))) { + hw->phy.write_reg(hw, TXGBE_MD_AUTO_NEG_ADVT, + TXGBE_MD_DEV_AUTO_NEG, reg_cu); + } + + DEBUGOUT("Set up FC; reg = 0x%08X\n", reg); +out: + return err; +} + /** * txgbe_start_hw - Prepare hardware for Tx/Rx * @hw: pointer to hardware structure @@ -36,6 +241,7 @@ static s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw, **/ s32 txgbe_start_hw(struct txgbe_hw *hw) { + s32 err; u16 device_caps; DEBUGFUNC("txgbe_start_hw"); @@ -49,6 +255,13 @@ s32 txgbe_start_hw(struct txgbe_hw *hw) /* Clear statistics registers */ hw->mac.clear_hw_cntrs(hw); + /* Setup flow control */ + err = txgbe_setup_fc(hw); + if (err != 0 && err != TXGBE_NOT_IMPLEMENTED) { + DEBUGOUT("Flow control setup failed, returning %d\n", err); + return err; + } + /* Cache bit indicating need for crosstalk fix */ switch (hw->mac.type) { case txgbe_mac_raptor: @@ -673,6 +886,136 @@ s32 txgbe_update_mc_addr_list(struct txgbe_hw *hw, u8 *mc_addr_list, return 0; } +/** + * txgbe_fc_enable - Enable flow control + * @hw: pointer to hardware structure + * + * Enable flow control according to the current settings. + **/ +s32 txgbe_fc_enable(struct txgbe_hw *hw) +{ + s32 err = 0; + u32 mflcn_reg, fccfg_reg; + u32 pause_time; + u32 fcrtl, fcrth; + int i; + + DEBUGFUNC("txgbe_fc_enable"); + + /* Validate the water mark configuration */ + if (!hw->fc.pause_time) { + err = TXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* Low water mark of zero causes XOFF floods */ + for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { + if ((hw->fc.current_mode & txgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + if (!hw->fc.low_water[i] || + hw->fc.low_water[i] >= hw->fc.high_water[i]) { + DEBUGOUT("Invalid water mark configuration\n"); + err = TXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + } + } + + /* Negotiate the fc mode to use */ + hw->mac.fc_autoneg(hw); + + /* Disable any previous flow control settings */ + mflcn_reg = rd32(hw, TXGBE_RXFCCFG); + mflcn_reg &= ~(TXGBE_RXFCCFG_FC | TXGBE_RXFCCFG_PFC); + + fccfg_reg = rd32(hw, TXGBE_TXFCCFG); + fccfg_reg &= ~(TXGBE_TXFCCFG_FC | TXGBE_TXFCCFG_PFC); + + /* + * The possible values of fc.current_mode are: + * 0: Flow control is completely disabled + * 1: Rx flow control is enabled (we can receive pause frames, + * but not send pause frames). + * 2: Tx flow control is enabled (we can send pause frames but + * we do not support receiving pause frames). + * 3: Both Rx and Tx flow control (symmetric) are enabled. + * other: Invalid. + */ + switch (hw->fc.current_mode) { + case txgbe_fc_none: + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ + break; + case txgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + mflcn_reg |= TXGBE_RXFCCFG_FC; + break; + case txgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + fccfg_reg |= TXGBE_TXFCCFG_FC; + break; + case txgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + mflcn_reg |= TXGBE_RXFCCFG_FC; + fccfg_reg |= TXGBE_TXFCCFG_FC; + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + err = TXGBE_ERR_CONFIG; + goto out; + } + + /* Set 802.3x based flow control settings. */ + wr32(hw, TXGBE_RXFCCFG, mflcn_reg); + wr32(hw, TXGBE_TXFCCFG, fccfg_reg); + + /* Set up and enable Rx high/low water mark thresholds, enable XON. */ + for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { + if ((hw->fc.current_mode & txgbe_fc_tx_pause) && + hw->fc.high_water[i]) { + fcrtl = TXGBE_FCWTRLO_TH(hw->fc.low_water[i]) | + TXGBE_FCWTRLO_XON; + fcrth = TXGBE_FCWTRHI_TH(hw->fc.high_water[i]) | + TXGBE_FCWTRHI_XOFF; + } else { + /* + * In order to prevent Tx hangs when the internal Tx + * switch is enabled we must set the high water mark + * to the Rx packet buffer size - 24KB. This allows + * the Tx switch to function even under heavy Rx + * workloads. + */ + fcrtl = 0; + fcrth = rd32(hw, TXGBE_PBRXSIZE(i)) - 24576; + } + wr32(hw, TXGBE_FCWTRLO(i), fcrtl); + wr32(hw, TXGBE_FCWTRHI(i), fcrth); + } + + /* Configure pause time (2 TCs per register) */ + pause_time = TXGBE_RXFCFSH_TIME(hw->fc.pause_time); + for (i = 0; i < (TXGBE_DCB_TC_MAX / 2); i++) + wr32(hw, TXGBE_FCXOFFTM(i), pause_time * 0x00010001); + + /* Configure flow control refresh threshold value */ + wr32(hw, TXGBE_RXFCRFSH, hw->fc.pause_time / 2); + +out: + return err; +} + /** * txgbe_acquire_swfw_sync - Acquire SWFW semaphore * @hw: pointer to hardware structure @@ -2090,6 +2433,82 @@ s32 txgbe_setup_sfp_modules(struct txgbe_hw *hw) return err; } +/** + * txgbe_prot_autoc_read_raptor - Hides MAC differences needed for AUTOC read + * @hw: pointer to hardware structure + * @locked: Return the if we locked for this read. + * @value: Value we read from AUTOC + * + * For this part we need to wrap read-modify-writes with a possible + * FW/SW lock. It is assumed this lock will be freed with the next + * prot_autoc_write_raptor(). + */ +s32 txgbe_prot_autoc_read_raptor(struct txgbe_hw *hw, bool *locked, u64 *value) +{ + s32 err; + bool lock_state = false; + + /* If LESM is on then we need to hold the SW/FW semaphore. */ + if (txgbe_verify_lesm_fw_enabled_raptor(hw)) { + err = hw->mac.acquire_swfw_sync(hw, + TXGBE_MNGSEM_SWPHY); + if (err != 0) + return TXGBE_ERR_SWFW_SYNC; + + lock_state = true; + } + + if (locked) + *locked = lock_state; + + *value = txgbe_autoc_read(hw); + return 0; +} + +/** + * txgbe_prot_autoc_write_raptor - Hides MAC differences needed for AUTOC write + * @hw: pointer to hardware structure + * @autoc: value to write to AUTOC + * @locked: bool to indicate whether the SW/FW lock was already taken by + * previous prot_autoc_read_raptor. + * + * This part may need to hold the SW/FW lock around all writes to + * AUTOC. Likewise after a write we need to do a pipeline reset. + */ +s32 txgbe_prot_autoc_write_raptor(struct txgbe_hw *hw, bool locked, u64 autoc) +{ + int err = 0; + + /* Blocked by MNG FW so bail */ + if (txgbe_check_reset_blocked(hw)) + goto out; + + /* We only need to get the lock if: + * - We didn't do it already (in the read part of a read-modify-write) + * - LESM is enabled. + */ + if (!locked && txgbe_verify_lesm_fw_enabled_raptor(hw)) { + err = hw->mac.acquire_swfw_sync(hw, + TXGBE_MNGSEM_SWPHY); + if (err != 0) + return TXGBE_ERR_SWFW_SYNC; + + locked = true; + } + + txgbe_autoc_write(hw, autoc); + err = txgbe_reset_pipeline_raptor(hw); + +out: + /* Free the SW/FW semaphore as we either grabbed it here or + * already had it when this function was called. + */ + if (locked) + hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + + return err; +} + /** * txgbe_init_ops_pf - Inits func ptrs and MAC type * @hw: pointer to hardware structure @@ -2147,6 +2566,8 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) mac->get_wwn_prefix = txgbe_get_wwn_prefix; mac->autoc_read = txgbe_autoc_read; mac->autoc_write = txgbe_autoc_write; + mac->prot_autoc_read = txgbe_prot_autoc_read_raptor; + mac->prot_autoc_write = txgbe_prot_autoc_write_raptor; /* RAR, Multicast, VLAN */ mac->set_rar = txgbe_set_rar; @@ -2164,6 +2585,10 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) mac->set_mac_anti_spoofing = txgbe_set_mac_anti_spoofing; mac->set_ethertype_anti_spoofing = txgbe_set_ethertype_anti_spoofing; + /* Flow Control */ + mac->fc_enable = txgbe_fc_enable; + mac->setup_fc = txgbe_setup_fc; + /* Link */ mac->get_link_capabilities = txgbe_get_link_capabilities_raptor; mac->check_link = txgbe_check_mac_link; diff --git a/drivers/net/txgbe/base/txgbe_hw.h b/drivers/net/txgbe/base/txgbe_hw.h index ffc2ae1d6..1e1cbb2eb 100644 --- a/drivers/net/txgbe/base/txgbe_hw.h +++ b/drivers/net/txgbe/base/txgbe_hw.h @@ -28,6 +28,10 @@ s32 txgbe_enable_sec_rx_path(struct txgbe_hw *hw); s32 txgbe_disable_sec_tx_path(struct txgbe_hw *hw); s32 txgbe_enable_sec_tx_path(struct txgbe_hw *hw); +s32 txgbe_fc_enable(struct txgbe_hw *hw); +bool txgbe_device_supports_autoneg_fc(struct txgbe_hw *hw); +s32 txgbe_setup_fc(struct txgbe_hw *hw); + s32 txgbe_validate_mac_addr(u8 *mac_addr); s32 txgbe_acquire_swfw_sync(struct txgbe_hw *hw, u32 mask); void txgbe_release_swfw_sync(struct txgbe_hw *hw, u32 mask); @@ -96,5 +100,7 @@ s32 txgbe_reset_hw(struct txgbe_hw *hw); s32 txgbe_start_hw_raptor(struct txgbe_hw *hw); s32 txgbe_init_phy_raptor(struct txgbe_hw *hw); s32 txgbe_enable_rx_dma_raptor(struct txgbe_hw *hw, u32 regval); +s32 txgbe_prot_autoc_read_raptor(struct txgbe_hw *hw, bool *locked, u64 *value); +s32 txgbe_prot_autoc_write_raptor(struct txgbe_hw *hw, bool locked, u64 value); bool txgbe_verify_lesm_fw_enabled_raptor(struct txgbe_hw *hw); #endif /* _TXGBE_HW_H_ */ diff --git a/drivers/net/txgbe/base/txgbe_type.h b/drivers/net/txgbe/base/txgbe_type.h index 34994bb3b..d851648de 100644 --- a/drivers/net/txgbe/base/txgbe_type.h +++ b/drivers/net/txgbe/base/txgbe_type.h @@ -153,6 +153,14 @@ enum txgbe_media_type { txgbe_media_type_virtual }; +/* Flow Control Settings */ +enum txgbe_fc_mode { + txgbe_fc_none = 0, + txgbe_fc_rx_pause, + txgbe_fc_tx_pause, + txgbe_fc_full, + txgbe_fc_default +}; /* Smart Speed Settings */ #define TXGBE_SMARTSPEED_MAX_RETRIES 3 @@ -222,6 +230,19 @@ struct txgbe_bus_info { u16 instance_id; }; +/* Flow control parameters */ +struct txgbe_fc_info { + u32 high_water[TXGBE_DCB_TC_MAX]; /* Flow Ctrl High-water */ + u32 low_water[TXGBE_DCB_TC_MAX]; /* Flow Ctrl Low-water */ + u16 pause_time; /* Flow Control Pause timer */ + bool send_xon; /* Flow control send XON */ + bool strict_ieee; /* Strict IEEE mode */ + bool disable_fc_autoneg; /* Do not autonegotiate FC */ + bool fc_was_autonegged; /* Is current_mode the result of autonegging? */ + enum txgbe_fc_mode current_mode; /* FC mode in effect */ + enum txgbe_fc_mode requested_mode; /* FC mode requested by caller */ +}; + /* Statistics counters collected by the MAC */ /* PB[] RxTx */ struct txgbe_pb_stats { @@ -633,6 +654,7 @@ struct txgbe_hw { void *back; struct txgbe_mac_info mac; struct txgbe_addr_filter_info addr_ctrl; + struct txgbe_fc_info fc; struct txgbe_phy_info phy; struct txgbe_link_info link; struct txgbe_rom_info rom; diff --git a/drivers/net/txgbe/txgbe_ethdev.c b/drivers/net/txgbe/txgbe_ethdev.c index fa98f05b5..a2cc7f715 100644 --- a/drivers/net/txgbe/txgbe_ethdev.c +++ b/drivers/net/txgbe/txgbe_ethdev.c @@ -404,11 +404,12 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) struct txgbe_vfta *shadow_vfta = TXGBE_DEV_VFTA(eth_dev); struct txgbe_hwstrip *hwstrip = TXGBE_DEV_HWSTRIP(eth_dev); struct txgbe_dcb_config *dcb_config = TXGBE_DEV_DCB_CONFIG(eth_dev); + struct txgbe_bw_conf *bw_conf = TXGBE_DEV_BW_CONF(eth_dev); struct rte_intr_handle *intr_handle = &pci_dev->intr_handle; const struct rte_memzone *mz; uint32_t ctrl_ext; uint16_t csum; - int err; + int err, i; PMD_INIT_FUNC_TRACE(); @@ -473,6 +474,16 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) memset(dcb_config, 0, sizeof(struct txgbe_dcb_config)); txgbe_dcb_init(hw, dcb_config); + /* Get Hardware Flow Control setting */ + hw->fc.requested_mode = txgbe_fc_full; + hw->fc.current_mode = txgbe_fc_full; + hw->fc.pause_time = TXGBE_FC_PAUSE_TIME; + for (i = 0; i < TXGBE_DCB_TC_MAX; i++) { + hw->fc.low_water[i] = TXGBE_FC_XON_LOTH; + hw->fc.high_water[i] = TXGBE_FC_XOFF_HITH; + } + hw->fc.send_xon = 1; + err = hw->rom.init_params(hw); if (err != 0) { PMD_INIT_LOG(ERR, "The EEPROM init failed: %d", err); @@ -590,6 +601,9 @@ eth_txgbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) /* enable support intr */ txgbe_enable_intr(eth_dev); + /* initialize bandwidth configuration info */ + memset(bw_conf, 0, sizeof(struct txgbe_bw_conf)); + return 0; } @@ -2682,6 +2696,110 @@ txgbe_dev_interrupt_handler(void *param) txgbe_dev_interrupt_action(dev, dev->intr_handle); } +static int +txgbe_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct txgbe_hw *hw; + uint32_t mflcn_reg; + uint32_t fccfg_reg; + int rx_pause; + int tx_pause; + + hw = TXGBE_DEV_HW(dev); + + fc_conf->pause_time = hw->fc.pause_time; + fc_conf->high_water = hw->fc.high_water[0]; + fc_conf->low_water = hw->fc.low_water[0]; + fc_conf->send_xon = hw->fc.send_xon; + fc_conf->autoneg = !hw->fc.disable_fc_autoneg; + + /* + * Return rx_pause status according to actual setting of + * RXFCCFG register. + */ + mflcn_reg = rd32(hw, TXGBE_RXFCCFG); + if (mflcn_reg & (TXGBE_RXFCCFG_FC | TXGBE_RXFCCFG_PFC)) + rx_pause = 1; + else + rx_pause = 0; + + /* + * Return tx_pause status according to actual setting of + * TXFCCFG register. + */ + fccfg_reg = rd32(hw, TXGBE_TXFCCFG); + if (fccfg_reg & (TXGBE_TXFCCFG_FC | TXGBE_TXFCCFG_PFC)) + tx_pause = 1; + else + tx_pause = 0; + + if (rx_pause && tx_pause) + fc_conf->mode = RTE_FC_FULL; + else if (rx_pause) + fc_conf->mode = RTE_FC_RX_PAUSE; + else if (tx_pause) + fc_conf->mode = RTE_FC_TX_PAUSE; + else + fc_conf->mode = RTE_FC_NONE; + + return 0; +} + +static int +txgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct txgbe_hw *hw; + int err; + uint32_t rx_buf_size; + uint32_t max_high_water; + enum txgbe_fc_mode rte_fcmode_2_txgbe_fcmode[] = { + txgbe_fc_none, + txgbe_fc_rx_pause, + txgbe_fc_tx_pause, + txgbe_fc_full + }; + + PMD_INIT_FUNC_TRACE(); + + hw = TXGBE_DEV_HW(dev); + rx_buf_size = rd32(hw, TXGBE_PBRXSIZE(0)); + PMD_INIT_LOG(DEBUG, "Rx packet buffer size = 0x%x", rx_buf_size); + + /* + * At least reserve one Ethernet frame for watermark + * high_water/low_water in kilo bytes for txgbe + */ + max_high_water = (rx_buf_size - RTE_ETHER_MAX_LEN) >> 10; + if (fc_conf->high_water > max_high_water || + fc_conf->high_water < fc_conf->low_water) { + PMD_INIT_LOG(ERR, "Invalid high/low water setup value in KB"); + PMD_INIT_LOG(ERR, "High_water must <= 0x%x", max_high_water); + return -EINVAL; + } + + hw->fc.requested_mode = rte_fcmode_2_txgbe_fcmode[fc_conf->mode]; + hw->fc.pause_time = fc_conf->pause_time; + hw->fc.high_water[0] = fc_conf->high_water; + hw->fc.low_water[0] = fc_conf->low_water; + hw->fc.send_xon = fc_conf->send_xon; + hw->fc.disable_fc_autoneg = !fc_conf->autoneg; + + err = txgbe_fc_enable(hw); + + /* Not negotiated is not an error case */ + if (err == 0 || err == TXGBE_ERR_FC_NOT_NEGOTIATED) { + wr32m(hw, TXGBE_MACRXFLT, TXGBE_MACRXFLT_CTL_MASK, + (fc_conf->mac_ctrl_frame_fwd + ? TXGBE_MACRXFLT_CTL_NOPS : TXGBE_MACRXFLT_CTL_DROP)); + txgbe_flush(hw); + + return 0; + } + + PMD_INIT_LOG(ERR, "txgbe_fc_enable = 0x%x", err); + return -EIO; +} + int txgbe_dev_rss_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf, @@ -3167,6 +3285,8 @@ static const struct eth_dev_ops txgbe_eth_dev_ops = { .rx_queue_release = txgbe_dev_rx_queue_release, .tx_queue_setup = txgbe_dev_tx_queue_setup, .tx_queue_release = txgbe_dev_tx_queue_release, + .flow_ctrl_get = txgbe_flow_ctrl_get, + .flow_ctrl_set = txgbe_flow_ctrl_set, .mac_addr_add = txgbe_add_rar, .mac_addr_remove = txgbe_remove_rar, .mac_addr_set = txgbe_set_default_mac_addr, diff --git a/drivers/net/txgbe/txgbe_ethdev.h b/drivers/net/txgbe/txgbe_ethdev.h index 733b90363..99ca6aa9d 100644 --- a/drivers/net/txgbe/txgbe_ethdev.h +++ b/drivers/net/txgbe/txgbe_ethdev.h @@ -327,6 +327,13 @@ txgbe_ethertype_filter_insert(struct txgbe_filter_info *filter_info, return (i < TXGBE_ETF_ID_MAX ? i : -1); } +/* High threshold controlling when to start sending XOFF frames. */ +#define TXGBE_FC_XOFF_HITH 128 /*KB*/ +/* Low threshold controlling when to start sending XON frames. */ +#define TXGBE_FC_XON_LOTH 64 /*KB*/ + +/* Timer value included in XOFF frames. */ +#define TXGBE_FC_PAUSE_TIME 0x680 #define TXGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */ #define TXGBE_LINK_UP_CHECK_TIMEOUT 1000 /* ms */ -- 2.18.4