From patchwork Thu Oct 21 09:50:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 102562 X-Patchwork-Delegate: ferruh.yigit@amd.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 4E6EAA0547; Thu, 21 Oct 2021 11:53:37 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id E181C4125D; Thu, 21 Oct 2021 11:51:13 +0200 (CEST) Received: from smtpproxy21.qq.com (smtpbg704.qq.com [203.205.195.105]) by mails.dpdk.org (Postfix) with ESMTP id 89D2841208 for ; Thu, 21 Oct 2021 11:51:09 +0200 (CEST) X-QQ-mid: bizesmtp38t1634809864tzjqlfap Received: from jiawenwu.trustnetic.com (unknown [183.129.236.74]) by esmtp6.qq.com (ESMTP) with id ; Thu, 21 Oct 2021 17:51:04 +0800 (CST) X-QQ-SSF: 01400000000000E0I000000A0000000 X-QQ-FEAT: CGxwVt8GOWFdnIqzIbtS3kB8gdmpnRNEnhWG4vQGUvOWr8qpnbqp2c0sn1O2b MQ8fnujck0Q5o4kGsKBvOrst9T832oGUwyMC47w4wPadcZ46yzsM4rpy6SgWWjvoCh34wSQ tVj1CruTwlpvh5JETw5eZ6kkQkkqVQUgqck3i7VsYJUBjvn/v19GODw2+YbrQXooJF7I4ua ZZo6qj2cNLwwtgqYv0CXbJuMo9ozTpRuVHZrv9RQxYDakmBxfVofqCyELSZzdXxStCPgGBt Z3qsF6/OU4hzjYAub3AEffiTJa2tTkffKZmbR/YtHyffBbgaBfYoZjxDtzKcqnw0tfkTb3V k8Ul/KtqakMbEe1kZWEszVEU8yr3OuPUc6swOrxqkuszyrPOVs= X-QQ-GoodBg: 2 From: Jiawen Wu To: dev@dpdk.org Cc: Jiawen Wu Date: Thu, 21 Oct 2021 17:50:16 +0800 Message-Id: <20211021095023.18288-20-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.21.0.windows.1 In-Reply-To: <20211021095023.18288-1-jiawenwu@trustnetic.com> References: <20211021095023.18288-1-jiawenwu@trustnetic.com> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybgforeign:qybgforeign6 X-QQ-Bgrelay: 1 Subject: [dpdk-dev] [PATCH v2 19/26] net/ngbe: support flow control X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 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" Support to get and set flow control. Signed-off-by: Jiawen Wu --- doc/guides/nics/features/ngbe.ini | 1 + doc/guides/nics/ngbe.rst | 1 + doc/guides/rel_notes/release_21_11.rst | 1 + drivers/net/ngbe/base/ngbe_dummy.h | 31 +++ drivers/net/ngbe/base/ngbe_hw.c | 334 +++++++++++++++++++++++++ drivers/net/ngbe/base/ngbe_hw.h | 6 + drivers/net/ngbe/base/ngbe_phy.c | 9 + drivers/net/ngbe/base/ngbe_phy.h | 3 + drivers/net/ngbe/base/ngbe_phy_mvl.c | 57 +++++ drivers/net/ngbe/base/ngbe_phy_mvl.h | 4 + drivers/net/ngbe/base/ngbe_phy_rtl.c | 42 ++++ drivers/net/ngbe/base/ngbe_phy_rtl.h | 3 + drivers/net/ngbe/base/ngbe_phy_yt.c | 44 ++++ drivers/net/ngbe/base/ngbe_phy_yt.h | 6 + drivers/net/ngbe/base/ngbe_type.h | 32 +++ drivers/net/ngbe/ngbe_ethdev.c | 111 ++++++++ drivers/net/ngbe/ngbe_ethdev.h | 8 + 17 files changed, 693 insertions(+) diff --git a/doc/guides/nics/features/ngbe.ini b/doc/guides/nics/features/ngbe.ini index ffb91d17da..1652e611fb 100644 --- a/doc/guides/nics/features/ngbe.ini +++ b/doc/guides/nics/features/ngbe.ini @@ -22,6 +22,7 @@ RSS key update = Y RSS reta update = Y SR-IOV = Y VLAN filter = Y +Flow control = Y CRC offload = Y VLAN offload = Y QinQ offload = Y diff --git a/doc/guides/nics/ngbe.rst b/doc/guides/nics/ngbe.rst index 1ca2a70074..978bb09495 100644 --- a/doc/guides/nics/ngbe.rst +++ b/doc/guides/nics/ngbe.rst @@ -23,6 +23,7 @@ Features - Port hardware statistics - Jumbo frames - Link state information +- Link flow control - Scattered and gather for TX and RX - FW version diff --git a/doc/guides/rel_notes/release_21_11.rst b/doc/guides/rel_notes/release_21_11.rst index ad25e6aeb2..7ff9a0385f 100644 --- a/doc/guides/rel_notes/release_21_11.rst +++ b/doc/guides/rel_notes/release_21_11.rst @@ -152,6 +152,7 @@ New Features * Added device basic statistics and extended stats. * Added multi-queue and RSS. * Added SRIOV. + * Added flow control. * **Added multi-process support for testpmd.** diff --git a/drivers/net/ngbe/base/ngbe_dummy.h b/drivers/net/ngbe/base/ngbe_dummy.h index 940b448734..0baabcbae7 100644 --- a/drivers/net/ngbe/base/ngbe_dummy.h +++ b/drivers/net/ngbe/base/ngbe_dummy.h @@ -154,6 +154,17 @@ static inline void ngbe_mac_set_vlan_anti_spoofing_dummy(struct ngbe_hw *TUP0, bool TUP1, int TUP2) { } +static inline s32 ngbe_mac_fc_enable_dummy(struct ngbe_hw *TUP0) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline s32 ngbe_mac_setup_fc_dummy(struct ngbe_hw *TUP0) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline void ngbe_mac_fc_autoneg_dummy(struct ngbe_hw *TUP0) +{ +} static inline s32 ngbe_mac_init_thermal_ssth_dummy(struct ngbe_hw *TUP0) { return NGBE_ERR_OPS_DUMMY; @@ -205,6 +216,20 @@ static inline s32 ngbe_phy_check_link_dummy(struct ngbe_hw *TUP0, u32 *TUP1, { return NGBE_ERR_OPS_DUMMY; } +static inline s32 ngbe_get_phy_advertised_pause_dummy(struct ngbe_hw *TUP0, + u8 *TUP1) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline s32 ngbe_get_phy_lp_advertised_pause_dummy(struct ngbe_hw *TUP0, + u8 *TUP1) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline s32 ngbe_set_phy_pause_adv_dummy(struct ngbe_hw *TUP0, u16 TUP1) +{ + return NGBE_ERR_OPS_DUMMY; +} /* struct ngbe_mbx_operations */ static inline void ngbe_mbx_init_params_dummy(struct ngbe_hw *TUP0) @@ -264,6 +289,9 @@ static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw) hw->mac.set_vlvf = ngbe_mac_set_vlvf_dummy; hw->mac.set_mac_anti_spoofing = ngbe_mac_set_mac_anti_spoofing_dummy; hw->mac.set_vlan_anti_spoofing = ngbe_mac_set_vlan_anti_spoofing_dummy; + hw->mac.fc_enable = ngbe_mac_fc_enable_dummy; + hw->mac.setup_fc = ngbe_mac_setup_fc_dummy; + hw->mac.fc_autoneg = ngbe_mac_fc_autoneg_dummy; hw->mac.init_thermal_sensor_thresh = ngbe_mac_init_thermal_ssth_dummy; hw->mac.check_overtemp = ngbe_mac_check_overtemp_dummy; hw->phy.identify = ngbe_phy_identify_dummy; @@ -275,6 +303,9 @@ static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw) hw->phy.write_reg_unlocked = ngbe_phy_write_reg_unlocked_dummy; hw->phy.setup_link = ngbe_phy_setup_link_dummy; hw->phy.check_link = ngbe_phy_check_link_dummy; + hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_dummy; + hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_dummy; + hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_dummy; hw->mbx.init_params = ngbe_mbx_init_params_dummy; hw->mbx.read = ngbe_mbx_read_dummy; hw->mbx.write = ngbe_mbx_write_dummy; diff --git a/drivers/net/ngbe/base/ngbe_hw.c b/drivers/net/ngbe/base/ngbe_hw.c index 541d916479..8262e50a80 100644 --- a/drivers/net/ngbe/base/ngbe_hw.c +++ b/drivers/net/ngbe/base/ngbe_hw.c @@ -18,6 +18,8 @@ **/ s32 ngbe_start_hw(struct ngbe_hw *hw) { + s32 err; + DEBUGFUNC("ngbe_start_hw"); /* Clear the VLAN filter table */ @@ -26,6 +28,13 @@ s32 ngbe_start_hw(struct ngbe_hw *hw) /* Clear statistics registers */ hw->mac.clear_hw_cntrs(hw); + /* Setup flow control */ + err = hw->mac.setup_fc(hw); + if (err != 0 && err != NGBE_NOT_IMPLEMENTED) { + DEBUGOUT("Flow control setup failed, returning %d\n", err); + return err; + } + /* Clear adapter stopped flag */ hw->adapter_stopped = false; @@ -703,6 +712,326 @@ s32 ngbe_update_mc_addr_list(struct ngbe_hw *hw, u8 *mc_addr_list, return 0; } +/** + * ngbe_setup_fc_em - Set up flow control + * @hw: pointer to hardware structure + * + * Called at init time to set up flow control. + **/ +s32 ngbe_setup_fc_em(struct ngbe_hw *hw) +{ + s32 err = 0; + u16 reg_cu = 0; + + DEBUGFUNC("ngbe_setup_fc"); + + /* Validate the requested mode */ + if (hw->fc.strict_ieee && hw->fc.requested_mode == ngbe_fc_rx_pause) { + DEBUGOUT("ngbe_fc_rx_pause not valid in strict IEEE mode\n"); + err = NGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* + * 1gig 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 == ngbe_fc_default) + hw->fc.requested_mode = ngbe_fc_full; + + /* + * 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 ngbe_fc_none: + /* Flow control completely disabled by software override. */ + break; + case ngbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + if (hw->phy.type == ngbe_phy_mvl_sfi || + hw->phy.type == ngbe_phy_yt8521s_sfi) + reg_cu |= MVL_FANA_ASM_PAUSE; + else + reg_cu |= 0x800; /*need to merge rtl and mvl on page 0*/ + break; + case ngbe_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 ngbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + if (hw->phy.type == ngbe_phy_mvl_sfi || + hw->phy.type == ngbe_phy_yt8521s_sfi) + reg_cu |= MVL_FANA_SYM_PAUSE; + else + reg_cu |= 0xC00; /*need to merge rtl and mvl on page 0*/ + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + err = NGBE_ERR_CONFIG; + goto out; + } + + err = hw->phy.set_pause_adv(hw, reg_cu); + +out: + return err; +} + +/** + * ngbe_fc_enable - Enable flow control + * @hw: pointer to hardware structure + * + * Enable flow control according to the current settings. + **/ +s32 ngbe_fc_enable(struct ngbe_hw *hw) +{ + s32 err = 0; + u32 mflcn_reg, fccfg_reg; + u32 pause_time; + u32 fcrtl, fcrth; + + DEBUGFUNC("ngbe_fc_enable"); + + /* Validate the water mark configuration */ + if (!hw->fc.pause_time) { + err = NGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } + + /* Low water mark of zero causes XOFF floods */ + if ((hw->fc.current_mode & ngbe_fc_tx_pause) && hw->fc.high_water) { + if (!hw->fc.low_water || + hw->fc.low_water >= hw->fc.high_water) { + DEBUGOUT("Invalid water mark configuration\n"); + err = NGBE_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, NGBE_RXFCCFG); + mflcn_reg &= ~NGBE_RXFCCFG_FC; + + fccfg_reg = rd32(hw, NGBE_TXFCCFG); + fccfg_reg &= ~NGBE_TXFCCFG_FC; + /* + * 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 ngbe_fc_none: + /* + * Flow control is disabled by software override or autoneg. + * The code below will actually disable it in the HW. + */ + break; + case ngbe_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 |= NGBE_RXFCCFG_FC; + break; + case ngbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + fccfg_reg |= NGBE_TXFCCFG_FC; + break; + case ngbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + mflcn_reg |= NGBE_RXFCCFG_FC; + fccfg_reg |= NGBE_TXFCCFG_FC; + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + err = NGBE_ERR_CONFIG; + goto out; + } + + /* Set 802.3x based flow control settings. */ + wr32(hw, NGBE_RXFCCFG, mflcn_reg); + wr32(hw, NGBE_TXFCCFG, fccfg_reg); + + /* Set up and enable Rx high/low water mark thresholds, enable XON. */ + if ((hw->fc.current_mode & ngbe_fc_tx_pause) && + hw->fc.high_water) { + fcrtl = NGBE_FCWTRLO_TH(hw->fc.low_water) | + NGBE_FCWTRLO_XON; + fcrth = NGBE_FCWTRHI_TH(hw->fc.high_water) | + NGBE_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, NGBE_PBRXSIZE) - 24576; + } + wr32(hw, NGBE_FCWTRLO, fcrtl); + wr32(hw, NGBE_FCWTRHI, fcrth); + + /* Configure pause time */ + pause_time = NGBE_RXFCFSH_TIME(hw->fc.pause_time); + wr32(hw, NGBE_FCXOFFTM, pause_time * 0x00010000); + + /* Configure flow control refresh threshold value */ + wr32(hw, NGBE_RXFCRFSH, hw->fc.pause_time / 2); + +out: + return err; +} + +/** + * ngbe_negotiate_fc - Negotiate flow control + * @hw: pointer to hardware structure + * @adv_reg: flow control advertised settings + * @lp_reg: link partner's flow control settings + * @adv_sym: symmetric pause bit in advertisement + * @adv_asm: asymmetric pause bit in advertisement + * @lp_sym: symmetric pause bit in link partner advertisement + * @lp_asm: asymmetric pause bit in link partner advertisement + * + * Find the intersection between advertised settings and link partner's + * advertised settings + **/ +s32 ngbe_negotiate_fc(struct ngbe_hw *hw, u32 adv_reg, u32 lp_reg, + u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm) +{ + if ((!(adv_reg)) || (!(lp_reg))) { + DEBUGOUT("Local or link partner's advertised flow control " + "settings are NULL. Local: %x, link partner: %x\n", + adv_reg, lp_reg); + return NGBE_ERR_FC_NOT_NEGOTIATED; + } + + if ((adv_reg & adv_sym) && (lp_reg & lp_sym)) { + /* + * Now we need to check if the user selected Rx ONLY + * of pause frames. In this case, we had to advertise + * FULL flow control because we could not advertise RX + * ONLY. Hence, we must now check to see if we need to + * turn OFF the TRANSMISSION of PAUSE frames. + */ + if (hw->fc.requested_mode == ngbe_fc_full) { + hw->fc.current_mode = ngbe_fc_full; + DEBUGOUT("Flow Control = FULL.\n"); + } else { + hw->fc.current_mode = ngbe_fc_rx_pause; + DEBUGOUT("Flow Control=RX PAUSE frames only\n"); + } + } else if (!(adv_reg & adv_sym) && (adv_reg & adv_asm) && + (lp_reg & lp_sym) && (lp_reg & lp_asm)) { + hw->fc.current_mode = ngbe_fc_tx_pause; + DEBUGOUT("Flow Control = TX PAUSE frames only.\n"); + } else if ((adv_reg & adv_sym) && (adv_reg & adv_asm) && + !(lp_reg & lp_sym) && (lp_reg & lp_asm)) { + hw->fc.current_mode = ngbe_fc_rx_pause; + DEBUGOUT("Flow Control = RX PAUSE frames only.\n"); + } else { + hw->fc.current_mode = ngbe_fc_none; + DEBUGOUT("Flow Control = NONE.\n"); + } + return 0; +} + +/** + * ngbe_fc_autoneg_em - Enable flow control IEEE clause 37 + * @hw: pointer to hardware structure + * + * Enable flow control according to IEEE clause 37. + **/ +STATIC s32 ngbe_fc_autoneg_em(struct ngbe_hw *hw) +{ + u8 technology_ability_reg = 0; + u8 lp_technology_ability_reg = 0; + + hw->phy.get_adv_pause(hw, &technology_ability_reg); + hw->phy.get_lp_adv_pause(hw, &lp_technology_ability_reg); + + return ngbe_negotiate_fc(hw, (u32)technology_ability_reg, + (u32)lp_technology_ability_reg, + NGBE_TAF_SYM_PAUSE, NGBE_TAF_ASM_PAUSE, + NGBE_TAF_SYM_PAUSE, NGBE_TAF_ASM_PAUSE); +} + +/** + * ngbe_fc_autoneg - Configure flow control + * @hw: pointer to hardware structure + * + * Compares our advertised flow control capabilities to those advertised by + * our link partner, and determines the proper flow control mode to use. + **/ +void ngbe_fc_autoneg(struct ngbe_hw *hw) +{ + s32 err = NGBE_ERR_FC_NOT_NEGOTIATED; + u32 speed; + bool link_up; + + DEBUGFUNC("ngbe_fc_autoneg"); + + /* + * AN should have completed when the cable was plugged in. + * Look for reasons to bail out. Bail out if: + * - FC autoneg is disabled, or if + * - link is not up. + */ + if (hw->fc.disable_fc_autoneg) { + DEBUGOUT("Flow control autoneg is disabled"); + goto out; + } + + hw->mac.check_link(hw, &speed, &link_up, false); + if (!link_up) { + DEBUGOUT("The link is down"); + goto out; + } + + err = ngbe_fc_autoneg_em(hw); + +out: + if (err == 0) { + hw->fc.fc_was_autonegged = true; + } else { + hw->fc.fc_was_autonegged = false; + hw->fc.current_mode = hw->fc.requested_mode; + } +} + /** * ngbe_acquire_swfw_sync - Acquire SWFW semaphore * @hw: pointer to hardware structure @@ -1520,6 +1849,11 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw) mac->set_mac_anti_spoofing = ngbe_set_mac_anti_spoofing; mac->set_vlan_anti_spoofing = ngbe_set_vlan_anti_spoofing; + /* Flow Control */ + mac->fc_enable = ngbe_fc_enable; + mac->fc_autoneg = ngbe_fc_autoneg; + mac->setup_fc = ngbe_setup_fc_em; + /* Link */ mac->get_link_capabilities = ngbe_get_link_capabilities_em; mac->check_link = ngbe_check_mac_link_em; diff --git a/drivers/net/ngbe/base/ngbe_hw.h b/drivers/net/ngbe/base/ngbe_hw.h index 83ad646dde..a84ddca6ac 100644 --- a/drivers/net/ngbe/base/ngbe_hw.h +++ b/drivers/net/ngbe/base/ngbe_hw.h @@ -42,6 +42,10 @@ s32 ngbe_update_mc_addr_list(struct ngbe_hw *hw, u8 *mc_addr_list, s32 ngbe_disable_sec_rx_path(struct ngbe_hw *hw); s32 ngbe_enable_sec_rx_path(struct ngbe_hw *hw); +s32 ngbe_setup_fc_em(struct ngbe_hw *hw); +s32 ngbe_fc_enable(struct ngbe_hw *hw); +void ngbe_fc_autoneg(struct ngbe_hw *hw); + s32 ngbe_validate_mac_addr(u8 *mac_addr); s32 ngbe_acquire_swfw_sync(struct ngbe_hw *hw, u32 mask); void ngbe_release_swfw_sync(struct ngbe_hw *hw, u32 mask); @@ -64,6 +68,8 @@ s32 ngbe_mac_check_overtemp(struct ngbe_hw *hw); void ngbe_disable_rx(struct ngbe_hw *hw); void ngbe_enable_rx(struct ngbe_hw *hw); void ngbe_set_mta(struct ngbe_hw *hw, u8 *mc_addr); +s32 ngbe_negotiate_fc(struct ngbe_hw *hw, u32 adv_reg, u32 lp_reg, + u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm); s32 ngbe_init_shared_code(struct ngbe_hw *hw); s32 ngbe_set_mac_type(struct ngbe_hw *hw); s32 ngbe_init_ops_pf(struct ngbe_hw *hw); diff --git a/drivers/net/ngbe/base/ngbe_phy.c b/drivers/net/ngbe/base/ngbe_phy.c index 691171ee9f..51b0a2ec60 100644 --- a/drivers/net/ngbe/base/ngbe_phy.c +++ b/drivers/net/ngbe/base/ngbe_phy.c @@ -429,18 +429,27 @@ s32 ngbe_init_phy(struct ngbe_hw *hw) hw->phy.init_hw = ngbe_init_phy_rtl; hw->phy.check_link = ngbe_check_phy_link_rtl; hw->phy.setup_link = ngbe_setup_phy_link_rtl; + hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_rtl; + hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_rtl; + hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_rtl; break; case ngbe_phy_mvl: case ngbe_phy_mvl_sfi: hw->phy.init_hw = ngbe_init_phy_mvl; hw->phy.check_link = ngbe_check_phy_link_mvl; hw->phy.setup_link = ngbe_setup_phy_link_mvl; + hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_mvl; + hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_mvl; + hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_mvl; break; case ngbe_phy_yt8521s: case ngbe_phy_yt8521s_sfi: hw->phy.init_hw = ngbe_init_phy_yt; hw->phy.check_link = ngbe_check_phy_link_yt; hw->phy.setup_link = ngbe_setup_phy_link_yt; + hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_yt; + hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_yt; + hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_yt; default: break; } diff --git a/drivers/net/ngbe/base/ngbe_phy.h b/drivers/net/ngbe/base/ngbe_phy.h index 5d6ff1711c..f262ff3350 100644 --- a/drivers/net/ngbe/base/ngbe_phy.h +++ b/drivers/net/ngbe/base/ngbe_phy.h @@ -42,6 +42,9 @@ typedef struct mdi_reg mdi_reg_t; #define NGBE_MD22_PHY_ID_HIGH 0x2 /* PHY ID High Reg*/ #define NGBE_MD22_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ +#define NGBE_TAF_SYM_PAUSE 0x1 +#define NGBE_TAF_ASM_PAUSE 0x2 + s32 ngbe_mdi_map_register(mdi_reg_t *reg, mdi_reg_22_t *reg22); bool ngbe_validate_phy_addr(struct ngbe_hw *hw, u32 phy_addr); diff --git a/drivers/net/ngbe/base/ngbe_phy_mvl.c b/drivers/net/ngbe/base/ngbe_phy_mvl.c index 86b0a072c1..2eb351d258 100644 --- a/drivers/net/ngbe/base/ngbe_phy_mvl.c +++ b/drivers/net/ngbe/base/ngbe_phy_mvl.c @@ -209,6 +209,63 @@ s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw) return status; } +s32 ngbe_get_phy_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit) +{ + u16 value; + s32 status = 0; + + if (hw->phy.type == ngbe_phy_mvl) { + status = hw->phy.read_reg(hw, MVL_ANA, 0, &value); + value &= MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE; + *pause_bit = (u8)(value >> 10); + } else { + status = hw->phy.read_reg(hw, MVL_ANA, 0, &value); + value &= MVL_FANA_PAUSE_MASK; + *pause_bit = (u8)(value >> 7); + } + + return status; +} + +s32 ngbe_get_phy_lp_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit) +{ + u16 value; + s32 status = 0; + + if (hw->phy.type == ngbe_phy_mvl) { + status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value); + value &= MVL_CLPAR_ASM_PAUSE | MVL_CLPAR_PAUSE; + *pause_bit = (u8)(value >> 10); + } else { + status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value); + value &= MVL_FLPAR_PAUSE_MASK; + *pause_bit = (u8)(value >> 7); + } + + return status; +} + +s32 ngbe_set_phy_pause_adv_mvl(struct ngbe_hw *hw, u16 pause_bit) +{ + u16 value; + s32 status = 0; + + DEBUGFUNC("ngbe_set_phy_pause_adv_mvl"); + + if (hw->phy.type == ngbe_phy_mvl) { + status = hw->phy.read_reg(hw, MVL_ANA, 0, &value); + value &= ~(MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE); + } else { + status = hw->phy.read_reg(hw, MVL_ANA, 0, &value); + value &= ~MVL_FANA_PAUSE_MASK; + } + + value |= pause_bit; + status = hw->phy.write_reg(hw, MVL_ANA, 0, value); + + return status; +} + s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw, u32 *speed, bool *link_up) { diff --git a/drivers/net/ngbe/base/ngbe_phy_mvl.h b/drivers/net/ngbe/base/ngbe_phy_mvl.h index 74d5ecba77..a2b5202d4b 100644 --- a/drivers/net/ngbe/base/ngbe_phy_mvl.h +++ b/drivers/net/ngbe/base/ngbe_phy_mvl.h @@ -94,4 +94,8 @@ s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw, u32 *speed, bool *link_up); s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed, bool autoneg_wait_to_complete); +s32 ngbe_get_phy_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit); +s32 ngbe_get_phy_lp_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit); +s32 ngbe_set_phy_pause_adv_mvl(struct ngbe_hw *hw, u16 pause_bit); + #endif /* _NGBE_PHY_MVL_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_phy_rtl.c b/drivers/net/ngbe/base/ngbe_phy_rtl.c index 83830921c2..7b08b7a46c 100644 --- a/drivers/net/ngbe/base/ngbe_phy_rtl.c +++ b/drivers/net/ngbe/base/ngbe_phy_rtl.c @@ -249,6 +249,48 @@ s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw) return status; } +s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit) +{ + u16 value; + s32 status = 0; + + status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value); + value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE; + *pause_bit = (u8)(value >> 10); + return status; +} + +s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit) +{ + u16 value; + s32 status = 0; + + status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); + + status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value); + value = value & RTL_BMSR_ANC; + + /* if AN complete then check lp adv pause */ + status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value); + value &= RTL_ANLPAR_LP; + *pause_bit = (u8)(value >> 10); + return status; +} + +s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit) +{ + u16 value; + s32 status = 0; + + status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value); + value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE); + value |= pause_bit; + + status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value); + + return status; +} + s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up) { s32 status = 0; diff --git a/drivers/net/ngbe/base/ngbe_phy_rtl.h b/drivers/net/ngbe/base/ngbe_phy_rtl.h index 9ce2058eac..d717a1915c 100644 --- a/drivers/net/ngbe/base/ngbe_phy_rtl.h +++ b/drivers/net/ngbe/base/ngbe_phy_rtl.h @@ -83,6 +83,9 @@ s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw, s32 ngbe_init_phy_rtl(struct ngbe_hw *hw); s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw); +s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit); +s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit); +s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit); s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up); diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.c b/drivers/net/ngbe/base/ngbe_phy_yt.c index 2a7061c100..8db0f9ce48 100644 --- a/drivers/net/ngbe/base/ngbe_phy_yt.c +++ b/drivers/net/ngbe/base/ngbe_phy_yt.c @@ -234,6 +234,50 @@ s32 ngbe_reset_phy_yt(struct ngbe_hw *hw) return status; } +s32 ngbe_get_phy_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit) +{ + u16 value; + s32 status = 0; + + DEBUGFUNC("ngbe_get_phy_advertised_pause_yt"); + + status = hw->phy.read_reg(hw, YT_ANA, 0, &value); + value &= YT_FANA_PAUSE_MASK; + *pause_bit = (u8)(value >> 7); + + return status; +} + +s32 ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit) +{ + u16 value; + s32 status = 0; + + DEBUGFUNC("ngbe_get_phy_lp_advertised_pause_yt"); + + status = hw->phy.read_reg(hw, YT_LPAR, 0, &value); + value &= YT_FLPAR_PAUSE_MASK; + *pause_bit = (u8)(value >> 7); + + return status; +} + +s32 ngbe_set_phy_pause_adv_yt(struct ngbe_hw *hw, u16 pause_bit) +{ + u16 value; + s32 status = 0; + + DEBUGFUNC("ngbe_set_phy_pause_adv_yt"); + + + status = hw->phy.read_reg(hw, YT_ANA, 0, &value); + value &= ~YT_FANA_PAUSE_MASK; + value |= pause_bit; + status = hw->phy.write_reg(hw, YT_ANA, 0, value); + + return status; +} + s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw, u32 *speed, bool *link_up) { diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.h b/drivers/net/ngbe/base/ngbe_phy_yt.h index 157339cce8..e729e0c854 100644 --- a/drivers/net/ngbe/base/ngbe_phy_yt.h +++ b/drivers/net/ngbe/base/ngbe_phy_yt.h @@ -73,4 +73,10 @@ s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw, u32 *speed, bool *link_up); s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, bool autoneg_wait_to_complete); +s32 ngbe_get_phy_advertised_pause_yt(struct ngbe_hw *hw, + u8 *pause_bit); +s32 ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw *hw, + u8 *pause_bit); +s32 ngbe_set_phy_pause_adv_yt(struct ngbe_hw *hw, u16 pause_bit); + #endif /* _NGBE_PHY_YT_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_type.h b/drivers/net/ngbe/base/ngbe_type.h index 7a85f82abd..310d32ecfa 100644 --- a/drivers/net/ngbe/base/ngbe_type.h +++ b/drivers/net/ngbe/base/ngbe_type.h @@ -67,6 +67,15 @@ enum ngbe_media_type { ngbe_media_type_virtual }; +/* Flow Control Settings */ +enum ngbe_fc_mode { + ngbe_fc_none = 0, + ngbe_fc_rx_pause, + ngbe_fc_tx_pause, + ngbe_fc_full, + ngbe_fc_default +}; + struct ngbe_hw; struct ngbe_addr_filter_info { @@ -82,6 +91,19 @@ struct ngbe_bus_info { u8 lan_id; }; +/* Flow control parameters */ +struct ngbe_fc_info { + u32 high_water; /* Flow Ctrl High-water */ + u32 low_water; /* 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 ngbe_fc_mode current_mode; /* FC mode in effect */ + enum ngbe_fc_mode requested_mode; /* FC mode requested by caller */ +}; + /* Statistics counters collected by the MAC */ /* PB[] RxTx */ struct ngbe_pb_stats { @@ -263,6 +285,11 @@ struct ngbe_mac_info { void (*set_vlan_anti_spoofing)(struct ngbe_hw *hw, bool enable, int vf); + /* Flow Control */ + s32 (*fc_enable)(struct ngbe_hw *hw); + s32 (*setup_fc)(struct ngbe_hw *hw); + void (*fc_autoneg)(struct ngbe_hw *hw); + /* Manageability interface */ s32 (*init_thermal_sensor_thresh)(struct ngbe_hw *hw); s32 (*check_overtemp)(struct ngbe_hw *hw); @@ -302,6 +329,10 @@ struct ngbe_phy_info { s32 (*setup_link)(struct ngbe_hw *hw, u32 speed, bool autoneg_wait_to_complete); s32 (*check_link)(struct ngbe_hw *hw, u32 *speed, bool *link_up); + s32 (*set_phy_power)(struct ngbe_hw *hw, bool on); + s32 (*get_adv_pause)(struct ngbe_hw *hw, u8 *pause_bit); + s32 (*get_lp_adv_pause)(struct ngbe_hw *hw, u8 *pause_bit); + s32 (*set_pause_adv)(struct ngbe_hw *hw, u16 pause_bit); enum ngbe_media_type media_type; enum ngbe_phy_type type; @@ -349,6 +380,7 @@ struct ngbe_hw { void *back; struct ngbe_mac_info mac; struct ngbe_addr_filter_info addr_ctrl; + struct ngbe_fc_info fc; struct ngbe_phy_info phy; struct ngbe_rom_info rom; struct ngbe_bus_info bus; diff --git a/drivers/net/ngbe/ngbe_ethdev.c b/drivers/net/ngbe/ngbe_ethdev.c index 01a643fc9a..94d6de15f9 100644 --- a/drivers/net/ngbe/ngbe_ethdev.c +++ b/drivers/net/ngbe/ngbe_ethdev.c @@ -317,6 +317,14 @@ eth_ngbe_dev_init(struct rte_eth_dev *eth_dev, void *init_params __rte_unused) /* Unlock any pending hardware semaphore */ ngbe_swfw_lock_reset(hw); + /* Get Hardware Flow Control setting */ + hw->fc.requested_mode = ngbe_fc_full; + hw->fc.current_mode = ngbe_fc_full; + hw->fc.pause_time = NGBE_FC_PAUSE_TIME; + hw->fc.low_water = NGBE_FC_XON_LOTH; + hw->fc.high_water = NGBE_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); @@ -2180,6 +2188,107 @@ ngbe_dev_interrupt_handler(void *param) ngbe_dev_interrupt_action(dev); } +static int +ngbe_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + uint32_t mflcn_reg; + uint32_t fccfg_reg; + int rx_pause; + int tx_pause; + + fc_conf->pause_time = hw->fc.pause_time; + fc_conf->high_water = hw->fc.high_water; + fc_conf->low_water = hw->fc.low_water; + 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, NGBE_RXFCCFG); + if (mflcn_reg & NGBE_RXFCCFG_FC) + rx_pause = 1; + else + rx_pause = 0; + + /* + * Return tx_pause status according to actual setting of + * TXFCCFG register. + */ + fccfg_reg = rd32(hw, NGBE_TXFCCFG); + if (fccfg_reg & NGBE_TXFCCFG_FC) + 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 +ngbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + struct ngbe_hw *hw = ngbe_dev_hw(dev); + int err; + uint32_t rx_buf_size; + uint32_t max_high_water; + enum ngbe_fc_mode rte_fcmode_2_ngbe_fcmode[] = { + ngbe_fc_none, + ngbe_fc_rx_pause, + ngbe_fc_tx_pause, + ngbe_fc_full + }; + + PMD_INIT_FUNC_TRACE(); + + rx_buf_size = rd32(hw, NGBE_PBRXSIZE); + 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 ngbe + */ + 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_ngbe_fcmode[fc_conf->mode]; + hw->fc.pause_time = fc_conf->pause_time; + hw->fc.high_water = fc_conf->high_water; + hw->fc.low_water = fc_conf->low_water; + hw->fc.send_xon = fc_conf->send_xon; + hw->fc.disable_fc_autoneg = !fc_conf->autoneg; + + err = hw->mac.fc_enable(hw); + + /* Not negotiated is not an error case */ + if (err == 0 || err == NGBE_ERR_FC_NOT_NEGOTIATED) { + wr32m(hw, NGBE_MACRXFLT, NGBE_MACRXFLT_CTL_MASK, + (fc_conf->mac_ctrl_frame_fwd + ? NGBE_MACRXFLT_CTL_NOPS : NGBE_MACRXFLT_CTL_DROP)); + ngbe_flush(hw); + + return 0; + } + + PMD_INIT_LOG(ERR, "ngbe_fc_enable = 0x%x", err); + return -EIO; +} + int ngbe_dev_rss_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf, @@ -2583,6 +2692,8 @@ static const struct eth_dev_ops ngbe_eth_dev_ops = { .rx_queue_release = ngbe_dev_rx_queue_release, .tx_queue_setup = ngbe_dev_tx_queue_setup, .tx_queue_release = ngbe_dev_tx_queue_release, + .flow_ctrl_get = ngbe_flow_ctrl_get, + .flow_ctrl_set = ngbe_flow_ctrl_set, .mac_addr_add = ngbe_add_rar, .mac_addr_remove = ngbe_remove_rar, .mac_addr_set = ngbe_set_default_mac_addr, diff --git a/drivers/net/ngbe/ngbe_ethdev.h b/drivers/net/ngbe/ngbe_ethdev.h index 51a726a140..97260c56d0 100644 --- a/drivers/net/ngbe/ngbe_ethdev.h +++ b/drivers/net/ngbe/ngbe_ethdev.h @@ -276,6 +276,14 @@ void ngbe_pf_mbx_process(struct rte_eth_dev *eth_dev); int ngbe_pf_host_configure(struct rte_eth_dev *eth_dev); +/* High threshold controlling when to start sending XOFF frames. */ +#define NGBE_FC_XOFF_HITH 128 /*KB*/ +/* Low threshold controlling when to start sending XON frames. */ +#define NGBE_FC_XON_LOTH 64 /*KB*/ + +/* Timer value included in XOFF frames. */ +#define NGBE_FC_PAUSE_TIME 0x680 + #define NGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */ #define NGBE_LINK_UP_CHECK_TIMEOUT 1000 /* ms */ #define NGBE_VMDQ_NUM_UC_MAC 4096 /* Maximum nb. of UC MAC addr. */