[v4,5/5] net/iavf: implement new VLAN capability handling

Message ID 20201228112139.29445-6-haiyue.wang@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Qi Zhang
Headers
Series Add AVF & DCF VLAN feaure |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation success Compilation OK
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-abi-testing success Testing PASS
ci/iol-testing success Testing PASS

Commit Message

Wang, Haiyue Dec. 28, 2020, 11:21 a.m. UTC
  The new VLAN virtchnl opcodes introduce new settings like different TPID
filtering, stripping.

Query the PF's VLAN capabilities based on current device configuration,
then set the ethdev VLAN information that the VF can support.

The VLAN filtering and offload acceleration should be performed on the
outer VLAN tag when the double VLAN mode is enabled on the PF:
 a). 0x8100
 b). 0x8100 + 0x8100
 c). 0x9100 + 0x8100
 d). 0x88a8 + 0x8100

Signed-off-by: Qiming Yang <qiming.yang@intel.com>
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
---
 drivers/net/iavf/iavf.h        |  10 +++
 drivers/net/iavf/iavf_ethdev.c | 114 ++++++++++++++++++++++++++
 drivers/net/iavf/iavf_vchnl.c  | 141 +++++++++++++++++++++++++++++++++
 3 files changed, 265 insertions(+)
  

Patch

