From: "Qiu, Michael" <michael.qiu@intel.com>
To: "Zang, Zhida" <zhida.zang@intel.com>, "dev@dpdk.org" <dev@dpdk.org>
Subject: Re: [dpdk-dev] [PATCH v2] i40e: link flow control support
Date: Tue, 25 Nov 2014 11:31:40 +0000 [thread overview]
Message-ID: <533710CFB86FA344BFBF2D6802E60286C9A502@SHSMSX101.ccr.corp.intel.com> (raw)
In-Reply-To: <1416473922-8314-1-git-send-email-zhida.zang@intel.com>
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 {
next prev parent reply other threads:[~2014-11-25 11:20 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-20 8:58 zhida zang
2014-11-25 5:40 ` Zhang, Helin
2014-11-25 11:31 ` Qiu, Michael [this message]
2014-11-27 15:50 ` Thomas Monjalon
2014-11-28 0:33 ` Zhang, Helin
2014-12-02 2:56 ` Cao, Min
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=533710CFB86FA344BFBF2D6802E60286C9A502@SHSMSX101.ccr.corp.intel.com \
--to=michael.qiu@intel.com \
--cc=dev@dpdk.org \
--cc=zhida.zang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).