Tested-by: Min Cao <min.cao at intel.com>

Patch name:             [dpdk-dev] [PATCH v2] i40e: link flow control support
Test Flag:                      Tested-by
Tester name:            min.cao at intel.com
Result summary:         total 4 cases, 4 passed, 0 failed

Test Case 1:            
Name:                           flowctrl_off_pause_fwd_off
Environment:            OS: Fedora20 3.11.10-301.fc20.x86_64
                                gcc (GCC) 4.8.2
                                CPU: Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz
                                NIC: Fortville eagle/spirit 
Test result:    PASSED

Test Case 2:            
Name:                           flowctrl_on_pause_fwd_off
Environment:            OS: Fedora20 3.11.10-301.fc20.x86_64
                                gcc (GCC) 4.8.2
                                CPU: Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz
                                NIC: Fortville eagle/spirit 
Test result:    PASSED

Test Case 3:            
Name:                           flowctrl_off_pause_fwd_on
Environment:            OS: Fedora20 3.11.10-301.fc20.x86_64
                                gcc (GCC) 4.8.2
                                CPU: Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz
                                NIC: Fortville eagle/spirit 
Test result:    PASSED

Test Case 4:            
Name:                           flowctrl_on_pause_fwd_on
Environment:            OS: Fedora20 3.11.10-301.fc20.x86_64
                                gcc (GCC) 4.8.2
                                CPU: Intel(R) Xeon(R) CPU E5-2680 0 @ 2.70GHz
                                NIC: Fortville eagle/spirit 
Test result:    PASSED
-----Original Message-----
From: dev [mailto:dev-boun...@dpdk.org] On Behalf Of zhida zang
Sent: Thursday, November 20, 2014 4:59 PM
To: dev at dpdk.org
Subject: [dpdk-dev] [PATCH v2] i40e: link flow control support

From: zzang <zhida.z...@intel.com>

Add link flow control support for i40e

Signed-off-by: zhida zang <zhida.zang at intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 155 +++++++++++++++++++++++++++++++++++++-
 lib/librte_pmd_i40e/i40e_ethdev.h |  10 +++
 2 files changed, 162 insertions(+), 3 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c 
b/lib/librte_pmd_i40e/i40e_ethdev.c
index a860af7..183b0be 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -69,6 +69,18 @@
 #define I40E_DEFAULT_TX_WTHRESH      0
 #define I40E_DEFAULT_TX_RSBIT_THRESH 32

+/* Flow control default timer */
+#define I40E_DEFAULT_PAUSE_TIME 0xFFFFU
+
+/* Flow control default high water */
+#define I40E_DEFAULT_HIGH_WATER 0x1C40
+
+/* Flow control default low water */
+#define I40E_DEFAULT_LOW_WATER  0x1A40
+
+/* Flow control enable fwd bit */
+#define I40E_PRTMAC_FWD_CTRL   0x00000001
+
 /* Maximun number of MAC addresses */
 #define I40E_NUM_MACADDR_MAX       64
 #define I40E_CLEAR_PXE_WAIT_MS     200
@@ -98,6 +110,12 @@

 #define I40E_PRE_TX_Q_CFG_WAIT_US       10 /* 10 us */

+/* Receive Packet Buffer size */
+#define I40E_RXPBSIZE (968 * 1024)
+
+/* Receive Average Packet Size in Byte*/
+#define I40E_PACKET_AVERAGE_SIZE 128
+
 static int eth_i40e_dev_init(\
                        __attribute__((unused)) struct eth_driver *eth_drv,
                        struct rte_eth_dev *eth_dev);
@@ -131,6 +149,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,
@@ -237,6 +257,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,
@@ -358,6 +379,9 @@ 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->fc_conf.pause_time = I40E_DEFAULT_PAUSE_TIME;
+       pf->fc_conf.high_water[0] = I40E_DEFAULT_HIGH_WATER;
+       pf->fc_conf.low_water[0] = I40E_DEFAULT_LOW_WATER;

        hw->back = I40E_PF_TO_ADAPTER(pf);
        hw->hw_addr = (uint8_t *)(pci_dev->mem_resource[0].addr);