diff --git a/drivers/net/iavf/iavf.h b/drivers/net/iavf/iavf.h
index 9754273b2..c5d53bd9c 100644
--- a/drivers/net/iavf/iavf.h
+++ b/drivers/net/iavf/iavf.h
@@ -139,6 +139,7 @@  struct iavf_info {
 	struct virtchnl_version_info virtchnl_version;
 	struct virtchnl_vf_resource *vf_res; /* VF resource */
 	struct virtchnl_vsi_resource *vsi_res; /* LAN VSI */
+	struct virtchnl_vlan_caps vlan_v2_caps;
 	uint64_t supported_rxdid;
 	uint8_t *proto_xtr; /* proto xtr type for all queues */
 	volatile enum virtchnl_ops pend_cmd; /* pending command not finished */
@@ -173,6 +174,10 @@  struct iavf_info {
 	struct iavf_fdir_info fdir; /* flow director info */
 	/* indicate large VF support enabled or not */
 	bool lv_enabled;
+
+	/* used to set the VLAN Ethernet type for virtchnl VLAN V2 */
+	uint16_t outer_vlan_tpid;
+	uint16_t inner_vlan_tpid;
 };
 
 #define IAVF_MAX_PKT_TYPE 1024
@@ -297,6 +302,8 @@  int iavf_get_vf_resource(struct iavf_adapter *adapter);
 void iavf_handle_virtchnl_msg(struct rte_eth_dev *dev);
 int iavf_enable_vlan_strip(struct iavf_adapter *adapter);
 int iavf_disable_vlan_strip(struct iavf_adapter *adapter);
+int iavf_config_vlan_strip_v2(struct iavf_adapter *adapter, uint16_t tpid,
+			      bool enable);
 int iavf_switch_queue(struct iavf_adapter *adapter, uint16_t qid,
 		     bool rx, bool on);
 int iavf_switch_queue_lv(struct iavf_adapter *adapter, uint16_t qid,
@@ -310,6 +317,7 @@  int iavf_configure_rss_key(struct iavf_adapter *adapter);
 int iavf_configure_queues(struct iavf_adapter *adapter,
 			uint16_t num_queue_pairs, uint16_t index);
 int iavf_get_supported_rxdid(struct iavf_adapter *adapter);
+int iavf_get_vlan_offload_caps_v2(struct iavf_adapter *adapter);
 int iavf_config_irq_map(struct iavf_adapter *adapter);
 int iavf_config_irq_map_lv(struct iavf_adapter *adapter, uint16_t num,
 			uint16_t index);
@@ -323,6 +331,8 @@  int iavf_config_promisc(struct iavf_adapter *adapter, bool enable_unicast,
 int iavf_add_del_eth_addr(struct iavf_adapter *adapter,
 			 struct rte_ether_addr *addr, bool add);
 int iavf_add_del_vlan(struct iavf_adapter *adapter, uint16_t vlanid, bool add);
+int iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t tpid,
+			 uint16_t vlanid, bool add);
 int iavf_fdir_add(struct iavf_adapter *adapter, struct iavf_fdir_conf *filter);
 int iavf_fdir_del(struct iavf_adapter *adapter, struct iavf_fdir_conf *filter);
 int iavf_fdir_check(struct iavf_adapter *adapter,
diff --git a/drivers/net/iavf/iavf_ethdev.c b/drivers/net/iavf/iavf_ethdev.c
index 49e6dd125..944dad75b 100644
--- a/drivers/net/iavf/iavf_ethdev.c
+++ b/drivers/net/iavf/iavf_ethdev.c
@@ -100,6 +100,8 @@  static void iavf_dev_del_mac_addr(struct rte_eth_dev *dev, uint32_t index);
 static int iavf_dev_vlan_filter_set(struct rte_eth_dev *dev,
 				   uint16_t vlan_id, int on);
 static int iavf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask);
+static int iavf_dev_vlan_tpid_set(struct rte_eth_dev *dev,
+				  enum rte_vlan_type vlan_type, uint16_t tpid);
 static int iavf_dev_rss_reta_update(struct rte_eth_dev *dev,
 				   struct rte_eth_rss_reta_entry64 *reta_conf,
 				   uint16_t reta_size);
@@ -176,6 +178,7 @@  static const struct eth_dev_ops iavf_eth_dev_ops = {
 	.mac_addr_remove            = iavf_dev_del_mac_addr,
 	.set_mc_addr_list			= iavf_set_mc_addr_list,
 	.vlan_filter_set            = iavf_dev_vlan_filter_set,
+	.vlan_tpid_set              = iavf_dev_vlan_tpid_set,
 	.vlan_offload_set           = iavf_dev_vlan_offload_set,
 	.rx_queue_start             = iavf_dev_rx_queue_start,
 	.rx_queue_stop              = iavf_dev_rx_queue_stop,
@@ -326,6 +329,12 @@  iavf_queues_req_reset(struct rte_eth_dev *dev, uint16_t num)
 	return 0;
 }
 
+static __rte_always_inline uint16_t
+iavf_vlan_tpid_used(struct iavf_info *vf, bool qinq)
+{
+	return qinq ? vf->outer_vlan_tpid : vf->inner_vlan_tpid;
+}
+
 static int
 iavf_dev_configure(struct rte_eth_dev *dev)
 {
@@ -389,6 +398,17 @@  iavf_dev_configure(struct rte_eth_dev *dev)
 		vf->max_rss_qregion = IAVF_MAX_NUM_QUEUES_DFLT;
 	}
 
+	/* Vlan v2 stripping setting */
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
+		bool qinq = !!(dev_conf->rxmode.offloads &
+			       DEV_RX_OFFLOAD_VLAN_EXTEND);
+		bool enable = !!(dev_conf->rxmode.offloads &
+				 DEV_RX_OFFLOAD_VLAN_STRIP);
+
+		iavf_config_vlan_strip_v2(ad, iavf_vlan_tpid_used(vf, qinq),
+					  enable);
+	}
+
 	/* Vlan stripping setting */
 	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN) {
 		if (dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
@@ -784,6 +804,9 @@  iavf_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 		DEV_RX_OFFLOAD_JUMBO_FRAME |
 		DEV_RX_OFFLOAD_VLAN_FILTER |
 		DEV_RX_OFFLOAD_RSS_HASH;
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2)
+		dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_VLAN_EXTEND;
+
 	dev_info->tx_offload_capa =
 		DEV_TX_OFFLOAD_VLAN_INSERT |
 		DEV_TX_OFFLOAD_QINQ_INSERT |
@@ -989,6 +1012,47 @@  iavf_dev_del_mac_addr(struct rte_eth_dev *dev, uint32_t index)
 	vf->mac_num--;
 }
 
