This patch enables the ETS-based Tx QoS for IAVF. Kernel tool is used to
configure ETS first. DCF is used to set bandwidth limit for VFs of each
TC. IAVF is supported to query QoS capability and set queue TC mapping.
Traffic Management API is utilized to configure the QoS hierarchy
scheduler tree. The scheduler tree will be passed to hardware to enable
all above functions.
Ting Xu (5):
common/iavf: add support for ETS-based Tx QoS
net/ice/base: support DCF query port ETS adminq
net/ice: support DCF link status event handling
net/ice: support QoS config VF bandwidth in DCF
net/iavf: query QoS cap and set queue TC mapping
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 117 ++++++
drivers/net/iavf/iavf.h | 45 +++
drivers/net/iavf/iavf_ethdev.c | 31 ++
drivers/net/iavf/iavf_tm.c | 675 +++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
drivers/net/ice/base/ice_dcb.c | 3 +-
drivers/net/ice/ice_dcf.c | 6 +-
drivers/net/ice/ice_dcf.h | 53 +++
drivers/net/ice/ice_dcf_ethdev.c | 67 ++-
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 81 ++++
drivers/net/ice/ice_dcf_sched.c | 604 +++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
15 files changed, 1740 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
create mode 100644 drivers/net/ice/ice_dcf_sched.c
--
2.17.1
This patch adds support to configure ETS-based Tx QoS. Three parts of
new virtchnl structures and opcodes are added to achieve:
1. Configure VF TC bandwidth limits.
2. VF queries current QoS configuration from PF.
3. Set up VF queue TC mapping.
Signed-off-by: Ting Xu <redacted>
---
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 117 ++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+)
In the adminq command query port ETS function, the root node teid is
needed. However, for DCF, the root node is not initialized, which will
cause error when we refer to the variable. In this patch, we will check
whether the root node is available or not first.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/base/ice_dcb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
When link status changes, DCF will receive virtchnl PF event message.
Add support to handle this event, change link status and update link
info.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.h | 6 ++++
drivers/net/ice/ice_dcf_ethdev.c | 54 ++++++++++++++++++++++++++++++--
drivers/net/ice/ice_dcf_parent.c | 51 ++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 3 deletions(-)
@@ -60,6 +60,10 @@ struct ice_dcf_hw {uint16_tnb_msix;uint16_trxq_map[16];structvirtchnl_eth_statseth_stats_offset;++/* Link status */+boollink_up;+uint32_tlink_speed;};intice_dcf_execute_virtchnl_cmd(structice_dcf_hw*hw,
@@ -880,11 +880,59 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)return0;}-staticint-ice_dcf_link_update(__rte_unusedstructrte_eth_dev*dev,+int+ice_dcf_link_update(structrte_eth_dev*dev,__rte_unusedintwait_to_complete){-return0;+structice_dcf_adapter*ad=dev->data->dev_private;+structice_dcf_hw*hw=&ad->real_hw;+structrte_eth_linknew_link;++memset(&new_link,0,sizeof(new_link));++/* Only read status info stored in VF, and the info is updated+*whenreceiveLINK_CHANGEevnetfromPFbyVirtchnnl.+*/+switch(hw->link_speed){+case10:+new_link.link_speed=ETH_SPEED_NUM_10M;+break;+case100:+new_link.link_speed=ETH_SPEED_NUM_100M;+break;+case1000:+new_link.link_speed=ETH_SPEED_NUM_1G;+break;+case10000:+new_link.link_speed=ETH_SPEED_NUM_10G;+break;+case20000:+new_link.link_speed=ETH_SPEED_NUM_20G;+break;+case25000:+new_link.link_speed=ETH_SPEED_NUM_25G;+break;+case40000:+new_link.link_speed=ETH_SPEED_NUM_40G;+break;+case50000:+new_link.link_speed=ETH_SPEED_NUM_50G;+break;+case100000:+new_link.link_speed=ETH_SPEED_NUM_100G;+break;+default:+new_link.link_speed=ETH_SPEED_NUM_NONE;+break;+}++new_link.link_duplex=ETH_LINK_FULL_DUPLEX;+new_link.link_status=hw->link_up?ETH_LINK_UP:+ETH_LINK_DOWN;+new_link.link_autoneg=!(dev->data->dev_conf.link_speeds&+ETH_LINK_SPEED_FIXED);++returnrte_eth_linkstatus_set(dev,&new_link);}/* Add UDP tunneling port */
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.c | 6 +-
drivers/net/ice/ice_dcf.h | 47 +++
drivers/net/ice/ice_dcf_ethdev.c | 13 +
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 30 ++
drivers/net/ice/ice_dcf_sched.c | 604 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 704 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_sched.c
@@ -30,6 +31,49 @@ struct dcf_virtchnl_cmd {volatileintpending;};+structice_dcf_tm_shaper_profile{+TAILQ_ENTRY(ice_dcf_tm_shaper_profile)node;+uint32_tshaper_profile_id;+uint32_treference_count;+structrte_tm_shaper_paramsprofile;+};++TAILQ_HEAD(ice_dcf_shaper_profile_list,ice_dcf_tm_shaper_profile);++/* Struct to store Traffic Manager node configuration. */+structice_dcf_tm_node{+TAILQ_ENTRY(ice_dcf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structice_dcf_tm_node*parent;+structice_dcf_tm_shaper_profile*shaper_profile;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(ice_dcf_tm_node_list,ice_dcf_tm_node);++/* node type of Traffic Manager */+enumice_dcf_tm_node_type{+ICE_DCF_TM_NODE_TYPE_PORT,+ICE_DCF_TM_NODE_TYPE_TC,+ICE_DCF_TM_NODE_TYPE_VSI,+ICE_DCF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structice_dcf_tm_conf{+structice_dcf_shaper_profile_listshaper_profile_list;+structice_dcf_tm_node*root;/* root node - port */+structice_dcf_tm_node_listtc_list;/* node list for all the TCs */+structice_dcf_tm_node_listvsi_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_vsi_node;+boolcommitted;+};+structice_dcf_hw{structiavf_hwavf;
@@ -45,6 +89,8 @@ struct ice_dcf_hw {uint16_t*vf_vsi_map;uint16_tpf_vsi_id;+structice_dcf_tm_conftm_conf;+structice_aqc_port_ets_elem*ets_config;structvirtchnl_version_infovirtchnl_version;structvirtchnl_vf_resource*vf_res;/* VF resource */structvirtchnl_vsi_resource*vsi_res;/* LAN VSI */
@@ -487,6 +510,13 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)returnerr;}+err=ice_dcf_query_port_ets(parent_hw,hw);+if(err){+PMD_INIT_LOG(ERR,"failed to query port ets with error %d",+err);+gotouninit_hw;+}+err=ice_dcf_load_pkg(parent_hw);if(err){PMD_INIT_LOG(ERR,"failed to load package with error %d",
@@ -0,0 +1,604 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"base/ice_sched.h"+#include"ice_dcf_ethdev.h"++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error);++conststructrte_tm_opsice_dcf_tm_ops={+.shaper_profile_add=ice_dcf_shaper_profile_add,+.shaper_profile_delete=ice_dcf_shaper_profile_del,+.hierarchy_commit=ice_dcf_hierarchy_commit,+.node_add=ice_dcf_node_add,+.node_delete=ice_dcf_node_delete,+};++void+ice_dcf_tm_conf_init(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;++/* initialize shaper profile list */+TAILQ_INIT(&hw->tm_conf.shaper_profile_list);++/* initialize node configuration */+hw->tm_conf.root=NULL;+TAILQ_INIT(&hw->tm_conf.tc_list);+TAILQ_INIT(&hw->tm_conf.vsi_list);+hw->tm_conf.nb_tc_node=0;+hw->tm_conf.nb_vsi_node=0;+hw->tm_conf.committed=false;+}++staticinlinestructice_dcf_tm_node*+dcf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumice_dcf_tm_node_type*node_type)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structice_dcf_tm_node_list*tc_list=&hw->tm_conf.tc_list;+structice_dcf_tm_node*tm_node;++if(hw->tm_conf.root&&hw->tm_conf.root->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_PORT;+returnhw->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,vsi_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_VSI;+returntm_node;+}+}++returnNULL;+}++staticinlinestructice_dcf_tm_shaper_profile*+dcf_shaper_profile_search(structrte_eth_dev*dev,+uint32_tshaper_profile_id)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_shaper_profile_list*shaper_profile_list=+&hw->tm_conf.shaper_profile_list;+structice_dcf_tm_shaper_profile*shaper_profile;++TAILQ_FOREACH(shaper_profile,shaper_profile_list,node){+if(shaper_profile_id==shaper_profile->shaper_profile_id)+returnshaper_profile;+}++returnNULL;+}++staticint+dcf_node_param_check(structice_dcf_hw*hw,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=8*hw->num_vfs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typeparent_node_type=ICE_DCF_TM_NODE_TYPE_MAX;+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_tm_shaper_profile*shaper_profile=NULL;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*parent_node;+structice_dcf_tm_node*tm_node;+uint16_ttc_nb=1;+inti,ret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=dcf_node_param_check(hw,node_id,priority,weight,+params,error);+if(ret)+returnret;++for(i=1;i<ICE_MAX_TRAFFIC_CLASS;i++){+if(hw->ets_config->tc_valid_bits&(1<<i))+tc_nb++;+}++/* check if the node is already existed */+if(dcf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* check the shaper profile id */+if(params->shaper_profile_id!=RTE_TM_SHAPER_PROFILE_ID_NONE){+shaper_profile=dcf_shaper_profile_search(dev,+params->shaper_profile_id);+if(!shaper_profile){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not exist";+return-EINVAL;+}+}++/* add root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=ICE_DCF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(hw->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+hw->tm_conf.root=tm_node;++return0;+}++/* TC or vsi node */+/* check the parent node */+parent_node=dcf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=ICE_DCF_TM_NODE_TYPE_PORT&&+parent_node_type!=ICE_DCF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not port or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the TC node number */+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(hw->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the vsi node number */+if(parent_node->reference_count>=hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many VSI for one TC";+return-EINVAL;+}+/* check the vsi node id */+if(node_id>tc_nb*hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large VSI id";+return-EINVAL;+}+}++/* add the TC or vsi node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->priority=priority;+tm_node->weight=weight;+tm_node->shaper_profile=shaper_profile;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,+tm_node,node);+tm_node->tc=hw->tm_conf.nb_tc_node;+hw->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,+tm_node,node);+tm_node->tc=parent_node->tc;+hw->tm_conf.nb_vsi_node++;+}+tm_node->parent->reference_count++;++/* increase the reference counter of the shaper profile */+if(shaper_profile)+shaper_profile->reference_count++;++return0;+}++staticint+ice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=dcf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==ICE_DCF_TM_NODE_TYPE_PORT){+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+rte_free(tm_node);+hw->tm_conf.root=NULL;+return0;+}++/* TC or VSI node */+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+tm_node->parent->reference_count--;+if(node_type==ICE_DCF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+hw->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+hw->tm_conf.nb_vsi_node--;+}+rte_free(tm_node);++return0;+}++staticint+dcf_shaper_profile_param_check(structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+/* min bucket size not supported */+if(profile->committed.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;+error->message="committed bucket size not supported";+return-EINVAL;+}+/* max bucket size not supported */+if(profile->peak.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;+error->message="peak bucket size not supported";+return-EINVAL;+}+/* length adjustment not supported */+if(profile->pkt_length_adjust){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;+error->message="packet length adjustment not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+intret;++if(!profile||!error)+return-EINVAL;++ret=dcf_shaper_profile_param_check(profile,error);+if(ret)+returnret;++shaper_profile=dcf_shaper_profile_search(dev,shaper_profile_id);++if(shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID exist";+return-EINVAL;+}++shaper_profile=rte_zmalloc("ice_dcf_tm_shaper_profile",+sizeof(structice_dcf_tm_shaper_profile),+0);+if(!shaper_profile)+return-ENOMEM;+shaper_profile->shaper_profile_id=shaper_profile_id;+rte_memcpy(&shaper_profile->profile,profile,+sizeof(structrte_tm_shaper_params));+TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);++return0;+}++staticint+ice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;++if(!error)+return-EINVAL;++shaper_profile=dcf_shaper_profile_search(dev,shaper_profile_id);++if(!shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID not exist";+return-EINVAL;+}++/* don't delete a profile if it's used by one or several nodes */+if(shaper_profile->reference_count){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE;+error->message="profile in use";+return-EINVAL;+}++TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,shaper_profile,node);+rte_free(shaper_profile);++return0;+}++staticint+ice_dcf_set_vf_bw(structice_dcf_hw*hw,+structvirtchnl_dcf_vf_bw_cfg_list*vf_bw,+uint16_tlen)+{+structdcf_virtchnl_cmdargs;+interr;++memset(&args,0,sizeof(args));+args.v_op=VIRTCHNL_OP_DCF_CONFIG_VF_TC;+args.req_msg=(uint8_t*)vf_bw;+args.req_msglen=len;+err=ice_dcf_execute_virtchnl_cmd(hw,&args);+if(err)+PMD_DRV_LOG(ERR,"fail to execute command %s",+"VIRTCHNL_OP_DCF_CONFIG_VF_TC");+returnerr;+}++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structvirtchnl_dcf_vf_bw_cfg_list*vf_bw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structrte_tm_shaper_params*profile;+structice_dcf_tm_node*tm_node;+uint32_tport_bw,cir_total;+uint16_tsize,vf_id;+intret;+intnum_elem=0;++size=sizeof(*vf_bw)++sizeof(vf_bw->cfg[0])*(hw->tm_conf.nb_tc_node-1);+vf_bw=rte_zmalloc("vf_bw",size,0);+if(!vf_bw)+returnICE_ERR_NO_MEMORY;++/* port bandwidth (Kbps) */+port_bw=hw->link_speed*1000;+cir_total=0;++for(vf_id=0;vf_id<hw->num_vfs;vf_id++){+num_elem=0;+vf_bw->vf_id=vf_id;+TAILQ_FOREACH(tm_node,vsi_list,node){+/* scan the nodes belong to one VSI */+if(tm_node->id-hw->num_vfs*tm_node->tc!=vf_id)+continue;+vf_bw->cfg[num_elem].tc_id=tm_node->tc;+vf_bw->cfg[num_elem].type=VIRTCHNL_BW_SHAPER;+if(tm_node->shaper_profile){+/* Transfer from Byte per seconds to Kbps */+profile=&tm_node->shaper_profile->profile;+vf_bw->cfg[num_elem].shaper.peak=+profile->peak.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].shaper.committed=+profile->committed.rate/1000*BITS_PER_BYTE;+}+cir_total+=vf_bw->cfg[num_elem].shaper.committed;+num_elem++;+}++/* check if total CIR is larger than port bandwidth */+if(cir_total>port_bw){+PMD_DRV_LOG(ERR,"Total CIR of all VFs is larger than port bandwidth");+returnICE_ERR_PARAM;+}+vf_bw->num_elem=num_elem;+ret=ice_dcf_set_vf_bw(hw,vf_bw,size);+if(ret)+returnret;+}++hw->tm_conf.committed=true;+returnICE_SUCCESS;+}
This patch added the support for VF to config the ETS-based Tx QoS,
including querying current QoS configuration from PF and config queue TC
mapping. PF QoS is configured in advance and the queried info is
provided to the user for future usage. VF queues are mapped to different
TCs in PF through virtchnl.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 45 +++
drivers/net/iavf/iavf_ethdev.c | 31 ++
drivers/net/iavf/iavf_tm.c | 675 +++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
5 files changed, 807 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
@@ -129,6 +133,38 @@ enum iavf_aq_result {IAVF_MSG_CMD,/* Read async command result */};+/* Struct to store Traffic Manager node configuration. */+structiavf_tm_node{+TAILQ_ENTRY(iavf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structiavf_tm_node*parent;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(iavf_tm_node_list,iavf_tm_node);++/* node type of Traffic Manager */+enumiavf_tm_node_type{+IAVF_TM_NODE_TYPE_PORT,+IAVF_TM_NODE_TYPE_TC,+IAVF_TM_NODE_TYPE_QUEUE,+IAVF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structiavf_tm_conf{+structiavf_tm_node*root;/* root node - vf vsi */+structiavf_tm_node_listtc_list;/* node list for all the TCs */+structiavf_tm_node_listqueue_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_queue_node;+boolcommitted;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -175,6 +211,9 @@ struct iavf_info {structiavf_fdir_infofdir;/* flow director info *//* indicate large VF support enabled or not */boollv_enabled;++structvirtchnl_qos_cap_list*qos_cap;+structiavf_tm_conftm_conf;};#define IAVF_MAX_PKT_TYPE 1024
@@ -806,6 +820,11 @@ iavf_dev_start(struct rte_eth_dev *dev)dev->data->nb_tx_queues);num_queue_pairs=vf->num_queue_pairs;+if(iavf_get_qos_cap(adapter)){+PMD_INIT_LOG(ERR,"Failed to get qos capability");+return-1;+}+if(iavf_init_queues(dev)!=0){PMD_DRV_LOG(ERR,"failed to do Queue init");return-1;
@@ -2090,6 +2109,15 @@ iavf_init_vf(struct rte_eth_dev *dev)PMD_INIT_LOG(ERR,"unable to allocate vf_res memory");gotoerr_api;}++bufsz=sizeof(structvirtchnl_qos_cap_list)++IAVF_MAX_TRAFFIC_CLASS*sizeof(structvirtchnl_qos_cap_elem);+vf->qos_cap=rte_zmalloc("qos_cap",bufsz,0);+if(!vf->qos_cap){+PMD_INIT_LOG(ERR,"unable to allocate qos_cap memory");+gotoerr_api;+}+if(iavf_get_vf_resource(adapter)!=0){PMD_INIT_LOG(ERR,"iavf_get_vf_config failed");gotoerr_alloc;
@@ -0,0 +1,675 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"iavf.h"++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintiavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintiavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintiavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error);+staticintiavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error);++conststructrte_tm_opsiavf_tm_ops={+.node_add=iavf_tm_node_add,+.node_delete=iavf_tm_node_delete,+.capabilities_get=iavf_tm_capabilities_get,+.level_capabilities_get=iavf_level_capabilities_get,+.node_capabilities_get=iavf_node_capabilities_get,+.node_type_get=iavf_node_type_get,+.hierarchy_commit=iavf_hierarchy_commit,+};++void+iavf_tm_conf_init(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++/* initialize node configuration */+vf->tm_conf.root=NULL;+TAILQ_INIT(&vf->tm_conf.tc_list);+TAILQ_INIT(&vf->tm_conf.queue_list);+vf->tm_conf.nb_tc_node=0;+vf->tm_conf.nb_queue_node=0;+vf->tm_conf.committed=false;+}+++staticinlinestructiavf_tm_node*+iavf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumiavf_tm_node_type*node_type)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node_list*tc_list=&vf->tm_conf.tc_list;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;++if(vf->tm_conf.root&&vf->tm_conf.root->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_PORT;+returnvf->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_QUEUE;+returntm_node;+}+}++returnNULL;+}++staticint+iavf_node_param_check(structiavf_info*vf,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shaper profile */+if(params->shaper_profile_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not supported";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=vf->num_queue_pairs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+iavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error)+{+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!is_leaf||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type==IAVF_TM_NODE_TYPE_QUEUE)+*is_leaf=true;+else+*is_leaf=false;++return0;+}++staticint+iavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+enumiavf_tm_node_typeparent_node_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;+structiavf_tm_node*parent_node;+uint16_ttc_nb=vf->qos_cap->num_elem;+intret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=iavf_node_param_check(vf,node_id,priority,weight,+params,error);+if(ret)+returnret;++/* check if the node is already existed */+if(iavf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=IAVF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(vf->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+vf->tm_conf.root=tm_node;+return0;+}++/* TC or queue node */+/* check the parent node */+parent_node=iavf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=IAVF_TM_NODE_TYPE_PORT&&+parent_node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not root or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the node number */+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(vf->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the queue number */+if(parent_node->reference_count>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many queues";+return-EINVAL;+}+if(node_id>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large queue id";+return-EINVAL;+}+}++/* add the TC or queue node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&vf->tm_conf.tc_list,+tm_node,node);+tm_node->tc=vf->tm_conf.nb_tc_node;+vf->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&vf->tm_conf.queue_list,+tm_node,node);+tm_node->tc=parent_node->tc;+vf->tm_conf.nb_queue_node++;+}+tm_node->parent->reference_count++;++return0;+}++staticint+iavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==IAVF_TM_NODE_TYPE_PORT){+rte_free(tm_node);+vf->tm_conf.root=NULL;+return0;+}++/* TC or queue node */+tm_node->parent->reference_count--;+if(node_type==IAVF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+vf->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+vf->tm_conf.nb_queue_node--;+}+rte_free(tm_node);++return0;+}++staticint+iavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_ttc_nb=vf->qos_cap->num_elem;++if(!cap||!error)+return-EINVAL;++if(tc_nb>vf->vf_res->num_queue_pairs)+return-EINVAL;++error->type=RTE_TM_ERROR_TYPE_NONE;++/* set all the parameters to 0 first. */+memset(cap,0,sizeof(structrte_tm_capabilities));++/**+*supportport+TCs+queues+*hereshowsthemaxcapabilitynotthecurrentconfiguration.+*/+cap->n_nodes_max=1+IAVF_MAX_TRAFFIC_CLASS++vf->num_queue_pairs;+cap->n_levels_max=3;/* port, TC, queue */+cap->non_leaf_nodes_identical=1;+cap->leaf_nodes_identical=1;+cap->shaper_n_max=cap->n_nodes_max;+cap->shaper_private_n_max=cap->n_nodes_max;+cap->shaper_private_dual_rate_n_max=0;+cap->shaper_private_rate_min=0;+/* GBps */+cap->shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->shaper_private_packet_mode_supported=0;+cap->shaper_private_byte_mode_supported=1;+cap->shaper_shared_n_max=0;+cap->shaper_shared_n_nodes_per_shaper_max=0;+cap->shaper_shared_n_shapers_per_node_max=0;+cap->shaper_shared_dual_rate_n_max=0;+cap->shaper_shared_rate_min=0;+cap->shaper_shared_rate_max=0;+cap->shaper_shared_packet_mode_supported=0;+cap->shaper_shared_byte_mode_supported=0;+cap->sched_n_children_max=vf->num_queue_pairs;+cap->sched_sp_n_priorities_max=1;+cap->sched_wfq_n_children_per_group_max=0;+cap->sched_wfq_n_groups_max=0;+cap->sched_wfq_weight_max=1;+cap->sched_wfq_packet_mode_supported=0;+cap->sched_wfq_byte_mode_supported=0;+cap->cman_head_drop_supported=0;+cap->dynamic_update_mask=0;+cap->shaper_pkt_length_adjust_min=RTE_TM_ETH_FRAMING_OVERHEAD;+cap->shaper_pkt_length_adjust_max=RTE_TM_ETH_FRAMING_OVERHEAD_FCS;+cap->cman_wred_context_n_max=0;+cap->cman_wred_context_private_n_max=0;+cap->cman_wred_context_shared_n_max=0;+cap->cman_wred_context_shared_n_nodes_per_context_max=0;+cap->cman_wred_context_shared_n_contexts_per_node_max=0;+cap->stats_mask=0;++return0;+}++staticint+iavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(!cap||!error)+return-EINVAL;++if(level_id>=IAVF_TM_NODE_TYPE_MAX){+error->type=RTE_TM_ERROR_TYPE_LEVEL_ID;+error->message="too deep level";+return-EINVAL;+}++/* root node */+if(level_id==IAVF_TM_NODE_TYPE_PORT){+cap->n_nodes_max=1;+cap->n_nodes_nonleaf_max=1;+cap->n_nodes_leaf_max=0;+}elseif(level_id==IAVF_TM_NODE_TYPE_TC){+/* TC */+cap->n_nodes_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_nonleaf_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_leaf_max=0;+}else{+/* queue */+cap->n_nodes_max=vf->num_queue_pairs;+cap->n_nodes_nonleaf_max=0;+cap->n_nodes_leaf_max=vf->num_queue_pairs;+}++cap->non_leaf_nodes_identical=true;+cap->leaf_nodes_identical=true;++if(level_id!=IAVF_TM_NODE_TYPE_QUEUE){+cap->nonleaf.shaper_private_supported=false;+cap->nonleaf.shaper_private_dual_rate_supported=false;+cap->nonleaf.shaper_private_rate_min=0;+/* GBps */+cap->nonleaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->nonleaf.shaper_private_packet_mode_supported=0;+cap->nonleaf.shaper_private_byte_mode_supported=1;+cap->nonleaf.shaper_shared_n_max=0;+cap->nonleaf.shaper_shared_packet_mode_supported=0;+cap->nonleaf.shaper_shared_byte_mode_supported=0;+if(level_id==IAVF_TM_NODE_TYPE_PORT)+cap->nonleaf.sched_n_children_max=+IAVF_MAX_TRAFFIC_CLASS;+else+cap->nonleaf.sched_n_children_max=+vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+cap->nonleaf.sched_wfq_packet_mode_supported=0;+cap->nonleaf.sched_wfq_byte_mode_supported=0;+cap->nonleaf.stats_mask=0;++return0;+}++/* queue node */+cap->leaf.shaper_private_supported=false;+cap->leaf.shaper_private_dual_rate_supported=false;+cap->leaf.shaper_private_rate_min=0;+/* GBps */+cap->leaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;;+cap->leaf.shaper_private_packet_mode_supported=0;+cap->leaf.shaper_private_byte_mode_supported=1;+cap->leaf.shaper_shared_n_max=0;+cap->leaf.shaper_shared_packet_mode_supported=0;+cap->leaf.shaper_shared_byte_mode_supported=0;+cap->leaf.cman_head_drop_supported=false;+cap->leaf.cman_wred_context_private_supported=true;+cap->leaf.cman_wred_context_shared_n_max=0;+cap->leaf.stats_mask=0;++return0;+}++staticint+iavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type;+structvirtchnl_qos_cap_elemtc_cap;+structiavf_tm_node*tm_node;++if(!cap||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="not support capability get";+return-EINVAL;+}++tc_cap=vf->qos_cap->cap[tm_node->tc];+if(tc_cap.tc_id!=tm_node->tc){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="tc not match";+return-EINVAL;+}++cap->shaper_private_supported=true;+cap->shaper_private_dual_rate_supported=false;+cap->shaper_private_rate_min=tc_cap.shaper.committed;+cap->shaper_private_rate_max=tc_cap.shaper.peak;+cap->shaper_shared_n_max=0;+cap->nonleaf.sched_n_children_max=vf->num_queue_pairs;++if(tc_cap.arbiter==VIRTCHNL_ABITER_ETS){+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=+vf->num_queue_pairs;+cap->nonleaf.sched_wfq_n_groups_max=1;+cap->nonleaf.sched_wfq_weight_max=tc_cap.weight;+}++if(tc_cap.arbiter==VIRTCHNL_ABITER_STRICT){+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+}++cap->stats_mask=0;++return0;+}++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structvirtchnl_queue_tc_mapping*q_tc_mapping;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;+uint16_tsize;+intindex=0,node_committed=0;+intret,i;++size=sizeof(*q_tc_mapping)+sizeof(q_tc_mapping->tc[0])*+(vf->qos_cap->num_elem-1);+q_tc_mapping=rte_zmalloc("q_tc",size,0);+q_tc_mapping->vsi_id=vf->vsi.vsi_id;+q_tc_mapping->num_tc=vf->qos_cap->num_elem;+q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){+q_tc_mapping->tc[tm_node->tc].req.queue_count++;+node_committed++;+}++for(i=0;i<IAVF_MAX_TRAFFIC_CLASS;i++){+q_tc_mapping->tc[i].req.start_queue_id=index;+index+=q_tc_mapping->tc[i].req.queue_count;+}+if(node_committed<vf->num_queue_pairs){+PMD_DRV_LOG(ERR,"queue node is less than allocated queue pairs");+returnIAVF_ERR_PARAM;+}++ret=iavf_set_q_tc_map(dev,q_tc_mapping,size);+if(ret)+returnret;++returnIAVF_SUCCESS;+}
This patch enables the ETS-based Tx QoS for IAVF. Kernel tool is used to
configure ETS first. DCF is used to set bandwidth limit for VFs of each
TC. IAVF is supported to query QoS capability and set queue TC mapping.
Traffic Management API is utilized to configure the QoS hierarchy
scheduler tree. The scheduler tree will be passed to hardware to enable
all above functions.
Ting Xu (5):
common/iavf: support ETS-based QoS offload configuration
net/ice/base: support DCF query port ETS adminq
net/ice: support DCF link status event handling
net/ice: support QoS config VF bandwidth in DCF
net/iavf: query QoS cap and set queue TC mapping
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 125 ++++++
drivers/net/iavf/iavf.h | 45 ++
drivers/net/iavf/iavf_ethdev.c | 31 ++
drivers/net/iavf/iavf_tm.c | 663 +++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
drivers/net/ice/base/ice_dcb.c | 3 +-
drivers/net/ice/ice_dcf.c | 6 +-
drivers/net/ice/ice_dcf.h | 53 +++
drivers/net/ice/ice_dcf_ethdev.c | 67 ++-
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 81 ++++
drivers/net/ice/ice_dcf_sched.c | 688 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
15 files changed, 1820 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
create mode 100644 drivers/net/ice/ice_dcf_sched.c
--
2.25.1
This patch adds new virtchnl opcodes and structures for QoS
configuration, which includes:
1. VIRTCHNL_VF_OFFLOAD_TC, to negotiate the capability supporting QoS
configuration. If VF and PF both have this flag, then the ETS-based QoS
offload function is supported.
2. VIRTCHNL_OP_DCF_CONFIG_BW, DCF is supposed to configure min and max
bandwidth for each VF per enabled TCs. To make the VSI node bandwidth
configuration work, DCF also needs to configure TC node bandwidth
directly.
3. VIRTCHNL_OP_GET_QOS_CAPS, VF queries current QoS configuration, such
as enabled TCs, arbiter type, up2tc and bandwidth of VSI node. The
configuration is previously set by DCB and DCF, and now is the potential
QoS capability of VF. VF can take it as reference to configure queue TC
mapping.
4. VIRTCHNL_OP_CONFIG_TC_MAP, set VF queues to TC mapping for all Tx and
Rx queues. Queues mapping to one TC should be continuous and all
allocated queues should be mapped.
Signed-off-by: Ting Xu <redacted>
---
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 125 ++++++++++++++++++++++++++++++++
2 files changed, 127 insertions(+)
In the adminq command query port ETS function, the root node teid is
needed. However, for DCF, the root node is not initialized, which will
cause error when we refer to the variable. In this patch, we will check
whether the root node is available or not first.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/base/ice_dcb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
When link status changes, DCF will receive virtchnl PF event message.
Add support to handle this event, change link status and update link
info.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.h | 6 ++++
drivers/net/ice/ice_dcf_ethdev.c | 54 ++++++++++++++++++++++++++++++--
drivers/net/ice/ice_dcf_parent.c | 51 ++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 3 deletions(-)
@@ -60,6 +60,10 @@ struct ice_dcf_hw {uint16_tnb_msix;uint16_trxq_map[16];structvirtchnl_eth_statseth_stats_offset;++/* Link status */+boollink_up;+uint32_tlink_speed;};intice_dcf_execute_virtchnl_cmd(structice_dcf_hw*hw,
@@ -880,11 +880,59 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)return0;}-staticint-ice_dcf_link_update(__rte_unusedstructrte_eth_dev*dev,+int+ice_dcf_link_update(structrte_eth_dev*dev,__rte_unusedintwait_to_complete){-return0;+structice_dcf_adapter*ad=dev->data->dev_private;+structice_dcf_hw*hw=&ad->real_hw;+structrte_eth_linknew_link;++memset(&new_link,0,sizeof(new_link));++/* Only read status info stored in VF, and the info is updated+*whenreceiveLINK_CHANGEeventfromPFbyvirtchnl.+*/+switch(hw->link_speed){+case10:+new_link.link_speed=ETH_SPEED_NUM_10M;+break;+case100:+new_link.link_speed=ETH_SPEED_NUM_100M;+break;+case1000:+new_link.link_speed=ETH_SPEED_NUM_1G;+break;+case10000:+new_link.link_speed=ETH_SPEED_NUM_10G;+break;+case20000:+new_link.link_speed=ETH_SPEED_NUM_20G;+break;+case25000:+new_link.link_speed=ETH_SPEED_NUM_25G;+break;+case40000:+new_link.link_speed=ETH_SPEED_NUM_40G;+break;+case50000:+new_link.link_speed=ETH_SPEED_NUM_50G;+break;+case100000:+new_link.link_speed=ETH_SPEED_NUM_100G;+break;+default:+new_link.link_speed=ETH_SPEED_NUM_NONE;+break;+}++new_link.link_duplex=ETH_LINK_FULL_DUPLEX;+new_link.link_status=hw->link_up?ETH_LINK_UP:+ETH_LINK_DOWN;+new_link.link_autoneg=!(dev->data->dev_conf.link_speeds&+ETH_LINK_SPEED_FIXED);++returnrte_eth_linkstatus_set(dev,&new_link);}/* Add UDP tunneling port */
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.c | 6 +-
drivers/net/ice/ice_dcf.h | 47 +++
drivers/net/ice/ice_dcf_ethdev.c | 13 +
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 30 ++
drivers/net/ice/ice_dcf_sched.c | 688 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 788 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_sched.c
@@ -30,6 +31,49 @@ struct dcf_virtchnl_cmd {volatileintpending;};+structice_dcf_tm_shaper_profile{+TAILQ_ENTRY(ice_dcf_tm_shaper_profile)node;+uint32_tshaper_profile_id;+uint32_treference_count;+structrte_tm_shaper_paramsprofile;+};++TAILQ_HEAD(ice_dcf_shaper_profile_list,ice_dcf_tm_shaper_profile);++/* Struct to store Traffic Manager node configuration. */+structice_dcf_tm_node{+TAILQ_ENTRY(ice_dcf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structice_dcf_tm_node*parent;+structice_dcf_tm_shaper_profile*shaper_profile;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(ice_dcf_tm_node_list,ice_dcf_tm_node);++/* node type of Traffic Manager */+enumice_dcf_tm_node_type{+ICE_DCF_TM_NODE_TYPE_PORT,+ICE_DCF_TM_NODE_TYPE_TC,+ICE_DCF_TM_NODE_TYPE_VSI,+ICE_DCF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structice_dcf_tm_conf{+structice_dcf_shaper_profile_listshaper_profile_list;+structice_dcf_tm_node*root;/* root node - port */+structice_dcf_tm_node_listtc_list;/* node list for all the TCs */+structice_dcf_tm_node_listvsi_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_vsi_node;+boolcommitted;+};+structice_dcf_hw{structiavf_hwavf;
@@ -45,6 +89,8 @@ struct ice_dcf_hw {uint16_t*vf_vsi_map;uint16_tpf_vsi_id;+structice_dcf_tm_conftm_conf;+structice_aqc_port_ets_elem*ets_config;structvirtchnl_version_infovirtchnl_version;structvirtchnl_vf_resource*vf_res;/* VF resource */structvirtchnl_vsi_resource*vsi_res;/* LAN VSI */
@@ -487,6 +510,13 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)returnerr;}+err=ice_dcf_query_port_ets(parent_hw,hw);+if(err){+PMD_INIT_LOG(ERR,"failed to query port ets with error %d",+err);+gotouninit_hw;+}+err=ice_dcf_load_pkg(parent_hw);if(err){PMD_INIT_LOG(ERR,"failed to load package with error %d",
@@ -0,0 +1,688 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"base/ice_sched.h"+#include"ice_dcf_ethdev.h"++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error);++conststructrte_tm_opsice_dcf_tm_ops={+.shaper_profile_add=ice_dcf_shaper_profile_add,+.shaper_profile_delete=ice_dcf_shaper_profile_del,+.hierarchy_commit=ice_dcf_hierarchy_commit,+.node_add=ice_dcf_node_add,+.node_delete=ice_dcf_node_delete,+};++void+ice_dcf_tm_conf_init(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;++/* initialize shaper profile list */+TAILQ_INIT(&hw->tm_conf.shaper_profile_list);++/* initialize node configuration */+hw->tm_conf.root=NULL;+TAILQ_INIT(&hw->tm_conf.tc_list);+TAILQ_INIT(&hw->tm_conf.vsi_list);+hw->tm_conf.nb_tc_node=0;+hw->tm_conf.nb_vsi_node=0;+hw->tm_conf.committed=false;+}++staticinlinestructice_dcf_tm_node*+dcf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumice_dcf_tm_node_type*node_type)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structice_dcf_tm_node_list*tc_list=&hw->tm_conf.tc_list;+structice_dcf_tm_node*tm_node;++if(hw->tm_conf.root&&hw->tm_conf.root->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_PORT;+returnhw->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,vsi_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_VSI;+returntm_node;+}+}++returnNULL;+}++staticinlinestructice_dcf_tm_shaper_profile*+dcf_shaper_profile_search(structrte_eth_dev*dev,+uint32_tshaper_profile_id)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_shaper_profile_list*shaper_profile_list=+&hw->tm_conf.shaper_profile_list;+structice_dcf_tm_shaper_profile*shaper_profile;++TAILQ_FOREACH(shaper_profile,shaper_profile_list,node){+if(shaper_profile_id==shaper_profile->shaper_profile_id)+returnshaper_profile;+}++returnNULL;+}++staticint+dcf_node_param_check(structice_dcf_hw*hw,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=8*hw->num_vfs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typeparent_node_type=ICE_DCF_TM_NODE_TYPE_MAX;+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_tm_shaper_profile*shaper_profile=NULL;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*parent_node;+structice_dcf_tm_node*tm_node;+uint16_ttc_nb=1;+inti,ret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=dcf_node_param_check(hw,node_id,priority,weight,+params,error);+if(ret)+returnret;++for(i=1;i<ICE_MAX_TRAFFIC_CLASS;i++){+if(hw->ets_config->tc_valid_bits&(1<<i))+tc_nb++;+}++/* check if the node is already existed */+if(dcf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* check the shaper profile id */+if(params->shaper_profile_id!=RTE_TM_SHAPER_PROFILE_ID_NONE){+shaper_profile=dcf_shaper_profile_search(dev,+params->shaper_profile_id);+if(!shaper_profile){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not exist";+return-EINVAL;+}+}++/* add root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=ICE_DCF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(hw->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+hw->tm_conf.root=tm_node;++return0;+}++/* TC or vsi node */+/* check the parent node */+parent_node=dcf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=ICE_DCF_TM_NODE_TYPE_PORT&&+parent_node_type!=ICE_DCF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not port or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the TC node number */+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(hw->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the vsi node number */+if(parent_node->reference_count>=hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many VSI for one TC";+return-EINVAL;+}+/* check the vsi node id */+if(node_id>tc_nb*hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large VSI id";+return-EINVAL;+}+}++/* add the TC or vsi node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->priority=priority;+tm_node->weight=weight;+tm_node->shaper_profile=shaper_profile;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,+tm_node,node);+tm_node->tc=hw->tm_conf.nb_tc_node;+hw->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,+tm_node,node);+tm_node->tc=parent_node->tc;+hw->tm_conf.nb_vsi_node++;+}+tm_node->parent->reference_count++;++/* increase the reference counter of the shaper profile */+if(shaper_profile)+shaper_profile->reference_count++;++return0;+}++staticint+ice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=dcf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==ICE_DCF_TM_NODE_TYPE_PORT){+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+rte_free(tm_node);+hw->tm_conf.root=NULL;+return0;+}++/* TC or VSI node */+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+tm_node->parent->reference_count--;+if(node_type==ICE_DCF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+hw->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+hw->tm_conf.nb_vsi_node--;+}+rte_free(tm_node);++return0;+}++staticint+dcf_shaper_profile_param_check(structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+/* min bucket size not supported */+if(profile->committed.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;+error->message="committed bucket size not supported";+return-EINVAL;+}+/* max bucket size not supported */+if(profile->peak.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;+error->message="peak bucket size not supported";+return-EINVAL;+}+/* length adjustment not supported */+if(profile->pkt_length_adjust){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;+error->message="packet length adjustment not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+intret;++if(!profile||!error)+return-EINVAL;++ret=dcf_shaper_profile_param_check(profile,error);+if(ret)+returnret;++shaper_profile=dcf_shaper_profile_search(dev,shaper_profile_id);++if(shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID exist";+return-EINVAL;+}++shaper_profile=rte_zmalloc("ice_dcf_tm_shaper_profile",+sizeof(structice_dcf_tm_shaper_profile),+0);+if(!shaper_profile)+return-ENOMEM;+shaper_profile->shaper_profile_id=shaper_profile_id;+rte_memcpy(&shaper_profile->profile,profile,+sizeof(structrte_tm_shaper_params));+TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);++return0;+}++staticint+ice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;++if(!error)+return-EINVAL;++shaper_profile=dcf_shaper_profile_search(dev,shaper_profile_id);++if(!shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID not exist";+return-EINVAL;+}++/* don't delete a profile if it's used by one or several nodes */+if(shaper_profile->reference_count){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE;+error->message="profile in use";+return-EINVAL;+}++TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,shaper_profile,node);+rte_free(shaper_profile);++return0;+}++staticint+ice_dcf_set_vf_bw(structice_dcf_hw*hw,+structvirtchnl_dcf_bw_cfg_list*vf_bw,+uint16_tlen)+{+structdcf_virtchnl_cmdargs;+interr;++memset(&args,0,sizeof(args));+args.v_op=VIRTCHNL_OP_DCF_CONFIG_BW;+args.req_msg=(uint8_t*)vf_bw;+args.req_msglen=len;+err=ice_dcf_execute_virtchnl_cmd(hw,&args);+if(err)+PMD_DRV_LOG(ERR,"fail to execute command %s",+"VIRTCHNL_OP_DCF_CONFIG_VF_TC");+returnerr;+}++staticint+ice_dcf_validate_tc_bw(structvirtchnl_dcf_bw_cfg_list*tc_bw,+uint32_tport_bw)+{+structvirtchnl_dcf_bw_cfg*cfg;+boollowest_cir_mark=false;+u32total_peak,rest_peak;+u32committed,peak;+inti;++total_peak=0;+for(i=0;i<tc_bw->num_elem;i++)+total_peak+=tc_bw->cfg[i].shaper.peak;++for(i=0;i<tc_bw->num_elem;i++){+cfg=&tc_bw->cfg[i];+peak=cfg->shaper.peak;+committed=cfg->shaper.committed;+rest_peak=total_peak-peak;++if(lowest_cir_mark&&peak==0){+PMD_DRV_LOG(ERR,"Max bandwidth must be configured for TC%u \n",+cfg->tc_id);+return-EINVAL;+}++if(!lowest_cir_mark&&committed)+lowest_cir_mark=true;++if(committed&&committed+rest_peak>port_bw){+PMD_DRV_LOG(ERR,"Total value of TC%u min bandwidth and other TCs' max bandwidth %ukbps should be less than port link speed %ukbps \n",+cfg->tc_id,committed+rest_peak,port_bw);+return-EINVAL;+}++if(committed&&committed<ICE_SCHED_MIN_BW){+PMD_DRV_LOG(ERR,"If TC%u min Tx bandwidth is set, it cannot be less than 500Kbps \n",+cfg->tc_id);+return-EINVAL;+}++if(peak&&committed>peak){+PMD_DRV_LOG(ERR,"TC%u Min Tx bandwidth cannot be greater than max Tx bandwidth \n",+cfg->tc_id);+return-EINVAL;+}++if(peak>port_bw){+PMD_DRV_LOG(ERR,"TC%u max Tx bandwidth %uKbps is greater than current link speed %uKbps \n",+cfg->tc_id,peak,port_bw);+return-EINVAL;+}+}++return0;+}+staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structvirtchnl_dcf_bw_cfg_list*vf_bw;+structvirtchnl_dcf_bw_cfg_list*tc_bw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structrte_tm_shaper_params*profile;+structice_dcf_tm_node*tm_node;+uint32_tport_bw,cir_total;+uint16_tsize,vf_id;+intnum_elem=0;+intret,i;++size=sizeof(structvirtchnl_dcf_bw_cfg_list)++sizeof(structvirtchnl_dcf_bw_cfg)*+(hw->tm_conf.nb_tc_node-1);+vf_bw=rte_zmalloc("vf_bw",size,0);+if(!vf_bw)+returnICE_ERR_NO_MEMORY;+tc_bw=rte_zmalloc("tc_bw",size,0);+if(!tc_bw)+returnICE_ERR_NO_MEMORY;++/* port bandwidth (Kbps) */+port_bw=hw->link_speed*1000;+cir_total=0;++/* init tc bw configuration */+tc_bw->vf_id=VIRTCHNL_DCF_TC_LEVEL;+tc_bw->num_elem=hw->tm_conf.nb_tc_node;+for(i=0;i<tc_bw->num_elem;i++){+tc_bw->cfg[i].tc_id=i;+tc_bw->cfg[i].type=VIRTCHNL_BW_SHAPER;+}++for(vf_id=0;vf_id<hw->num_vfs;vf_id++){+num_elem=0;+vf_bw->vf_id=vf_id;+TAILQ_FOREACH(tm_node,vsi_list,node){+/* scan the nodes belong to one VSI */+if(tm_node->id-hw->num_vfs*tm_node->tc!=vf_id)+continue;+vf_bw->cfg[num_elem].tc_id=tm_node->tc;+vf_bw->cfg[num_elem].type=VIRTCHNL_BW_SHAPER;+if(tm_node->shaper_profile){+/* Transfer from Byte per seconds to Kbps */+profile=&tm_node->shaper_profile->profile;+vf_bw->cfg[num_elem].shaper.peak=+profile->peak.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].shaper.committed=+profile->committed.rate/1000*BITS_PER_BYTE;+}+cir_total+=vf_bw->cfg[num_elem].shaper.committed;+num_elem++;++/* update tc node bw configuration */+tc_bw->cfg[tm_node->tc].shaper.peak+=+vf_bw->cfg[num_elem].shaper.peak;+tc_bw->cfg[tm_node->tc].shaper.committed+=+vf_bw->cfg[num_elem].shaper.committed;+}++/* check if total CIR is larger than port bandwidth */+if(cir_total>port_bw){+PMD_DRV_LOG(ERR,"Total CIR of all VFs is larger than port bandwidth");+returnICE_ERR_PARAM;+}+vf_bw->num_elem=num_elem;+ret=ice_dcf_set_vf_bw(hw,vf_bw,size);+if(ret)+returnret;+memset(vf_bw,0,size);+}++/* check and commit tc node bw configuration */+ret=ice_dcf_validate_tc_bw(tc_bw,port_bw);+if(ret)+returnret;+ret=ice_dcf_set_vf_bw(hw,tc_bw,size);+if(ret)+returnret;++hw->tm_conf.committed=true;+returnICE_SUCCESS;+}
This patch added the support for VF to config the ETS-based Tx QoS,
including querying current QoS configuration from PF and config queue TC
mapping. PF QoS is configured in advance and the queried info is
provided to the user for future usage. VF queues are mapped to different
TCs in PF through virtchnl.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 45 +++
drivers/net/iavf/iavf_ethdev.c | 31 ++
drivers/net/iavf/iavf_tm.c | 663 +++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
5 files changed, 795 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
@@ -129,6 +133,38 @@ enum iavf_aq_result {IAVF_MSG_CMD,/* Read async command result */};+/* Struct to store Traffic Manager node configuration. */+structiavf_tm_node{+TAILQ_ENTRY(iavf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structiavf_tm_node*parent;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(iavf_tm_node_list,iavf_tm_node);++/* node type of Traffic Manager */+enumiavf_tm_node_type{+IAVF_TM_NODE_TYPE_PORT,+IAVF_TM_NODE_TYPE_TC,+IAVF_TM_NODE_TYPE_QUEUE,+IAVF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structiavf_tm_conf{+structiavf_tm_node*root;/* root node - vf vsi */+structiavf_tm_node_listtc_list;/* node list for all the TCs */+structiavf_tm_node_listqueue_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_queue_node;+boolcommitted;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -175,6 +211,9 @@ struct iavf_info {structiavf_fdir_infofdir;/* flow director info *//* indicate large VF support enabled or not */boollv_enabled;++structvirtchnl_qos_cap_list*qos_cap;+structiavf_tm_conftm_conf;};#define IAVF_MAX_PKT_TYPE 1024
@@ -806,6 +820,11 @@ iavf_dev_start(struct rte_eth_dev *dev)dev->data->nb_tx_queues);num_queue_pairs=vf->num_queue_pairs;+if(iavf_get_qos_cap(adapter)){+PMD_INIT_LOG(ERR,"Failed to get qos capability");+return-1;+}+if(iavf_init_queues(dev)!=0){PMD_DRV_LOG(ERR,"failed to do Queue init");return-1;
@@ -2090,6 +2109,15 @@ iavf_init_vf(struct rte_eth_dev *dev)PMD_INIT_LOG(ERR,"unable to allocate vf_res memory");gotoerr_api;}++bufsz=sizeof(structvirtchnl_qos_cap_list)++IAVF_MAX_TRAFFIC_CLASS*sizeof(structvirtchnl_qos_cap_elem);+vf->qos_cap=rte_zmalloc("qos_cap",bufsz,0);+if(!vf->qos_cap){+PMD_INIT_LOG(ERR,"unable to allocate qos_cap memory");+gotoerr_api;+}+if(iavf_get_vf_resource(adapter)!=0){PMD_INIT_LOG(ERR,"iavf_get_vf_config failed");gotoerr_alloc;
@@ -0,0 +1,663 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"iavf.h"++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintiavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintiavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintiavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error);+staticintiavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error);++conststructrte_tm_opsiavf_tm_ops={+.node_add=iavf_tm_node_add,+.node_delete=iavf_tm_node_delete,+.capabilities_get=iavf_tm_capabilities_get,+.level_capabilities_get=iavf_level_capabilities_get,+.node_capabilities_get=iavf_node_capabilities_get,+.node_type_get=iavf_node_type_get,+.hierarchy_commit=iavf_hierarchy_commit,+};++void+iavf_tm_conf_init(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++/* initialize node configuration */+vf->tm_conf.root=NULL;+TAILQ_INIT(&vf->tm_conf.tc_list);+TAILQ_INIT(&vf->tm_conf.queue_list);+vf->tm_conf.nb_tc_node=0;+vf->tm_conf.nb_queue_node=0;+vf->tm_conf.committed=false;+}+++staticinlinestructiavf_tm_node*+iavf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumiavf_tm_node_type*node_type)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node_list*tc_list=&vf->tm_conf.tc_list;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;++if(vf->tm_conf.root&&vf->tm_conf.root->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_PORT;+returnvf->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_QUEUE;+returntm_node;+}+}++returnNULL;+}++staticint+iavf_node_param_check(structiavf_info*vf,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shaper profile */+if(params->shaper_profile_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not supported";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=vf->num_queue_pairs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+iavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error)+{+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!is_leaf||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type==IAVF_TM_NODE_TYPE_QUEUE)+*is_leaf=true;+else+*is_leaf=false;++return0;+}++staticint+iavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+enumiavf_tm_node_typeparent_node_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;+structiavf_tm_node*parent_node;+uint16_ttc_nb=vf->qos_cap->num_elem;+intret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=iavf_node_param_check(vf,node_id,priority,weight,+params,error);+if(ret)+returnret;++/* check if the node is already existed */+if(iavf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=IAVF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(vf->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+vf->tm_conf.root=tm_node;+return0;+}++/* TC or queue node */+/* check the parent node */+parent_node=iavf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=IAVF_TM_NODE_TYPE_PORT&&+parent_node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not root or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the node number */+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(vf->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the queue number */+if(parent_node->reference_count>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many queues";+return-EINVAL;+}+if(node_id>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large queue id";+return-EINVAL;+}+}++/* add the TC or queue node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&vf->tm_conf.tc_list,+tm_node,node);+tm_node->tc=vf->tm_conf.nb_tc_node;+vf->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&vf->tm_conf.queue_list,+tm_node,node);+tm_node->tc=parent_node->tc;+vf->tm_conf.nb_queue_node++;+}+tm_node->parent->reference_count++;++return0;+}++staticint+iavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==IAVF_TM_NODE_TYPE_PORT){+rte_free(tm_node);+vf->tm_conf.root=NULL;+return0;+}++/* TC or queue node */+tm_node->parent->reference_count--;+if(node_type==IAVF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+vf->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+vf->tm_conf.nb_queue_node--;+}+rte_free(tm_node);++return0;+}++staticint+iavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_ttc_nb=vf->qos_cap->num_elem;++if(!cap||!error)+return-EINVAL;++if(tc_nb>vf->vf_res->num_queue_pairs)+return-EINVAL;++error->type=RTE_TM_ERROR_TYPE_NONE;++/* set all the parameters to 0 first. */+memset(cap,0,sizeof(structrte_tm_capabilities));++/**+*supportport+TCs+queues+*hereshowsthemaxcapabilitynotthecurrentconfiguration.+*/+cap->n_nodes_max=1+IAVF_MAX_TRAFFIC_CLASS++vf->num_queue_pairs;+cap->n_levels_max=3;/* port, TC, queue */+cap->non_leaf_nodes_identical=1;+cap->leaf_nodes_identical=1;+cap->shaper_n_max=cap->n_nodes_max;+cap->shaper_private_n_max=cap->n_nodes_max;+cap->shaper_private_dual_rate_n_max=0;+cap->shaper_private_rate_min=0;+/* GBps */+cap->shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->shaper_private_packet_mode_supported=0;+cap->shaper_private_byte_mode_supported=1;+cap->shaper_shared_n_max=0;+cap->shaper_shared_n_nodes_per_shaper_max=0;+cap->shaper_shared_n_shapers_per_node_max=0;+cap->shaper_shared_dual_rate_n_max=0;+cap->shaper_shared_rate_min=0;+cap->shaper_shared_rate_max=0;+cap->shaper_shared_packet_mode_supported=0;+cap->shaper_shared_byte_mode_supported=0;+cap->sched_n_children_max=vf->num_queue_pairs;+cap->sched_sp_n_priorities_max=1;+cap->sched_wfq_n_children_per_group_max=0;+cap->sched_wfq_n_groups_max=0;+cap->sched_wfq_weight_max=1;+cap->sched_wfq_packet_mode_supported=0;+cap->sched_wfq_byte_mode_supported=0;+cap->cman_head_drop_supported=0;+cap->dynamic_update_mask=0;+cap->shaper_pkt_length_adjust_min=RTE_TM_ETH_FRAMING_OVERHEAD;+cap->shaper_pkt_length_adjust_max=RTE_TM_ETH_FRAMING_OVERHEAD_FCS;+cap->cman_wred_context_n_max=0;+cap->cman_wred_context_private_n_max=0;+cap->cman_wred_context_shared_n_max=0;+cap->cman_wred_context_shared_n_nodes_per_context_max=0;+cap->cman_wred_context_shared_n_contexts_per_node_max=0;+cap->stats_mask=0;++return0;+}++staticint+iavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(!cap||!error)+return-EINVAL;++if(level_id>=IAVF_TM_NODE_TYPE_MAX){+error->type=RTE_TM_ERROR_TYPE_LEVEL_ID;+error->message="too deep level";+return-EINVAL;+}++/* root node */+if(level_id==IAVF_TM_NODE_TYPE_PORT){+cap->n_nodes_max=1;+cap->n_nodes_nonleaf_max=1;+cap->n_nodes_leaf_max=0;+}elseif(level_id==IAVF_TM_NODE_TYPE_TC){+/* TC */+cap->n_nodes_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_nonleaf_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_leaf_max=0;+}else{+/* queue */+cap->n_nodes_max=vf->num_queue_pairs;+cap->n_nodes_nonleaf_max=0;+cap->n_nodes_leaf_max=vf->num_queue_pairs;+}++cap->non_leaf_nodes_identical=true;+cap->leaf_nodes_identical=true;++if(level_id!=IAVF_TM_NODE_TYPE_QUEUE){+cap->nonleaf.shaper_private_supported=true;+cap->nonleaf.shaper_private_dual_rate_supported=false;+cap->nonleaf.shaper_private_rate_min=0;+/* GBps */+cap->nonleaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->nonleaf.shaper_private_packet_mode_supported=0;+cap->nonleaf.shaper_private_byte_mode_supported=1;+cap->nonleaf.shaper_shared_n_max=0;+cap->nonleaf.shaper_shared_packet_mode_supported=0;+cap->nonleaf.shaper_shared_byte_mode_supported=0;+if(level_id==IAVF_TM_NODE_TYPE_PORT)+cap->nonleaf.sched_n_children_max=+IAVF_MAX_TRAFFIC_CLASS;+else+cap->nonleaf.sched_n_children_max=+vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+cap->nonleaf.sched_wfq_packet_mode_supported=0;+cap->nonleaf.sched_wfq_byte_mode_supported=0;+cap->nonleaf.stats_mask=0;++return0;+}++/* queue node */+cap->leaf.shaper_private_supported=false;+cap->leaf.shaper_private_dual_rate_supported=false;+cap->leaf.shaper_private_rate_min=0;+/* GBps */+cap->leaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->leaf.shaper_private_packet_mode_supported=0;+cap->leaf.shaper_private_byte_mode_supported=1;+cap->leaf.shaper_shared_n_max=0;+cap->leaf.shaper_shared_packet_mode_supported=0;+cap->leaf.shaper_shared_byte_mode_supported=0;+cap->leaf.cman_head_drop_supported=false;+cap->leaf.cman_wred_context_private_supported=true;+cap->leaf.cman_wred_context_shared_n_max=0;+cap->leaf.stats_mask=0;++return0;+}++staticint+iavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type;+structvirtchnl_qos_cap_elemtc_cap;+structiavf_tm_node*tm_node;++if(!cap||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="not support capability get";+return-EINVAL;+}++tc_cap=vf->qos_cap->cap[tm_node->tc];+if(tc_cap.tc_id!=tm_node->tc){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="tc not match";+return-EINVAL;+}++cap->shaper_private_supported=true;+cap->shaper_private_dual_rate_supported=false;+cap->shaper_private_rate_min=tc_cap.shaper.committed;+cap->shaper_private_rate_max=tc_cap.shaper.peak;+cap->shaper_shared_n_max=0;+cap->nonleaf.sched_n_children_max=vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=1;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=tc_cap.weight;+cap->stats_mask=0;++return0;+}++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structvirtchnl_queue_tc_mapping*q_tc_mapping;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;+uint16_tsize;+intindex=0,node_committed=0;+intret,i;++size=sizeof(*q_tc_mapping)+sizeof(q_tc_mapping->tc[0])*+(vf->qos_cap->num_elem-1);+q_tc_mapping=rte_zmalloc("q_tc",size,0);+q_tc_mapping->vsi_id=vf->vsi.vsi_id;+q_tc_mapping->num_tc=vf->qos_cap->num_elem;+q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){+q_tc_mapping->tc[tm_node->tc].req.queue_count++;+node_committed++;+}++for(i=0;i<IAVF_MAX_TRAFFIC_CLASS;i++){+q_tc_mapping->tc[i].req.start_queue_id=index;+index+=q_tc_mapping->tc[i].req.queue_count;+}+if(node_committed<vf->num_queue_pairs){+PMD_DRV_LOG(ERR,"queue node is less than allocated queue pairs");+returnIAVF_ERR_PARAM;+}++ret=iavf_set_q_tc_map(dev,q_tc_mapping,size);+if(ret)+returnret;++returnIAVF_SUCCESS;+}
This patch enables the ETS-based Tx QoS for IAVF. Kernel tool is used to
configure ETS first. DCF is used to set bandwidth limit for VFs of each
TC. IAVF is supported to query QoS capability and set queue TC mapping.
Traffic Management API is utilized to configure the QoS hierarchy
scheduler tree. The scheduler tree will be passed to hardware to enable
all above functions.
Ting Xu (5):
common/iavf: support ETS-based QoS offload configuration
net/ice/base: support DCF query port ETS adminq
net/ice: support DCF link status event handling
net/ice: support QoS config VF bandwidth in DCF
net/iavf: query QoS cap and set queue TC mapping
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 ++++++
drivers/net/iavf/iavf.h | 45 ++
drivers/net/iavf/iavf_ethdev.c | 31 ++
drivers/net/iavf/iavf_tm.c | 667 +++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
drivers/net/ice/base/ice_dcb.c | 3 +-
drivers/net/ice/ice_dcf.c | 6 +-
drivers/net/ice/ice_dcf.h | 53 +++
drivers/net/ice/ice_dcf_ethdev.c | 67 ++-
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 81 ++++
drivers/net/ice/ice_dcf_sched.c | 697 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
15 files changed, 1839 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
create mode 100644 drivers/net/ice/ice_dcf_sched.c
--
2.25.1
This patch adds new virtchnl opcodes and structures for QoS
configuration, which includes:
1. VIRTCHNL_VF_OFFLOAD_TC, to negotiate the capability supporting QoS
configuration. If VF and PF both have this flag, then the ETS-based QoS
offload function is supported.
2. VIRTCHNL_OP_DCF_CONFIG_BW, DCF is supposed to configure min and max
bandwidth for each VF per enabled TCs. To make the VSI node bandwidth
configuration work, DCF also needs to configure TC node bandwidth
directly.
3. VIRTCHNL_OP_GET_QOS_CAPS, VF queries current QoS configuration, such
as enabled TCs, arbiter type, up2tc and bandwidth of VSI node. The
configuration is previously set by DCB and DCF, and now is the potential
QoS capability of VF. VF can take it as reference to configure queue TC
mapping.
4. VIRTCHNL_OP_CONFIG_TC_MAP, set VF queues to TC mapping for all Tx and
Rx queues. Queues mapping to one TC should be continuous and all
allocated queues should be mapped.
Signed-off-by: Ting Xu <redacted>
---
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 ++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
In the adminq command query port ETS function, the root node teid is
needed. However, for DCF, the root node is not initialized, which will
cause error when we refer to the variable. In this patch, we will check
whether the root node is available or not first.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/base/ice_dcb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
When link status changes, DCF will receive virtchnl PF event message.
Add support to handle this event, change link status and update link
info.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.h | 6 ++++
drivers/net/ice/ice_dcf_ethdev.c | 54 ++++++++++++++++++++++++++++++--
drivers/net/ice/ice_dcf_parent.c | 51 ++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 3 deletions(-)
@@ -60,6 +60,10 @@ struct ice_dcf_hw {uint16_tnb_msix;uint16_trxq_map[16];structvirtchnl_eth_statseth_stats_offset;++/* Link status */+boollink_up;+uint32_tlink_speed;};intice_dcf_execute_virtchnl_cmd(structice_dcf_hw*hw,
@@ -881,11 +881,59 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)return0;}-staticint-ice_dcf_link_update(__rte_unusedstructrte_eth_dev*dev,+int+ice_dcf_link_update(structrte_eth_dev*dev,__rte_unusedintwait_to_complete){-return0;+structice_dcf_adapter*ad=dev->data->dev_private;+structice_dcf_hw*hw=&ad->real_hw;+structrte_eth_linknew_link;++memset(&new_link,0,sizeof(new_link));++/* Only read status info stored in VF, and the info is updated+*whenreceiveLINK_CHANGEeventfromPFbyvirtchnl.+*/+switch(hw->link_speed){+case10:+new_link.link_speed=ETH_SPEED_NUM_10M;+break;+case100:+new_link.link_speed=ETH_SPEED_NUM_100M;+break;+case1000:+new_link.link_speed=ETH_SPEED_NUM_1G;+break;+case10000:+new_link.link_speed=ETH_SPEED_NUM_10G;+break;+case20000:+new_link.link_speed=ETH_SPEED_NUM_20G;+break;+case25000:+new_link.link_speed=ETH_SPEED_NUM_25G;+break;+case40000:+new_link.link_speed=ETH_SPEED_NUM_40G;+break;+case50000:+new_link.link_speed=ETH_SPEED_NUM_50G;+break;+case100000:+new_link.link_speed=ETH_SPEED_NUM_100G;+break;+default:+new_link.link_speed=ETH_SPEED_NUM_NONE;+break;+}++new_link.link_duplex=ETH_LINK_FULL_DUPLEX;+new_link.link_status=hw->link_up?ETH_LINK_UP:+ETH_LINK_DOWN;+new_link.link_autoneg=!(dev->data->dev_conf.link_speeds&+ETH_LINK_SPEED_FIXED);++returnrte_eth_linkstatus_set(dev,&new_link);}/* Add UDP tunneling port */
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.c | 6 +-
drivers/net/ice/ice_dcf.h | 47 +++
drivers/net/ice/ice_dcf_ethdev.c | 13 +
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 30 ++
drivers/net/ice/ice_dcf_sched.c | 697 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 797 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_sched.c
@@ -30,6 +31,49 @@ struct dcf_virtchnl_cmd {volatileintpending;};+structice_dcf_tm_shaper_profile{+TAILQ_ENTRY(ice_dcf_tm_shaper_profile)node;+uint32_tshaper_profile_id;+uint32_treference_count;+structrte_tm_shaper_paramsprofile;+};++TAILQ_HEAD(ice_dcf_shaper_profile_list,ice_dcf_tm_shaper_profile);++/* Struct to store Traffic Manager node configuration. */+structice_dcf_tm_node{+TAILQ_ENTRY(ice_dcf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structice_dcf_tm_node*parent;+structice_dcf_tm_shaper_profile*shaper_profile;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(ice_dcf_tm_node_list,ice_dcf_tm_node);++/* node type of Traffic Manager */+enumice_dcf_tm_node_type{+ICE_DCF_TM_NODE_TYPE_PORT,+ICE_DCF_TM_NODE_TYPE_TC,+ICE_DCF_TM_NODE_TYPE_VSI,+ICE_DCF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structice_dcf_tm_conf{+structice_dcf_shaper_profile_listshaper_profile_list;+structice_dcf_tm_node*root;/* root node - port */+structice_dcf_tm_node_listtc_list;/* node list for all the TCs */+structice_dcf_tm_node_listvsi_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_vsi_node;+boolcommitted;+};+structice_dcf_hw{structiavf_hwavf;
@@ -45,6 +89,8 @@ struct ice_dcf_hw {uint16_t*vf_vsi_map;uint16_tpf_vsi_id;+structice_dcf_tm_conftm_conf;+structice_aqc_port_ets_elem*ets_config;structvirtchnl_version_infovirtchnl_version;structvirtchnl_vf_resource*vf_res;/* VF resource */structvirtchnl_vsi_resource*vsi_res;/* LAN VSI */
@@ -486,6 +509,13 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)returnerr;}+err=ice_dcf_query_port_ets(parent_hw,hw);+if(err){+PMD_INIT_LOG(ERR,"failed to query port ets with error %d",+err);+gotouninit_hw;+}+err=ice_dcf_load_pkg(parent_hw);if(err){PMD_INIT_LOG(ERR,"failed to load package with error %d",
@@ -0,0 +1,697 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"base/ice_sched.h"+#include"ice_dcf_ethdev.h"++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error);++conststructrte_tm_opsice_dcf_tm_ops={+.shaper_profile_add=ice_dcf_shaper_profile_add,+.shaper_profile_delete=ice_dcf_shaper_profile_del,+.hierarchy_commit=ice_dcf_hierarchy_commit,+.node_add=ice_dcf_node_add,+.node_delete=ice_dcf_node_delete,+};++void+ice_dcf_tm_conf_init(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;++/* initialize shaper profile list */+TAILQ_INIT(&hw->tm_conf.shaper_profile_list);++/* initialize node configuration */+hw->tm_conf.root=NULL;+TAILQ_INIT(&hw->tm_conf.tc_list);+TAILQ_INIT(&hw->tm_conf.vsi_list);+hw->tm_conf.nb_tc_node=0;+hw->tm_conf.nb_vsi_node=0;+hw->tm_conf.committed=false;+}++staticinlinestructice_dcf_tm_node*+dcf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumice_dcf_tm_node_type*node_type)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structice_dcf_tm_node_list*tc_list=&hw->tm_conf.tc_list;+structice_dcf_tm_node*tm_node;++if(hw->tm_conf.root&&hw->tm_conf.root->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_PORT;+returnhw->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,vsi_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_VSI;+returntm_node;+}+}++returnNULL;+}++staticinlinestructice_dcf_tm_shaper_profile*+dcf_shaper_profile_search(structrte_eth_dev*dev,+uint32_tshaper_profile_id)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_shaper_profile_list*shaper_profile_list=+&hw->tm_conf.shaper_profile_list;+structice_dcf_tm_shaper_profile*shaper_profile;++TAILQ_FOREACH(shaper_profile,shaper_profile_list,node){+if(shaper_profile_id==shaper_profile->shaper_profile_id)+returnshaper_profile;+}++returnNULL;+}++staticint+dcf_node_param_check(structice_dcf_hw*hw,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=8*hw->num_vfs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typeparent_node_type=ICE_DCF_TM_NODE_TYPE_MAX;+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_tm_shaper_profile*shaper_profile=NULL;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*parent_node;+structice_dcf_tm_node*tm_node;+uint16_ttc_nb=1;+inti,ret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=dcf_node_param_check(hw,node_id,priority,weight,+params,error);+if(ret)+returnret;++for(i=1;i<ICE_MAX_TRAFFIC_CLASS;i++){+if(hw->ets_config->tc_valid_bits&(1<<i))+tc_nb++;+}++/* check if the node is already existed */+if(dcf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* check the shaper profile id */+if(params->shaper_profile_id!=RTE_TM_SHAPER_PROFILE_ID_NONE){+shaper_profile=dcf_shaper_profile_search(dev,+params->shaper_profile_id);+if(!shaper_profile){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not exist";+return-EINVAL;+}+}++/* add root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=ICE_DCF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(hw->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+hw->tm_conf.root=tm_node;++return0;+}++/* TC or vsi node */+/* check the parent node */+parent_node=dcf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=ICE_DCF_TM_NODE_TYPE_PORT&&+parent_node_type!=ICE_DCF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not port or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the TC node number */+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(hw->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the vsi node number */+if(parent_node->reference_count>=hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many VSI for one TC";+return-EINVAL;+}+/* check the vsi node id */+if(node_id>tc_nb*hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large VSI id";+return-EINVAL;+}+}++/* add the TC or vsi node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->priority=priority;+tm_node->weight=weight;+tm_node->shaper_profile=shaper_profile;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,+tm_node,node);+tm_node->tc=hw->tm_conf.nb_tc_node;+hw->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,+tm_node,node);+tm_node->tc=parent_node->tc;+hw->tm_conf.nb_vsi_node++;+}+tm_node->parent->reference_count++;++/* increase the reference counter of the shaper profile */+if(shaper_profile)+shaper_profile->reference_count++;++return0;+}++staticint+ice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=dcf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==ICE_DCF_TM_NODE_TYPE_PORT){+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+rte_free(tm_node);+hw->tm_conf.root=NULL;+return0;+}++/* TC or VSI node */+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+tm_node->parent->reference_count--;+if(node_type==ICE_DCF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+hw->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+hw->tm_conf.nb_vsi_node--;+}+rte_free(tm_node);++return0;+}++staticint+dcf_shaper_profile_param_check(structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+/* min bucket size not supported */+if(profile->committed.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;+error->message="committed bucket size not supported";+return-EINVAL;+}+/* max bucket size not supported */+if(profile->peak.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;+error->message="peak bucket size not supported";+return-EINVAL;+}+/* length adjustment not supported */+if(profile->pkt_length_adjust){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;+error->message="packet length adjustment not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+intret;++if(!profile||!error)+return-EINVAL;++ret=dcf_shaper_profile_param_check(profile,error);+if(ret)+returnret;++shaper_profile=dcf_shaper_profile_search(dev,shaper_profile_id);++if(shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID exist";+return-EINVAL;+}++shaper_profile=rte_zmalloc("ice_dcf_tm_shaper_profile",+sizeof(structice_dcf_tm_shaper_profile),+0);+if(!shaper_profile)+return-ENOMEM;+shaper_profile->shaper_profile_id=shaper_profile_id;+rte_memcpy(&shaper_profile->profile,profile,+sizeof(structrte_tm_shaper_params));+TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);++return0;+}++staticint+ice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;++if(!error)+return-EINVAL;++shaper_profile=dcf_shaper_profile_search(dev,shaper_profile_id);++if(!shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID not exist";+return-EINVAL;+}++/* don't delete a profile if it's used by one or several nodes */+if(shaper_profile->reference_count){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE;+error->message="profile in use";+return-EINVAL;+}++TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,shaper_profile,node);+rte_free(shaper_profile);++return0;+}++staticint+ice_dcf_set_vf_bw(structice_dcf_hw*hw,+structvirtchnl_dcf_bw_cfg_list*vf_bw,+uint16_tlen)+{+structdcf_virtchnl_cmdargs;+interr;++memset(&args,0,sizeof(args));+args.v_op=VIRTCHNL_OP_DCF_CONFIG_BW;+args.req_msg=(uint8_t*)vf_bw;+args.req_msglen=len;+err=ice_dcf_execute_virtchnl_cmd(hw,&args);+if(err)+PMD_DRV_LOG(ERR,"fail to execute command %s",+"VIRTCHNL_OP_DCF_CONFIG_BW");+returnerr;+}++staticint+ice_dcf_validate_tc_bw(structvirtchnl_dcf_bw_cfg_list*tc_bw,+uint32_tport_bw)+{+structvirtchnl_dcf_bw_cfg*cfg;+boollowest_cir_mark=false;+u32total_peak,rest_peak;+u32committed,peak;+inti;++total_peak=0;+for(i=0;i<tc_bw->num_elem;i++)+total_peak+=tc_bw->cfg[i].shaper.peak;++for(i=0;i<tc_bw->num_elem;i++){+cfg=&tc_bw->cfg[i];+peak=cfg->shaper.peak;+committed=cfg->shaper.committed;+rest_peak=total_peak-peak;++if(lowest_cir_mark&&peak==0){+PMD_DRV_LOG(ERR,"Max bandwidth must be configured for TC%u\n",+cfg->tc_num);+return-EINVAL;+}++if(!lowest_cir_mark&&committed)+lowest_cir_mark=true;++if(committed&&committed+rest_peak>port_bw){+PMD_DRV_LOG(ERR,"Total value of TC%u min bandwidth and other TCs' max bandwidth %ukbps should be less than port link speed %ukbps\n",+cfg->tc_num,committed+rest_peak,port_bw);+return-EINVAL;+}++if(committed&&committed<ICE_SCHED_MIN_BW){+PMD_DRV_LOG(ERR,"If TC%u min Tx bandwidth is set, it cannot be less than 500Kbps\n",+cfg->tc_num);+return-EINVAL;+}++if(peak&&committed>peak){+PMD_DRV_LOG(ERR,"TC%u Min Tx bandwidth cannot be greater than max Tx bandwidth\n",+cfg->tc_num);+return-EINVAL;+}++if(peak>port_bw){+PMD_DRV_LOG(ERR,"TC%u max Tx bandwidth %uKbps is greater than current link speed %uKbps\n",+cfg->tc_num,peak,port_bw);+return-EINVAL;+}+}++return0;+}+staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structvirtchnl_dcf_bw_cfg_list*vf_bw;+structvirtchnl_dcf_bw_cfg_list*tc_bw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structrte_tm_shaper_params*profile;+structice_dcf_tm_node*tm_node;+uint32_tport_bw,cir_total;+uint16_tsize,vf_id;+intnum_elem=0;+intret,i;++size=sizeof(structvirtchnl_dcf_bw_cfg_list)++sizeof(structvirtchnl_dcf_bw_cfg)*+(hw->tm_conf.nb_tc_node-1);+vf_bw=rte_zmalloc("vf_bw",size,0);+if(!vf_bw)+returnICE_ERR_NO_MEMORY;+tc_bw=rte_zmalloc("tc_bw",size,0);+if(!tc_bw)+returnICE_ERR_NO_MEMORY;++/* port bandwidth (Kbps) */+port_bw=hw->link_speed*1000;+cir_total=0;++/* init tc bw configuration */+#define ICE_DCF_SCHED_TC_NODE 0xffff+tc_bw->vf_id=ICE_DCF_SCHED_TC_NODE;+tc_bw->node_type=VIRTCHNL_DCF_TARGET_TC_BW;+tc_bw->num_elem=hw->tm_conf.nb_tc_node;+for(i=0;i<tc_bw->num_elem;i++){+tc_bw->cfg[i].tc_num=i;+tc_bw->cfg[i].type=VIRTCHNL_BW_SHAPER;+tc_bw->cfg[i].bw_type|=+VIRTCHNL_DCF_BW_PIR|VIRTCHNL_DCF_BW_CIR;+}++for(vf_id=0;vf_id<hw->num_vfs;vf_id++){+num_elem=0;+vf_bw->vf_id=vf_id;+vf_bw->node_type=VIRTCHNL_DCF_TARGET_VF_BW;+TAILQ_FOREACH(tm_node,vsi_list,node){+/* scan the nodes belong to one VSI */+if(tm_node->id-hw->num_vfs*tm_node->tc!=vf_id)+continue;+vf_bw->cfg[num_elem].tc_num=tm_node->tc;+vf_bw->cfg[num_elem].type=VIRTCHNL_BW_SHAPER;+if(tm_node->shaper_profile){+/* Transfer from Byte per seconds to Kbps */+profile=&tm_node->shaper_profile->profile;+vf_bw->cfg[num_elem].shaper.peak=+profile->peak.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].shaper.committed=+profile->committed.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].bw_type|=+VIRTCHNL_DCF_BW_PIR|+VIRTCHNL_DCF_BW_CIR;+}++/* update tc node bw configuration */+tc_bw->cfg[tm_node->tc].shaper.peak+=+vf_bw->cfg[num_elem].shaper.peak;+tc_bw->cfg[tm_node->tc].shaper.committed+=+vf_bw->cfg[num_elem].shaper.committed;++cir_total+=vf_bw->cfg[num_elem].shaper.committed;+num_elem++;+}++/* check if total CIR is larger than port bandwidth */+if(cir_total>port_bw){+PMD_DRV_LOG(ERR,"Total CIR of all VFs is larger than port bandwidth");+returnICE_ERR_PARAM;+}+vf_bw->num_elem=num_elem;+ret=ice_dcf_set_vf_bw(hw,vf_bw,size);+if(ret)+returnret;+memset(vf_bw,0,size);+}++/* check and commit tc node bw configuration */+ret=ice_dcf_validate_tc_bw(tc_bw,port_bw);+if(ret)+returnret;+ret=ice_dcf_set_vf_bw(hw,tc_bw,size);+if(ret)+returnret;++hw->tm_conf.committed=true;+returnICE_SUCCESS;+}
This patch added the support for VF to config the ETS-based Tx QoS,
including querying current QoS configuration from PF and config queue TC
mapping. PF QoS is configured in advance and the queried info is
provided to the user for future usage. VF queues are mapped to different
TCs in PF through virtchnl.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 45 +++
drivers/net/iavf/iavf_ethdev.c | 31 ++
drivers/net/iavf/iavf_tm.c | 667 +++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
5 files changed, 799 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
@@ -129,6 +133,38 @@ enum iavf_aq_result {IAVF_MSG_CMD,/* Read async command result */};+/* Struct to store Traffic Manager node configuration. */+structiavf_tm_node{+TAILQ_ENTRY(iavf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structiavf_tm_node*parent;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(iavf_tm_node_list,iavf_tm_node);++/* node type of Traffic Manager */+enumiavf_tm_node_type{+IAVF_TM_NODE_TYPE_PORT,+IAVF_TM_NODE_TYPE_TC,+IAVF_TM_NODE_TYPE_QUEUE,+IAVF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structiavf_tm_conf{+structiavf_tm_node*root;/* root node - vf vsi */+structiavf_tm_node_listtc_list;/* node list for all the TCs */+structiavf_tm_node_listqueue_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_queue_node;+boolcommitted;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -175,6 +211,9 @@ struct iavf_info {structiavf_fdir_infofdir;/* flow director info *//* indicate large VF support enabled or not */boollv_enabled;++structvirtchnl_qos_cap_list*qos_cap;+structiavf_tm_conftm_conf;};#define IAVF_MAX_PKT_TYPE 1024
@@ -806,6 +820,11 @@ iavf_dev_start(struct rte_eth_dev *dev)dev->data->nb_tx_queues);num_queue_pairs=vf->num_queue_pairs;+if(iavf_get_qos_cap(adapter)){+PMD_INIT_LOG(ERR,"Failed to get qos capability");+return-1;+}+if(iavf_init_queues(dev)!=0){PMD_DRV_LOG(ERR,"failed to do Queue init");return-1;
@@ -2090,6 +2109,15 @@ iavf_init_vf(struct rte_eth_dev *dev)PMD_INIT_LOG(ERR,"unable to allocate vf_res memory");gotoerr_api;}++bufsz=sizeof(structvirtchnl_qos_cap_list)++IAVF_MAX_TRAFFIC_CLASS*sizeof(structvirtchnl_qos_cap_elem);+vf->qos_cap=rte_zmalloc("qos_cap",bufsz,0);+if(!vf->qos_cap){+PMD_INIT_LOG(ERR,"unable to allocate qos_cap memory");+gotoerr_api;+}+if(iavf_get_vf_resource(adapter)!=0){PMD_INIT_LOG(ERR,"iavf_get_vf_config failed");gotoerr_alloc;
@@ -0,0 +1,667 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"iavf.h"++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintiavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintiavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintiavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error);+staticintiavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error);++conststructrte_tm_opsiavf_tm_ops={+.node_add=iavf_tm_node_add,+.node_delete=iavf_tm_node_delete,+.capabilities_get=iavf_tm_capabilities_get,+.level_capabilities_get=iavf_level_capabilities_get,+.node_capabilities_get=iavf_node_capabilities_get,+.node_type_get=iavf_node_type_get,+.hierarchy_commit=iavf_hierarchy_commit,+};++void+iavf_tm_conf_init(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++/* initialize node configuration */+vf->tm_conf.root=NULL;+TAILQ_INIT(&vf->tm_conf.tc_list);+TAILQ_INIT(&vf->tm_conf.queue_list);+vf->tm_conf.nb_tc_node=0;+vf->tm_conf.nb_queue_node=0;+vf->tm_conf.committed=false;+}+++staticinlinestructiavf_tm_node*+iavf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumiavf_tm_node_type*node_type)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node_list*tc_list=&vf->tm_conf.tc_list;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;++if(vf->tm_conf.root&&vf->tm_conf.root->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_PORT;+returnvf->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_QUEUE;+returntm_node;+}+}++returnNULL;+}++staticint+iavf_node_param_check(structiavf_info*vf,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shaper profile */+if(params->shaper_profile_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not supported";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=vf->num_queue_pairs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+iavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error)+{+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!is_leaf||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type==IAVF_TM_NODE_TYPE_QUEUE)+*is_leaf=true;+else+*is_leaf=false;++return0;+}++staticint+iavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+enumiavf_tm_node_typeparent_node_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;+structiavf_tm_node*parent_node;+uint16_ttc_nb=vf->qos_cap->num_elem;+intret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=iavf_node_param_check(vf,node_id,priority,weight,+params,error);+if(ret)+returnret;++/* check if the node is already existed */+if(iavf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=IAVF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(vf->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+vf->tm_conf.root=tm_node;+return0;+}++/* TC or queue node */+/* check the parent node */+parent_node=iavf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=IAVF_TM_NODE_TYPE_PORT&&+parent_node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not root or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the node number */+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(vf->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the queue number */+if(parent_node->reference_count>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many queues";+return-EINVAL;+}+if(node_id>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large queue id";+return-EINVAL;+}+}++/* add the TC or queue node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&vf->tm_conf.tc_list,+tm_node,node);+tm_node->tc=vf->tm_conf.nb_tc_node;+vf->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&vf->tm_conf.queue_list,+tm_node,node);+tm_node->tc=parent_node->tc;+vf->tm_conf.nb_queue_node++;+}+tm_node->parent->reference_count++;++return0;+}++staticint+iavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==IAVF_TM_NODE_TYPE_PORT){+rte_free(tm_node);+vf->tm_conf.root=NULL;+return0;+}++/* TC or queue node */+tm_node->parent->reference_count--;+if(node_type==IAVF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+vf->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+vf->tm_conf.nb_queue_node--;+}+rte_free(tm_node);++return0;+}++staticint+iavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_ttc_nb=vf->qos_cap->num_elem;++if(!cap||!error)+return-EINVAL;++if(tc_nb>vf->vf_res->num_queue_pairs)+return-EINVAL;++error->type=RTE_TM_ERROR_TYPE_NONE;++/* set all the parameters to 0 first. */+memset(cap,0,sizeof(structrte_tm_capabilities));++/**+*supportport+TCs+queues+*hereshowsthemaxcapabilitynotthecurrentconfiguration.+*/+cap->n_nodes_max=1+IAVF_MAX_TRAFFIC_CLASS++vf->num_queue_pairs;+cap->n_levels_max=3;/* port, TC, queue */+cap->non_leaf_nodes_identical=1;+cap->leaf_nodes_identical=1;+cap->shaper_n_max=cap->n_nodes_max;+cap->shaper_private_n_max=cap->n_nodes_max;+cap->shaper_private_dual_rate_n_max=0;+cap->shaper_private_rate_min=0;+/* GBps */+cap->shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->shaper_private_packet_mode_supported=0;+cap->shaper_private_byte_mode_supported=1;+cap->shaper_shared_n_max=0;+cap->shaper_shared_n_nodes_per_shaper_max=0;+cap->shaper_shared_n_shapers_per_node_max=0;+cap->shaper_shared_dual_rate_n_max=0;+cap->shaper_shared_rate_min=0;+cap->shaper_shared_rate_max=0;+cap->shaper_shared_packet_mode_supported=0;+cap->shaper_shared_byte_mode_supported=0;+cap->sched_n_children_max=vf->num_queue_pairs;+cap->sched_sp_n_priorities_max=1;+cap->sched_wfq_n_children_per_group_max=0;+cap->sched_wfq_n_groups_max=0;+cap->sched_wfq_weight_max=1;+cap->sched_wfq_packet_mode_supported=0;+cap->sched_wfq_byte_mode_supported=0;+cap->cman_head_drop_supported=0;+cap->dynamic_update_mask=0;+cap->shaper_pkt_length_adjust_min=RTE_TM_ETH_FRAMING_OVERHEAD;+cap->shaper_pkt_length_adjust_max=RTE_TM_ETH_FRAMING_OVERHEAD_FCS;+cap->cman_wred_context_n_max=0;+cap->cman_wred_context_private_n_max=0;+cap->cman_wred_context_shared_n_max=0;+cap->cman_wred_context_shared_n_nodes_per_context_max=0;+cap->cman_wred_context_shared_n_contexts_per_node_max=0;+cap->stats_mask=0;++return0;+}++staticint+iavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(!cap||!error)+return-EINVAL;++if(level_id>=IAVF_TM_NODE_TYPE_MAX){+error->type=RTE_TM_ERROR_TYPE_LEVEL_ID;+error->message="too deep level";+return-EINVAL;+}++/* root node */+if(level_id==IAVF_TM_NODE_TYPE_PORT){+cap->n_nodes_max=1;+cap->n_nodes_nonleaf_max=1;+cap->n_nodes_leaf_max=0;+}elseif(level_id==IAVF_TM_NODE_TYPE_TC){+/* TC */+cap->n_nodes_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_nonleaf_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_leaf_max=0;+}else{+/* queue */+cap->n_nodes_max=vf->num_queue_pairs;+cap->n_nodes_nonleaf_max=0;+cap->n_nodes_leaf_max=vf->num_queue_pairs;+}++cap->non_leaf_nodes_identical=true;+cap->leaf_nodes_identical=true;++if(level_id!=IAVF_TM_NODE_TYPE_QUEUE){+cap->nonleaf.shaper_private_supported=true;+cap->nonleaf.shaper_private_dual_rate_supported=false;+cap->nonleaf.shaper_private_rate_min=0;+/* GBps */+cap->nonleaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->nonleaf.shaper_private_packet_mode_supported=0;+cap->nonleaf.shaper_private_byte_mode_supported=1;+cap->nonleaf.shaper_shared_n_max=0;+cap->nonleaf.shaper_shared_packet_mode_supported=0;+cap->nonleaf.shaper_shared_byte_mode_supported=0;+if(level_id==IAVF_TM_NODE_TYPE_PORT)+cap->nonleaf.sched_n_children_max=+IAVF_MAX_TRAFFIC_CLASS;+else+cap->nonleaf.sched_n_children_max=+vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+cap->nonleaf.sched_wfq_packet_mode_supported=0;+cap->nonleaf.sched_wfq_byte_mode_supported=0;+cap->nonleaf.stats_mask=0;++return0;+}++/* queue node */+cap->leaf.shaper_private_supported=false;+cap->leaf.shaper_private_dual_rate_supported=false;+cap->leaf.shaper_private_rate_min=0;+/* GBps */+cap->leaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->leaf.shaper_private_packet_mode_supported=0;+cap->leaf.shaper_private_byte_mode_supported=1;+cap->leaf.shaper_shared_n_max=0;+cap->leaf.shaper_shared_packet_mode_supported=0;+cap->leaf.shaper_shared_byte_mode_supported=0;+cap->leaf.cman_head_drop_supported=false;+cap->leaf.cman_wred_context_private_supported=true;+cap->leaf.cman_wred_context_shared_n_max=0;+cap->leaf.stats_mask=0;++return0;+}++staticint+iavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type;+structvirtchnl_qos_cap_elemtc_cap;+structiavf_tm_node*tm_node;++if(!cap||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="not support capability get";+return-EINVAL;+}++tc_cap=vf->qos_cap->cap[tm_node->tc];+if(tc_cap.tc_num!=tm_node->tc){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="tc not match";+return-EINVAL;+}++cap->shaper_private_supported=true;+cap->shaper_private_dual_rate_supported=false;+cap->shaper_private_rate_min=tc_cap.shaper.committed;+cap->shaper_private_rate_max=tc_cap.shaper.peak;+cap->shaper_shared_n_max=0;+cap->nonleaf.sched_n_children_max=vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=1;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=tc_cap.weight;+cap->stats_mask=0;++return0;+}++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structvirtchnl_queue_tc_mapping*q_tc_mapping;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;+uint16_tsize;+intindex=0,node_committed=0;+intret,i;++size=sizeof(*q_tc_mapping)+sizeof(q_tc_mapping->tc[0])*+(vf->qos_cap->num_elem-1);+q_tc_mapping=rte_zmalloc("q_tc",size,0);+q_tc_mapping->vsi_id=vf->vsi.vsi_id;+q_tc_mapping->num_tc=vf->qos_cap->num_elem;+q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->tc>=q_tc_mapping->num_tc){+PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);+returnIAVF_ERR_PARAM;+}+q_tc_mapping->tc[tm_node->tc].req.queue_count++;+node_committed++;+}++for(i=0;i<IAVF_MAX_TRAFFIC_CLASS;i++){+q_tc_mapping->tc[i].req.start_queue_id=index;+index+=q_tc_mapping->tc[i].req.queue_count;+}+if(node_committed<vf->num_queue_pairs){+PMD_DRV_LOG(ERR,"queue node is less than allocated queue pairs");+returnIAVF_ERR_PARAM;+}++ret=iavf_set_q_tc_map(dev,q_tc_mapping,size);+if(ret)+returnret;++returnIAVF_SUCCESS;+}
This patch enables the ETS-based Tx QoS for IAVF. Kernel tool is used to
configure ETS first. DCF is used to set bandwidth limit for VFs of each
TC. IAVF is supported to query QoS capability and set queue TC mapping.
Traffic Management API is utilized to configure the QoS hierarchy
scheduler tree. The scheduler tree will be passed to hardware to enable
all above functions.
Ting Xu (7):
common/iavf: support ETS-based QoS offload configuration
net/ice/base: support DCF query port ETS adminq
net/ice: support DCF link status event handling
net/ice: support QoS config VF bandwidth in DCF
net/iavf: query QoS cap and set queue TC mapping
net/iavf: check Tx packet with correct UP and queue
doc: release note for ETS-based Tx QoS
doc/guides/rel_notes/release_21_08.rst | 7 +
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 +++++
drivers/net/iavf/iavf.h | 56 ++
drivers/net/iavf/iavf_ethdev.c | 34 ++
drivers/net/iavf/iavf_rxtx.c | 43 ++
drivers/net/iavf/iavf_tm.c | 727 +++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 +-
drivers/net/iavf/meson.build | 1 +
drivers/net/ice/base/ice_dcb.c | 3 +-
drivers/net/ice/ice_dcf.c | 9 +-
drivers/net/ice/ice_dcf.h | 54 ++
drivers/net/ice/ice_dcf_ethdev.c | 68 ++-
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 81 +++
drivers/net/ice/ice_dcf_sched.c | 759 +++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
17 files changed, 2030 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
create mode 100644 drivers/net/ice/ice_dcf_sched.c
--
2.17.1
This patch adds new virtchnl opcodes and structures for QoS
configuration, which includes:
1. VIRTCHNL_VF_OFFLOAD_TC, to negotiate the capability supporting QoS
configuration. If VF and PF both have this flag, then the ETS-based QoS
offload function is supported.
2. VIRTCHNL_OP_DCF_CONFIG_BW, DCF is supposed to configure min and max
bandwidth for each VF per enabled TCs. To make the VSI node bandwidth
configuration work, DCF also needs to configure TC node bandwidth
directly.
3. VIRTCHNL_OP_GET_QOS_CAPS, VF queries current QoS configuration, such
as enabled TCs, arbiter type, up2tc and bandwidth of VSI node. The
configuration is previously set by DCB and DCF, and now is the potential
QoS capability of VF. VF can take it as reference to configure queue TC
mapping.
4. VIRTCHNL_OP_CONFIG_TC_MAP, set VF queues to TC mapping for all Tx and
Rx queues. Queues mapping to one TC should be continuous and all
allocated queues should be mapped.
Signed-off-by: Ting Xu <redacted>
---
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 ++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
In the adminq command query port ETS function, the root node teid is
needed. However, for DCF, the root node is not initialized, which will
cause error when we refer to the variable. In this patch, we will check
whether the root node is available or not first.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/base/ice_dcb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
When link status changes, DCF will receive virtchnl PF event message.
Add support to handle this event, change link status and update link
info.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.h | 6 ++++
drivers/net/ice/ice_dcf_ethdev.c | 54 ++++++++++++++++++++++++++++++--
drivers/net/ice/ice_dcf_parent.c | 51 ++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 3 deletions(-)
@@ -60,6 +60,10 @@ struct ice_dcf_hw {uint16_tnb_msix;uint16_trxq_map[16];structvirtchnl_eth_statseth_stats_offset;++/* Link status */+boollink_up;+uint32_tlink_speed;};intice_dcf_execute_virtchnl_cmd(structice_dcf_hw*hw,
@@ -881,11 +881,59 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)return0;}-staticint-ice_dcf_link_update(__rte_unusedstructrte_eth_dev*dev,+int+ice_dcf_link_update(structrte_eth_dev*dev,__rte_unusedintwait_to_complete){-return0;+structice_dcf_adapter*ad=dev->data->dev_private;+structice_dcf_hw*hw=&ad->real_hw;+structrte_eth_linknew_link;++memset(&new_link,0,sizeof(new_link));++/* Only read status info stored in VF, and the info is updated+*whenreceiveLINK_CHANGEeventfromPFbyvirtchnl.+*/+switch(hw->link_speed){+case10:+new_link.link_speed=ETH_SPEED_NUM_10M;+break;+case100:+new_link.link_speed=ETH_SPEED_NUM_100M;+break;+case1000:+new_link.link_speed=ETH_SPEED_NUM_1G;+break;+case10000:+new_link.link_speed=ETH_SPEED_NUM_10G;+break;+case20000:+new_link.link_speed=ETH_SPEED_NUM_20G;+break;+case25000:+new_link.link_speed=ETH_SPEED_NUM_25G;+break;+case40000:+new_link.link_speed=ETH_SPEED_NUM_40G;+break;+case50000:+new_link.link_speed=ETH_SPEED_NUM_50G;+break;+case100000:+new_link.link_speed=ETH_SPEED_NUM_100G;+break;+default:+new_link.link_speed=ETH_SPEED_NUM_NONE;+break;+}++new_link.link_duplex=ETH_LINK_FULL_DUPLEX;+new_link.link_status=hw->link_up?ETH_LINK_UP:+ETH_LINK_DOWN;+new_link.link_autoneg=!(dev->data->dev_conf.link_speeds&+ETH_LINK_SPEED_FIXED);++returnrte_eth_linkstatus_set(dev,&new_link);}/* Add UDP tunneling port */
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.c | 9 +-
drivers/net/ice/ice_dcf.h | 48 ++
drivers/net/ice/ice_dcf_ethdev.c | 14 +
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 30 ++
drivers/net/ice/ice_dcf_sched.c | 759 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 864 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_sched.c
@@ -30,6 +31,49 @@ struct dcf_virtchnl_cmd {volatileintpending;};+structice_dcf_tm_shaper_profile{+TAILQ_ENTRY(ice_dcf_tm_shaper_profile)node;+uint32_tshaper_profile_id;+uint32_treference_count;+structrte_tm_shaper_paramsprofile;+};++TAILQ_HEAD(ice_dcf_shaper_profile_list,ice_dcf_tm_shaper_profile);++/* Struct to store Traffic Manager node configuration. */+structice_dcf_tm_node{+TAILQ_ENTRY(ice_dcf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structice_dcf_tm_node*parent;+structice_dcf_tm_shaper_profile*shaper_profile;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(ice_dcf_tm_node_list,ice_dcf_tm_node);++/* node type of Traffic Manager */+enumice_dcf_tm_node_type{+ICE_DCF_TM_NODE_TYPE_PORT,+ICE_DCF_TM_NODE_TYPE_TC,+ICE_DCF_TM_NODE_TYPE_VSI,+ICE_DCF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structice_dcf_tm_conf{+structice_dcf_shaper_profile_listshaper_profile_list;+structice_dcf_tm_node*root;/* root node - port */+structice_dcf_tm_node_listtc_list;/* node list for all the TCs */+structice_dcf_tm_node_listvsi_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_vsi_node;+boolcommitted;+};+structice_dcf_hw{structiavf_hwavf;
@@ -45,6 +89,8 @@ struct ice_dcf_hw {uint16_t*vf_vsi_map;uint16_tpf_vsi_id;+structice_dcf_tm_conftm_conf;+structice_aqc_port_ets_elem*ets_config;structvirtchnl_version_infovirtchnl_version;structvirtchnl_vf_resource*vf_res;/* VF resource */structvirtchnl_vsi_resource*vsi_res;/* LAN VSI */
@@ -486,6 +509,13 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)returnerr;}+err=ice_dcf_query_port_ets(parent_hw,hw);+if(err){+PMD_INIT_LOG(ERR,"failed to query port ets with error %d",+err);+gotouninit_hw;+}+err=ice_dcf_load_pkg(parent_hw);if(err){PMD_INIT_LOG(ERR,"failed to load package with error %d",
@@ -0,0 +1,759 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"base/ice_sched.h"+#include"ice_dcf_ethdev.h"++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error);++conststructrte_tm_opsice_dcf_tm_ops={+.shaper_profile_add=ice_dcf_shaper_profile_add,+.shaper_profile_delete=ice_dcf_shaper_profile_del,+.hierarchy_commit=ice_dcf_hierarchy_commit,+.node_add=ice_dcf_node_add,+.node_delete=ice_dcf_node_delete,+};++void+ice_dcf_tm_conf_init(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;++/* initialize shaper profile list */+TAILQ_INIT(&hw->tm_conf.shaper_profile_list);++/* initialize node configuration */+hw->tm_conf.root=NULL;+TAILQ_INIT(&hw->tm_conf.tc_list);+TAILQ_INIT(&hw->tm_conf.vsi_list);+hw->tm_conf.nb_tc_node=0;+hw->tm_conf.nb_vsi_node=0;+hw->tm_conf.committed=false;+}++void+ice_dcf_tm_conf_uninit(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+structice_dcf_tm_node*tm_node;++/* clear node configuration */+while((tm_node=TAILQ_FIRST(&hw->tm_conf.vsi_list))){+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+rte_free(tm_node);+}+hw->tm_conf.nb_vsi_node=0;+while((tm_node=TAILQ_FIRST(&hw->tm_conf.tc_list))){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+rte_free(tm_node);+}+hw->tm_conf.nb_tc_node=0;+if(hw->tm_conf.root){+rte_free(hw->tm_conf.root);+hw->tm_conf.root=NULL;+}++/* Remove all shaper profiles */+while((shaper_profile=+TAILQ_FIRST(&hw->tm_conf.shaper_profile_list))){+TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);+rte_free(shaper_profile);+}+}++staticinlinestructice_dcf_tm_node*+ice_dcf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumice_dcf_tm_node_type*node_type)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structice_dcf_tm_node_list*tc_list=&hw->tm_conf.tc_list;+structice_dcf_tm_node*tm_node;++if(hw->tm_conf.root&&hw->tm_conf.root->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_PORT;+returnhw->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,vsi_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_VSI;+returntm_node;+}+}++returnNULL;+}++staticinlinestructice_dcf_tm_shaper_profile*+ice_dcf_shaper_profile_search(structrte_eth_dev*dev,+uint32_tshaper_profile_id)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_shaper_profile_list*shaper_profile_list=+&hw->tm_conf.shaper_profile_list;+structice_dcf_tm_shaper_profile*shaper_profile;++TAILQ_FOREACH(shaper_profile,shaper_profile_list,node){+if(shaper_profile_id==shaper_profile->shaper_profile_id)+returnshaper_profile;+}++returnNULL;+}++staticint+ice_dcf_node_param_check(structice_dcf_hw*hw,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=8*hw->num_vfs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typeparent_node_type=ICE_DCF_TM_NODE_TYPE_MAX;+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_tm_shaper_profile*shaper_profile=NULL;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*parent_node;+structice_dcf_tm_node*tm_node;+uint16_ttc_nb=1;+inti,ret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=ice_dcf_node_param_check(hw,node_id,priority,weight,+params,error);+if(ret)+returnret;++for(i=1;i<ICE_MAX_TRAFFIC_CLASS;i++){+if(hw->ets_config->tc_valid_bits&(1<<i))+tc_nb++;+}++/* check if the node is already existed */+if(ice_dcf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* check the shaper profile id */+if(params->shaper_profile_id!=RTE_TM_SHAPER_PROFILE_ID_NONE){+shaper_profile=ice_dcf_shaper_profile_search(dev,+params->shaper_profile_id);+if(!shaper_profile){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not exist";+return-EINVAL;+}+}++/* add root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=ICE_DCF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(hw->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+hw->tm_conf.root=tm_node;++return0;+}++/* TC or vsi node */+/* check the parent node */+parent_node=ice_dcf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=ICE_DCF_TM_NODE_TYPE_PORT&&+parent_node_type!=ICE_DCF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not port or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the TC node number */+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(hw->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the vsi node number */+if(parent_node->reference_count>=hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many VSI for one TC";+return-EINVAL;+}+/* check the vsi node id */+if(node_id>tc_nb*hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large VSI id";+return-EINVAL;+}+}++/* add the TC or vsi node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->priority=priority;+tm_node->weight=weight;+tm_node->shaper_profile=shaper_profile;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,+tm_node,node);+tm_node->tc=hw->tm_conf.nb_tc_node;+hw->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,+tm_node,node);+tm_node->tc=parent_node->tc;+hw->tm_conf.nb_vsi_node++;+}+tm_node->parent->reference_count++;++/* increase the reference counter of the shaper profile */+if(shaper_profile)+shaper_profile->reference_count++;++return0;+}++staticint+ice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=ice_dcf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==ICE_DCF_TM_NODE_TYPE_PORT){+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+rte_free(tm_node);+hw->tm_conf.root=NULL;+return0;+}++/* TC or VSI node */+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+tm_node->parent->reference_count--;+if(node_type==ICE_DCF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+hw->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+hw->tm_conf.nb_vsi_node--;+}+rte_free(tm_node);++return0;+}++staticint+ice_dcf_shaper_profile_param_check(structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+/* min bucket size not supported */+if(profile->committed.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;+error->message="committed bucket size not supported";+return-EINVAL;+}+/* max bucket size not supported */+if(profile->peak.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;+error->message="peak bucket size not supported";+return-EINVAL;+}+/* length adjustment not supported */+if(profile->pkt_length_adjust){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;+error->message="packet length adjustment not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+intret;++if(!profile||!error)+return-EINVAL;++ret=ice_dcf_shaper_profile_param_check(profile,error);+if(ret)+returnret;++shaper_profile=ice_dcf_shaper_profile_search(dev,shaper_profile_id);++if(shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID exist";+return-EINVAL;+}++shaper_profile=rte_zmalloc("ice_dcf_tm_shaper_profile",+sizeof(structice_dcf_tm_shaper_profile),+0);+if(!shaper_profile)+return-ENOMEM;+shaper_profile->shaper_profile_id=shaper_profile_id;+rte_memcpy(&shaper_profile->profile,profile,+sizeof(structrte_tm_shaper_params));+TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);++return0;+}++staticint+ice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;++if(!error)+return-EINVAL;++shaper_profile=ice_dcf_shaper_profile_search(dev,shaper_profile_id);++if(!shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID not exist";+return-EINVAL;+}++/* don't delete a profile if it's used by one or several nodes */+if(shaper_profile->reference_count){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE;+error->message="profile in use";+return-EINVAL;+}++TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,shaper_profile,node);+rte_free(shaper_profile);++return0;+}++staticint+ice_dcf_set_vf_bw(structice_dcf_hw*hw,+structvirtchnl_dcf_bw_cfg_list*vf_bw,+uint16_tlen)+{+structdcf_virtchnl_cmdargs;+interr;++memset(&args,0,sizeof(args));+args.v_op=VIRTCHNL_OP_DCF_CONFIG_BW;+args.req_msg=(uint8_t*)vf_bw;+args.req_msglen=len;+err=ice_dcf_execute_virtchnl_cmd(hw,&args);+if(err)+PMD_DRV_LOG(ERR,"fail to execute command %s",+"VIRTCHNL_OP_DCF_CONFIG_BW");+returnerr;+}++staticint+ice_dcf_validate_tc_bw(structvirtchnl_dcf_bw_cfg_list*tc_bw,+uint32_tport_bw)+{+structvirtchnl_dcf_bw_cfg*cfg;+boollowest_cir_mark=false;+u32total_peak,rest_peak;+u32committed,peak;+inti;++total_peak=0;+for(i=0;i<tc_bw->num_elem;i++)+total_peak+=tc_bw->cfg[i].shaper.peak;++for(i=0;i<tc_bw->num_elem;i++){+cfg=&tc_bw->cfg[i];+peak=cfg->shaper.peak;+committed=cfg->shaper.committed;+rest_peak=total_peak-peak;++if(lowest_cir_mark&&peak==0){+PMD_DRV_LOG(ERR,"Max bandwidth must be configured for TC%u",+cfg->tc_num);+return-EINVAL;+}++if(!lowest_cir_mark&&committed)+lowest_cir_mark=true;++if(committed&&committed+rest_peak>port_bw){+PMD_DRV_LOG(ERR,"Total value of TC%u min bandwidth and other TCs' max bandwidth %ukbps should be less than port link speed %ukbps",+cfg->tc_num,committed+rest_peak,port_bw);+return-EINVAL;+}++if(committed&&committed<ICE_SCHED_MIN_BW){+PMD_DRV_LOG(ERR,"If TC%u min Tx bandwidth is set, it cannot be less than 500Kbps",+cfg->tc_num);+return-EINVAL;+}++if(peak&&committed>peak){+PMD_DRV_LOG(ERR,"TC%u Min Tx bandwidth cannot be greater than max Tx bandwidth",+cfg->tc_num);+return-EINVAL;+}++if(peak>port_bw){+PMD_DRV_LOG(ERR,"TC%u max Tx bandwidth %uKbps is greater than current link speed %uKbps",+cfg->tc_num,peak,port_bw);+return-EINVAL;+}+}++return0;+}+staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+intclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structvirtchnl_dcf_bw_cfg_list*vf_bw;+structvirtchnl_dcf_bw_cfg_list*tc_bw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structrte_tm_shaper_params*profile;+structice_dcf_tm_node*tm_node;+uint32_tport_bw,cir_total;+uint16_tsize,vf_id;+uint8_tnum_elem=0;+inti,ret_val=ICE_SUCCESS;++/* check if all TC nodes are set */+if(BIT(hw->tm_conf.nb_tc_node)&hw->ets_config->tc_valid_bits){+PMD_DRV_LOG(ERR,"Not all enabled TC nodes are set");+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++size=sizeof(structvirtchnl_dcf_bw_cfg_list)++sizeof(structvirtchnl_dcf_bw_cfg)*+(hw->tm_conf.nb_tc_node-1);+vf_bw=rte_zmalloc("vf_bw",size,0);+if(!vf_bw){+ret_val=ICE_ERR_NO_MEMORY;+gotofail_clear;+}+tc_bw=rte_zmalloc("tc_bw",size,0);+if(!tc_bw){+ret_val=ICE_ERR_NO_MEMORY;+gotofail_clear;+}++/* port bandwidth (Kbps) */+port_bw=hw->link_speed*1000;+cir_total=0;++/* init tc bw configuration */+#define ICE_DCF_SCHED_TC_NODE 0xffff+tc_bw->vf_id=ICE_DCF_SCHED_TC_NODE;+tc_bw->node_type=VIRTCHNL_DCF_TARGET_TC_BW;+tc_bw->num_elem=hw->tm_conf.nb_tc_node;+for(i=0;i<tc_bw->num_elem;i++){+tc_bw->cfg[i].tc_num=i;+tc_bw->cfg[i].type=VIRTCHNL_BW_SHAPER;+tc_bw->cfg[i].bw_type|=+VIRTCHNL_DCF_BW_PIR|VIRTCHNL_DCF_BW_CIR;+}++for(vf_id=0;vf_id<hw->num_vfs;vf_id++){+num_elem=0;+vf_bw->vf_id=vf_id;+vf_bw->node_type=VIRTCHNL_DCF_TARGET_VF_BW;+TAILQ_FOREACH(tm_node,vsi_list,node){+/* scan the nodes belong to one VSI */+if(tm_node->id-hw->num_vfs*tm_node->tc!=vf_id)+continue;+vf_bw->cfg[num_elem].tc_num=tm_node->tc;+vf_bw->cfg[num_elem].type=VIRTCHNL_BW_SHAPER;+if(tm_node->shaper_profile){+/* Transfer from Byte per seconds to Kbps */+profile=&tm_node->shaper_profile->profile;+vf_bw->cfg[num_elem].shaper.peak=+profile->peak.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].shaper.committed=+profile->committed.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].bw_type|=+VIRTCHNL_DCF_BW_PIR|+VIRTCHNL_DCF_BW_CIR;+}++/* update tc node bw configuration */+tc_bw->cfg[tm_node->tc].shaper.peak+=+vf_bw->cfg[num_elem].shaper.peak;+tc_bw->cfg[tm_node->tc].shaper.committed+=+vf_bw->cfg[num_elem].shaper.committed;++cir_total+=vf_bw->cfg[num_elem].shaper.committed;+num_elem++;+}++/* check if all TC nodes are set with VF vsi nodes */+if(num_elem!=hw->tm_conf.nb_tc_node){+PMD_DRV_LOG(ERR,"VF%u vsi nodes are not set to all TC nodes",+vf_id);+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++vf_bw->num_elem=num_elem;+ret_val=ice_dcf_set_vf_bw(hw,vf_bw,size);+if(ret_val)+gotofail_clear;+memset(vf_bw,0,size);+}++/* check if total CIR is larger than port bandwidth */+if(cir_total>port_bw){+PMD_DRV_LOG(ERR,"Total CIR of all VFs is larger than port bandwidth");+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++/* check and commit tc node bw configuration */+ret_val=ice_dcf_validate_tc_bw(tc_bw,port_bw);+if(ret_val)+gotofail_clear;+ret_val=ice_dcf_set_vf_bw(hw,tc_bw,size);+if(ret_val)+gotofail_clear;++hw->tm_conf.committed=true;+returnret_val;++fail_clear:+/* clear all the traffic manager configuration */+if(clear_on_fail){+ice_dcf_tm_conf_uninit(dev);+ice_dcf_tm_conf_init(dev);+}+returnret_val;+}
This patch added the support for VF to config the ETS-based Tx QoS,
including querying current QoS configuration from PF and config queue TC
mapping. PF QoS is configured in advance and the queried info is
provided to the user for future usage. VF queues are mapped to different
TCs in PF through virtchnl.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 46 +++
drivers/net/iavf/iavf_ethdev.c | 34 ++
drivers/net/iavf/iavf_tm.c | 714 +++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
5 files changed, 850 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
@@ -129,6 +133,38 @@ enum iavf_aq_result {IAVF_MSG_CMD,/* Read async command result */};+/* Struct to store Traffic Manager node configuration. */+structiavf_tm_node{+TAILQ_ENTRY(iavf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structiavf_tm_node*parent;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(iavf_tm_node_list,iavf_tm_node);++/* node type of Traffic Manager */+enumiavf_tm_node_type{+IAVF_TM_NODE_TYPE_PORT,+IAVF_TM_NODE_TYPE_TC,+IAVF_TM_NODE_TYPE_QUEUE,+IAVF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structiavf_tm_conf{+structiavf_tm_node*root;/* root node - vf vsi */+structiavf_tm_node_listtc_list;/* node list for all the TCs */+structiavf_tm_node_listqueue_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_queue_node;+boolcommitted;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -175,6 +211,9 @@ struct iavf_info {structiavf_fdir_infofdir;/* flow director info *//* indicate large VF support enabled or not */boollv_enabled;++structvirtchnl_qos_cap_list*qos_cap;+structiavf_tm_conftm_conf;};#define IAVF_MAX_PKT_TYPE 1024
@@ -806,6 +820,11 @@ iavf_dev_start(struct rte_eth_dev *dev)dev->data->nb_tx_queues);num_queue_pairs=vf->num_queue_pairs;+if(iavf_get_qos_cap(adapter)){+PMD_INIT_LOG(ERR,"Failed to get qos capability");+return-1;+}+if(iavf_init_queues(dev)!=0){PMD_DRV_LOG(ERR,"failed to do Queue init");return-1;
@@ -0,0 +1,714 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"iavf.h"++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintiavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintiavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintiavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error);+staticintiavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error);++conststructrte_tm_opsiavf_tm_ops={+.node_add=iavf_tm_node_add,+.node_delete=iavf_tm_node_delete,+.capabilities_get=iavf_tm_capabilities_get,+.level_capabilities_get=iavf_level_capabilities_get,+.node_capabilities_get=iavf_node_capabilities_get,+.node_type_get=iavf_node_type_get,+.hierarchy_commit=iavf_hierarchy_commit,+};++void+iavf_tm_conf_init(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++/* initialize node configuration */+vf->tm_conf.root=NULL;+TAILQ_INIT(&vf->tm_conf.tc_list);+TAILQ_INIT(&vf->tm_conf.queue_list);+vf->tm_conf.nb_tc_node=0;+vf->tm_conf.nb_queue_node=0;+vf->tm_conf.committed=false;+}++void+iavf_tm_conf_uninit(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node*tm_node;++/* clear node configuration */+while((tm_node=TAILQ_FIRST(&vf->tm_conf.queue_list))){+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+rte_free(tm_node);+}+vf->tm_conf.nb_queue_node=0;+while((tm_node=TAILQ_FIRST(&vf->tm_conf.tc_list))){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+rte_free(tm_node);+}+vf->tm_conf.nb_tc_node=0;+if(vf->tm_conf.root){+rte_free(vf->tm_conf.root);+vf->tm_conf.root=NULL;+}+}++staticinlinestructiavf_tm_node*+iavf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumiavf_tm_node_type*node_type)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node_list*tc_list=&vf->tm_conf.tc_list;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;++if(vf->tm_conf.root&&vf->tm_conf.root->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_PORT;+returnvf->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_QUEUE;+returntm_node;+}+}++returnNULL;+}++staticint+iavf_node_param_check(structiavf_info*vf,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shaper profile */+if(params->shaper_profile_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not supported";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=vf->num_queue_pairs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+iavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error)+{+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!is_leaf||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type==IAVF_TM_NODE_TYPE_QUEUE)+*is_leaf=true;+else+*is_leaf=false;++return0;+}++staticint+iavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+enumiavf_tm_node_typeparent_node_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;+structiavf_tm_node*parent_node;+uint16_ttc_nb=vf->qos_cap->num_elem;+intret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=iavf_node_param_check(vf,node_id,priority,weight,+params,error);+if(ret)+returnret;++/* check if the node is already existed */+if(iavf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=IAVF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(vf->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+vf->tm_conf.root=tm_node;+return0;+}++/* TC or queue node */+/* check the parent node */+parent_node=iavf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=IAVF_TM_NODE_TYPE_PORT&&+parent_node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not root or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the node number */+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(vf->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the queue number */+if(parent_node->reference_count>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many queues";+return-EINVAL;+}+if(node_id>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large queue id";+return-EINVAL;+}+}++/* add the TC or queue node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&vf->tm_conf.tc_list,+tm_node,node);+tm_node->tc=vf->tm_conf.nb_tc_node;+vf->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&vf->tm_conf.queue_list,+tm_node,node);+tm_node->tc=parent_node->tc;+vf->tm_conf.nb_queue_node++;+}+tm_node->parent->reference_count++;++return0;+}++staticint+iavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==IAVF_TM_NODE_TYPE_PORT){+rte_free(tm_node);+vf->tm_conf.root=NULL;+return0;+}++/* TC or queue node */+tm_node->parent->reference_count--;+if(node_type==IAVF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+vf->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+vf->tm_conf.nb_queue_node--;+}+rte_free(tm_node);++return0;+}++staticint+iavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_ttc_nb=vf->qos_cap->num_elem;++if(!cap||!error)+return-EINVAL;++if(tc_nb>vf->vf_res->num_queue_pairs)+return-EINVAL;++error->type=RTE_TM_ERROR_TYPE_NONE;++/* set all the parameters to 0 first. */+memset(cap,0,sizeof(structrte_tm_capabilities));++/**+*supportport+TCs+queues+*hereshowsthemaxcapabilitynotthecurrentconfiguration.+*/+cap->n_nodes_max=1+IAVF_MAX_TRAFFIC_CLASS++vf->num_queue_pairs;+cap->n_levels_max=3;/* port, TC, queue */+cap->non_leaf_nodes_identical=1;+cap->leaf_nodes_identical=1;+cap->shaper_n_max=cap->n_nodes_max;+cap->shaper_private_n_max=cap->n_nodes_max;+cap->shaper_private_dual_rate_n_max=0;+cap->shaper_private_rate_min=0;+/* GBps */+cap->shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->shaper_private_packet_mode_supported=0;+cap->shaper_private_byte_mode_supported=1;+cap->shaper_shared_n_max=0;+cap->shaper_shared_n_nodes_per_shaper_max=0;+cap->shaper_shared_n_shapers_per_node_max=0;+cap->shaper_shared_dual_rate_n_max=0;+cap->shaper_shared_rate_min=0;+cap->shaper_shared_rate_max=0;+cap->shaper_shared_packet_mode_supported=0;+cap->shaper_shared_byte_mode_supported=0;+cap->sched_n_children_max=vf->num_queue_pairs;+cap->sched_sp_n_priorities_max=1;+cap->sched_wfq_n_children_per_group_max=0;+cap->sched_wfq_n_groups_max=0;+cap->sched_wfq_weight_max=1;+cap->sched_wfq_packet_mode_supported=0;+cap->sched_wfq_byte_mode_supported=0;+cap->cman_head_drop_supported=0;+cap->dynamic_update_mask=0;+cap->shaper_pkt_length_adjust_min=RTE_TM_ETH_FRAMING_OVERHEAD;+cap->shaper_pkt_length_adjust_max=RTE_TM_ETH_FRAMING_OVERHEAD_FCS;+cap->cman_wred_context_n_max=0;+cap->cman_wred_context_private_n_max=0;+cap->cman_wred_context_shared_n_max=0;+cap->cman_wred_context_shared_n_nodes_per_context_max=0;+cap->cman_wred_context_shared_n_contexts_per_node_max=0;+cap->stats_mask=0;++return0;+}++staticint+iavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(!cap||!error)+return-EINVAL;++if(level_id>=IAVF_TM_NODE_TYPE_MAX){+error->type=RTE_TM_ERROR_TYPE_LEVEL_ID;+error->message="too deep level";+return-EINVAL;+}++/* root node */+if(level_id==IAVF_TM_NODE_TYPE_PORT){+cap->n_nodes_max=1;+cap->n_nodes_nonleaf_max=1;+cap->n_nodes_leaf_max=0;+}elseif(level_id==IAVF_TM_NODE_TYPE_TC){+/* TC */+cap->n_nodes_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_nonleaf_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_leaf_max=0;+}else{+/* queue */+cap->n_nodes_max=vf->num_queue_pairs;+cap->n_nodes_nonleaf_max=0;+cap->n_nodes_leaf_max=vf->num_queue_pairs;+}++cap->non_leaf_nodes_identical=true;+cap->leaf_nodes_identical=true;++if(level_id!=IAVF_TM_NODE_TYPE_QUEUE){+cap->nonleaf.shaper_private_supported=true;+cap->nonleaf.shaper_private_dual_rate_supported=false;+cap->nonleaf.shaper_private_rate_min=0;+/* GBps */+cap->nonleaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->nonleaf.shaper_private_packet_mode_supported=0;+cap->nonleaf.shaper_private_byte_mode_supported=1;+cap->nonleaf.shaper_shared_n_max=0;+cap->nonleaf.shaper_shared_packet_mode_supported=0;+cap->nonleaf.shaper_shared_byte_mode_supported=0;+if(level_id==IAVF_TM_NODE_TYPE_PORT)+cap->nonleaf.sched_n_children_max=+IAVF_MAX_TRAFFIC_CLASS;+else+cap->nonleaf.sched_n_children_max=+vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+cap->nonleaf.sched_wfq_packet_mode_supported=0;+cap->nonleaf.sched_wfq_byte_mode_supported=0;+cap->nonleaf.stats_mask=0;++return0;+}++/* queue node */+cap->leaf.shaper_private_supported=false;+cap->leaf.shaper_private_dual_rate_supported=false;+cap->leaf.shaper_private_rate_min=0;+/* GBps */+cap->leaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->leaf.shaper_private_packet_mode_supported=0;+cap->leaf.shaper_private_byte_mode_supported=1;+cap->leaf.shaper_shared_n_max=0;+cap->leaf.shaper_shared_packet_mode_supported=0;+cap->leaf.shaper_shared_byte_mode_supported=0;+cap->leaf.cman_head_drop_supported=false;+cap->leaf.cman_wred_context_private_supported=true;+cap->leaf.cman_wred_context_shared_n_max=0;+cap->leaf.stats_mask=0;++return0;+}++staticint+iavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type;+structvirtchnl_qos_cap_elemtc_cap;+structiavf_tm_node*tm_node;++if(!cap||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="not support capability get";+return-EINVAL;+}++tc_cap=vf->qos_cap->cap[tm_node->tc];+if(tc_cap.tc_num!=tm_node->tc){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="tc not match";+return-EINVAL;+}++cap->shaper_private_supported=true;+cap->shaper_private_dual_rate_supported=false;+cap->shaper_private_rate_min=tc_cap.shaper.committed;+cap->shaper_private_rate_max=tc_cap.shaper.peak;+cap->shaper_shared_n_max=0;+cap->nonleaf.sched_n_children_max=vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=1;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=tc_cap.weight;+cap->stats_mask=0;++return0;+}++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+intclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structvirtchnl_queue_tc_mapping*q_tc_mapping;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;+uint16_tsize;+intindex=0,node_committed=0;+inti,ret_val=IAVF_SUCCESS;++/* check if all TC nodes are set with VF vsi */+if(vf->tm_conf.nb_tc_node!=vf->qos_cap->num_elem){+PMD_DRV_LOG(ERR,"Does not set VF vsi nodes to all TCs");+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}++size=sizeof(*q_tc_mapping)+sizeof(q_tc_mapping->tc[0])*+(vf->qos_cap->num_elem-1);+q_tc_mapping=rte_zmalloc("q_tc",size,0);+if(!q_tc_mapping){+ret_val=IAVF_ERR_NO_MEMORY;+gotofail_clear;+}++q_tc_mapping->vsi_id=vf->vsi.vsi_id;+q_tc_mapping->num_tc=vf->qos_cap->num_elem;+q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->tc>=q_tc_mapping->num_tc){+PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}+q_tc_mapping->tc[tm_node->tc].req.queue_count++;+node_committed++;+}++/* All queues allocated to this VF should be mapped */+if(node_committed<vf->num_queue_pairs){+PMD_DRV_LOG(ERR,"queue node is less than allocated queue pairs");+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}++for(i=0;i<q_tc_mapping->num_tc;i++){+q_tc_mapping->tc[i].req.start_queue_id=index;+index+=q_tc_mapping->tc[i].req.queue_count;+}++ret_val=iavf_set_q_tc_map(dev,q_tc_mapping,size);+if(ret_val)+gotofail_clear;++vf->tm_conf.committed=true;+returnret_val;++fail_clear:+/* clear all the traffic manager configuration */+if(clear_on_fail){+iavf_tm_conf_uninit(dev);+iavf_tm_conf_init(dev);+}+returnret_val;+}
Add check in the Tx packet preparation function, to guarantee that the
packet with specific user priority is distributed to the correct Tx
queue according to the configured Tx queue TC mapping.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 10 +++++++++
drivers/net/iavf/iavf_rxtx.c | 43 ++++++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_tm.c | 13 +++++++++++
3 files changed, 66 insertions(+)
@@ -165,6 +167,13 @@ struct iavf_tm_conf {boolcommitted;};+/* Struct to store queue TC mapping. Queue is continuous in one TC */+structiavf_qtc_map{+uint8_ttc;+uint16_tstart_queue_id;+uint16_tqueue_count;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -2342,14 +2342,49 @@ iavf_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)returnnb_tx;}+/* Check if the packet with vlan user priority is transmitted in the+*correctqueue.+*/+staticint+iavf_check_vlan_up2tc(structiavf_tx_queue*txq,uint8_ttc,structrte_mbuf*m)+{+structrte_eth_dev*dev=&rte_eth_devices[txq->port_id];+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_tup;++up=m->vlan_tci>>IAVF_VLAN_TAG_PCP_OFFSET;++if(!(vf->qos_cap->cap[tc].tc_prio&BIT(up))){+PMD_TX_LOG(ERR,"packet with vlan pcp %u cannot transmit in queue %u\n",+up,txq->queue_id);+return-1;+}else{+return0;+}+}+/* TX prep functions */uint16_tiavf_prep_pkts(__rte_unusedvoid*tx_queue,structrte_mbuf**tx_pkts,uint16_tnb_pkts){inti,ret;+uint8_ttc=0;uint64_tol_flags;structrte_mbuf*m;+structiavf_tx_queue*txq=tx_queue;+structrte_eth_dev*dev=&rte_eth_devices[txq->port_id];+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(vf->tm_conf.committed){+for(i=0;i<vf->qos_cap->num_elem;i++){+if(txq->queue_id>=vf->qtc_map[i].start_queue_id&&+txq->queue_id<(vf->qtc_map[i].start_queue_id++vf->qtc_map[i].queue_count))+break;+}+tc=i;+}for(i=0;i<nb_pkts;i++){m=tx_pkts[i];
@@ -653,6 +653,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,structvirtchnl_queue_tc_mapping*q_tc_mapping;structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;structiavf_tm_node*tm_node;+structiavf_qtc_map*qtc_map;uint16_tsize;intindex=0,node_committed=0;inti,ret_val=IAVF_SUCCESS;
@@ -675,6 +676,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,q_tc_mapping->vsi_id=vf->vsi.vsi_id;q_tc_mapping->num_tc=vf->qos_cap->num_elem;q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){if(tm_node->tc>=q_tc_mapping->num_tc){PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);
@@ -692,15 +694,26 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,gotofail_clear;}+/* store the queue TC mapping info */+qtc_map=rte_zmalloc("qtc_map",+sizeof(structiavf_qtc_map)*q_tc_mapping->num_tc,0);+if(!qtc_map)+returnIAVF_ERR_NO_MEMORY;+for(i=0;i<q_tc_mapping->num_tc;i++){q_tc_mapping->tc[i].req.start_queue_id=index;index+=q_tc_mapping->tc[i].req.queue_count;+qtc_map[i].tc=i;+qtc_map[i].start_queue_id=+q_tc_mapping->tc[i].req.start_queue_id;+qtc_map[i].queue_count=q_tc_mapping->tc[i].req.queue_count;}ret_val=iavf_set_q_tc_map(dev,q_tc_mapping,size);if(ret_val)gotofail_clear;+vf->qtc_map=qtc_map;vf->tm_conf.committed=true;returnret_val;
@@ -55,6 +55,13 @@ New Features Also, make sure to start the actual text at the margin. =======================================================+***Updated Intel iavf driver.**++* Added Tx QoS VF queue TC mapping.++***Updated Intel ice driver.**++* Added Tx QoS TC bandwidth configuration in DCF. Removed Items -------------
This patch enables the ETS-based Tx QoS for IAVF. Kernel tool is used to
configure ETS first. DCF is used to set bandwidth limit for VFs of each
TC. IAVF is supported to query QoS capability and set queue TC mapping.
Traffic Management API is utilized to configure the QoS hierarchy
scheduler tree. The scheduler tree will be passed to hardware to enable
all above functions.
Ting Xu (7):
common/iavf: support ETS-based QoS offload configuration
net/ice/base: support DCF query port ETS adminq
net/ice: support DCF link status event handling
net/ice: support QoS config VF bandwidth in DCF
net/iavf: query QoS cap and set queue TC mapping
net/iavf: check Tx packet with correct UP and queue
doc: release note for ETS-based Tx QoS
doc/guides/rel_notes/release_21_08.rst | 7 +
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 +++++
drivers/net/iavf/iavf.h | 56 ++
drivers/net/iavf/iavf_ethdev.c | 34 ++
drivers/net/iavf/iavf_rxtx.c | 43 ++
drivers/net/iavf/iavf_tm.c | 737 ++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 +-
drivers/net/iavf/meson.build | 1 +
drivers/net/ice/base/ice_dcb.c | 3 +-
drivers/net/ice/ice_dcf.c | 9 +-
drivers/net/ice/ice_dcf.h | 54 ++
drivers/net/ice/ice_dcf_ethdev.c | 68 ++-
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 81 +++
drivers/net/ice/ice_dcf_sched.c | 759 +++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
17 files changed, 2040 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
create mode 100644 drivers/net/ice/ice_dcf_sched.c
--
2.17.1
This patch adds new virtchnl opcodes and structures for QoS
configuration, which includes:
1. VIRTCHNL_VF_OFFLOAD_TC, to negotiate the capability supporting QoS
configuration. If VF and PF both have this flag, then the ETS-based QoS
offload function is supported.
2. VIRTCHNL_OP_DCF_CONFIG_BW, DCF is supposed to configure min and max
bandwidth for each VF per enabled TCs. To make the VSI node bandwidth
configuration work, DCF also needs to configure TC node bandwidth
directly.
3. VIRTCHNL_OP_GET_QOS_CAPS, VF queries current QoS configuration, such
as enabled TCs, arbiter type, up2tc and bandwidth of VSI node. The
configuration is previously set by DCB and DCF, and now is the potential
QoS capability of VF. VF can take it as reference to configure queue TC
mapping.
4. VIRTCHNL_OP_CONFIG_TC_MAP, set VF queues to TC mapping for all Tx and
Rx queues. Queues mapping to one TC should be continuous and all
allocated queues should be mapped.
Signed-off-by: Ting Xu <redacted>
---
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 ++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
In the adminq command query port ETS function, the root node teid is
needed. However, for DCF, the root node is not initialized, which will
cause error when we refer to the variable. In this patch, we will check
whether the root node is available or not first.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/base/ice_dcb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
When link status changes, DCF will receive virtchnl PF event message.
Add support to handle this event, change link status and update link
info.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.h | 6 ++++
drivers/net/ice/ice_dcf_ethdev.c | 54 ++++++++++++++++++++++++++++++--
drivers/net/ice/ice_dcf_parent.c | 51 ++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 3 deletions(-)
@@ -60,6 +60,10 @@ struct ice_dcf_hw {uint16_tnb_msix;uint16_trxq_map[16];structvirtchnl_eth_statseth_stats_offset;++/* Link status */+boollink_up;+uint32_tlink_speed;};intice_dcf_execute_virtchnl_cmd(structice_dcf_hw*hw,
@@ -881,11 +881,59 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)return0;}-staticint-ice_dcf_link_update(__rte_unusedstructrte_eth_dev*dev,+int+ice_dcf_link_update(structrte_eth_dev*dev,__rte_unusedintwait_to_complete){-return0;+structice_dcf_adapter*ad=dev->data->dev_private;+structice_dcf_hw*hw=&ad->real_hw;+structrte_eth_linknew_link;++memset(&new_link,0,sizeof(new_link));++/* Only read status info stored in VF, and the info is updated+*whenreceiveLINK_CHANGEeventfromPFbyvirtchnl.+*/+switch(hw->link_speed){+case10:+new_link.link_speed=ETH_SPEED_NUM_10M;+break;+case100:+new_link.link_speed=ETH_SPEED_NUM_100M;+break;+case1000:+new_link.link_speed=ETH_SPEED_NUM_1G;+break;+case10000:+new_link.link_speed=ETH_SPEED_NUM_10G;+break;+case20000:+new_link.link_speed=ETH_SPEED_NUM_20G;+break;+case25000:+new_link.link_speed=ETH_SPEED_NUM_25G;+break;+case40000:+new_link.link_speed=ETH_SPEED_NUM_40G;+break;+case50000:+new_link.link_speed=ETH_SPEED_NUM_50G;+break;+case100000:+new_link.link_speed=ETH_SPEED_NUM_100G;+break;+default:+new_link.link_speed=ETH_SPEED_NUM_NONE;+break;+}++new_link.link_duplex=ETH_LINK_FULL_DUPLEX;+new_link.link_status=hw->link_up?ETH_LINK_UP:+ETH_LINK_DOWN;+new_link.link_autoneg=!(dev->data->dev_conf.link_speeds&+ETH_LINK_SPEED_FIXED);++returnrte_eth_linkstatus_set(dev,&new_link);}/* Add UDP tunneling port */
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.c | 9 +-
drivers/net/ice/ice_dcf.h | 48 ++
drivers/net/ice/ice_dcf_ethdev.c | 14 +
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 30 ++
drivers/net/ice/ice_dcf_sched.c | 759 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 864 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_sched.c
@@ -30,6 +31,49 @@ struct dcf_virtchnl_cmd {volatileintpending;};+structice_dcf_tm_shaper_profile{+TAILQ_ENTRY(ice_dcf_tm_shaper_profile)node;+uint32_tshaper_profile_id;+uint32_treference_count;+structrte_tm_shaper_paramsprofile;+};++TAILQ_HEAD(ice_dcf_shaper_profile_list,ice_dcf_tm_shaper_profile);++/* Struct to store Traffic Manager node configuration. */+structice_dcf_tm_node{+TAILQ_ENTRY(ice_dcf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structice_dcf_tm_node*parent;+structice_dcf_tm_shaper_profile*shaper_profile;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(ice_dcf_tm_node_list,ice_dcf_tm_node);++/* node type of Traffic Manager */+enumice_dcf_tm_node_type{+ICE_DCF_TM_NODE_TYPE_PORT,+ICE_DCF_TM_NODE_TYPE_TC,+ICE_DCF_TM_NODE_TYPE_VSI,+ICE_DCF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structice_dcf_tm_conf{+structice_dcf_shaper_profile_listshaper_profile_list;+structice_dcf_tm_node*root;/* root node - port */+structice_dcf_tm_node_listtc_list;/* node list for all the TCs */+structice_dcf_tm_node_listvsi_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_vsi_node;+boolcommitted;+};+structice_dcf_hw{structiavf_hwavf;
@@ -45,6 +89,8 @@ struct ice_dcf_hw {uint16_t*vf_vsi_map;uint16_tpf_vsi_id;+structice_dcf_tm_conftm_conf;+structice_aqc_port_ets_elem*ets_config;structvirtchnl_version_infovirtchnl_version;structvirtchnl_vf_resource*vf_res;/* VF resource */structvirtchnl_vsi_resource*vsi_res;/* LAN VSI */
@@ -486,6 +509,13 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)returnerr;}+err=ice_dcf_query_port_ets(parent_hw,hw);+if(err){+PMD_INIT_LOG(ERR,"failed to query port ets with error %d",+err);+gotouninit_hw;+}+err=ice_dcf_load_pkg(parent_hw);if(err){PMD_INIT_LOG(ERR,"failed to load package with error %d",
@@ -0,0 +1,759 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"base/ice_sched.h"+#include"ice_dcf_ethdev.h"++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error);++conststructrte_tm_opsice_dcf_tm_ops={+.shaper_profile_add=ice_dcf_shaper_profile_add,+.shaper_profile_delete=ice_dcf_shaper_profile_del,+.hierarchy_commit=ice_dcf_hierarchy_commit,+.node_add=ice_dcf_node_add,+.node_delete=ice_dcf_node_delete,+};++void+ice_dcf_tm_conf_init(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;++/* initialize shaper profile list */+TAILQ_INIT(&hw->tm_conf.shaper_profile_list);++/* initialize node configuration */+hw->tm_conf.root=NULL;+TAILQ_INIT(&hw->tm_conf.tc_list);+TAILQ_INIT(&hw->tm_conf.vsi_list);+hw->tm_conf.nb_tc_node=0;+hw->tm_conf.nb_vsi_node=0;+hw->tm_conf.committed=false;+}++void+ice_dcf_tm_conf_uninit(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+structice_dcf_tm_node*tm_node;++/* clear node configuration */+while((tm_node=TAILQ_FIRST(&hw->tm_conf.vsi_list))){+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+rte_free(tm_node);+}+hw->tm_conf.nb_vsi_node=0;+while((tm_node=TAILQ_FIRST(&hw->tm_conf.tc_list))){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+rte_free(tm_node);+}+hw->tm_conf.nb_tc_node=0;+if(hw->tm_conf.root){+rte_free(hw->tm_conf.root);+hw->tm_conf.root=NULL;+}++/* Remove all shaper profiles */+while((shaper_profile=+TAILQ_FIRST(&hw->tm_conf.shaper_profile_list))){+TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);+rte_free(shaper_profile);+}+}++staticinlinestructice_dcf_tm_node*+ice_dcf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumice_dcf_tm_node_type*node_type)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structice_dcf_tm_node_list*tc_list=&hw->tm_conf.tc_list;+structice_dcf_tm_node*tm_node;++if(hw->tm_conf.root&&hw->tm_conf.root->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_PORT;+returnhw->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,vsi_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_VSI;+returntm_node;+}+}++returnNULL;+}++staticinlinestructice_dcf_tm_shaper_profile*+ice_dcf_shaper_profile_search(structrte_eth_dev*dev,+uint32_tshaper_profile_id)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_shaper_profile_list*shaper_profile_list=+&hw->tm_conf.shaper_profile_list;+structice_dcf_tm_shaper_profile*shaper_profile;++TAILQ_FOREACH(shaper_profile,shaper_profile_list,node){+if(shaper_profile_id==shaper_profile->shaper_profile_id)+returnshaper_profile;+}++returnNULL;+}++staticint+ice_dcf_node_param_check(structice_dcf_hw*hw,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=8*hw->num_vfs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typeparent_node_type=ICE_DCF_TM_NODE_TYPE_MAX;+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_tm_shaper_profile*shaper_profile=NULL;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*parent_node;+structice_dcf_tm_node*tm_node;+uint16_ttc_nb=1;+inti,ret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=ice_dcf_node_param_check(hw,node_id,priority,weight,+params,error);+if(ret)+returnret;++for(i=1;i<ICE_MAX_TRAFFIC_CLASS;i++){+if(hw->ets_config->tc_valid_bits&(1<<i))+tc_nb++;+}++/* check if the node is already existed */+if(ice_dcf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* check the shaper profile id */+if(params->shaper_profile_id!=RTE_TM_SHAPER_PROFILE_ID_NONE){+shaper_profile=ice_dcf_shaper_profile_search(dev,+params->shaper_profile_id);+if(!shaper_profile){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not exist";+return-EINVAL;+}+}++/* add root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=ICE_DCF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(hw->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+hw->tm_conf.root=tm_node;++return0;+}++/* TC or vsi node */+/* check the parent node */+parent_node=ice_dcf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=ICE_DCF_TM_NODE_TYPE_PORT&&+parent_node_type!=ICE_DCF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not port or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=(uint32_t)(parent_node_type+1)){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the TC node number */+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(hw->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the vsi node number */+if(parent_node->reference_count>=hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many VSI for one TC";+return-EINVAL;+}+/* check the vsi node id */+if(node_id>tc_nb*hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large VSI id";+return-EINVAL;+}+}++/* add the TC or vsi node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->priority=priority;+tm_node->weight=weight;+tm_node->shaper_profile=shaper_profile;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,+tm_node,node);+tm_node->tc=hw->tm_conf.nb_tc_node;+hw->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,+tm_node,node);+tm_node->tc=parent_node->tc;+hw->tm_conf.nb_vsi_node++;+}+tm_node->parent->reference_count++;++/* increase the reference counter of the shaper profile */+if(shaper_profile)+shaper_profile->reference_count++;++return0;+}++staticint+ice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=ice_dcf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==ICE_DCF_TM_NODE_TYPE_PORT){+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+rte_free(tm_node);+hw->tm_conf.root=NULL;+return0;+}++/* TC or VSI node */+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+tm_node->parent->reference_count--;+if(node_type==ICE_DCF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+hw->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+hw->tm_conf.nb_vsi_node--;+}+rte_free(tm_node);++return0;+}++staticint+ice_dcf_shaper_profile_param_check(structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+/* min bucket size not supported */+if(profile->committed.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;+error->message="committed bucket size not supported";+return-EINVAL;+}+/* max bucket size not supported */+if(profile->peak.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;+error->message="peak bucket size not supported";+return-EINVAL;+}+/* length adjustment not supported */+if(profile->pkt_length_adjust){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;+error->message="packet length adjustment not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+intret;++if(!profile||!error)+return-EINVAL;++ret=ice_dcf_shaper_profile_param_check(profile,error);+if(ret)+returnret;++shaper_profile=ice_dcf_shaper_profile_search(dev,shaper_profile_id);++if(shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID exist";+return-EINVAL;+}++shaper_profile=rte_zmalloc("ice_dcf_tm_shaper_profile",+sizeof(structice_dcf_tm_shaper_profile),+0);+if(!shaper_profile)+return-ENOMEM;+shaper_profile->shaper_profile_id=shaper_profile_id;+rte_memcpy(&shaper_profile->profile,profile,+sizeof(structrte_tm_shaper_params));+TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);++return0;+}++staticint+ice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;++if(!error)+return-EINVAL;++shaper_profile=ice_dcf_shaper_profile_search(dev,shaper_profile_id);++if(!shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID not exist";+return-EINVAL;+}++/* don't delete a profile if it's used by one or several nodes */+if(shaper_profile->reference_count){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE;+error->message="profile in use";+return-EINVAL;+}++TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,shaper_profile,node);+rte_free(shaper_profile);++return0;+}++staticint+ice_dcf_set_vf_bw(structice_dcf_hw*hw,+structvirtchnl_dcf_bw_cfg_list*vf_bw,+uint16_tlen)+{+structdcf_virtchnl_cmdargs;+interr;++memset(&args,0,sizeof(args));+args.v_op=VIRTCHNL_OP_DCF_CONFIG_BW;+args.req_msg=(uint8_t*)vf_bw;+args.req_msglen=len;+err=ice_dcf_execute_virtchnl_cmd(hw,&args);+if(err)+PMD_DRV_LOG(ERR,"fail to execute command %s",+"VIRTCHNL_OP_DCF_CONFIG_BW");+returnerr;+}++staticint+ice_dcf_validate_tc_bw(structvirtchnl_dcf_bw_cfg_list*tc_bw,+uint32_tport_bw)+{+structvirtchnl_dcf_bw_cfg*cfg;+boollowest_cir_mark=false;+u32total_peak,rest_peak;+u32committed,peak;+inti;++total_peak=0;+for(i=0;i<tc_bw->num_elem;i++)+total_peak+=tc_bw->cfg[i].shaper.peak;++for(i=0;i<tc_bw->num_elem;i++){+cfg=&tc_bw->cfg[i];+peak=cfg->shaper.peak;+committed=cfg->shaper.committed;+rest_peak=total_peak-peak;++if(lowest_cir_mark&&peak==0){+PMD_DRV_LOG(ERR,"Max bandwidth must be configured for TC%u",+cfg->tc_num);+return-EINVAL;+}++if(!lowest_cir_mark&&committed)+lowest_cir_mark=true;++if(committed&&committed+rest_peak>port_bw){+PMD_DRV_LOG(ERR,"Total value of TC%u min bandwidth and other TCs' max bandwidth %ukbps should be less than port link speed %ukbps",+cfg->tc_num,committed+rest_peak,port_bw);+return-EINVAL;+}++if(committed&&committed<ICE_SCHED_MIN_BW){+PMD_DRV_LOG(ERR,"If TC%u min Tx bandwidth is set, it cannot be less than 500Kbps",+cfg->tc_num);+return-EINVAL;+}++if(peak&&committed>peak){+PMD_DRV_LOG(ERR,"TC%u Min Tx bandwidth cannot be greater than max Tx bandwidth",+cfg->tc_num);+return-EINVAL;+}++if(peak>port_bw){+PMD_DRV_LOG(ERR,"TC%u max Tx bandwidth %uKbps is greater than current link speed %uKbps",+cfg->tc_num,peak,port_bw);+return-EINVAL;+}+}++return0;+}+staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+intclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structvirtchnl_dcf_bw_cfg_list*vf_bw;+structvirtchnl_dcf_bw_cfg_list*tc_bw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structrte_tm_shaper_params*profile;+structice_dcf_tm_node*tm_node;+uint32_tport_bw,cir_total;+uint16_tsize,vf_id;+uint8_tnum_elem=0;+inti,ret_val=ICE_SUCCESS;++/* check if all TC nodes are set */+if(BIT(hw->tm_conf.nb_tc_node)&hw->ets_config->tc_valid_bits){+PMD_DRV_LOG(ERR,"Not all enabled TC nodes are set");+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++size=sizeof(structvirtchnl_dcf_bw_cfg_list)++sizeof(structvirtchnl_dcf_bw_cfg)*+(hw->tm_conf.nb_tc_node-1);+vf_bw=rte_zmalloc("vf_bw",size,0);+if(!vf_bw){+ret_val=ICE_ERR_NO_MEMORY;+gotofail_clear;+}+tc_bw=rte_zmalloc("tc_bw",size,0);+if(!tc_bw){+ret_val=ICE_ERR_NO_MEMORY;+gotofail_clear;+}++/* port bandwidth (Kbps) */+port_bw=hw->link_speed*1000;+cir_total=0;++/* init tc bw configuration */+#define ICE_DCF_SCHED_TC_NODE 0xffff+tc_bw->vf_id=ICE_DCF_SCHED_TC_NODE;+tc_bw->node_type=VIRTCHNL_DCF_TARGET_TC_BW;+tc_bw->num_elem=hw->tm_conf.nb_tc_node;+for(i=0;i<tc_bw->num_elem;i++){+tc_bw->cfg[i].tc_num=i;+tc_bw->cfg[i].type=VIRTCHNL_BW_SHAPER;+tc_bw->cfg[i].bw_type|=+VIRTCHNL_DCF_BW_PIR|VIRTCHNL_DCF_BW_CIR;+}++for(vf_id=0;vf_id<hw->num_vfs;vf_id++){+num_elem=0;+vf_bw->vf_id=vf_id;+vf_bw->node_type=VIRTCHNL_DCF_TARGET_VF_BW;+TAILQ_FOREACH(tm_node,vsi_list,node){+/* scan the nodes belong to one VSI */+if(tm_node->id-hw->num_vfs*tm_node->tc!=vf_id)+continue;+vf_bw->cfg[num_elem].tc_num=tm_node->tc;+vf_bw->cfg[num_elem].type=VIRTCHNL_BW_SHAPER;+if(tm_node->shaper_profile){+/* Transfer from Byte per seconds to Kbps */+profile=&tm_node->shaper_profile->profile;+vf_bw->cfg[num_elem].shaper.peak=+profile->peak.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].shaper.committed=+profile->committed.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].bw_type|=+VIRTCHNL_DCF_BW_PIR|+VIRTCHNL_DCF_BW_CIR;+}++/* update tc node bw configuration */+tc_bw->cfg[tm_node->tc].shaper.peak+=+vf_bw->cfg[num_elem].shaper.peak;+tc_bw->cfg[tm_node->tc].shaper.committed+=+vf_bw->cfg[num_elem].shaper.committed;++cir_total+=vf_bw->cfg[num_elem].shaper.committed;+num_elem++;+}++/* check if all TC nodes are set with VF vsi nodes */+if(num_elem!=hw->tm_conf.nb_tc_node){+PMD_DRV_LOG(ERR,"VF%u vsi nodes are not set to all TC nodes, node id should be continuous",+vf_id);+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++vf_bw->num_elem=num_elem;+ret_val=ice_dcf_set_vf_bw(hw,vf_bw,size);+if(ret_val)+gotofail_clear;+memset(vf_bw,0,size);+}++/* check if total CIR is larger than port bandwidth */+if(cir_total>port_bw){+PMD_DRV_LOG(ERR,"Total CIR of all VFs is larger than port bandwidth");+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++/* check and commit tc node bw configuration */+ret_val=ice_dcf_validate_tc_bw(tc_bw,port_bw);+if(ret_val)+gotofail_clear;+ret_val=ice_dcf_set_vf_bw(hw,tc_bw,size);+if(ret_val)+gotofail_clear;++hw->tm_conf.committed=true;+returnret_val;++fail_clear:+/* clear all the traffic manager configuration */+if(clear_on_fail){+ice_dcf_tm_conf_uninit(dev);+ice_dcf_tm_conf_init(dev);+}+returnret_val;+}
This patch added the support for VF to config the ETS-based Tx QoS,
including querying current QoS configuration from PF and config queue TC
mapping. PF QoS is configured in advance and the queried info is
provided to the user for future usage. VF queues are mapped to different
TCs in PF through virtchnl.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 46 +++
drivers/net/iavf/iavf_ethdev.c | 34 ++
drivers/net/iavf/iavf_tm.c | 724 +++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
5 files changed, 860 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
@@ -129,6 +133,38 @@ enum iavf_aq_result {IAVF_MSG_CMD,/* Read async command result */};+/* Struct to store Traffic Manager node configuration. */+structiavf_tm_node{+TAILQ_ENTRY(iavf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structiavf_tm_node*parent;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(iavf_tm_node_list,iavf_tm_node);++/* node type of Traffic Manager */+enumiavf_tm_node_type{+IAVF_TM_NODE_TYPE_PORT,+IAVF_TM_NODE_TYPE_TC,+IAVF_TM_NODE_TYPE_QUEUE,+IAVF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structiavf_tm_conf{+structiavf_tm_node*root;/* root node - vf vsi */+structiavf_tm_node_listtc_list;/* node list for all the TCs */+structiavf_tm_node_listqueue_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_queue_node;+boolcommitted;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -175,6 +211,9 @@ struct iavf_info {structiavf_fdir_infofdir;/* flow director info *//* indicate large VF support enabled or not */boollv_enabled;++structvirtchnl_qos_cap_list*qos_cap;+structiavf_tm_conftm_conf;};#define IAVF_MAX_PKT_TYPE 1024
@@ -806,6 +820,11 @@ iavf_dev_start(struct rte_eth_dev *dev)dev->data->nb_tx_queues);num_queue_pairs=vf->num_queue_pairs;+if(iavf_get_qos_cap(adapter)){+PMD_INIT_LOG(ERR,"Failed to get qos capability");+return-1;+}+if(iavf_init_queues(dev)!=0){PMD_DRV_LOG(ERR,"failed to do Queue init");return-1;
@@ -0,0 +1,724 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"iavf.h"++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintiavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintiavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintiavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error);+staticintiavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error);++conststructrte_tm_opsiavf_tm_ops={+.node_add=iavf_tm_node_add,+.node_delete=iavf_tm_node_delete,+.capabilities_get=iavf_tm_capabilities_get,+.level_capabilities_get=iavf_level_capabilities_get,+.node_capabilities_get=iavf_node_capabilities_get,+.node_type_get=iavf_node_type_get,+.hierarchy_commit=iavf_hierarchy_commit,+};++void+iavf_tm_conf_init(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++/* initialize node configuration */+vf->tm_conf.root=NULL;+TAILQ_INIT(&vf->tm_conf.tc_list);+TAILQ_INIT(&vf->tm_conf.queue_list);+vf->tm_conf.nb_tc_node=0;+vf->tm_conf.nb_queue_node=0;+vf->tm_conf.committed=false;+}++void+iavf_tm_conf_uninit(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node*tm_node;++/* clear node configuration */+while((tm_node=TAILQ_FIRST(&vf->tm_conf.queue_list))){+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+rte_free(tm_node);+}+vf->tm_conf.nb_queue_node=0;+while((tm_node=TAILQ_FIRST(&vf->tm_conf.tc_list))){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+rte_free(tm_node);+}+vf->tm_conf.nb_tc_node=0;+if(vf->tm_conf.root){+rte_free(vf->tm_conf.root);+vf->tm_conf.root=NULL;+}+}++staticinlinestructiavf_tm_node*+iavf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumiavf_tm_node_type*node_type)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node_list*tc_list=&vf->tm_conf.tc_list;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;++if(vf->tm_conf.root&&vf->tm_conf.root->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_PORT;+returnvf->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_QUEUE;+returntm_node;+}+}++returnNULL;+}++staticint+iavf_node_param_check(structiavf_info*vf,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shaper profile */+if(params->shaper_profile_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not supported";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=vf->num_queue_pairs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+iavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error)+{+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!is_leaf||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type==IAVF_TM_NODE_TYPE_QUEUE)+*is_leaf=true;+else+*is_leaf=false;++return0;+}++staticint+iavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+enumiavf_tm_node_typeparent_node_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;+structiavf_tm_node*parent_node;+uint16_ttc_nb=vf->qos_cap->num_elem;+intret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=iavf_node_param_check(vf,node_id,priority,weight,+params,error);+if(ret)+returnret;++/* check if the node is already existed */+if(iavf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=IAVF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(vf->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+vf->tm_conf.root=tm_node;+return0;+}++/* TC or queue node */+/* check the parent node */+parent_node=iavf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=IAVF_TM_NODE_TYPE_PORT&&+parent_node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not root or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the node number */+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(vf->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the queue number */+if(parent_node->reference_count>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many queues";+return-EINVAL;+}+if(node_id>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large queue id";+return-EINVAL;+}+}++/* add the TC or queue node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&vf->tm_conf.tc_list,+tm_node,node);+tm_node->tc=vf->tm_conf.nb_tc_node;+vf->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&vf->tm_conf.queue_list,+tm_node,node);+tm_node->tc=parent_node->tc;+vf->tm_conf.nb_queue_node++;+}+tm_node->parent->reference_count++;++return0;+}++staticint+iavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==IAVF_TM_NODE_TYPE_PORT){+rte_free(tm_node);+vf->tm_conf.root=NULL;+return0;+}++/* TC or queue node */+tm_node->parent->reference_count--;+if(node_type==IAVF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+vf->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+vf->tm_conf.nb_queue_node--;+}+rte_free(tm_node);++return0;+}++staticint+iavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_ttc_nb=vf->qos_cap->num_elem;++if(!cap||!error)+return-EINVAL;++if(tc_nb>vf->vf_res->num_queue_pairs)+return-EINVAL;++error->type=RTE_TM_ERROR_TYPE_NONE;++/* set all the parameters to 0 first. */+memset(cap,0,sizeof(structrte_tm_capabilities));++/**+*supportport+TCs+queues+*hereshowsthemaxcapabilitynotthecurrentconfiguration.+*/+cap->n_nodes_max=1+IAVF_MAX_TRAFFIC_CLASS++vf->num_queue_pairs;+cap->n_levels_max=3;/* port, TC, queue */+cap->non_leaf_nodes_identical=1;+cap->leaf_nodes_identical=1;+cap->shaper_n_max=cap->n_nodes_max;+cap->shaper_private_n_max=cap->n_nodes_max;+cap->shaper_private_dual_rate_n_max=0;+cap->shaper_private_rate_min=0;+/* GBps */+cap->shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->shaper_private_packet_mode_supported=0;+cap->shaper_private_byte_mode_supported=1;+cap->shaper_shared_n_max=0;+cap->shaper_shared_n_nodes_per_shaper_max=0;+cap->shaper_shared_n_shapers_per_node_max=0;+cap->shaper_shared_dual_rate_n_max=0;+cap->shaper_shared_rate_min=0;+cap->shaper_shared_rate_max=0;+cap->shaper_shared_packet_mode_supported=0;+cap->shaper_shared_byte_mode_supported=0;+cap->sched_n_children_max=vf->num_queue_pairs;+cap->sched_sp_n_priorities_max=1;+cap->sched_wfq_n_children_per_group_max=0;+cap->sched_wfq_n_groups_max=0;+cap->sched_wfq_weight_max=1;+cap->sched_wfq_packet_mode_supported=0;+cap->sched_wfq_byte_mode_supported=0;+cap->cman_head_drop_supported=0;+cap->dynamic_update_mask=0;+cap->shaper_pkt_length_adjust_min=RTE_TM_ETH_FRAMING_OVERHEAD;+cap->shaper_pkt_length_adjust_max=RTE_TM_ETH_FRAMING_OVERHEAD_FCS;+cap->cman_wred_context_n_max=0;+cap->cman_wred_context_private_n_max=0;+cap->cman_wred_context_shared_n_max=0;+cap->cman_wred_context_shared_n_nodes_per_context_max=0;+cap->cman_wred_context_shared_n_contexts_per_node_max=0;+cap->stats_mask=0;++return0;+}++staticint+iavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(!cap||!error)+return-EINVAL;++if(level_id>=IAVF_TM_NODE_TYPE_MAX){+error->type=RTE_TM_ERROR_TYPE_LEVEL_ID;+error->message="too deep level";+return-EINVAL;+}++/* root node */+if(level_id==IAVF_TM_NODE_TYPE_PORT){+cap->n_nodes_max=1;+cap->n_nodes_nonleaf_max=1;+cap->n_nodes_leaf_max=0;+}elseif(level_id==IAVF_TM_NODE_TYPE_TC){+/* TC */+cap->n_nodes_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_nonleaf_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_leaf_max=0;+}else{+/* queue */+cap->n_nodes_max=vf->num_queue_pairs;+cap->n_nodes_nonleaf_max=0;+cap->n_nodes_leaf_max=vf->num_queue_pairs;+}++cap->non_leaf_nodes_identical=true;+cap->leaf_nodes_identical=true;++if(level_id!=IAVF_TM_NODE_TYPE_QUEUE){+cap->nonleaf.shaper_private_supported=true;+cap->nonleaf.shaper_private_dual_rate_supported=false;+cap->nonleaf.shaper_private_rate_min=0;+/* GBps */+cap->nonleaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->nonleaf.shaper_private_packet_mode_supported=0;+cap->nonleaf.shaper_private_byte_mode_supported=1;+cap->nonleaf.shaper_shared_n_max=0;+cap->nonleaf.shaper_shared_packet_mode_supported=0;+cap->nonleaf.shaper_shared_byte_mode_supported=0;+if(level_id==IAVF_TM_NODE_TYPE_PORT)+cap->nonleaf.sched_n_children_max=+IAVF_MAX_TRAFFIC_CLASS;+else+cap->nonleaf.sched_n_children_max=+vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+cap->nonleaf.sched_wfq_packet_mode_supported=0;+cap->nonleaf.sched_wfq_byte_mode_supported=0;+cap->nonleaf.stats_mask=0;++return0;+}++/* queue node */+cap->leaf.shaper_private_supported=false;+cap->leaf.shaper_private_dual_rate_supported=false;+cap->leaf.shaper_private_rate_min=0;+/* GBps */+cap->leaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->leaf.shaper_private_packet_mode_supported=0;+cap->leaf.shaper_private_byte_mode_supported=1;+cap->leaf.shaper_shared_n_max=0;+cap->leaf.shaper_shared_packet_mode_supported=0;+cap->leaf.shaper_shared_byte_mode_supported=0;+cap->leaf.cman_head_drop_supported=false;+cap->leaf.cman_wred_context_private_supported=true;+cap->leaf.cman_wred_context_shared_n_max=0;+cap->leaf.stats_mask=0;++return0;+}++staticint+iavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type;+structvirtchnl_qos_cap_elemtc_cap;+structiavf_tm_node*tm_node;++if(!cap||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="not support capability get";+return-EINVAL;+}++tc_cap=vf->qos_cap->cap[tm_node->tc];+if(tc_cap.tc_num!=tm_node->tc){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="tc not match";+return-EINVAL;+}++cap->shaper_private_supported=true;+cap->shaper_private_dual_rate_supported=false;+cap->shaper_private_rate_min=tc_cap.shaper.committed;+cap->shaper_private_rate_max=tc_cap.shaper.peak;+cap->shaper_shared_n_max=0;+cap->nonleaf.sched_n_children_max=vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=1;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=tc_cap.weight;+cap->stats_mask=0;++return0;+}++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+intclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_adapter*adapter=+IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);+structvirtchnl_queue_tc_mapping*q_tc_mapping;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;+uint16_tsize;+intindex=0,node_committed=0;+inti,ret_val=IAVF_SUCCESS;++/* check if port is stopped */+if(adapter->stopped!=1){+PMD_DRV_LOG(ERR,"Please stop port first");+ret_val=IAVF_ERR_NOT_READY;+gotoerr;+}++/* check if all TC nodes are set with VF vsi */+if(vf->tm_conf.nb_tc_node!=vf->qos_cap->num_elem){+PMD_DRV_LOG(ERR,"Does not set VF vsi nodes to all TCs");+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}++size=sizeof(*q_tc_mapping)+sizeof(q_tc_mapping->tc[0])*+(vf->qos_cap->num_elem-1);+q_tc_mapping=rte_zmalloc("q_tc",size,0);+if(!q_tc_mapping){+ret_val=IAVF_ERR_NO_MEMORY;+gotofail_clear;+}++q_tc_mapping->vsi_id=vf->vsi.vsi_id;+q_tc_mapping->num_tc=vf->qos_cap->num_elem;+q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->tc>=q_tc_mapping->num_tc){+PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}+q_tc_mapping->tc[tm_node->tc].req.queue_count++;+node_committed++;+}++/* All queues allocated to this VF should be mapped */+if(node_committed<vf->num_queue_pairs){+PMD_DRV_LOG(ERR,"queue node is less than allocated queue pairs");+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}++for(i=0;i<q_tc_mapping->num_tc;i++){+q_tc_mapping->tc[i].req.start_queue_id=index;+index+=q_tc_mapping->tc[i].req.queue_count;+}++ret_val=iavf_set_q_tc_map(dev,q_tc_mapping,size);+if(ret_val)+gotofail_clear;++vf->tm_conf.committed=true;+returnret_val;++fail_clear:+/* clear all the traffic manager configuration */+if(clear_on_fail){+iavf_tm_conf_uninit(dev);+iavf_tm_conf_init(dev);+}+err:+returnret_val;+}
Add check in the Tx packet preparation function, to guarantee that the
packet with specific user priority is distributed to the correct Tx
queue according to the configured Tx queue TC mapping.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 10 +++++++++
drivers/net/iavf/iavf_rxtx.c | 43 ++++++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_tm.c | 13 +++++++++++
3 files changed, 66 insertions(+)
@@ -165,6 +167,13 @@ struct iavf_tm_conf {boolcommitted;};+/* Struct to store queue TC mapping. Queue is continuous in one TC */+structiavf_qtc_map{+uint8_ttc;+uint16_tstart_queue_id;+uint16_tqueue_count;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -2342,14 +2342,49 @@ iavf_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)returnnb_tx;}+/* Check if the packet with vlan user priority is transmitted in the+*correctqueue.+*/+staticint+iavf_check_vlan_up2tc(structiavf_tx_queue*txq,uint8_ttc,structrte_mbuf*m)+{+structrte_eth_dev*dev=&rte_eth_devices[txq->port_id];+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_tup;++up=m->vlan_tci>>IAVF_VLAN_TAG_PCP_OFFSET;++if(!(vf->qos_cap->cap[tc].tc_prio&BIT(up))){+PMD_TX_LOG(ERR,"packet with vlan pcp %u cannot transmit in queue %u\n",+up,txq->queue_id);+return-1;+}else{+return0;+}+}+/* TX prep functions */uint16_tiavf_prep_pkts(__rte_unusedvoid*tx_queue,structrte_mbuf**tx_pkts,uint16_tnb_pkts){inti,ret;+uint8_ttc=0;uint64_tol_flags;structrte_mbuf*m;+structiavf_tx_queue*txq=tx_queue;+structrte_eth_dev*dev=&rte_eth_devices[txq->port_id];+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(vf->tm_conf.committed){+for(i=0;i<vf->qos_cap->num_elem;i++){+if(txq->queue_id>=vf->qtc_map[i].start_queue_id&&+txq->queue_id<(vf->qtc_map[i].start_queue_id++vf->qtc_map[i].queue_count))+break;+}+tc=i;+}for(i=0;i<nb_pkts;i++){m=tx_pkts[i];
@@ -655,6 +655,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,structvirtchnl_queue_tc_mapping*q_tc_mapping;structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;structiavf_tm_node*tm_node;+structiavf_qtc_map*qtc_map;uint16_tsize;intindex=0,node_committed=0;inti,ret_val=IAVF_SUCCESS;
@@ -684,6 +685,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,q_tc_mapping->vsi_id=vf->vsi.vsi_id;q_tc_mapping->num_tc=vf->qos_cap->num_elem;q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){if(tm_node->tc>=q_tc_mapping->num_tc){PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);
@@ -701,15 +703,26 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,gotofail_clear;}+/* store the queue TC mapping info */+qtc_map=rte_zmalloc("qtc_map",+sizeof(structiavf_qtc_map)*q_tc_mapping->num_tc,0);+if(!qtc_map)+returnIAVF_ERR_NO_MEMORY;+for(i=0;i<q_tc_mapping->num_tc;i++){q_tc_mapping->tc[i].req.start_queue_id=index;index+=q_tc_mapping->tc[i].req.queue_count;+qtc_map[i].tc=i;+qtc_map[i].start_queue_id=+q_tc_mapping->tc[i].req.start_queue_id;+qtc_map[i].queue_count=q_tc_mapping->tc[i].req.queue_count;}ret_val=iavf_set_q_tc_map(dev,q_tc_mapping,size);if(ret_val)gotofail_clear;+vf->qtc_map=qtc_map;vf->tm_conf.committed=true;returnret_val;
@@ -55,6 +55,13 @@ New Features Also, make sure to start the actual text at the margin. =======================================================+***Updated Intel iavf driver.**++* Added Tx QoS VF queue TC mapping.++***Updated Intel ice driver.**++* Added Tx QoS TC bandwidth configuration in DCF. Removed Items -------------
This patch enables the ETS-based Tx QoS for IAVF. Kernel tool is used to
configure ETS first. DCF is used to set bandwidth limit for VFs of each
TC. IAVF is supported to query QoS capability and set queue TC mapping.
Traffic Management API is utilized to configure the QoS hierarchy
scheduler tree. The scheduler tree will be passed to hardware to enable
all above functions.
Ting Xu (7):
common/iavf: support ETS-based QoS offload configuration
net/ice/base: support DCF query port ETS adminq
net/ice: support DCF link status event handling
net/ice: support QoS config VF bandwidth in DCF
net/iavf: query QoS cap and set queue TC mapping
net/iavf: check Tx packet with correct UP and queue
doc: release note for ETS-based Tx QoS
doc/guides/rel_notes/release_21_08.rst | 7 +
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 +++++
drivers/net/iavf/iavf.h | 56 ++
drivers/net/iavf/iavf_ethdev.c | 37 ++
drivers/net/iavf/iavf_rxtx.c | 49 ++
drivers/net/iavf/iavf_rxtx.h | 1 +
drivers/net/iavf/iavf_tm.c | 743 ++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 +-
drivers/net/iavf/meson.build | 1 +
drivers/net/ice/base/ice_dcb.c | 3 +-
drivers/net/ice/ice_dcf.c | 9 +-
drivers/net/ice/ice_dcf.h | 54 ++
drivers/net/ice/ice_dcf_ethdev.c | 68 ++-
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 83 +++
drivers/net/ice/ice_dcf_sched.c | 765 +++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
18 files changed, 2064 insertions(+), 7 deletions(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
create mode 100644 drivers/net/ice/ice_dcf_sched.c
--
2.17.1
This patch adds new virtchnl opcodes and structures for QoS
configuration, which includes:
1. VIRTCHNL_VF_OFFLOAD_TC, to negotiate the capability supporting QoS
configuration. If VF and PF both have this flag, then the ETS-based QoS
offload function is supported.
2. VIRTCHNL_OP_DCF_CONFIG_BW, DCF is supposed to configure min and max
bandwidth for each VF per enabled TCs. To make the VSI node bandwidth
configuration work, DCF also needs to configure TC node bandwidth
directly.
3. VIRTCHNL_OP_GET_QOS_CAPS, VF queries current QoS configuration, such
as enabled TCs, arbiter type, up2tc and bandwidth of VSI node. The
configuration is previously set by DCB and DCF, and now is the potential
QoS capability of VF. VF can take it as reference to configure queue TC
mapping.
4. VIRTCHNL_OP_CONFIG_TC_MAP, set VF queues to TC mapping for all Tx and
Rx queues. Queues mapping to one TC should be continuous and all
allocated queues should be mapped.
Signed-off-by: Ting Xu <redacted>
---
drivers/common/iavf/iavf_type.h | 2 +
drivers/common/iavf/virtchnl.h | 131 ++++++++++++++++++++++++++++++++
2 files changed, 133 insertions(+)
In the adminq command query port ETS function, the root node teid is
needed. However, for DCF, the root node is not initialized, which will
cause error when we refer to the variable. In this patch, we will check
whether the root node is available or not first.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/base/ice_dcb.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
When link status changes, DCF will receive virtchnl PF event message.
Add support to handle this event, change link status and update link
info.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.h | 6 ++++
drivers/net/ice/ice_dcf_ethdev.c | 54 ++++++++++++++++++++++++++++++--
drivers/net/ice/ice_dcf_parent.c | 51 ++++++++++++++++++++++++++++++
3 files changed, 108 insertions(+), 3 deletions(-)
@@ -60,6 +60,10 @@ struct ice_dcf_hw {uint16_tnb_msix;uint16_trxq_map[16];structvirtchnl_eth_statseth_stats_offset;++/* Link status */+boollink_up;+uint32_tlink_speed;};intice_dcf_execute_virtchnl_cmd(structice_dcf_hw*hw,
@@ -881,11 +881,59 @@ ice_dcf_dev_close(struct rte_eth_dev *dev)return0;}-staticint-ice_dcf_link_update(__rte_unusedstructrte_eth_dev*dev,+int+ice_dcf_link_update(structrte_eth_dev*dev,__rte_unusedintwait_to_complete){-return0;+structice_dcf_adapter*ad=dev->data->dev_private;+structice_dcf_hw*hw=&ad->real_hw;+structrte_eth_linknew_link;++memset(&new_link,0,sizeof(new_link));++/* Only read status info stored in VF, and the info is updated+*whenreceiveLINK_CHANGEeventfromPFbyvirtchnl.+*/+switch(hw->link_speed){+case10:+new_link.link_speed=ETH_SPEED_NUM_10M;+break;+case100:+new_link.link_speed=ETH_SPEED_NUM_100M;+break;+case1000:+new_link.link_speed=ETH_SPEED_NUM_1G;+break;+case10000:+new_link.link_speed=ETH_SPEED_NUM_10G;+break;+case20000:+new_link.link_speed=ETH_SPEED_NUM_20G;+break;+case25000:+new_link.link_speed=ETH_SPEED_NUM_25G;+break;+case40000:+new_link.link_speed=ETH_SPEED_NUM_40G;+break;+case50000:+new_link.link_speed=ETH_SPEED_NUM_50G;+break;+case100000:+new_link.link_speed=ETH_SPEED_NUM_100G;+break;+default:+new_link.link_speed=ETH_SPEED_NUM_NONE;+break;+}++new_link.link_duplex=ETH_LINK_FULL_DUPLEX;+new_link.link_status=hw->link_up?ETH_LINK_UP:+ETH_LINK_DOWN;+new_link.link_autoneg=!(dev->data->dev_conf.link_speeds&+ETH_LINK_SPEED_FIXED);++returnrte_eth_linkstatus_set(dev,&new_link);}/* Add UDP tunneling port */
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/ice/ice_dcf.c | 9 +-
drivers/net/ice/ice_dcf.h | 48 ++
drivers/net/ice/ice_dcf_ethdev.c | 14 +
drivers/net/ice/ice_dcf_ethdev.h | 3 +
drivers/net/ice/ice_dcf_parent.c | 32 ++
drivers/net/ice/ice_dcf_sched.c | 765 +++++++++++++++++++++++++++++++
drivers/net/ice/meson.build | 3 +-
7 files changed, 872 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ice/ice_dcf_sched.c
@@ -30,6 +31,49 @@ struct dcf_virtchnl_cmd {volatileintpending;};+structice_dcf_tm_shaper_profile{+TAILQ_ENTRY(ice_dcf_tm_shaper_profile)node;+uint32_tshaper_profile_id;+uint32_treference_count;+structrte_tm_shaper_paramsprofile;+};++TAILQ_HEAD(ice_dcf_shaper_profile_list,ice_dcf_tm_shaper_profile);++/* Struct to store Traffic Manager node configuration. */+structice_dcf_tm_node{+TAILQ_ENTRY(ice_dcf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structice_dcf_tm_node*parent;+structice_dcf_tm_shaper_profile*shaper_profile;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(ice_dcf_tm_node_list,ice_dcf_tm_node);++/* node type of Traffic Manager */+enumice_dcf_tm_node_type{+ICE_DCF_TM_NODE_TYPE_PORT,+ICE_DCF_TM_NODE_TYPE_TC,+ICE_DCF_TM_NODE_TYPE_VSI,+ICE_DCF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structice_dcf_tm_conf{+structice_dcf_shaper_profile_listshaper_profile_list;+structice_dcf_tm_node*root;/* root node - port */+structice_dcf_tm_node_listtc_list;/* node list for all the TCs */+structice_dcf_tm_node_listvsi_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_vsi_node;+boolcommitted;+};+structice_dcf_hw{structiavf_hwavf;
@@ -45,6 +89,8 @@ struct ice_dcf_hw {uint16_t*vf_vsi_map;uint16_tpf_vsi_id;+structice_dcf_tm_conftm_conf;+structice_aqc_port_ets_elem*ets_config;structvirtchnl_version_infovirtchnl_version;structvirtchnl_vf_resource*vf_res;/* VF resource */structvirtchnl_vsi_resource*vsi_res;/* LAN VSI */
@@ -486,6 +509,15 @@ ice_dcf_init_parent_adapter(struct rte_eth_dev *eth_dev)returnerr;}+if(hw->vf_res->vf_cap_flags&VIRTCHNL_VF_OFFLOAD_QOS){+err=ice_dcf_query_port_ets(parent_hw,hw);+if(err){+PMD_INIT_LOG(ERR,"failed to query port ets with error %d",+err);+gotouninit_hw;+}+}+err=ice_dcf_load_pkg(parent_hw);if(err){PMD_INIT_LOG(ERR,"failed to load package with error %d",
@@ -0,0 +1,765 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"base/ice_sched.h"+#include"ice_dcf_ethdev.h"++staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error);+staticintice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error);++conststructrte_tm_opsice_dcf_tm_ops={+.shaper_profile_add=ice_dcf_shaper_profile_add,+.shaper_profile_delete=ice_dcf_shaper_profile_del,+.hierarchy_commit=ice_dcf_hierarchy_commit,+.node_add=ice_dcf_node_add,+.node_delete=ice_dcf_node_delete,+};++void+ice_dcf_tm_conf_init(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;++/* initialize shaper profile list */+TAILQ_INIT(&hw->tm_conf.shaper_profile_list);++/* initialize node configuration */+hw->tm_conf.root=NULL;+TAILQ_INIT(&hw->tm_conf.tc_list);+TAILQ_INIT(&hw->tm_conf.vsi_list);+hw->tm_conf.nb_tc_node=0;+hw->tm_conf.nb_vsi_node=0;+hw->tm_conf.committed=false;+}++void+ice_dcf_tm_conf_uninit(structrte_eth_dev*dev)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+structice_dcf_tm_node*tm_node;++/* clear node configuration */+while((tm_node=TAILQ_FIRST(&hw->tm_conf.vsi_list))){+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+rte_free(tm_node);+}+hw->tm_conf.nb_vsi_node=0;+while((tm_node=TAILQ_FIRST(&hw->tm_conf.tc_list))){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+rte_free(tm_node);+}+hw->tm_conf.nb_tc_node=0;+if(hw->tm_conf.root){+rte_free(hw->tm_conf.root);+hw->tm_conf.root=NULL;+}++/* Remove all shaper profiles */+while((shaper_profile=+TAILQ_FIRST(&hw->tm_conf.shaper_profile_list))){+TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);+rte_free(shaper_profile);+}+}++staticinlinestructice_dcf_tm_node*+ice_dcf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumice_dcf_tm_node_type*node_type)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structice_dcf_tm_node_list*tc_list=&hw->tm_conf.tc_list;+structice_dcf_tm_node*tm_node;++if(hw->tm_conf.root&&hw->tm_conf.root->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_PORT;+returnhw->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,vsi_list,node){+if(tm_node->id==node_id){+*node_type=ICE_DCF_TM_NODE_TYPE_VSI;+returntm_node;+}+}++returnNULL;+}++staticinlinestructice_dcf_tm_shaper_profile*+ice_dcf_shaper_profile_search(structrte_eth_dev*dev,+uint32_tshaper_profile_id)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_shaper_profile_list*shaper_profile_list=+&hw->tm_conf.shaper_profile_list;+structice_dcf_tm_shaper_profile*shaper_profile;++TAILQ_FOREACH(shaper_profile,shaper_profile_list,node){+if(shaper_profile_id==shaper_profile->shaper_profile_id)+returnshaper_profile;+}++returnNULL;+}++staticint+ice_dcf_node_param_check(structice_dcf_hw*hw,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=8*hw->num_vfs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typeparent_node_type=ICE_DCF_TM_NODE_TYPE_MAX;+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_tm_shaper_profile*shaper_profile=NULL;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*parent_node;+structice_dcf_tm_node*tm_node;+uint16_ttc_nb=1;+inti,ret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=ice_dcf_node_param_check(hw,node_id,priority,weight,+params,error);+if(ret)+returnret;++for(i=1;i<ICE_MAX_TRAFFIC_CLASS;i++){+if(hw->ets_config->tc_valid_bits&(1<<i))+tc_nb++;+}++/* check if the node is already existed */+if(ice_dcf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* check the shaper profile id */+if(params->shaper_profile_id!=RTE_TM_SHAPER_PROFILE_ID_NONE){+shaper_profile=ice_dcf_shaper_profile_search(dev,+params->shaper_profile_id);+if(!shaper_profile){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not exist";+return-EINVAL;+}+}++/* add root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=ICE_DCF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(hw->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+hw->tm_conf.root=tm_node;++return0;+}++/* TC or vsi node */+/* check the parent node */+parent_node=ice_dcf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=ICE_DCF_TM_NODE_TYPE_PORT&&+parent_node_type!=ICE_DCF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not port or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=(uint32_t)(parent_node_type+1)){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the TC node number */+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(hw->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the vsi node number */+if(parent_node->reference_count>=hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many VSI for one TC";+return-EINVAL;+}+/* check the vsi node id */+if(node_id>tc_nb*hw->num_vfs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large VSI id";+return-EINVAL;+}+}++/* add the TC or vsi node */+tm_node=rte_zmalloc("ice_dcf_tm_node",+sizeof(structice_dcf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->priority=priority;+tm_node->weight=weight;+tm_node->shaper_profile=shaper_profile;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==ICE_DCF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&hw->tm_conf.tc_list,+tm_node,node);+tm_node->tc=hw->tm_conf.nb_tc_node;+hw->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&hw->tm_conf.vsi_list,+tm_node,node);+tm_node->tc=parent_node->tc;+hw->tm_conf.nb_vsi_node++;+}+tm_node->parent->reference_count++;++/* increase the reference counter of the shaper profile */+if(shaper_profile)+shaper_profile->reference_count++;++return0;+}++staticint+ice_dcf_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+enumice_dcf_tm_node_typenode_type=ICE_DCF_TM_NODE_TYPE_MAX;+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(hw->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=ice_dcf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==ICE_DCF_TM_NODE_TYPE_PORT){+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+rte_free(tm_node);+hw->tm_conf.root=NULL;+return0;+}++/* TC or VSI node */+if(tm_node->shaper_profile)+tm_node->shaper_profile->reference_count--;+tm_node->parent->reference_count--;+if(node_type==ICE_DCF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&hw->tm_conf.tc_list,tm_node,node);+hw->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&hw->tm_conf.vsi_list,tm_node,node);+hw->tm_conf.nb_vsi_node--;+}+rte_free(tm_node);++return0;+}++staticint+ice_dcf_shaper_profile_param_check(structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+/* min bucket size not supported */+if(profile->committed.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE;+error->message="committed bucket size not supported";+return-EINVAL;+}+/* max bucket size not supported */+if(profile->peak.size){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE;+error->message="peak bucket size not supported";+return-EINVAL;+}+/* length adjustment not supported */+if(profile->pkt_length_adjust){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN;+error->message="packet length adjustment not supported";+return-EINVAL;+}++return0;+}++staticint+ice_dcf_shaper_profile_add(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_shaper_params*profile,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;+intret;++if(!profile||!error)+return-EINVAL;++ret=ice_dcf_shaper_profile_param_check(profile,error);+if(ret)+returnret;++shaper_profile=ice_dcf_shaper_profile_search(dev,shaper_profile_id);++if(shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID exist";+return-EINVAL;+}++shaper_profile=rte_zmalloc("ice_dcf_tm_shaper_profile",+sizeof(structice_dcf_tm_shaper_profile),+0);+if(!shaper_profile)+return-ENOMEM;+shaper_profile->shaper_profile_id=shaper_profile_id;+rte_memcpy(&shaper_profile->profile,profile,+sizeof(structrte_tm_shaper_params));+TAILQ_INSERT_TAIL(&hw->tm_conf.shaper_profile_list,+shaper_profile,node);++return0;+}++staticint+ice_dcf_shaper_profile_del(structrte_eth_dev*dev,+uint32_tshaper_profile_id,+structrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structice_dcf_tm_shaper_profile*shaper_profile;++if(!error)+return-EINVAL;++shaper_profile=ice_dcf_shaper_profile_search(dev,shaper_profile_id);++if(!shaper_profile){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID;+error->message="profile ID not exist";+return-EINVAL;+}++/* don't delete a profile if it's used by one or several nodes */+if(shaper_profile->reference_count){+error->type=RTE_TM_ERROR_TYPE_SHAPER_PROFILE;+error->message="profile in use";+return-EINVAL;+}++TAILQ_REMOVE(&hw->tm_conf.shaper_profile_list,shaper_profile,node);+rte_free(shaper_profile);++return0;+}++staticint+ice_dcf_set_vf_bw(structice_dcf_hw*hw,+structvirtchnl_dcf_bw_cfg_list*vf_bw,+uint16_tlen)+{+structdcf_virtchnl_cmdargs;+interr;++memset(&args,0,sizeof(args));+args.v_op=VIRTCHNL_OP_DCF_CONFIG_BW;+args.req_msg=(uint8_t*)vf_bw;+args.req_msglen=len;+err=ice_dcf_execute_virtchnl_cmd(hw,&args);+if(err)+PMD_DRV_LOG(ERR,"fail to execute command %s",+"VIRTCHNL_OP_DCF_CONFIG_BW");+returnerr;+}++staticint+ice_dcf_validate_tc_bw(structvirtchnl_dcf_bw_cfg_list*tc_bw,+uint32_tport_bw)+{+structvirtchnl_dcf_bw_cfg*cfg;+boollowest_cir_mark=false;+u32total_peak,rest_peak;+u32committed,peak;+inti;++total_peak=0;+for(i=0;i<tc_bw->num_elem;i++)+total_peak+=tc_bw->cfg[i].shaper.peak;++for(i=0;i<tc_bw->num_elem;i++){+cfg=&tc_bw->cfg[i];+peak=cfg->shaper.peak;+committed=cfg->shaper.committed;+rest_peak=total_peak-peak;++if(lowest_cir_mark&&peak==0){+PMD_DRV_LOG(ERR,"Max bandwidth must be configured for TC%u",+cfg->tc_num);+return-EINVAL;+}++if(!lowest_cir_mark&&committed)+lowest_cir_mark=true;++if(committed&&committed+rest_peak>port_bw){+PMD_DRV_LOG(ERR,"Total value of TC%u min bandwidth and other TCs' max bandwidth %ukbps should be less than port link speed %ukbps",+cfg->tc_num,committed+rest_peak,port_bw);+return-EINVAL;+}++if(committed&&committed<ICE_SCHED_MIN_BW){+PMD_DRV_LOG(ERR,"If TC%u min Tx bandwidth is set, it cannot be less than 500Kbps",+cfg->tc_num);+return-EINVAL;+}++if(peak&&committed>peak){+PMD_DRV_LOG(ERR,"TC%u Min Tx bandwidth cannot be greater than max Tx bandwidth",+cfg->tc_num);+return-EINVAL;+}++if(peak>port_bw){+PMD_DRV_LOG(ERR,"TC%u max Tx bandwidth %uKbps is greater than current link speed %uKbps",+cfg->tc_num,peak,port_bw);+return-EINVAL;+}+}++return0;+}+staticintice_dcf_hierarchy_commit(structrte_eth_dev*dev,+intclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structice_dcf_adapter*adapter=dev->data->dev_private;+structice_dcf_hw*hw=&adapter->real_hw;+structvirtchnl_dcf_bw_cfg_list*vf_bw;+structvirtchnl_dcf_bw_cfg_list*tc_bw;+structice_dcf_tm_node_list*vsi_list=&hw->tm_conf.vsi_list;+structrte_tm_shaper_params*profile;+structice_dcf_tm_node*tm_node;+uint32_tport_bw,cir_total;+uint16_tsize,vf_id;+uint8_tnum_elem=0;+inti,ret_val=ICE_SUCCESS;++if(!(hw->vf_res->vf_cap_flags&VIRTCHNL_VF_OFFLOAD_QOS)){+PMD_DRV_LOG(ERR,"Configure VF bandwidth is not supported");+ret_val=ICE_ERR_NOT_SUPPORTED;+gotofail_clear;+}++/* check if all TC nodes are set */+if(BIT(hw->tm_conf.nb_tc_node)&hw->ets_config->tc_valid_bits){+PMD_DRV_LOG(ERR,"Not all enabled TC nodes are set");+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++size=sizeof(structvirtchnl_dcf_bw_cfg_list)++sizeof(structvirtchnl_dcf_bw_cfg)*+(hw->tm_conf.nb_tc_node-1);+vf_bw=rte_zmalloc("vf_bw",size,0);+if(!vf_bw){+ret_val=ICE_ERR_NO_MEMORY;+gotofail_clear;+}+tc_bw=rte_zmalloc("tc_bw",size,0);+if(!tc_bw){+ret_val=ICE_ERR_NO_MEMORY;+gotofail_clear;+}++/* port bandwidth (Kbps) */+port_bw=hw->link_speed*1000;+cir_total=0;++/* init tc bw configuration */+#define ICE_DCF_SCHED_TC_NODE 0xffff+tc_bw->vf_id=ICE_DCF_SCHED_TC_NODE;+tc_bw->node_type=VIRTCHNL_DCF_TARGET_TC_BW;+tc_bw->num_elem=hw->tm_conf.nb_tc_node;+for(i=0;i<tc_bw->num_elem;i++){+tc_bw->cfg[i].tc_num=i;+tc_bw->cfg[i].type=VIRTCHNL_BW_SHAPER;+tc_bw->cfg[i].bw_type|=+VIRTCHNL_DCF_BW_PIR|VIRTCHNL_DCF_BW_CIR;+}++for(vf_id=0;vf_id<hw->num_vfs;vf_id++){+num_elem=0;+vf_bw->vf_id=vf_id;+vf_bw->node_type=VIRTCHNL_DCF_TARGET_VF_BW;+TAILQ_FOREACH(tm_node,vsi_list,node){+/* scan the nodes belong to one VSI */+if(tm_node->id-hw->num_vfs*tm_node->tc!=vf_id)+continue;+vf_bw->cfg[num_elem].tc_num=tm_node->tc;+vf_bw->cfg[num_elem].type=VIRTCHNL_BW_SHAPER;+if(tm_node->shaper_profile){+/* Transfer from Byte per seconds to Kbps */+profile=&tm_node->shaper_profile->profile;+vf_bw->cfg[num_elem].shaper.peak=+profile->peak.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].shaper.committed=+profile->committed.rate/1000*BITS_PER_BYTE;+vf_bw->cfg[num_elem].bw_type|=+VIRTCHNL_DCF_BW_PIR|+VIRTCHNL_DCF_BW_CIR;+}++/* update tc node bw configuration */+tc_bw->cfg[tm_node->tc].shaper.peak+=+vf_bw->cfg[num_elem].shaper.peak;+tc_bw->cfg[tm_node->tc].shaper.committed+=+vf_bw->cfg[num_elem].shaper.committed;++cir_total+=vf_bw->cfg[num_elem].shaper.committed;+num_elem++;+}++/* check if all TC nodes are set with VF vsi nodes */+if(num_elem!=hw->tm_conf.nb_tc_node){+PMD_DRV_LOG(ERR,"VF%u vsi nodes are not set to all TC nodes, node id should be continuous",+vf_id);+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++vf_bw->num_elem=num_elem;+ret_val=ice_dcf_set_vf_bw(hw,vf_bw,size);+if(ret_val)+gotofail_clear;+memset(vf_bw,0,size);+}++/* check if total CIR is larger than port bandwidth */+if(cir_total>port_bw){+PMD_DRV_LOG(ERR,"Total CIR of all VFs is larger than port bandwidth");+ret_val=ICE_ERR_PARAM;+gotofail_clear;+}++/* check and commit tc node bw configuration */+ret_val=ice_dcf_validate_tc_bw(tc_bw,port_bw);+if(ret_val)+gotofail_clear;+ret_val=ice_dcf_set_vf_bw(hw,tc_bw,size);+if(ret_val)+gotofail_clear;++hw->tm_conf.committed=true;+returnret_val;++fail_clear:+/* clear all the traffic manager configuration */+if(clear_on_fail){+ice_dcf_tm_conf_uninit(dev);+ice_dcf_tm_conf_init(dev);+}+returnret_val;+}
This patch added the support for VF to config the ETS-based Tx QoS,
including querying current QoS configuration from PF and config queue TC
mapping. PF QoS is configured in advance and the queried info is
provided to the user for future usage. VF queues are mapped to different
TCs in PF through virtchnl.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 46 +++
drivers/net/iavf/iavf_ethdev.c | 37 ++
drivers/net/iavf/iavf_tm.c | 730 +++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_vchnl.c | 56 ++-
drivers/net/iavf/meson.build | 1 +
5 files changed, 869 insertions(+), 1 deletion(-)
create mode 100644 drivers/net/iavf/iavf_tm.c
@@ -129,6 +133,38 @@ enum iavf_aq_result {IAVF_MSG_CMD,/* Read async command result */};+/* Struct to store Traffic Manager node configuration. */+structiavf_tm_node{+TAILQ_ENTRY(iavf_tm_node)node;+uint32_tid;+uint32_ttc;+uint32_tpriority;+uint32_tweight;+uint32_treference_count;+structiavf_tm_node*parent;+structrte_tm_node_paramsparams;+};++TAILQ_HEAD(iavf_tm_node_list,iavf_tm_node);++/* node type of Traffic Manager */+enumiavf_tm_node_type{+IAVF_TM_NODE_TYPE_PORT,+IAVF_TM_NODE_TYPE_TC,+IAVF_TM_NODE_TYPE_QUEUE,+IAVF_TM_NODE_TYPE_MAX,+};++/* Struct to store all the Traffic Manager configuration. */+structiavf_tm_conf{+structiavf_tm_node*root;/* root node - vf vsi */+structiavf_tm_node_listtc_list;/* node list for all the TCs */+structiavf_tm_node_listqueue_list;/* node list for all the queues */+uint32_tnb_tc_node;+uint32_tnb_queue_node;+boolcommitted;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -175,6 +211,9 @@ struct iavf_info {structiavf_fdir_infofdir;/* flow director info *//* indicate large VF support enabled or not */boollv_enabled;++structvirtchnl_qos_cap_list*qos_cap;+structiavf_tm_conftm_conf;};#define IAVF_MAX_PKT_TYPE 1024
@@ -806,6 +820,12 @@ iavf_dev_start(struct rte_eth_dev *dev)dev->data->nb_tx_queues);num_queue_pairs=vf->num_queue_pairs;+if(vf->vf_res->vf_cap_flags&VIRTCHNL_VF_OFFLOAD_QOS)+if(iavf_get_qos_cap(adapter)){+PMD_INIT_LOG(ERR,"Failed to get qos capability");+return-1;+}+if(iavf_init_queues(dev)!=0){PMD_DRV_LOG(ERR,"failed to do Queue init");return-1;
@@ -0,0 +1,730 @@+/* SPDX-License-Identifier: BSD-3-Clause+*Copyright(c)2010-2017IntelCorporation+*/+#include<rte_tm_driver.h>++#include"iavf.h"++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+__rte_unusedintclear_on_fail,+__rte_unusedstructrte_tm_error*error);+staticintiavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error);+staticintiavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error);+staticintiavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error);+staticintiavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error);+staticintiavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error);++conststructrte_tm_opsiavf_tm_ops={+.node_add=iavf_tm_node_add,+.node_delete=iavf_tm_node_delete,+.capabilities_get=iavf_tm_capabilities_get,+.level_capabilities_get=iavf_level_capabilities_get,+.node_capabilities_get=iavf_node_capabilities_get,+.node_type_get=iavf_node_type_get,+.hierarchy_commit=iavf_hierarchy_commit,+};++void+iavf_tm_conf_init(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++/* initialize node configuration */+vf->tm_conf.root=NULL;+TAILQ_INIT(&vf->tm_conf.tc_list);+TAILQ_INIT(&vf->tm_conf.queue_list);+vf->tm_conf.nb_tc_node=0;+vf->tm_conf.nb_queue_node=0;+vf->tm_conf.committed=false;+}++void+iavf_tm_conf_uninit(structrte_eth_dev*dev)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node*tm_node;++/* clear node configuration */+while((tm_node=TAILQ_FIRST(&vf->tm_conf.queue_list))){+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+rte_free(tm_node);+}+vf->tm_conf.nb_queue_node=0;+while((tm_node=TAILQ_FIRST(&vf->tm_conf.tc_list))){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+rte_free(tm_node);+}+vf->tm_conf.nb_tc_node=0;+if(vf->tm_conf.root){+rte_free(vf->tm_conf.root);+vf->tm_conf.root=NULL;+}+}++staticinlinestructiavf_tm_node*+iavf_tm_node_search(structrte_eth_dev*dev,+uint32_tnode_id,enumiavf_tm_node_type*node_type)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_tm_node_list*tc_list=&vf->tm_conf.tc_list;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;++if(vf->tm_conf.root&&vf->tm_conf.root->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_PORT;+returnvf->tm_conf.root;+}++TAILQ_FOREACH(tm_node,tc_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_TC;+returntm_node;+}+}++TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->id==node_id){+*node_type=IAVF_TM_NODE_TYPE_QUEUE;+returntm_node;+}+}++returnNULL;+}++staticint+iavf_node_param_check(structiavf_info*vf,uint32_tnode_id,+uint32_tpriority,uint32_tweight,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+/* checked all the unsupported parameter */+if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++if(priority){+error->type=RTE_TM_ERROR_TYPE_NODE_PRIORITY;+error->message="priority should be 0";+return-EINVAL;+}++if(weight!=1){+error->type=RTE_TM_ERROR_TYPE_NODE_WEIGHT;+error->message="weight must be 1";+return-EINVAL;+}++/* not support shaper profile */+if(params->shaper_profile_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID;+error->message="shaper profile not supported";+return-EINVAL;+}++/* not support shared shaper */+if(params->shared_shaper_id){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID;+error->message="shared shaper not supported";+return-EINVAL;+}+if(params->n_shared_shapers){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS;+error->message="shared shaper not supported";+return-EINVAL;+}++/* for non-leaf node */+if(node_id>=vf->num_queue_pairs){+if(params->nonleaf.wfq_weight_mode){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFQ not supported";+return-EINVAL;+}+if(params->nonleaf.n_sp_priorities!=1){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES;+error->message="SP priority not supported";+return-EINVAL;+}elseif(params->nonleaf.wfq_weight_mode&&+!(*params->nonleaf.wfq_weight_mode)){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE;+error->message="WFP should be byte mode";+return-EINVAL;+}++return0;+}++/* for leaf node */+if(params->leaf.cman){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN;+error->message="Congestion management not supported";+return-EINVAL;+}+if(params->leaf.wred.wred_profile_id!=+RTE_TM_WRED_PROFILE_ID_NONE){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.shared_wred_context_id){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID;+error->message="WRED not supported";+return-EINVAL;+}+if(params->leaf.wred.n_shared_wred_contexts){+error->type=+RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS;+error->message="WRED not supported";+return-EINVAL;+}++return0;+}++staticint+iavf_node_type_get(structrte_eth_dev*dev,uint32_tnode_id,+int*is_leaf,structrte_tm_error*error)+{+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!is_leaf||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type==IAVF_TM_NODE_TYPE_QUEUE)+*is_leaf=true;+else+*is_leaf=false;++return0;+}++staticint+iavf_tm_node_add(structrte_eth_dev*dev,uint32_tnode_id,+uint32_tparent_node_id,uint32_tpriority,+uint32_tweight,uint32_tlevel_id,+structrte_tm_node_params*params,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+enumiavf_tm_node_typeparent_node_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;+structiavf_tm_node*parent_node;+uint16_ttc_nb=vf->qos_cap->num_elem;+intret;++if(!params||!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++ret=iavf_node_param_check(vf,node_id,priority,weight,+params,error);+if(ret)+returnret;++/* check if the node is already existed */+if(iavf_tm_node_search(dev,node_id,&node_type)){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="node id already used";+return-EINVAL;+}++/* root node if not have a parent */+if(parent_node_id==RTE_TM_NODE_ID_NULL){+/* check level */+if(level_id!=IAVF_TM_NODE_TYPE_PORT){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* obviously no more than one root */+if(vf->tm_conf.root){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="already have a root";+return-EINVAL;+}++/* add the root node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->parent=NULL;+tm_node->reference_count=0;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+vf->tm_conf.root=tm_node;+return0;+}++/* TC or queue node */+/* check the parent node */+parent_node=iavf_tm_node_search(dev,parent_node_id,+&parent_node_type);+if(!parent_node){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent not exist";+return-EINVAL;+}+if(parent_node_type!=IAVF_TM_NODE_TYPE_PORT&&+parent_node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID;+error->message="parent is not root or TC";+return-EINVAL;+}+/* check level */+if(level_id!=RTE_TM_NODE_LEVEL_ID_ANY&&+level_id!=parent_node_type+1){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="Wrong level";+return-EINVAL;+}++/* check the node number */+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+/* check the TC number */+if(vf->tm_conf.nb_tc_node>=tc_nb){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many TCs";+return-EINVAL;+}+}else{+/* check the queue number */+if(parent_node->reference_count>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too many queues";+return-EINVAL;+}+if(node_id>=vf->num_queue_pairs){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="too large queue id";+return-EINVAL;+}+}++/* add the TC or queue node */+tm_node=rte_zmalloc("iavf_tm_node",+sizeof(structiavf_tm_node),+0);+if(!tm_node)+return-ENOMEM;+tm_node->id=node_id;+tm_node->reference_count=0;+tm_node->parent=parent_node;+rte_memcpy(&tm_node->params,params,+sizeof(structrte_tm_node_params));+if(parent_node_type==IAVF_TM_NODE_TYPE_PORT){+TAILQ_INSERT_TAIL(&vf->tm_conf.tc_list,+tm_node,node);+tm_node->tc=vf->tm_conf.nb_tc_node;+vf->tm_conf.nb_tc_node++;+}else{+TAILQ_INSERT_TAIL(&vf->tm_conf.queue_list,+tm_node,node);+tm_node->tc=parent_node->tc;+vf->tm_conf.nb_queue_node++;+}+tm_node->parent->reference_count++;++return0;+}++staticint+iavf_tm_node_delete(structrte_eth_dev*dev,uint32_tnode_id,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type=IAVF_TM_NODE_TYPE_MAX;+structiavf_tm_node*tm_node;++if(!error)+return-EINVAL;++/* if already committed */+if(vf->tm_conf.committed){+error->type=RTE_TM_ERROR_TYPE_UNSPECIFIED;+error->message="already committed";+return-EINVAL;+}++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++/* the node should have no child */+if(tm_node->reference_count){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message=+"cannot delete a node which has children";+return-EINVAL;+}++/* root node */+if(node_type==IAVF_TM_NODE_TYPE_PORT){+rte_free(tm_node);+vf->tm_conf.root=NULL;+return0;+}++/* TC or queue node */+tm_node->parent->reference_count--;+if(node_type==IAVF_TM_NODE_TYPE_TC){+TAILQ_REMOVE(&vf->tm_conf.tc_list,tm_node,node);+vf->tm_conf.nb_tc_node--;+}else{+TAILQ_REMOVE(&vf->tm_conf.queue_list,tm_node,node);+vf->tm_conf.nb_queue_node--;+}+rte_free(tm_node);++return0;+}++staticint+iavf_tm_capabilities_get(structrte_eth_dev*dev,+structrte_tm_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_ttc_nb=vf->qos_cap->num_elem;++if(!cap||!error)+return-EINVAL;++if(tc_nb>vf->vf_res->num_queue_pairs)+return-EINVAL;++error->type=RTE_TM_ERROR_TYPE_NONE;++/* set all the parameters to 0 first. */+memset(cap,0,sizeof(structrte_tm_capabilities));++/**+*supportport+TCs+queues+*hereshowsthemaxcapabilitynotthecurrentconfiguration.+*/+cap->n_nodes_max=1+IAVF_MAX_TRAFFIC_CLASS++vf->num_queue_pairs;+cap->n_levels_max=3;/* port, TC, queue */+cap->non_leaf_nodes_identical=1;+cap->leaf_nodes_identical=1;+cap->shaper_n_max=cap->n_nodes_max;+cap->shaper_private_n_max=cap->n_nodes_max;+cap->shaper_private_dual_rate_n_max=0;+cap->shaper_private_rate_min=0;+/* GBps */+cap->shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->shaper_private_packet_mode_supported=0;+cap->shaper_private_byte_mode_supported=1;+cap->shaper_shared_n_max=0;+cap->shaper_shared_n_nodes_per_shaper_max=0;+cap->shaper_shared_n_shapers_per_node_max=0;+cap->shaper_shared_dual_rate_n_max=0;+cap->shaper_shared_rate_min=0;+cap->shaper_shared_rate_max=0;+cap->shaper_shared_packet_mode_supported=0;+cap->shaper_shared_byte_mode_supported=0;+cap->sched_n_children_max=vf->num_queue_pairs;+cap->sched_sp_n_priorities_max=1;+cap->sched_wfq_n_children_per_group_max=0;+cap->sched_wfq_n_groups_max=0;+cap->sched_wfq_weight_max=1;+cap->sched_wfq_packet_mode_supported=0;+cap->sched_wfq_byte_mode_supported=0;+cap->cman_head_drop_supported=0;+cap->dynamic_update_mask=0;+cap->shaper_pkt_length_adjust_min=RTE_TM_ETH_FRAMING_OVERHEAD;+cap->shaper_pkt_length_adjust_max=RTE_TM_ETH_FRAMING_OVERHEAD_FCS;+cap->cman_wred_context_n_max=0;+cap->cman_wred_context_private_n_max=0;+cap->cman_wred_context_shared_n_max=0;+cap->cman_wred_context_shared_n_nodes_per_context_max=0;+cap->cman_wred_context_shared_n_contexts_per_node_max=0;+cap->stats_mask=0;++return0;+}++staticint+iavf_level_capabilities_get(structrte_eth_dev*dev,+uint32_tlevel_id,+structrte_tm_level_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);++if(!cap||!error)+return-EINVAL;++if(level_id>=IAVF_TM_NODE_TYPE_MAX){+error->type=RTE_TM_ERROR_TYPE_LEVEL_ID;+error->message="too deep level";+return-EINVAL;+}++/* root node */+if(level_id==IAVF_TM_NODE_TYPE_PORT){+cap->n_nodes_max=1;+cap->n_nodes_nonleaf_max=1;+cap->n_nodes_leaf_max=0;+}elseif(level_id==IAVF_TM_NODE_TYPE_TC){+/* TC */+cap->n_nodes_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_nonleaf_max=IAVF_MAX_TRAFFIC_CLASS;+cap->n_nodes_leaf_max=0;+}else{+/* queue */+cap->n_nodes_max=vf->num_queue_pairs;+cap->n_nodes_nonleaf_max=0;+cap->n_nodes_leaf_max=vf->num_queue_pairs;+}++cap->non_leaf_nodes_identical=true;+cap->leaf_nodes_identical=true;++if(level_id!=IAVF_TM_NODE_TYPE_QUEUE){+cap->nonleaf.shaper_private_supported=true;+cap->nonleaf.shaper_private_dual_rate_supported=false;+cap->nonleaf.shaper_private_rate_min=0;+/* GBps */+cap->nonleaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->nonleaf.shaper_private_packet_mode_supported=0;+cap->nonleaf.shaper_private_byte_mode_supported=1;+cap->nonleaf.shaper_shared_n_max=0;+cap->nonleaf.shaper_shared_packet_mode_supported=0;+cap->nonleaf.shaper_shared_byte_mode_supported=0;+if(level_id==IAVF_TM_NODE_TYPE_PORT)+cap->nonleaf.sched_n_children_max=+IAVF_MAX_TRAFFIC_CLASS;+else+cap->nonleaf.sched_n_children_max=+vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=0;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=1;+cap->nonleaf.sched_wfq_packet_mode_supported=0;+cap->nonleaf.sched_wfq_byte_mode_supported=0;+cap->nonleaf.stats_mask=0;++return0;+}++/* queue node */+cap->leaf.shaper_private_supported=false;+cap->leaf.shaper_private_dual_rate_supported=false;+cap->leaf.shaper_private_rate_min=0;+/* GBps */+cap->leaf.shaper_private_rate_max=+vf->link_speed*1000/IAVF_BITS_PER_BYTE;+cap->leaf.shaper_private_packet_mode_supported=0;+cap->leaf.shaper_private_byte_mode_supported=1;+cap->leaf.shaper_shared_n_max=0;+cap->leaf.shaper_shared_packet_mode_supported=0;+cap->leaf.shaper_shared_byte_mode_supported=0;+cap->leaf.cman_head_drop_supported=false;+cap->leaf.cman_wred_context_private_supported=true;+cap->leaf.cman_wred_context_shared_n_max=0;+cap->leaf.stats_mask=0;++return0;+}++staticint+iavf_node_capabilities_get(structrte_eth_dev*dev,+uint32_tnode_id,+structrte_tm_node_capabilities*cap,+structrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+enumiavf_tm_node_typenode_type;+structvirtchnl_qos_cap_elemtc_cap;+structiavf_tm_node*tm_node;++if(!cap||!error)+return-EINVAL;++if(node_id==RTE_TM_NODE_ID_NULL){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="invalid node id";+return-EINVAL;+}++/* check if the node id exists */+tm_node=iavf_tm_node_search(dev,node_id,&node_type);+if(!tm_node){+error->type=RTE_TM_ERROR_TYPE_NODE_ID;+error->message="no such node";+return-EINVAL;+}++if(node_type!=IAVF_TM_NODE_TYPE_TC){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="not support capability get";+return-EINVAL;+}++tc_cap=vf->qos_cap->cap[tm_node->tc];+if(tc_cap.tc_num!=tm_node->tc){+error->type=RTE_TM_ERROR_TYPE_NODE_PARAMS;+error->message="tc not match";+return-EINVAL;+}++cap->shaper_private_supported=true;+cap->shaper_private_dual_rate_supported=false;+cap->shaper_private_rate_min=tc_cap.shaper.committed;+cap->shaper_private_rate_max=tc_cap.shaper.peak;+cap->shaper_shared_n_max=0;+cap->nonleaf.sched_n_children_max=vf->num_queue_pairs;+cap->nonleaf.sched_sp_n_priorities_max=1;+cap->nonleaf.sched_wfq_n_children_per_group_max=1;+cap->nonleaf.sched_wfq_n_groups_max=0;+cap->nonleaf.sched_wfq_weight_max=tc_cap.weight;+cap->stats_mask=0;++return0;+}++staticintiavf_hierarchy_commit(structrte_eth_dev*dev,+intclear_on_fail,+__rte_unusedstructrte_tm_error*error)+{+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+structiavf_adapter*adapter=+IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);+structvirtchnl_queue_tc_mapping*q_tc_mapping;+structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;+structiavf_tm_node*tm_node;+uint16_tsize;+intindex=0,node_committed=0;+inti,ret_val=IAVF_SUCCESS;++/* check if port is stopped */+if(adapter->stopped!=1){+PMD_DRV_LOG(ERR,"Please stop port first");+ret_val=IAVF_ERR_NOT_READY;+gotoerr;+}++if(!(vf->vf_res->vf_cap_flags&VIRTCHNL_VF_OFFLOAD_QOS)){+PMD_DRV_LOG(ERR,"VF queue tc mapping is not supported");+ret_val=IAVF_NOT_SUPPORTED;+gotofail_clear;+}++/* check if all TC nodes are set with VF vsi */+if(vf->tm_conf.nb_tc_node!=vf->qos_cap->num_elem){+PMD_DRV_LOG(ERR,"Does not set VF vsi nodes to all TCs");+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}++size=sizeof(*q_tc_mapping)+sizeof(q_tc_mapping->tc[0])*+(vf->qos_cap->num_elem-1);+q_tc_mapping=rte_zmalloc("q_tc",size,0);+if(!q_tc_mapping){+ret_val=IAVF_ERR_NO_MEMORY;+gotofail_clear;+}++q_tc_mapping->vsi_id=vf->vsi.vsi_id;+q_tc_mapping->num_tc=vf->qos_cap->num_elem;+q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){+if(tm_node->tc>=q_tc_mapping->num_tc){+PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}+q_tc_mapping->tc[tm_node->tc].req.queue_count++;+node_committed++;+}++/* All queues allocated to this VF should be mapped */+if(node_committed<vf->num_queue_pairs){+PMD_DRV_LOG(ERR,"queue node is less than allocated queue pairs");+ret_val=IAVF_ERR_PARAM;+gotofail_clear;+}++for(i=0;i<q_tc_mapping->num_tc;i++){+q_tc_mapping->tc[i].req.start_queue_id=index;+index+=q_tc_mapping->tc[i].req.queue_count;+}++ret_val=iavf_set_q_tc_map(dev,q_tc_mapping,size);+if(ret_val)+gotofail_clear;++vf->tm_conf.committed=true;+returnret_val;++fail_clear:+/* clear all the traffic manager configuration */+if(clear_on_fail){+iavf_tm_conf_uninit(dev);+iavf_tm_conf_init(dev);+}+err:+returnret_val;+}
Add check in the Tx packet preparation function, to guarantee that the
packet with specific user priority is distributed to the correct Tx
queue according to the configured Tx queue TC mapping.
Signed-off-by: Ting Xu <redacted>
---
drivers/net/iavf/iavf.h | 10 ++++++++
drivers/net/iavf/iavf_rxtx.c | 49 ++++++++++++++++++++++++++++++++++++
drivers/net/iavf/iavf_rxtx.h | 1 +
drivers/net/iavf/iavf_tm.c | 13 ++++++++++
4 files changed, 73 insertions(+)
@@ -165,6 +167,13 @@ struct iavf_tm_conf {boolcommitted;};+/* Struct to store queue TC mapping. Queue is continuous in one TC */+structiavf_qtc_map{+uint8_ttc;+uint16_tstart_queue_id;+uint16_tqueue_count;+};+/* Structure to store private data specific for VF instance. */structiavf_info{uint16_tnum_queue_pairs;
@@ -785,6 +785,22 @@ iavf_dev_tx_queue_setup(struct rte_eth_dev *dev,ad->tx_vec_allowed=false;}+if(vf->vf_res->vf_cap_flags&VIRTCHNL_VF_OFFLOAD_QOS&&+vf->tm_conf.committed){+inttc;+for(tc=0;tc<vf->qos_cap->num_elem;tc++){+if(txq->queue_id>=vf->qtc_map[tc].start_queue_id&&+txq->queue_id<(vf->qtc_map[tc].start_queue_id++vf->qtc_map[tc].queue_count))+break;+}+if(tc>=vf->qos_cap->num_elem){+PMD_INIT_LOG(ERR,"Queue TC mapping is not correct");+return-EINVAL;+}+txq->tc=tc;+}+return0;}
@@ -2342,6 +2358,27 @@ iavf_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)returnnb_tx;}+/* Check if the packet with vlan user priority is transmitted in the+*correctqueue.+*/+staticint+iavf_check_vlan_up2tc(structiavf_tx_queue*txq,structrte_mbuf*m)+{+structrte_eth_dev*dev=&rte_eth_devices[txq->port_id];+structiavf_info*vf=IAVF_DEV_PRIVATE_TO_VF(dev->data->dev_private);+uint16_tup;++up=m->vlan_tci>>IAVF_VLAN_TAG_PCP_OFFSET;++if(!(vf->qos_cap->cap[txq->tc].tc_prio&BIT(up))){+PMD_TX_LOG(ERR,"packet with vlan pcp %u cannot transmit in queue %u\n",+up,txq->queue_id);+return-1;+}else{+return0;+}+}+/* TX prep functions */uint16_tiavf_prep_pkts(__rte_unusedvoid*tx_queue,structrte_mbuf**tx_pkts,
@@ -655,6 +655,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,structvirtchnl_queue_tc_mapping*q_tc_mapping;structiavf_tm_node_list*queue_list=&vf->tm_conf.queue_list;structiavf_tm_node*tm_node;+structiavf_qtc_map*qtc_map;uint16_tsize;intindex=0,node_committed=0;inti,ret_val=IAVF_SUCCESS;
@@ -690,6 +691,7 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,q_tc_mapping->vsi_id=vf->vsi.vsi_id;q_tc_mapping->num_tc=vf->qos_cap->num_elem;q_tc_mapping->num_queue_pairs=vf->num_queue_pairs;+TAILQ_FOREACH(tm_node,queue_list,node){if(tm_node->tc>=q_tc_mapping->num_tc){PMD_DRV_LOG(ERR,"TC%d is not enabled",tm_node->tc);
@@ -707,15 +709,26 @@ static int iavf_hierarchy_commit(struct rte_eth_dev *dev,gotofail_clear;}+/* store the queue TC mapping info */+qtc_map=rte_zmalloc("qtc_map",+sizeof(structiavf_qtc_map)*q_tc_mapping->num_tc,0);+if(!qtc_map)+returnIAVF_ERR_NO_MEMORY;+for(i=0;i<q_tc_mapping->num_tc;i++){q_tc_mapping->tc[i].req.start_queue_id=index;index+=q_tc_mapping->tc[i].req.queue_count;+qtc_map[i].tc=i;+qtc_map[i].start_queue_id=+q_tc_mapping->tc[i].req.start_queue_id;+qtc_map[i].queue_count=q_tc_mapping->tc[i].req.queue_count;}ret_val=iavf_set_q_tc_map(dev,q_tc_mapping,size);if(ret_val)gotofail_clear;+vf->qtc_map=qtc_map;vf->tm_conf.committed=true;returnret_val;
@@ -55,6 +55,13 @@ New Features Also, make sure to start the actual text at the margin. =======================================================+***Updated Intel iavf driver.**++* Added Tx QoS VF queue TC mapping.++***Updated Intel ice driver.**++* Added Tx QoS TC bandwidth configuration in DCF. Removed Items -------------
From: Thomas Monjalon <hidden> Date: 2021-07-07 09:23:20
01/07/2021 12:20, Ting Xu:
This patch supports the ETS-based QoS configuration. It enables the DCF
to configure bandwidth limits for each VF VSI of different TCs. A
hierarchy scheduler tree is built with port, TC and VSI nodes.
Signed-off-by: Qiming Yang <redacted>
Signed-off-by: Ting Xu <redacted>