From patchwork Sun Sep 28 07:08:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: zzang X-Patchwork-Id: 618 Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [IPv6:::1]) by dpdk.org (Postfix) with ESMTP id BDE467E0F; Sun, 28 Sep 2014 09:01:46 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id 74E4D5929 for ; Sun, 28 Sep 2014 09:01:44 +0200 (CEST) Received: from fmsmga002.fm.intel.com ([10.253.24.26]) by fmsmga101.fm.intel.com with ESMTP; 28 Sep 2014 00:08:13 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.04,613,1406617200"; d="scan'208";a="606521961" Received: from shvmail01.sh.intel.com ([10.239.29.42]) by fmsmga002.fm.intel.com with ESMTP; 28 Sep 2014 00:08:12 -0700 Received: from shecgisg004.sh.intel.com (shecgisg004.sh.intel.com [10.239.29.89]) by shvmail01.sh.intel.com with ESMTP id s8S78B5h029233; Sun, 28 Sep 2014 15:08:11 +0800 Received: from shecgisg004.sh.intel.com (localhost [127.0.0.1]) by shecgisg004.sh.intel.com (8.13.6/8.13.6/SuSE Linux 0.8) with ESMTP id s8S7897A010853; Sun, 28 Sep 2014 15:08:11 +0800 Received: (from zzang@localhost) by shecgisg004.sh.intel.com (8.13.6/8.13.6/Submit) id s8S788Qv010849; Sun, 28 Sep 2014 15:08:08 +0800 From: zzang To: dev@dpdk.org Date: Sun, 28 Sep 2014 15:08:06 +0800 Message-Id: <1411888086-10818-1-git-send-email-zhida.zang@intel.com> X-Mailer: git-send-email 1.7.4.1 Subject: [dpdk-dev] [PATCH] i40e: support of link flow control X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: patches and discussions about DPDK List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Zhida Zang Add support of link flow control. Signed-off-by: Zhida Zang Acked-by: Helin Zhang --- 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 {