+static int
+iavf_dev_vlan_tpid_set(struct rte_eth_dev *dev, enum rte_vlan_type vlan_type,
+		       uint16_t tpid)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+	bool qinq = !!(dev->data->dev_conf.rxmode.offloads &
+		       DEV_RX_OFFLOAD_VLAN_EXTEND);
+
+	if (vlan_type != ETH_VLAN_TYPE_INNER &&
+	    vlan_type != ETH_VLAN_TYPE_OUTER) {
+		PMD_DRV_LOG(ERR, "Unsupported vlan type");
+		return -EINVAL;
+	}
+
+	if (!qinq) {
+		PMD_DRV_LOG(ERR, "QinQ not enabled");
+		return -EINVAL;
+	}
+
+	if (vlan_type == ETH_VLAN_TYPE_OUTER) {
+		switch (tpid) {
+		case RTE_ETHER_TYPE_QINQ:
+		case RTE_ETHER_TYPE_VLAN:
+		case RTE_ETHER_TYPE_QINQ1:
+			vf->outer_vlan_tpid = tpid;
+			break;
+		default:
+			PMD_DRV_LOG(ERR, "Invalid TPID: %x", tpid);
+			return -EINVAL;
+		}
+	} else {
+		PMD_DRV_LOG(ERR,
+			    "Can accelerate only outer vlan in QinQ");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 iavf_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 {
@@ -997,6 +1061,18 @@  iavf_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
 	int err;
 
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
+		bool qinq = !!(dev->data->dev_conf.rxmode.offloads &
+			       DEV_RX_OFFLOAD_VLAN_EXTEND);
+
+		err = iavf_add_del_vlan_v2(adapter,
+					   iavf_vlan_tpid_used(vf, qinq),
+					   vlan_id, on);
+		if (err)
+			return -EIO;
+		return 0;
+	}
+
 	if (!(vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
 		return -ENOTSUP;
 
@@ -1006,6 +1082,31 @@  iavf_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 	return 0;
 }
 
+static int
+iavf_dev_vlan_offload_set_v2(struct rte_eth_dev *dev, int mask)
+{
+	struct iavf_adapter *adapter =
+		IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+	uint16_t qinq = !!(dev_conf->rxmode.offloads &
+			   DEV_RX_OFFLOAD_VLAN_EXTEND);
+	int err;
+
+	if (mask & ETH_VLAN_STRIP_MASK) {
+		bool enable = !!(dev_conf->rxmode.offloads &
+				 DEV_RX_OFFLOAD_VLAN_STRIP);
+
+		err = iavf_config_vlan_strip_v2(adapter,
+						iavf_vlan_tpid_used(vf, qinq),
+						enable);
+		if (err)
+			return -EIO;
+	}
+
+	return 0;
+}
+
 static int
 iavf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
@@ -1015,6 +1116,9 @@  iavf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 	struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
 	int err;
 
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2)
+		return iavf_dev_vlan_offload_set_v2(dev, mask);
+
 	if (!(vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
 		return -ENOTSUP;
 
@@ -1898,6 +2002,16 @@  iavf_init_vf(struct rte_eth_dev *dev)
 		}
 	}
 
+	if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2) {
+		if (iavf_get_vlan_offload_caps_v2(adapter) != 0) {
+			PMD_INIT_LOG(ERR, "failed to do get VLAN offload v2 capabilities");
+			goto err_rss;
+		}
+
+		vf->outer_vlan_tpid = RTE_ETHER_TYPE_VLAN;
+		vf->inner_vlan_tpid = RTE_ETHER_TYPE_VLAN;
+	}
+
 	iavf_init_proto_xtr(dev);
 
 	return 0;
