From: Zhida Zang <zhida.z...@intel.com> Add support of link flow control.
Signed-off-by: Zhida Zang <zhida.zang at intel.com> Acked-by: Helin Zhang <helin.zhang at intel.com> --- lib/librte_pmd_i40e/i40e_ethdev.c | 216 +++++++++++++++++++++++++++++++++++++- lib/librte_pmd_i40e/i40e_ethdev.h | 1 + 2 files changed, 214 insertions(+), 3 deletions(-) diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c index a00d6ca..02abcac 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev.c +++ b/lib/librte_pmd_i40e/i40e_ethdev.c @@ -58,6 +58,14 @@ #include "i40e_rxtx.h" #include "i40e_pf.h" +/* Flow control default timer */ +#define I40E_DEFAULT_PAUSE_TIME 0xFFFFU + +/* Flow control bit */ +#define I40E_PRTMAC_ENABLE_RX 0x00000100 +#define I40E_PRTMAC_ENABLE_TX 0x00000100 +#define I40E_PRTMAC_FWD_CTRL 0x00000001 + /* Maximun number of MAC addresses */ #define I40E_NUM_MACADDR_MAX 64 #define I40E_CLEAR_PXE_WAIT_MS 200 @@ -150,6 +158,8 @@ static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev, static int i40e_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on); static int i40e_dev_led_on(struct rte_eth_dev *dev); static int i40e_dev_led_off(struct rte_eth_dev *dev); +static int i40e_flow_ctrl_get(struct rte_eth_dev *dev, + struct rte_eth_fc_conf *fc_conf); static int i40e_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); static int i40e_priority_flow_ctrl_set(struct rte_eth_dev *dev, @@ -248,6 +258,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = { .tx_queue_release = i40e_dev_tx_queue_release, .dev_led_on = i40e_dev_led_on, .dev_led_off = i40e_dev_led_off, + .flow_ctrl_get = i40e_flow_ctrl_get, .flow_ctrl_set = i40e_flow_ctrl_set, .priority_flow_ctrl_set = i40e_priority_flow_ctrl_set, .mac_addr_add = i40e_macaddr_add, @@ -366,6 +377,7 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv, pf->adapter = I40E_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private); pf->adapter->eth_dev = dev; pf->dev_data = dev->data; + pf->pause_time = I40E_DEFAULT_PAUSE_TIME; hw->back = I40E_PF_TO_ADAPTER(pf); hw->hw_addr = (uint8_t *)(pci_dev->mem_resource[0].addr); @@ -1488,12 +1500,210 @@ i40e_dev_led_off(struct rte_eth_dev *dev) } static int -i40e_flow_ctrl_set(__rte_unused struct rte_eth_dev *dev, - __rte_unused struct rte_eth_fc_conf *fc_conf) +i40e_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) +{ + uint32_t mflcn_reg, fccfg_reg, rx_reg, tx_reg; + int rx_pause, tx_pause; + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + fc_conf->pause_time = pf->pause_time; + + if (i40e_is_40G_device(hw->device_id)) { + rx_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE); + tx_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE); + + if (rx_reg & I40E_PRTMAC_ENABLE_RX) + rx_pause = 1; + else + rx_pause = 0; + + if (tx_reg & I40E_PRTMAC_ENABLE_TX) + tx_pause = 1; + else + tx_pause = 0; + } else { + mflcn_reg = I40E_READ_REG(hw, I40E_PRTDCB_MFLCN); + if (mflcn_reg & (0x1 << I40E_PRTDCB_MFLCN_RFCE_SHIFT)) + rx_pause = 1; + else + rx_pause = 0; + + fccfg_reg = I40E_READ_REG(hw, I40E_PRTDCB_FCCFG); + if (fccfg_reg & (0x1 << I40E_PRTDCB_FCCFG_TFCE_SHIFT)) + 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 i40e_40g_fc_enable(struct i40e_hw *hw, uint16_t pause_time) +{ + uint32_t gpp_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP); + uint32_t ppp_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP); + uint32_t gcp_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP); + uint32_t rx_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE); + uint32_t tx_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE); + + gpp_reg |= + I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK; + ppp_reg &= + ~I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK; + gcp_reg |= + I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK; + + /* clear previous settings */ + rx_reg &= ~I40E_PRTMAC_ENABLE_RX; + tx_reg &= ~I40E_PRTMAC_ENABLE_TX; + + switch (hw->fc.current_mode) { + case I40E_FC_NONE: + break; + case I40E_FC_RX_PAUSE: + rx_reg |= I40E_PRTMAC_ENABLE_RX; + break; + case I40E_FC_TX_PAUSE: + tx_reg |= I40E_PRTMAC_ENABLE_TX; + break; + case I40E_FC_FULL: + rx_reg |= I40E_PRTMAC_ENABLE_RX; + tx_reg |= I40E_PRTMAC_ENABLE_TX; + break; + default: + PMD_INIT_LOG(ERR, "Flow control param set incorrectly\n"); + return -EIO; + } + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP, gpp_reg); + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP, ppp_reg); + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP, gcp_reg); + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE, rx_reg); + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE, tx_reg); + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(8), + pause_time / 2); + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(8), pause_time); + + return 0; +} + +static int i40e_10g_fc_enable(struct i40e_hw *hw, uint16_t pause_time) +{ + uint32_t mflcn_reg, fccfg_reg, reg; + int i; + + /* Disable any previous flow control settings */ + mflcn_reg = I40E_READ_REG(hw, I40E_PRTDCB_MFLCN); + mflcn_reg &= ~(I40E_PRTDCB_MFLCN_RPFCM_MASK | + I40E_PRTDCB_MFLCN_RFCE_MASK); + + fccfg_reg = I40E_READ_REG(hw, I40E_PRTDCB_FCCFG); + fccfg_reg &= ~I40E_PRTDCB_FCCFG_TFCE_MASK; + + switch (hw->fc.current_mode) { + case I40E_FC_NONE: + break; + case I40E_FC_RX_PAUSE: + mflcn_reg |= (0x1 << I40E_PRTDCB_MFLCN_RFCE_SHIFT); + break; + case I40E_FC_TX_PAUSE: + fccfg_reg |= (0x1 << I40E_PRTDCB_FCCFG_TFCE_SHIFT); + break; + case I40E_FC_FULL: + mflcn_reg |= (0x1 << I40E_PRTDCB_MFLCN_RFCE_SHIFT); + fccfg_reg |= (0x1 << I40E_PRTDCB_FCCFG_TFCE_SHIFT); + break; + default: + PMD_INIT_LOG(ERR, "Flow control param set incorrectly\n"); + return -EIO; + } + mflcn_reg |= (0x1 << I40E_PRTDCB_MFLCN_DPF_SHIFT); + I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg); + I40E_WRITE_REG(hw, I40E_PRTDCB_FCCFG, fccfg_reg); + + /* Configure pause time (2 TCs per register) */ + reg = (uint32_t)pause_time * (uint32_t)0x00010001; + for (i = 0; i < 4; i++) + I40E_WRITE_REG(hw, I40E_PRTDCB_FCTTVN(i), reg); + + /* Configure flow control refresh threshold value */ + I40E_WRITE_REG(hw, I40E_PRTDCB_FCRTV, pause_time / 2); + + return 0; +} + +static int +i40e_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) { + uint32_t mflcn_reg, fctrl_reg; + u8 aq_failure; + int err; + enum i40e_fc_mode rte_fcmode_2_i40e_fcmode[] = { + I40E_FC_NONE, + I40E_FC_RX_PAUSE, + I40E_FC_TX_PAUSE, + I40E_FC_FULL + }; + struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + hw->fc.requested_mode = rte_fcmode_2_i40e_fcmode[fc_conf->mode]; + pf->pause_time = fc_conf->pause_time; + PMD_INIT_FUNC_TRACE(); - return -ENOSYS; + err = i40e_set_fc(hw, &aq_failure, 1); + if (err < 0) { + PMD_INIT_LOG(ERR, "i40e_set_fc = %d\n", err); + return err; + } + + if (i40e_is_40G_device(hw->device_id)) { + err = i40e_40g_fc_enable(hw, pf->pause_time); + if (err < 0) + return err; + + fctrl_reg = I40E_READ_REG(hw, + I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL); + if (fc_conf->mac_ctrl_frame_fwd != 0) + fctrl_reg |= I40E_PRTMAC_FWD_CTRL; + else + fctrl_reg &= ~I40E_PRTMAC_FWD_CTRL; + + I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL, + fctrl_reg); + } else { + err = i40e_10g_fc_enable(hw, pf->pause_time); + if (err < 0) + return err; + + mflcn_reg = I40E_READ_REG(hw, I40E_PRTDCB_MFLCN); + /* set or clear MFLCN.PMCF bit depending on configuration */ + if (fc_conf->mac_ctrl_frame_fwd != 0) + mflcn_reg |= I40E_PRTDCB_MFLCN_PMCF_MASK; + else + mflcn_reg &= ~I40E_PRTDCB_MFLCN_PMCF_MASK; + + I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg); + } + + I40E_WRITE_FLUSH(hw); + + return 0; } static int diff --git a/lib/librte_pmd_i40e/i40e_ethdev.h b/lib/librte_pmd_i40e/i40e_ethdev.h index 64deef2..676f70b 100644 --- a/lib/librte_pmd_i40e/i40e_ethdev.h +++ b/lib/librte_pmd_i40e/i40e_ethdev.h @@ -216,6 +216,7 @@ struct i40e_pf { uint16_t vmdq_nb_qps; /* The number of queue pairs of VMDq */ uint16_t vf_nb_qps; /* The number of queue pairs of VF */ uint16_t fdir_nb_qps; /* The number of queue pairs of Flow Director */ + uint16_t pause_time; /* Flow control pause timer */ }; enum pending_msg { -- 1.8.1.4