@@ -1516,12 +1540,137 @@ 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)
 {
+       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->fc_conf.pause_time;
+       fc_conf->high_water = (pf->fc_conf.high_water[0] *
+                               I40E_PACKET_AVERAGE_SIZE) >> 10;
+       fc_conf->low_water = (pf->fc_conf.low_water[0] *
+                               I40E_PACKET_AVERAGE_SIZE) >> 10;
+
+       /*
+        * Return current mode according to actual setting
+        */
+       switch (hw->fc.current_mode) {
+       case I40E_FC_FULL:
+               fc_conf->mode = RTE_FC_FULL;
+               break;
+       case I40E_FC_TX_PAUSE:
+               fc_conf->mode = I40E_FC_TX_PAUSE;
+               break;
+       case I40E_FC_RX_PAUSE:
+               fc_conf->mode = I40E_FC_RX_PAUSE;
+               break;
+       case I40E_FC_NONE:
+               fc_conf->mode = RTE_FC_NONE;
+               break;
+       default:
+               break;
+       };
+
+       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, reg;
+       uint32_t max_high_water;
+       uint8_t i, 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
+       };
+
+       max_high_water = I40E_RXPBSIZE >> 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, "
+                       "High_water must <= %d.", max_high_water);
+               return -EINVAL;
+       }
+
+       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->fc_conf.pause_time = fc_conf->pause_time;
+       pf->fc_conf.high_water[0] = (fc_conf->high_water << 10) /
+                               I40E_PACKET_AVERAGE_SIZE;
+       pf->fc_conf.low_water[0] = (fc_conf->low_water << 10) /
+                               I40E_PACKET_AVERAGE_SIZE;
+
        PMD_INIT_FUNC_TRACE();

-       return -ENOSYS;
+       err = i40e_set_fc(hw, &aq_failure, true);
+       if (err < 0) {
+               PMD_INIT_LOG(ERR, "failed to set link flow control,"
+                       "err = %d", aq_failure);
+               return err;
+       }
+
+       if (i40e_is_40G_device(hw->device_id)) {
+
+               /*
+                * Configure flow control refresh threshold,
+                * the value for stat_tx_pause_refresh_timer[8]
+                * is used for global pause operation.
+                */
+               I40E_WRITE_REG(hw,
+                       I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(8),
+                       pf->fc_conf.pause_time);
+
+               /* configure the timer value included in transmitted pause
+                * frame,
+                * the value for stat_tx_pause_quanta[8] is used for global
+                * pause operation
+                */
+               I40E_WRITE_REG(hw, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(8),
+                       pf->fc_conf.pause_time);
+
+               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 {
+               /* Configure pause time (2 TCs per register) */
+               reg = (uint32_t)pf->fc_conf.pause_time * (uint32_t)0x00010001;
+               for (i = 0; i < I40E_MAX_TRAFFIC_CLASS / 2; i++)
+                       I40E_WRITE_REG(hw, I40E_PRTDCB_FCTTVN(i), reg);
+
+               /* Configure flow control refresh threshold value */
+               I40E_WRITE_REG(hw, I40E_PRTDCB_FCRTV,
+                               pf->fc_conf.pause_time / 2);
+
+               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_REG(hw, I40E_GLRPB_PHW, pf->fc_conf.high_water[0]);
+       I40E_WRITE_REG(hw, I40E_GLRPB_PLW, pf->fc_conf.low_water[0]);
+
+       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 e61d258..c793c2d 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.h
+++ b/lib/librte_pmd_i40e/i40e_ethdev.h
@@ -231,6 +231,14 @@ struct i40e_pf_vf {
        uint16_t lan_nb_qps; /* Actual queues allocated */
        uint16_t reset_cnt; /* Total vf reset times */
 };
+/*
+ * Structure to store private data for flow control.
+ */
+struct i40e_fc_conf {
+       uint16_t pause_time; /* Flow control pause timer */
+       uint32_t high_water[I40E_MAX_TRAFFIC_CLASS]; /* FC high water */
+       uint32_t low_water[I40E_MAX_TRAFFIC_CLASS]; /* FC low water */
+};

 /*
  * Structure to store private data specific for PF instance.
@@ -264,6 +272,8 @@ struct i40e_pf {
        /* store VXLAN UDP ports */
        uint16_t vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS];
        uint16_t vxlan_bitmap; /* Vxlan bit mask */
+
+       struct i40e_fc_conf fc_conf; /* Flow control conf */
 };

 enum pending_msg {
-- 
1.9.3

Reply via email to