diff --git a/drivers/net/iavf/iavf_vchnl.c b/drivers/net/iavf/iavf_vchnl.c
index c33194cdc..b2b5ace31 100644
--- a/drivers/net/iavf/iavf_vchnl.c
+++ b/drivers/net/iavf/iavf_vchnl.c
@@ -174,6 +174,7 @@  iavf_execute_vf_cmd(struct iavf_adapter *adapter, struct iavf_cmd_info *args)
 	case VIRTCHNL_OP_VERSION:
 	case VIRTCHNL_OP_GET_VF_RESOURCES:
 	case VIRTCHNL_OP_GET_SUPPORTED_RXDIDS:
+	case VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS:
 		/* for init virtchnl ops, need to poll the response */
 		do {
 			result = iavf_read_msg_from_pf(adapter, args->out_size,
@@ -366,6 +367,28 @@  iavf_enable_vlan_strip(struct iavf_adapter *adapter)
 	return ret;
 }
 
+static uint16_t
+iavf_vc_vlan_tpid_flag(uint16_t tpid)
+{
+	uint16_t flag = VIRTCHNL_VLAN_UNSUPPORTED;
+
+	switch (tpid) {
+	case RTE_ETHER_TYPE_VLAN:
+		flag = VIRTCHNL_VLAN_ETHERTYPE_8100;
+		break;
+	case RTE_ETHER_TYPE_QINQ1:
+		flag = VIRTCHNL_VLAN_ETHERTYPE_9100;
+		break;
+	case RTE_ETHER_TYPE_QINQ:
+		flag = VIRTCHNL_VLAN_ETHERTYPE_88A8;
+		break;
+	default:
+		break;
+	}
+
+	return flag;
+}
+
 int
 iavf_disable_vlan_strip(struct iavf_adapter *adapter)
 {
@@ -387,6 +410,52 @@  iavf_disable_vlan_strip(struct iavf_adapter *adapter)
 	return ret;
 }
 
+int
+iavf_config_vlan_strip_v2(struct iavf_adapter *adapter, uint16_t tpid,
+			  bool enable)
+{
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+	struct virtchnl_vlan_strip vlan_strip;
+	struct iavf_cmd_info args;
+	u16 stripping_caps;
+	u16 vlan_tpid_flag;
+	u16 *vlan_setting;
+	int ret;
+
+	/* Give priority over outer if it's enabled */
+	if (vf->vlan_v2_caps.offloads.outer_stripping) {
+		stripping_caps = vf->vlan_v2_caps.offloads.outer_stripping;
+		vlan_setting = &vlan_strip.outer_ethertype_setting;
+	} else if (vf->vlan_v2_caps.offloads.inner_stripping) {
+		stripping_caps = vf->vlan_v2_caps.offloads.inner_stripping;
+		vlan_setting = &vlan_strip.inner_ethertype_setting;
+	} else {
+		return -ENOTSUP;
+	}
+
+	vlan_tpid_flag = iavf_vc_vlan_tpid_flag(tpid);
+	if (!(stripping_caps & vlan_tpid_flag))
+		return -EINVAL;
+
+	memset(&vlan_strip, 0, sizeof(vlan_strip));
+	vlan_strip.vsi_id = vf->vsi_res->vsi_id;
+	*vlan_setting = vlan_tpid_flag;
+
+	args.ops = enable ? VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2 :
+			    VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2;
+	args.in_args = (uint8_t *)&vlan_strip;
+	args.in_args_size = sizeof(vlan_strip);
+	args.out_buffer = vf->aq_resp;
+	args.out_size = IAVF_AQ_BUF_SZ;
+	ret = iavf_execute_vf_cmd(adapter, &args);
+	if (ret)
+		PMD_DRV_LOG(ERR, "fail to execute command %s",
+			    enable ? "VIRTCHNL_OP_ENABLE_VLAN_STRIPPING_V2" :
+				     "VIRTCHNL_OP_DISABLE_VLAN_STRIPPING_V2");
+
+	return ret;
+}
+
 #define VIRTCHNL_VERSION_MAJOR_START 1
 #define VIRTCHNL_VERSION_MINOR_START 1
 
@@ -459,6 +528,7 @@  iavf_get_vf_resource(struct iavf_adapter *adapter)
 		VIRTCHNL_VF_OFFLOAD_ADV_RSS_PF |
 		VIRTCHNL_VF_OFFLOAD_REQ_QUEUES |
 		VIRTCHNL_VF_OFFLOAD_CRC |
+		VIRTCHNL_VF_OFFLOAD_VLAN_V2 |
 		VIRTCHNL_VF_LARGE_NUM_QPAIRS;
 
 	args.in_args = (uint8_t *)&caps;
@@ -522,6 +592,31 @@  iavf_get_supported_rxdid(struct iavf_adapter *adapter)
 	return 0;
 }
 
