net/iavf: support new VLAN capabilities
authorHaiyue Wang <haiyue.wang@intel.com>
Tue, 12 Jan 2021 08:13:02 +0000 (16:13 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 13 Jan 2021 17:51:58 +0000 (18:51 +0100)
The new VLAN virtchnl opcodes introduce new capabilities like VLAN
filtering, stripping and insertion.

The AVF needs to query the VLAN capabilities based on current device
configuration firstly.

AVF is able to configure inner VLAN filter when port VLAN is enabled
base on negotiation; and AVF is able to configure outer VLAN (0x8100)
if port VLAN is disabled to be compatible with legacy mode.

When port VLAN is updated by DCF, the AVF needs to reset to query the
new VLAN capabilities.

Signed-off-by: Qiming Yang <qiming.yang@intel.com>
Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Qi Zhang <qi.z.zhang@intel.com>
drivers/net/iavf/iavf.h
drivers/net/iavf/iavf_ethdev.c
drivers/net/iavf/iavf_vchnl.c

index 9754273..af11268 100644 (file)
@@ -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 */
@@ -310,6 +311,11 @@ 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_config_vlan_strip_v2(struct iavf_adapter *adapter, bool enable);
+int iavf_config_vlan_insert_v2(struct iavf_adapter *adapter, bool enable);
+int iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t vlanid,
+                        bool add);
+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);
index 49e6dd1..e22c62e 100644 (file)
@@ -326,13 +326,52 @@ iavf_queues_req_reset(struct rte_eth_dev *dev, uint16_t num)
        return 0;
 }
 
+static int
+iavf_dev_vlan_insert_set(struct rte_eth_dev *dev)
+{
+       struct iavf_adapter *adapter =
+               IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       bool enable;
+
+       if (!(vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN_V2))
+               return 0;
+
+       enable = !!(dev->data->dev_conf.txmode.offloads &
+                   DEV_TX_OFFLOAD_VLAN_INSERT);
+       iavf_config_vlan_insert_v2(adapter, enable);
+
+       return 0;
+}
+
+static int
+iavf_dev_init_vlan(struct rte_eth_dev *dev)
+{
+       int err;
+
+       err = iavf_dev_vlan_offload_set(dev,
+                                       ETH_VLAN_STRIP_MASK |
+                                       ETH_QINQ_STRIP_MASK |
+                                       ETH_VLAN_FILTER_MASK |
+                                       ETH_VLAN_EXTEND_MASK);
+       if (err) {
+               PMD_DRV_LOG(ERR, "Failed to update vlan offload");
+               return err;
+       }
+
+       err = iavf_dev_vlan_insert_set(dev);
+       if (err)
+               PMD_DRV_LOG(ERR, "Failed to update vlan insertion");
+
+       return err;
+}
+
 static int
 iavf_dev_configure(struct rte_eth_dev *dev)
 {
        struct iavf_adapter *ad =
                IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
        struct iavf_info *vf =  IAVF_DEV_PRIVATE_TO_VF(ad);
-       struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
        uint16_t num_queue_pairs = RTE_MAX(dev->data->nb_rx_queues,
                dev->data->nb_tx_queues);
        int ret;
@@ -389,12 +428,10 @@ iavf_dev_configure(struct rte_eth_dev *dev)
                vf->max_rss_qregion = IAVF_MAX_NUM_QUEUES_DFLT;
        }
 
-       /* Vlan stripping setting */
-       if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN) {
-               if (dev_conf->rxmode.offloads & DEV_RX_OFFLOAD_VLAN_STRIP)
-                       iavf_enable_vlan_strip(ad);
-               else
-                       iavf_disable_vlan_strip(ad);
+       ret = iavf_dev_init_vlan(dev);
+       if (ret) {
+               PMD_DRV_LOG(ERR, "configure VLAN failed: %d", ret);
+               return -1;
        }
 
        if (vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_RSS_PF) {
@@ -784,6 +821,7 @@ 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;
+
        dev_info->tx_offload_capa =
                DEV_TX_OFFLOAD_VLAN_INSERT |
                DEV_TX_OFFLOAD_QINQ_INSERT |
@@ -997,6 +1035,13 @@ 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) {
+               err = iavf_add_del_vlan_v2(adapter, vlan_id, on);
+               if (err)
+                       return -EIO;
+               return 0;
+       }
+
        if (!(vf->vf_res->vf_cap_flags & VIRTCHNL_VF_OFFLOAD_VLAN))
                return -ENOTSUP;
 
@@ -1006,6 +1051,54 @@ iavf_dev_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
        return 0;
 }
 
