* [dpdk-dev] [PATCH] i40e: add link flow control support for FVL
@ 2015-09-25 5:52 Zhe Tao
2015-10-27 3:43 ` Zhang, Helin
2015-10-29 12:56 ` [dpdk-dev] [PATCH v2] " Zhe Tao
0 siblings, 2 replies; 9+ messages in thread
From: Zhe Tao @ 2015-09-25 5:52 UTC (permalink / raw)
To: dev
Feature Add: Rx/Tx flow control support for the i40e
All the Rx/Tx LFC enable/disable operation is done by the F/W,
so PMD driver need to use the Set PHY Config AD command to trigger the PHY
to do the auto-negotiation, after the Tx/Rx pause ability is negotiated,
the F/W will help us to set the related LFC enable/disable registers.
PMD driver also need to configure the related registers to control how often
to send the pause frame and what the value in the pause frame.
Signed-off-by: Zhe Tao <zhe.tao@intel.com>
---
drivers/net/i40e/i40e_ethdev.c | 170 ++++++++++++++++++++++++++++++++++++++++-
drivers/net/i40e/i40e_ethdev.h | 12 +++
2 files changed, 179 insertions(+), 3 deletions(-)
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2dd9fdc..223ceb9 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -81,6 +81,27 @@
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */
+/* Flow control default timer */
+#define I40E_DEFAULT_PAUSE_TIME 0xFFFFU
+
+/* Flow control default high water */
+#define I40E_DEFAULT_HIGH_WATER (0x1C40/1024)
+
+/* Flow control default low water */
+#define I40E_DEFAULT_LOW_WATER (0x1A40/1024)
+
+/* Flow control enable fwd bit */
+#define I40E_PRTMAC_FWD_CTRL 0x00000001
+
+/* Receive Packet Buffer size */
+#define I40E_RXPBSIZE (968 * 1024)
+
+/* Kilobytes shift */
+#define I40E_KILOSHIFT 10
+
+/* Receive Average Packet Size in Byte*/
+#define I40E_PACKET_AVERAGE_SIZE 128
+
/* Mask of PF interrupt causes */
#define I40E_PFINT_ICR0_ENA_MASK ( \
I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | \
@@ -145,6 +166,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,
@@ -272,6 +295,7 @@ static const 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,
@@ -411,6 +435,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
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[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_HIGH_WATER;
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_LOW_WATER;
hw->back = I40E_PF_TO_ADAPTER(pf);
hw->hw_addr = (uint8_t *)(pci_dev->mem_resource[0].addr);
@@ -1782,12 +1809,149 @@ 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[I40E_MAX_TRAFFIC_CLASS];
+ fc_conf->low_water = pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS];
+
+ /* 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;
+ struct i40e_hw *hw;
+ struct i40e_pf *pf;
+ enum i40e_fc_mode rte_fcmode_2_i40e_fcmode[] = {
+ [RTE_FC_NONE] = I40E_FC_NONE,
+ [RTE_FC_RX_PAUSE] = I40E_FC_RX_PAUSE,
+ [RTE_FC_TX_PAUSE] = I40E_FC_TX_PAUSE,
+ [RTE_FC_FULL] = I40E_FC_FULL
+ };
+
+ /* high_water field in the rte_eth_fc_conf using the kilobytes unit */
+
+ max_high_water = I40E_RXPBSIZE >> I40E_KILOSHIFT;
+ 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;
+ }
+
+ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ 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[I40E_MAX_TRAFFIC_CLASS] = fc_conf->high_water;
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = fc_conf->low_water;
+
PMD_INIT_FUNC_TRACE();
- return -ENOSYS;
+ /* All the link flow control related enable/disable register
+ * configuration is handle by the F/W
+ */
+ err = i40e_set_fc(hw, &aq_failure, true);
+ if (err < 0)
+ 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 & MFLCN.DPF bits
+ *depending on configuration */
+ if (fc_conf->mac_ctrl_frame_fwd != 0) {
+ mflcn_reg |= I40E_PRTDCB_MFLCN_PMCF_MASK;
+ mflcn_reg &= ~I40E_PRTDCB_MFLCN_DPF_MASK;
+ } else {
+ mflcn_reg &= ~I40E_PRTDCB_MFLCN_PMCF_MASK;
+ mflcn_reg |= I40E_PRTDCB_MFLCN_DPF_MASK;
+ }
+
+ I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg);
+ }
+
+ /* config the water marker both based on the packets and bytes */
+ I40E_WRITE_REG(hw, I40E_GLRPB_PHW,
+ (pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+ I40E_WRITE_REG(hw, I40E_GLRPB_PLW,
+ (pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+ I40E_WRITE_REG(hw, I40E_GLRPB_GHW,
+ pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT);
+ I40E_WRITE_REG(hw, I40E_GLRPB_GLW,
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT);
+
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}
static int
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 6185657..7f253d3 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -282,6 +282,17 @@ struct i40e_pf_vf {
};
/*
+ * Structure to store private data for flow control.
+ */
+struct i40e_fc_conf {
+ uint16_t pause_time; /* Flow control pause timer */
+ /* FC high water 0-7 for pfc and 8 for lfc unit:kilobytes */
+ uint32_t high_water[I40E_MAX_TRAFFIC_CLASS+1];
+ /* FC low water 0-7 for pfc and 8 for lfc unit:kilobytes */
+ uint32_t low_water[I40E_MAX_TRAFFIC_CLASS+1];
+};
+
+/*
* Structure to store private data for VMDQ instance
*/
struct i40e_vmdq_info {
@@ -385,6 +396,7 @@ struct i40e_pf {
struct i40e_vmdq_info *vmdq;
struct i40e_fdir_info fdir; /* flow director info */
+ struct i40e_fc_conf fc_conf; /* Flow control conf */
struct i40e_mirror_rule_list mirror_list;
uint16_t nb_mirror_rule; /* The number of mirror rules */
};
--
1.9.3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [dpdk-dev] [PATCH] i40e: add link flow control support for FVL
2015-09-25 5:52 [dpdk-dev] [PATCH] i40e: add link flow control support for FVL Zhe Tao
@ 2015-10-27 3:43 ` Zhang, Helin
2015-10-29 12:56 ` [dpdk-dev] [PATCH v2] " Zhe Tao
1 sibling, 0 replies; 9+ messages in thread
From: Zhang, Helin @ 2015-10-27 3:43 UTC (permalink / raw)
To: Tao, Zhe, dev
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Zhe Tao
> Sent: Friday, September 25, 2015 1:53 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH] i40e: add link flow control support for FVL
>
> Feature Add: Rx/Tx flow control support for the i40e
>
> All the Rx/Tx LFC enable/disable operation is done by the F/W, so PMD driver
> need to use the Set PHY Config AD command to trigger the PHY to do the
> auto-negotiation, after the Tx/Rx pause ability is negotiated, the F/W will help us
> to set the related LFC enable/disable registers.
> PMD driver also need to configure the related registers to control how often to
> send the pause frame and what the value in the pause frame.
>
> Signed-off-by: Zhe Tao <zhe.tao@intel.com>
> ---
> drivers/net/i40e/i40e_ethdev.c | 170
> ++++++++++++++++++++++++++++++++++++++++-
> drivers/net/i40e/i40e_ethdev.h | 12 +++
> 2 files changed, 179 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
> index 2dd9fdc..223ceb9 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -81,6 +81,27 @@
>
> #define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */
>
> +/* Flow control default timer */
> +#define I40E_DEFAULT_PAUSE_TIME 0xFFFFU
> +
> +/* Flow control default high water */
> +#define I40E_DEFAULT_HIGH_WATER (0x1C40/1024)
> +
> +/* Flow control default low water */
> +#define I40E_DEFAULT_LOW_WATER (0x1A40/1024)
> +
> +/* Flow control enable fwd bit */
> +#define I40E_PRTMAC_FWD_CTRL 0x00000001
> +
> +/* Receive Packet Buffer size */
> +#define I40E_RXPBSIZE (968 * 1024)
> +
> +/* Kilobytes shift */
> +#define I40E_KILOSHIFT 10
> +
> +/* Receive Average Packet Size in Byte*/ #define
> +I40E_PACKET_AVERAGE_SIZE 128
> +
> /* Mask of PF interrupt causes */
> #define I40E_PFINT_ICR0_ENA_MASK ( \
> I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | \
> @@ -145,6 +166,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, @@ -272,6 +295,7 @@
> static const 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,
> @@ -411,6 +435,9 @@ eth_i40e_dev_init(struct rte_eth_dev *dev)
> 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[I40E_MAX_TRAFFIC_CLASS] =
> I40E_DEFAULT_HIGH_WATER;
> + pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] =
> +I40E_DEFAULT_LOW_WATER;
It would be better to put above changes into i40e_pf_parameter_init().
>
> hw->back = I40E_PF_TO_ADAPTER(pf);
> hw->hw_addr = (uint8_t *)(pci_dev->mem_resource[0].addr);
> @@ -1782,12 +1809,149 @@ 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[I40E_MAX_TRAFFIC_CLASS];
> + fc_conf->low_water = pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS];
> +
> + /* 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;
> + struct i40e_hw *hw;
> + struct i40e_pf *pf;
> + enum i40e_fc_mode rte_fcmode_2_i40e_fcmode[] = {
> + [RTE_FC_NONE] = I40E_FC_NONE,
> + [RTE_FC_RX_PAUSE] = I40E_FC_RX_PAUSE,
> + [RTE_FC_TX_PAUSE] = I40E_FC_TX_PAUSE,
> + [RTE_FC_FULL] = I40E_FC_FULL
> + };
> +
> + /* high_water field in the rte_eth_fc_conf using the kilobytes unit */
> +
> + max_high_water = I40E_RXPBSIZE >> I40E_KILOSHIFT;
> + 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;
> + }
> +
> + hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> + 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[I40E_MAX_TRAFFIC_CLASS] =
> fc_conf->high_water;
> + pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = fc_conf->low_water;
> +
> PMD_INIT_FUNC_TRACE();
>
> - return -ENOSYS;
> + /* All the link flow control related enable/disable register
> + * configuration is handle by the F/W
> + */
> + err = i40e_set_fc(hw, &aq_failure, true);
> + if (err < 0)
> + return err;
> +
> + if (i40e_is_40G_device(hw->device_id)) {
Please write your own function to check if it is 40G or not, as the function above is
not up to date.
> + /* 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 & MFLCN.DPF bits
> + *depending on configuration */
> + if (fc_conf->mac_ctrl_frame_fwd != 0) {
> + mflcn_reg |= I40E_PRTDCB_MFLCN_PMCF_MASK;
> + mflcn_reg &= ~I40E_PRTDCB_MFLCN_DPF_MASK;
> + } else {
> + mflcn_reg &= ~I40E_PRTDCB_MFLCN_PMCF_MASK;
> + mflcn_reg |= I40E_PRTDCB_MFLCN_DPF_MASK;
> + }
> +
> + I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg);
> + }
> +
> + /* config the water marker both based on the packets and bytes */
> + I40E_WRITE_REG(hw, I40E_GLRPB_PHW,
> + (pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
> + << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
> + I40E_WRITE_REG(hw, I40E_GLRPB_PLW,
> + (pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
> + << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
> + I40E_WRITE_REG(hw, I40E_GLRPB_GHW,
> + pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
> + << I40E_KILOSHIFT);
> + I40E_WRITE_REG(hw, I40E_GLRPB_GLW,
> + pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
> + << I40E_KILOSHIFT);
> +
> + I40E_WRITE_FLUSH(hw);
> +
> + return 0;
> }
>
> static int
> diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
> index 6185657..7f253d3 100644
> --- a/drivers/net/i40e/i40e_ethdev.h
> +++ b/drivers/net/i40e/i40e_ethdev.h
> @@ -282,6 +282,17 @@ struct i40e_pf_vf { };
>
> /*
> + * Structure to store private data for flow control.
> + */
> +struct i40e_fc_conf {
> + uint16_t pause_time; /* Flow control pause timer */
> + /* FC high water 0-7 for pfc and 8 for lfc unit:kilobytes */
> + uint32_t high_water[I40E_MAX_TRAFFIC_CLASS+1];
> + /* FC low water 0-7 for pfc and 8 for lfc unit:kilobytes */
> + uint32_t low_water[I40E_MAX_TRAFFIC_CLASS+1];
Would it be clearer to define high/low water for pfc and lfc separately?
Why define them in kilo bytes? Why not in bytes?
Regards,
Helin
> +};
> +
> +/*
> * Structure to store private data for VMDQ instance
> */
> struct i40e_vmdq_info {
> @@ -385,6 +396,7 @@ struct i40e_pf {
> struct i40e_vmdq_info *vmdq;
>
> struct i40e_fdir_info fdir; /* flow director info */
> + struct i40e_fc_conf fc_conf; /* Flow control conf */
> struct i40e_mirror_rule_list mirror_list;
> uint16_t nb_mirror_rule; /* The number of mirror rules */
> };
> --
> 1.9.3
^ permalink raw reply [flat|nested] 9+ messages in thread
* [dpdk-dev] [PATCH v2] i40e: add link flow control support for FVL
2015-09-25 5:52 [dpdk-dev] [PATCH] i40e: add link flow control support for FVL Zhe Tao
2015-10-27 3:43 ` Zhang, Helin
@ 2015-10-29 12:56 ` Zhe Tao
2015-10-29 13:18 ` Wu, Jingjing
2015-10-30 4:57 ` [dpdk-dev] [PATCH v3] " Zhe Tao
1 sibling, 2 replies; 9+ messages in thread
From: Zhe Tao @ 2015-10-29 12:56 UTC (permalink / raw)
To: dev
Feature Add: Rx/Tx flow control support for the i40e
All the Rx/Tx LFC enable/disable operation is done by the F/W,
so PMD driver need to use the Set PHY Config AD command to trigger the PHY
to do the auto-negotiation, after the Tx/Rx pause ability is negotiated,
the F/W will help us to set the related LFC enable/disable registers.
PMD driver also need to configure the related registers to control
how often to send the pause frame and what the value in the pause frame.
Signed-off-by: Zhe Tao <zhe.tao@intel.com>
---
PATCH V1: Add the LFC support for i40e
PATCH v2: move the LFC parameters init to the i40e_pf_parameter_init
drivers/net/i40e/i40e_ethdev.c | 170 ++++++++++++++++++++++++++++++++++++++++-
drivers/net/i40e/i40e_ethdev.h | 12 +++
2 files changed, 179 insertions(+), 3 deletions(-)
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2dd9fdc..e68e0b7 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -81,6 +81,27 @@
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */
+/* Flow control default timer */
+#define I40E_DEFAULT_PAUSE_TIME 0xFFFFU
+
+/* Flow control default high water */
+#define I40E_DEFAULT_HIGH_WATER (0x1C40/1024)
+
+/* Flow control default low water */
+#define I40E_DEFAULT_LOW_WATER (0x1A40/1024)
+
+/* Flow control enable fwd bit */
+#define I40E_PRTMAC_FWD_CTRL 0x00000001
+
+/* Receive Packet Buffer size */
+#define I40E_RXPBSIZE (968 * 1024)
+
+/* Kilobytes shift */
+#define I40E_KILOSHIFT 10
+
+/* Receive Average Packet Size in Byte*/
+#define I40E_PACKET_AVERAGE_SIZE 128
+
/* Mask of PF interrupt causes */
#define I40E_PFINT_ICR0_ENA_MASK ( \
I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | \
@@ -145,6 +166,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,
@@ -272,6 +295,7 @@ static const 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,
@@ -1782,12 +1806,148 @@ 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[I40E_MAX_TRAFFIC_CLASS];
+ fc_conf->low_water = pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS];
+
+ /* 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 = RTE_FC_TX_PAUSE;
+ break;
+ case I40E_FC_RX_PAUSE:
+ fc_conf->mode = RTE_FC_RX_PAUSE;
+ break;
+ case I40E_FC_NONE:
+ default:
+ fc_conf->mode = RTE_FC_NONE;
+ };
+
+ 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;
+ struct i40e_hw *hw;
+ struct i40e_pf *pf;
+ enum i40e_fc_mode rte_fcmode_2_i40e_fcmode[] = {
+ [RTE_FC_NONE] = I40E_FC_NONE,
+ [RTE_FC_RX_PAUSE] = I40E_FC_RX_PAUSE,
+ [RTE_FC_TX_PAUSE] = I40E_FC_TX_PAUSE,
+ [RTE_FC_FULL] = I40E_FC_FULL
+ };
+
+ /* high_water field in the rte_eth_fc_conf using the kilobytes unit */
+
+ max_high_water = I40E_RXPBSIZE >> I40E_KILOSHIFT;
+ 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;
+ }
+
+ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ 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[I40E_MAX_TRAFFIC_CLASS] = fc_conf->high_water;
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = fc_conf->low_water;
+
PMD_INIT_FUNC_TRACE();
- return -ENOSYS;
+ /* All the link flow control related enable/disable register
+ * configuration is handle by the F/W
+ */
+ err = i40e_set_fc(hw, &aq_failure, true);
+ if (err < 0)
+ return -ENOSYS;
+
+ 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 & MFLCN.DPF bits
+ *depending on configuration
+ */
+ if (fc_conf->mac_ctrl_frame_fwd != 0) {
+ mflcn_reg |= I40E_PRTDCB_MFLCN_PMCF_MASK;
+ mflcn_reg &= ~I40E_PRTDCB_MFLCN_DPF_MASK;
+ } else {
+ mflcn_reg &= ~I40E_PRTDCB_MFLCN_PMCF_MASK;
+ mflcn_reg |= I40E_PRTDCB_MFLCN_DPF_MASK;
+ }
+
+ I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg);
+ }
+
+ /* config the water marker both based on the packets and bytes */
+ I40E_WRITE_REG(hw, I40E_GLRPB_PHW,
+ (pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+ I40E_WRITE_REG(hw, I40E_GLRPB_PLW,
+ (pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+ I40E_WRITE_REG(hw, I40E_GLRPB_GHW,
+ pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT);
+ I40E_WRITE_REG(hw, I40E_GLRPB_GLW,
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT);
+
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}
static int
@@ -2247,6 +2407,10 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
PMD_INIT_LOG(ERR, "HW configuration doesn't support SRIOV");
return -EINVAL;
}
+ /* Add the parameter init for LFC */
+ pf->fc_conf.pause_time = I40E_DEFAULT_PAUSE_TIME;
+ pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_HIGH_WATER;
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_LOW_WATER;
pf->flags = I40E_FLAG_HEADER_SPLIT_DISABLED;
pf->max_num_vsi = RTE_MIN(hw->func_caps.num_vsis, I40E_MAX_NUM_VSIS);
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 6185657..8707a98 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -282,6 +282,17 @@ struct i40e_pf_vf {
};
/*
+ * Structure to store private data for flow control.
+ */
+struct i40e_fc_conf {
+ uint16_t pause_time; /* Flow control pause timer */
+ /* FC high water 0-7 for pfc and 8 for lfc unit:kilobytes */
+ uint32_t high_water[I40E_MAX_TRAFFIC_CLASS + 1];
+ /* FC low water 0-7 for pfc and 8 for lfc unit:kilobytes */
+ uint32_t low_water[I40E_MAX_TRAFFIC_CLASS + 1];
+};
+
+/*
* Structure to store private data for VMDQ instance
*/
struct i40e_vmdq_info {
@@ -385,6 +396,7 @@ struct i40e_pf {
struct i40e_vmdq_info *vmdq;
struct i40e_fdir_info fdir; /* flow director info */
+ struct i40e_fc_conf fc_conf; /* Flow control conf */
struct i40e_mirror_rule_list mirror_list;
uint16_t nb_mirror_rule; /* The number of mirror rules */
};
--
1.9.3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [dpdk-dev] [PATCH v2] i40e: add link flow control support for FVL
2015-10-29 12:56 ` [dpdk-dev] [PATCH v2] " Zhe Tao
@ 2015-10-29 13:18 ` Wu, Jingjing
2015-10-30 4:57 ` [dpdk-dev] [PATCH v3] " Zhe Tao
1 sibling, 0 replies; 9+ messages in thread
From: Wu, Jingjing @ 2015-10-29 13:18 UTC (permalink / raw)
To: Tao, Zhe, dev
> -----Original Message-----
> From: Tao, Zhe
> Sent: Thursday, October 29, 2015 8:57 PM
> To: dev@dpdk.org
> Cc: Tao, Zhe; Wu, Jingjing
> Subject: [dpdk-dev][PATCH v2] i40e: add link flow control support for FVL
>
> Feature Add: Rx/Tx flow control support for the i40e
>
> All the Rx/Tx LFC enable/disable operation is done by the F/W,
> so PMD driver need to use the Set PHY Config AD command to trigger the PHY
> to do the auto-negotiation, after the Tx/Rx pause ability is negotiated,
> the F/W will help us to set the related LFC enable/disable registers.
> PMD driver also need to configure the related registers to control
> how often to send the pause frame and what the value in the pause frame.
>
> Signed-off-by: Zhe Tao <zhe.tao@intel.com>
I think release note is missed.
> ---
>
> PATCH V1: Add the LFC support for i40e
>
> PATCH v2: move the LFC parameters init to the i40e_pf_parameter_init
>
> drivers/net/i40e/i40e_ethdev.c | 170 ++++++++++++++++++++++++++++++++++++++++-
> drivers/net/i40e/i40e_ethdev.h | 12 +++
> 2 files changed, 179 insertions(+), 3 deletions(-)
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [dpdk-dev] [PATCH v3] i40e: add link flow control support for FVL
2015-10-29 12:56 ` [dpdk-dev] [PATCH v2] " Zhe Tao
2015-10-29 13:18 ` Wu, Jingjing
@ 2015-10-30 4:57 ` Zhe Tao
2015-10-30 5:13 ` Wu, Jingjing
` (2 more replies)
1 sibling, 3 replies; 9+ messages in thread
From: Zhe Tao @ 2015-10-30 4:57 UTC (permalink / raw)
To: dev
Feature Add: Rx/Tx flow control support for the i40e
All the Rx/Tx LFC enable/disable operation is done by the F/W,
so PMD driver need to use the Set PHY Config AD command to trigger the PHY
to do the auto-negotiation, after the Tx/Rx pause ability is negotiated,
the F/W will help us to set the related LFC enable/disable registers.
PMD driver also need to configure the related registers to control
how often to send the pause frame and what the value in the pause frame.
Signed-off-by: Zhe Tao <zhe.tao@intel.com>
---
PATCH V1: add the LFC support for i40e
PATCH v2: move the LFC parameters init to the i40e_pf_parameter_init
PATCH v3: update the release note
doc/guides/rel_notes/release_2_2.rst | 4 +
drivers/net/i40e/i40e_ethdev.c | 170 ++++++++++++++++++++++++++++++++++-
drivers/net/i40e/i40e_ethdev.h | 12 +++
3 files changed, 183 insertions(+), 3 deletions(-)
diff --git a/doc/guides/rel_notes/release_2_2.rst b/doc/guides/rel_notes/release_2_2.rst
index bc9b00f..3475aa7 100644
--- a/doc/guides/rel_notes/release_2_2.rst
+++ b/doc/guides/rel_notes/release_2_2.rst
@@ -39,6 +39,10 @@ Drivers
Fixed i40e issue that occurred when a DPDK application didn't initialize
ports if memory wasn't available on socket 0.
+* **i40e: Add the support for link flow control.**
+
+ Add the support for link flow control on FVL.
+
* **vhost: Fixed Qemu shutdown.**
Fixed issue with libvirt ``virsh destroy`` not killing the VM.
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 2dd9fdc..e68e0b7 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -81,6 +81,27 @@
#define I40E_PRE_TX_Q_CFG_WAIT_US 10 /* 10 us */
+/* Flow control default timer */
+#define I40E_DEFAULT_PAUSE_TIME 0xFFFFU
+
+/* Flow control default high water */
+#define I40E_DEFAULT_HIGH_WATER (0x1C40/1024)
+
+/* Flow control default low water */
+#define I40E_DEFAULT_LOW_WATER (0x1A40/1024)
+
+/* Flow control enable fwd bit */
+#define I40E_PRTMAC_FWD_CTRL 0x00000001
+
+/* Receive Packet Buffer size */
+#define I40E_RXPBSIZE (968 * 1024)
+
+/* Kilobytes shift */
+#define I40E_KILOSHIFT 10
+
+/* Receive Average Packet Size in Byte*/
+#define I40E_PACKET_AVERAGE_SIZE 128
+
/* Mask of PF interrupt causes */
#define I40E_PFINT_ICR0_ENA_MASK ( \
I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | \
@@ -145,6 +166,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,
@@ -272,6 +295,7 @@ static const 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,
@@ -1782,12 +1806,148 @@ 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[I40E_MAX_TRAFFIC_CLASS];
+ fc_conf->low_water = pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS];
+
+ /* 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 = RTE_FC_TX_PAUSE;
+ break;
+ case I40E_FC_RX_PAUSE:
+ fc_conf->mode = RTE_FC_RX_PAUSE;
+ break;
+ case I40E_FC_NONE:
+ default:
+ fc_conf->mode = RTE_FC_NONE;
+ };
+
+ 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;
+ struct i40e_hw *hw;
+ struct i40e_pf *pf;
+ enum i40e_fc_mode rte_fcmode_2_i40e_fcmode[] = {
+ [RTE_FC_NONE] = I40E_FC_NONE,
+ [RTE_FC_RX_PAUSE] = I40E_FC_RX_PAUSE,
+ [RTE_FC_TX_PAUSE] = I40E_FC_TX_PAUSE,
+ [RTE_FC_FULL] = I40E_FC_FULL
+ };
+
+ /* high_water field in the rte_eth_fc_conf using the kilobytes unit */
+
+ max_high_water = I40E_RXPBSIZE >> I40E_KILOSHIFT;
+ 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;
+ }
+
+ hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+ 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[I40E_MAX_TRAFFIC_CLASS] = fc_conf->high_water;
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = fc_conf->low_water;
+
PMD_INIT_FUNC_TRACE();
- return -ENOSYS;
+ /* All the link flow control related enable/disable register
+ * configuration is handle by the F/W
+ */
+ err = i40e_set_fc(hw, &aq_failure, true);
+ if (err < 0)
+ return -ENOSYS;
+
+ 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 & MFLCN.DPF bits
+ *depending on configuration
+ */
+ if (fc_conf->mac_ctrl_frame_fwd != 0) {
+ mflcn_reg |= I40E_PRTDCB_MFLCN_PMCF_MASK;
+ mflcn_reg &= ~I40E_PRTDCB_MFLCN_DPF_MASK;
+ } else {
+ mflcn_reg &= ~I40E_PRTDCB_MFLCN_PMCF_MASK;
+ mflcn_reg |= I40E_PRTDCB_MFLCN_DPF_MASK;
+ }
+
+ I40E_WRITE_REG(hw, I40E_PRTDCB_MFLCN, mflcn_reg);
+ }
+
+ /* config the water marker both based on the packets and bytes */
+ I40E_WRITE_REG(hw, I40E_GLRPB_PHW,
+ (pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+ I40E_WRITE_REG(hw, I40E_GLRPB_PLW,
+ (pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT) / I40E_PACKET_AVERAGE_SIZE);
+ I40E_WRITE_REG(hw, I40E_GLRPB_GHW,
+ pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT);
+ I40E_WRITE_REG(hw, I40E_GLRPB_GLW,
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS]
+ << I40E_KILOSHIFT);
+
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
}
static int
@@ -2247,6 +2407,10 @@ i40e_pf_parameter_init(struct rte_eth_dev *dev)
PMD_INIT_LOG(ERR, "HW configuration doesn't support SRIOV");
return -EINVAL;
}
+ /* Add the parameter init for LFC */
+ pf->fc_conf.pause_time = I40E_DEFAULT_PAUSE_TIME;
+ pf->fc_conf.high_water[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_HIGH_WATER;
+ pf->fc_conf.low_water[I40E_MAX_TRAFFIC_CLASS] = I40E_DEFAULT_LOW_WATER;
pf->flags = I40E_FLAG_HEADER_SPLIT_DISABLED;
pf->max_num_vsi = RTE_MIN(hw->func_caps.num_vsis, I40E_MAX_NUM_VSIS);
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 6185657..8707a98 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -282,6 +282,17 @@ struct i40e_pf_vf {
};
/*
+ * Structure to store private data for flow control.
+ */
+struct i40e_fc_conf {
+ uint16_t pause_time; /* Flow control pause timer */
+ /* FC high water 0-7 for pfc and 8 for lfc unit:kilobytes */
+ uint32_t high_water[I40E_MAX_TRAFFIC_CLASS + 1];
+ /* FC low water 0-7 for pfc and 8 for lfc unit:kilobytes */
+ uint32_t low_water[I40E_MAX_TRAFFIC_CLASS + 1];
+};
+
+/*
* Structure to store private data for VMDQ instance
*/
struct i40e_vmdq_info {
@@ -385,6 +396,7 @@ struct i40e_pf {
struct i40e_vmdq_info *vmdq;
struct i40e_fdir_info fdir; /* flow director info */
+ struct i40e_fc_conf fc_conf; /* Flow control conf */
struct i40e_mirror_rule_list mirror_list;
uint16_t nb_mirror_rule; /* The number of mirror rules */
};
--
1.9.3
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [dpdk-dev] [PATCH v3] i40e: add link flow control support for FVL
2015-10-30 4:57 ` [dpdk-dev] [PATCH v3] " Zhe Tao
@ 2015-10-30 5:13 ` Wu, Jingjing
2015-10-30 7:28 ` Zhang, Helin
2015-10-30 14:19 ` Thomas Monjalon
2 siblings, 0 replies; 9+ messages in thread
From: Wu, Jingjing @ 2015-10-30 5:13 UTC (permalink / raw)
To: Tao, Zhe, dev
> -----Original Message-----
> From: Tao, Zhe
> Sent: Friday, October 30, 2015 12:58 PM
> To: dev@dpdk.org
> Cc: Tao, Zhe; Wu, Jingjing
> Subject: [dpdk-dev][PATCH v3] i40e: add link flow control support for FVL
>
> Feature Add: Rx/Tx flow control support for the i40e
>
> All the Rx/Tx LFC enable/disable operation is done by the F/W, so PMD driver
> need to use the Set PHY Config AD command to trigger the PHY to do the
> auto-negotiation, after the Tx/Rx pause ability is negotiated, the F/W will
> help us to set the related LFC enable/disable registers.
> PMD driver also need to configure the related registers to control how often
> to send the pause frame and what the value in the pause frame.
>
> Signed-off-by: Zhe Tao <zhe.tao@intel.com>
> ---
>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
> PATCH V1: add the LFC support for i40e
>
> PATCH v2: move the LFC parameters init to the i40e_pf_parameter_init
>
> PATCH v3: update the release note
>
> doc/guides/rel_notes/release_2_2.rst | 4 +
> drivers/net/i40e/i40e_ethdev.c | 170
> ++++++++++++++++++++++++++++++++++-
> drivers/net/i40e/i40e_ethdev.h | 12 +++
> 3 files changed, 183 insertions(+), 3 deletions(-)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [dpdk-dev] [PATCH v3] i40e: add link flow control support for FVL
2015-10-30 4:57 ` [dpdk-dev] [PATCH v3] " Zhe Tao
2015-10-30 5:13 ` Wu, Jingjing
@ 2015-10-30 7:28 ` Zhang, Helin
2015-10-30 14:19 ` Thomas Monjalon
2 siblings, 0 replies; 9+ messages in thread
From: Zhang, Helin @ 2015-10-30 7:28 UTC (permalink / raw)
To: Tao, Zhe, dev
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Zhe Tao
> Sent: Friday, October 30, 2015 12:58 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v3] i40e: add link flow control support for FVL
>
> Feature Add: Rx/Tx flow control support for the i40e
>
> All the Rx/Tx LFC enable/disable operation is done by the F/W, so PMD driver
> need to use the Set PHY Config AD command to trigger the PHY to do the
> auto-negotiation, after the Tx/Rx pause ability is negotiated, the F/W will help us
> to set the related LFC enable/disable registers.
> PMD driver also need to configure the related registers to control how often to
> send the pause frame and what the value in the pause frame.
>
> Signed-off-by: Zhe Tao <zhe.tao@intel.com>
Acked-by: Helin Zhang <helin.zhang@intel.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [dpdk-dev] [PATCH v3] i40e: add link flow control support for FVL
2015-10-30 4:57 ` [dpdk-dev] [PATCH v3] " Zhe Tao
2015-10-30 5:13 ` Wu, Jingjing
2015-10-30 7:28 ` Zhang, Helin
@ 2015-10-30 14:19 ` Thomas Monjalon
2015-10-30 14:22 ` Thomas Monjalon
2 siblings, 1 reply; 9+ messages in thread
From: Thomas Monjalon @ 2015-10-30 14:19 UTC (permalink / raw)
To: Zhe Tao; +Cc: dev
2015-10-30 12:57, Zhe Tao:
> --- a/doc/guides/rel_notes/release_2_2.rst
> +++ b/doc/guides/rel_notes/release_2_2.rst
> @@ -39,6 +39,10 @@ Drivers
> Fixed i40e issue that occurred when a DPDK application didn't initialize
> ports if memory wasn't available on socket 0.
>
> +* **i40e: Add the support for link flow control.**
> +
> + Add the support for link flow control on FVL.
> +
It is added in the section "Resolved Issues".
Will be moved.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [dpdk-dev] [PATCH v3] i40e: add link flow control support for FVL
2015-10-30 14:19 ` Thomas Monjalon
@ 2015-10-30 14:22 ` Thomas Monjalon
0 siblings, 0 replies; 9+ messages in thread
From: Thomas Monjalon @ 2015-10-30 14:22 UTC (permalink / raw)
To: Zhe Tao; +Cc: dev
2015-10-30 15:19, Thomas Monjalon:
> 2015-10-30 12:57, Zhe Tao:
> > --- a/doc/guides/rel_notes/release_2_2.rst
> > +++ b/doc/guides/rel_notes/release_2_2.rst
> > @@ -39,6 +39,10 @@ Drivers
> > Fixed i40e issue that occurred when a DPDK application didn't initialize
> > ports if memory wasn't available on socket 0.
> >
> > +* **i40e: Add the support for link flow control.**
> > +
> > + Add the support for link flow control on FVL.
> > +
>
> It is added in the section "Resolved Issues".
> Will be moved.
Applied with above fix, thanks
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-10-30 14:24 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-25 5:52 [dpdk-dev] [PATCH] i40e: add link flow control support for FVL Zhe Tao
2015-10-27 3:43 ` Zhang, Helin
2015-10-29 12:56 ` [dpdk-dev] [PATCH v2] " Zhe Tao
2015-10-29 13:18 ` Wu, Jingjing
2015-10-30 4:57 ` [dpdk-dev] [PATCH v3] " Zhe Tao
2015-10-30 5:13 ` Wu, Jingjing
2015-10-30 7:28 ` Zhang, Helin
2015-10-30 14:19 ` Thomas Monjalon
2015-10-30 14:22 ` Thomas Monjalon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).