+int
+iavf_get_vlan_offload_caps_v2(struct iavf_adapter *adapter)
+{
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+	struct iavf_cmd_info args;
+	int ret;
+
+	args.ops = VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS;
+	args.in_args = NULL;
+	args.in_args_size = 0;
+	args.out_buffer = vf->aq_resp;
+	args.out_size = IAVF_AQ_BUF_SZ;
+
+	ret = iavf_execute_vf_cmd(adapter, &args);
+	if (ret) {
+		PMD_DRV_LOG(ERR,
+			    "Failed to execute command of VIRTCHNL_OP_GET_OFFLOAD_VLAN_V2_CAPS");
+		return ret;
+	}
+
+	rte_memcpy(&vf->vlan_v2_caps, vf->aq_resp, sizeof(vf->vlan_v2_caps));
+
+	return 0;
+}
+
 int
 iavf_enable_queues(struct iavf_adapter *adapter)
 {
@@ -1167,6 +1262,52 @@  iavf_add_del_vlan(struct iavf_adapter *adapter, uint16_t vlanid, bool add)
 	return err;
 }
 
+int
+iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t tpid,
+		     uint16_t vlanid, bool add)
+{
+	struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+	struct virtchnl_vlan_filter_list_v2 vlan_list;
+	struct virtchnl_vlan *vlan_setting;
+	struct iavf_cmd_info args;
+	uint16_t filtering_caps;
+	uint16_t vlan_tpid_flag;
+	int err;
+
+	/* Give priority over outer if it's enabled */
+	if (vf->vlan_v2_caps.filtering.outer) {
+		filtering_caps = vf->vlan_v2_caps.filtering.outer;
+		vlan_setting = &vlan_list.filters[0].outer;
+	} else if (vf->vlan_v2_caps.filtering.inner) {
+		filtering_caps = vf->vlan_v2_caps.filtering.inner;
+		vlan_setting = &vlan_list.filters[0].inner;
+	} else {
+		return -ENOTSUP;
+	}
+
+	vlan_tpid_flag = iavf_vc_vlan_tpid_flag(tpid);
+	if (!(filtering_caps & vlan_tpid_flag))
+		return -EINVAL;
+
+	memset(&vlan_list, 0, sizeof(vlan_list));
+	vlan_list.vport_id = vf->vsi_res->vsi_id;
+	vlan_list.num_elements = 1;
+	vlan_setting->tci = vlanid;
+	vlan_setting->tpid = tpid;
+
+	args.ops = add ? VIRTCHNL_OP_ADD_VLAN_V2 : VIRTCHNL_OP_DEL_VLAN_V2;
+	args.in_args = (uint8_t *)&vlan_list;
+	args.in_args_size = sizeof(vlan_list);
+	args.out_buffer = vf->aq_resp;
+	args.out_size = IAVF_AQ_BUF_SZ;
+	err = iavf_execute_vf_cmd(adapter, &args);
+	if (err)
+		PMD_DRV_LOG(ERR, "fail to execute command %s",
+			    add ? "OP_ADD_VLAN_V2" :  "OP_DEL_VLAN_V2");
+
+	return err;
+}
+
 int
 iavf_fdir_add(struct iavf_adapter *adapter,
 	struct iavf_fdir_conf *filter)