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]); + + 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
> -----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
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 {
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
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
Tested-by: Min Cao <min.cao@intel.com> Patch name: [dpdk-dev] [PATCH v2] i40e: link flow control support Test Flag: Tested-by Tester name: min.cao@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-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]); + + 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