+static void
+iavf_iterate_vlan_filters_v2(struct rte_eth_dev *dev, bool enable)
+{
+       struct rte_vlan_filter_conf *vfc = &dev->data->vlan_filter_conf;
+       struct iavf_adapter *adapter =
+               IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+       uint32_t i, j;
+       uint64_t ids;
+
+       for (i = 0; i < RTE_DIM(vfc->ids); i++) {
+               if (vfc->ids[i] == 0)
+                       continue;
+
+               ids = vfc->ids[i];
+               for (j = 0; ids != 0 && j < 64; j++, ids >>= 1) {
+                       if (ids & 1)
+                               iavf_add_del_vlan_v2(adapter,
+                                                    64 * i + j, enable);
+               }
+       }
+}
+
+static int
+iavf_dev_vlan_offload_set_v2(struct rte_eth_dev *dev, int mask)
+{
+       struct rte_eth_rxmode *rxmode = &dev->data->dev_conf.rxmode;
+       struct iavf_adapter *adapter =
+               IAVF_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+       bool enable;
+       int err;
+
+       if (mask & ETH_VLAN_FILTER_MASK) {
+               enable = !!(rxmode->offloads & DEV_RX_OFFLOAD_VLAN_FILTER);
+
+               iavf_iterate_vlan_filters_v2(dev, enable);
+       }
+
+       if (mask & ETH_VLAN_STRIP_MASK) {
+               enable = !!(rxmode->offloads & DEV_RX_OFFLOAD_VLAN_STRIP);
+
+               err = iavf_config_vlan_strip_v2(adapter, enable);
+               if (err)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
 static int
 iavf_dev_vlan_offload_set(struct rte_eth_dev *dev, int mask)
 {
@@ -1015,6 +1108,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 +1994,13 @@ 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;
+               }
+       }
+
        iavf_init_proto_xtr(dev);
 
        return 0;
index c33194c..3ef29d5 100644 (file)
@@ -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,
@@ -459,6 +460,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 +524,157 @@ iavf_get_supported_rxdid(struct iavf_adapter *adapter)
        return 0;
 }
 
+int
+iavf_config_vlan_strip_v2(struct iavf_adapter *adapter, bool enable)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       struct virtchnl_vlan_supported_caps *supported_caps;
+       struct virtchnl_vlan_offload vlan_strip;
+       struct iavf_cmd_info args;
+       uint32_t stripping_caps;
+       uint32_t *vlan_setting;
+       int ret;
+
+       supported_caps = &vf->vlan_v2_caps.offloads.stripping_support;
+       if (supported_caps->outer) {
+               stripping_caps = supported_caps->outer;
+               vlan_setting = &vlan_strip.outer_ethertype_setting;
+       } else {
+               stripping_caps = supported_caps->inner;
+               vlan_setting = &vlan_strip.inner_ethertype_setting;
+       }
+
+       if (!(stripping_caps & VIRTCHNL_VLAN_ETHERTYPE_8100))
+               return -ENOTSUP;
+
+       memset(&vlan_strip, 0, sizeof(vlan_strip));
+       vlan_strip.vport_id = vf->vsi_res->vsi_id;
+       *vlan_setting = VIRTCHNL_VLAN_ETHERTYPE_8100;
+
+       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;
+}
+
+int
+iavf_config_vlan_insert_v2(struct iavf_adapter *adapter, bool enable)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       struct virtchnl_vlan_supported_caps *supported_caps;
+       struct virtchnl_vlan_offload vlan_insert;
+       struct iavf_cmd_info args;
+       uint32_t insertion_caps;
+       uint32_t *vlan_setting;
+       int ret;
+
+       supported_caps = &vf->vlan_v2_caps.offloads.insertion_support;
+       if (supported_caps->outer) {
+               insertion_caps = supported_caps->outer;
+               vlan_setting = &vlan_insert.outer_ethertype_setting;
+       } else {
+               insertion_caps = supported_caps->inner;
+               vlan_setting = &vlan_insert.inner_ethertype_setting;
+       }
+
+       if (!(insertion_caps & VIRTCHNL_VLAN_ETHERTYPE_8100))
+               return -ENOTSUP;
+
+       memset(&vlan_insert, 0, sizeof(vlan_insert));
+       vlan_insert.vport_id = vf->vsi_res->vsi_id;
+       *vlan_setting = VIRTCHNL_VLAN_ETHERTYPE_8100;
+
+       args.ops = enable ? VIRTCHNL_OP_ENABLE_VLAN_INSERTION_V2 :
+                           VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2;
+       args.in_args = (uint8_t *)&vlan_insert;
+       args.in_args_size = sizeof(vlan_insert);
+       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_INSERTION_V2" :
+                                    "VIRTCHNL_OP_DISABLE_VLAN_INSERTION_V2");
+
+       return ret;
+}
+
+int
+iavf_add_del_vlan_v2(struct iavf_adapter *adapter, uint16_t vlanid, bool add)
+{
+       struct iavf_info *vf = IAVF_DEV_PRIVATE_TO_VF(adapter);
+       struct virtchnl_vlan_supported_caps *supported_caps;
+       struct virtchnl_vlan_filter_list_v2 vlan_filter;
+       struct virtchnl_vlan *vlan_setting;
+       struct iavf_cmd_info args;
+       uint32_t filtering_caps;
+       int err;
+
+       supported_caps = &vf->vlan_v2_caps.filtering.filtering_support;
+       if (supported_caps->outer) {
+               filtering_caps = supported_caps->outer;
+               vlan_setting = &vlan_filter.filters[0].outer;
+       } else {
+               filtering_caps = supported_caps->inner;
+               vlan_setting = &vlan_filter.filters[0].inner;
+       }
+
+       if (!(filtering_caps & VIRTCHNL_VLAN_ETHERTYPE_8100))
+               return -ENOTSUP;
+
+       memset(&vlan_filter, 0, sizeof(vlan_filter));
+       vlan_filter.vport_id = vf->vsi_res->vsi_id;
+       vlan_filter.num_elements = 1;
+       vlan_setting->tpid = RTE_ETHER_TYPE_VLAN;
+       vlan_setting->tci = vlanid;
+
+       args.ops = add ? VIRTCHNL_OP_ADD_VLAN_V2 : VIRTCHNL_OP_DEL_VLAN_V2;
+       args.in_args = (uint8_t *)&vlan_filter;
+       args.in_args_size = sizeof(vlan_filter);
+       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_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)
 {