[dpdk-dev,v2] i40e: link flow control support

Message ID 1416473922-8314-1-git-send-email-zhida.zang@intel.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

zzang Nov. 20, 2014, 8:58 a.m. UTC
From: zzang <zhida.zang@intel.com>

Add link flow control support for i40e

Signed-off-by: zhida zang <zhida.zang@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(-)
  

Comments

Zhang, Helin Nov. 25, 2014, 5:40 a.m. UTC | #1
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of zhida zang
> Sent: Thursday, November 20, 2014 4:59 PM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v2] i40e: link flow control support
> 
> From: zzang <zhida.zang@intel.com>
> 
> Add link flow control support for i40e
> 
> Signed-off-by: zhida zang <zhida.zang@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]);
Why sets the global high/low water of the whole chip (including possible 2 or 4 ports)?

> +
> +	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
  
Michael Qiu Nov. 25, 2014, 11:31 a.m. UTC | #2
On 11/20/2014 5:00 PM, zhida zang wrote:
> From: zzang <zhida.zang@intel.com>
>
> Add link flow control support for i40e
>
> Signed-off-by: zhida zang <zhida.zang@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

Here why so much zero? Can it just be 0x1 for simple?
> +
>  /* 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 {
  
Thomas Monjalon Nov. 27, 2014, 3:50 p.m. UTC | #3
Hi,

2014-11-20 16:58, zhida zang:
> From: zzang <zhida.zang@intel.com>
> 
> Add link flow control support for i40e
> 
> Signed-off-by: zhida zang <zhida.zang@intel.com>

This patch is pending with open questions.
Any news to submit a new version and/or acknowledge it?
  
Zhang, Helin Nov. 28, 2014, 12:33 a.m. UTC | #4
Hi Thomas

New version is needed for i40e flow control.

Regards,
Helin

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Thomas Monjalon
> Sent: Thursday, November 27, 2014 11:51 PM
> To: Zang, Zhida
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v2] i40e: link flow control support
> 
> Hi,
> 
> 2014-11-20 16:58, zhida zang:
> > From: zzang <zhida.zang@intel.com>
> >
> > Add link flow control support for i40e
> >
> > Signed-off-by: zhida zang <zhida.zang@intel.com>
> 
> This patch is pending with open questions.
> Any news to submit a new version and/or acknowledge it?
> 
> --
> Thomas
  

Patch

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 {