From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 7060642993; Thu, 20 Apr 2023 08:39:50 +0200 (CEST) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 0072F40A4B; Thu, 20 Apr 2023 08:39:49 +0200 (CEST) Received: from mga06.intel.com (mga06b.intel.com [134.134.136.31]) by mails.dpdk.org (Postfix) with ESMTP id 7B25C40687 for ; Thu, 20 Apr 2023 08:39:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1681972788; x=1713508788; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=siVaKrUzwT6oinKw9fYZJE57VJTLhpocJVSewuSfg9M=; b=je2RFePTmIvEIgucRLY7OScv4v1H0522V8J/XHkf2OSJCDLk9ugxdLG2 NnRtbmh+1r/PW+D7ZSB+bXyixoF/4oTdWowMQ8yF2bw8IB13keqVRrKUQ jlq2++LJh0uXk3X08PMBWFdDO7lacLxVxg5ETOYXYLaMFi/8O7zrylMXn Nrcw2NhJnjzgTMoua6l0DR3ueyXssGtvYsN23Xmk0yzqok8g0l4NjfQRm mzSXkpntrso1xB0hGYto5a00jVdk/O4h0ocRH4Kaca4I65VTiMagkVGRV vBu4IRIthVmwG/ysPpAdqAwntygf2l/l/ZFN564PjXZgdfeF5LEr0nTta w==; X-IronPort-AV: E=McAfee;i="6600,9927,10685"; a="408560648" X-IronPort-AV: E=Sophos;i="5.99,211,1677571200"; d="scan'208";a="408560648" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Apr 2023 23:39:47 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10685"; a="937936009" X-IronPort-AV: E=Sophos;i="5.99,211,1677571200"; d="scan'208";a="937936009" Received: from unknown (HELO localhost.localdomain) ([10.239.252.253]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Apr 2023 23:39:45 -0700 From: Mingjin Ye To: dev@dpdk.org Cc: yidingx.zhou@intel.com, Mingjin Ye , Qiming Yang , Qi Zhang Subject: [PATCH] net/ice: CVL support double vlan Date: Thu, 20 Apr 2023 06:16:56 +0000 Message-Id: <20230420061656.140315-1-mingjinx.ye@intel.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Aligned with kernel driver, optimized for inner and outer VLAN handling in DPDK, and implemented double vlan insertion and stripping support. 1.adjust vlan stripping Remove the judgment on dvm, vlan stripping only operates inner vlan. 2.support QinQ stripping This patch support ice outer vlan strip on and off in QinQ mode with mask bit of DEV_RX_OFFLOAD_QINQ_STRIP, users canuse "vlan set qinq_strip on 0" to enable or "vlan setqinq_strip off 0" to disable ice outer vlan strip when try with testpmd app. Note: Due to hardware limitations, QinQ stripping containing two tagged RX packets with the same EtherType (for example, two VLANs with EtherType =` ETH_P_8021Q`) is not supported. 3.Support outer tag type switching Add implementation of ethdev `vlan_tpid_set` api to enable Outer tags supp -ort processing `ETH_P_8021Q` `ETH_P_8021AD` `ETH_P_QINQ1` outer tag types. 4.Support outer port insertion If dvm is enabled, will support outer port vlan. User can use "tx_vlan set pvid 0 45 on" to enable or "tx_vlan set pvid 0 45 off" to disable ice outer vlan insertion try with testpmd app. Signed-off-by: Mingjin Ye --- drivers/net/ice/ice_ethdev.c | 427 +++++++++++++++++++++++++++++++++-- drivers/net/ice/ice_ethdev.h | 1 + 2 files changed, 414 insertions(+), 14 deletions(-) diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c index 9a88cf9796..e4e22044ab 100644 --- a/drivers/net/ice/ice_ethdev.c +++ b/drivers/net/ice/ice_ethdev.c @@ -56,6 +56,24 @@ static const char * const ice_valid_args[] = { #define PPS_OUT_DELAY_NS 1 +/* Maximum number of VSI */ +#define ICE_MAX_NUM_VSIS (768UL) + +/* The 119 bit offset of the LAN Rx queue context is the L2TSEL control bit. */ +#define ICE_L2TSEL_QRX_CONTEXT_REG_IDX 3 +#define ICE_L2TSEL_BIT_OFFSET 23 +enum ice_l2tsel { + ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND, + ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1, +}; + +/* 802.1Q VLAN Extended Header */ +#define ETH_P_8021Q 0x8100 +/* 802.1ad Service VLAN */ +#define ETH_P_8021AD 0x88A8 +/* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_QINQ1 0x9100 + struct proto_xtr_ol_flag { const struct rte_mbuf_dynflag param; bool required; @@ -130,6 +148,9 @@ static int ice_fw_version_get(struct rte_eth_dev *dev, char *fw_version, size_t fw_size); static int ice_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on); +static int ice_vlan_tpid_set(struct rte_eth_dev *dev, + enum rte_vlan_type vlan_type, + uint16_t tpid); static int ice_get_eeprom_length(struct rte_eth_dev *dev); static int ice_get_eeprom(struct rte_eth_dev *dev, struct rte_dev_eeprom_info *eeprom); @@ -252,6 +273,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { .rx_queue_intr_disable = ice_rx_queue_intr_disable, .fw_version_get = ice_fw_version_get, .vlan_pvid_set = ice_vlan_pvid_set, + .vlan_tpid_set = ice_vlan_tpid_set, .rxq_info_get = ice_rxq_info_get, .txq_info_get = ice_txq_info_get, .rx_burst_mode_get = ice_rx_burst_mode_get, @@ -1588,6 +1610,9 @@ ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type) hw->func_caps.common_cap.rss_table_size; pf->flags |= ICE_FLAG_RSS_AQ_CAPABLE; + /* Defines the type of outer tag expected */ + pf->outer_ethertype = ETH_P_8021Q; + memset(&vsi_ctx, 0, sizeof(vsi_ctx)); switch (type) { case ICE_VSI_PF: @@ -1615,6 +1640,9 @@ ice_setup_vsi(struct ice_pf *pf, enum ice_vsi_type type) (ICE_AQ_VSI_OUTER_TAG_VLAN_8100 << ICE_AQ_VSI_OUTER_TAG_TYPE_S) & ICE_AQ_VSI_OUTER_TAG_TYPE_M; + vsi_ctx.info.outer_vlan_flags |= + (ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING << + ICE_AQ_VSI_OUTER_VLAN_EMODE_S); } /* FDIR */ @@ -4431,11 +4459,87 @@ ice_vsi_dis_inner_stripping(struct ice_vsi *vsi) return ice_vsi_manage_vlan_stripping(vsi, false); } -static int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi) +/** + * tpid_to_vsi_outer_vlan_type - convert from TPID to VSI context based tag_type + * @tpid: tpid used to translate into VSI context based tag_type + * @tag_type: output variable to hold the VSI context based tag type + */ +static int tpid_to_vsi_outer_vlan_type(u16 tpid, u8 *tag_type) +{ + switch (tpid) { + case ETH_P_8021Q: + *tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_8100; + break; + case ETH_P_8021AD: + *tag_type = ICE_AQ_VSI_OUTER_TAG_STAG; + break; + case ETH_P_QINQ1: + *tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_9100; + break; + default: + *tag_type = 0; + return -EINVAL; + } + + return 0; +} + +/** + * ice_is_supported_port_vlan_proto - make sure the vlan_proto is supported + * @hw: hardware structure used to check the VLAN mode + * @vlan_proto: VLAN TPID being checked + * + * If the device is configured in Double VLAN Mode (DVM), it supports three + * types: ETH_P_8021Q, ETH_P_QINQ1 and ETH_P_8021AD. If the device is + * configured in Single VLAN Mode (SVM), then only ETH_P_8021Q is supported. + */ +static bool +ice_is_supported_port_vlan_proto(struct ice_hw *hw, u16 vlan_proto) +{ + bool is_supported = false; + + switch (vlan_proto) { + case ETH_P_8021Q: + is_supported = true; + break; + case ETH_P_8021AD: + if (ice_is_dvm_ena(hw)) + is_supported = true; + break; + case ETH_P_QINQ1: + if (ice_is_dvm_ena(hw)) + is_supported = true; + break; + } + + return is_supported; +} + +/** + * ice_vsi_ena_outer_stripping - enable outer VLAN stripping + * @vsi: VSI to configure + * @tpid: TPID to enable outer VLAN stripping for + * + * Enable outer VLAN stripping via VSI context. This function should only be + * used if DVM is supported. Also, this function should never be called directly + * as it should be part of ice_vsi_vlan_ops if it's needed. + * + * Since the VSI context only supports a single TPID for insertion and + * stripping, setting the TPID for stripping will affect the TPID for insertion. + * Callers need to be aware of this limitation. + * + * Only modify outer VLAN stripping settings and the VLAN TPID. Outer VLAN + * insertion settings are unmodified. + * + * This enables hardware to strip a VLAN tag with the specified TPID to be + * stripped from the packet and placed in the receive descriptor. + */ +static int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid) { struct ice_hw *hw = ICE_VSI_TO_HW(vsi); struct ice_vsi_ctx ctxt; enum ice_status status; + u8 tag_type; int err = 0; /* do not allow modifying VLAN stripping when a port VLAN is configured @@ -4444,6 +4548,9 @@ static int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi) if (vsi->info.port_based_outer_vlan) return 0; + if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type)) + return -EINVAL; + memset(&ctxt, 0, sizeof(ctxt)); ctxt.info.valid_sections = @@ -4454,8 +4561,8 @@ static int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi) ctxt.info.outer_vlan_flags |= (ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW_BOTH << ICE_AQ_VSI_OUTER_VLAN_EMODE_S) | - (ICE_AQ_VSI_OUTER_TAG_VLAN_8100 << - ICE_AQ_VSI_OUTER_TAG_TYPE_S); + ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) & + ICE_AQ_VSI_OUTER_TAG_TYPE_M); status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); if (status) { @@ -4503,22 +4610,104 @@ ice_vsi_dis_outer_stripping(struct ice_vsi *vsi) static int ice_vsi_config_vlan_stripping(struct ice_vsi *vsi, bool ena) { - struct ice_hw *hw = ICE_VSI_TO_HW(vsi); int ret; - if (ice_is_dvm_ena(hw)) { - if (ena) - ret = ice_vsi_ena_outer_stripping(vsi); - else - ret = ice_vsi_dis_outer_stripping(vsi); + if (ena) + ret = ice_vsi_ena_inner_stripping(vsi); + else + ret = ice_vsi_dis_inner_stripping(vsi); + + return ret; +} + +/** + * ice_vsi_update_l2tsel - update l2tsel field for all Rx rings on this VSI + * @vsi: VSI used to update l2tsel on + * @l2tsel: l2tsel setting requested + * + * Use the l2tsel setting to update all of the Rx queue context bits for l2tsel. + * This will modify which descriptor field the first offloaded VLAN will be + * stripped into. + */ +static void ice_vsi_update_l2tsel(struct ice_vsi *vsi, enum ice_l2tsel l2tsel) +{ + struct ice_hw *hw = ICE_VSI_TO_HW(vsi); + struct ice_pf *pf = ICE_VSI_TO_PF(vsi); + struct rte_eth_dev_data *dev_data = pf->dev_data; + u32 l2tsel_bit; + uint16_t i; + + if (l2tsel == ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND) + l2tsel_bit = 0; + else + l2tsel_bit = BIT(ICE_L2TSEL_BIT_OFFSET); + + for (i = 0; i < dev_data->nb_rx_queues; i++) { + u32 qrx_context_offset; + u32 regval; + + qrx_context_offset = + QRX_CONTEXT(ICE_L2TSEL_QRX_CONTEXT_REG_IDX, i); + + regval = rd32(hw, qrx_context_offset); + regval &= ~BIT(ICE_L2TSEL_BIT_OFFSET); + regval |= l2tsel_bit; + wr32(hw, qrx_context_offset, regval); + } +} + +/* Configure outer vlan stripping on or off in QinQ mode */ +static int +ice_vsi_config_outer_vlan_stripping(struct ice_vsi *vsi, bool on) +{ + uint16_t outer_ethertype = vsi->adapter->pf.outer_ethertype; + int err = 0; + + if (vsi->vsi_id >= ICE_MAX_NUM_VSIS) { + PMD_DRV_LOG(ERR, "VSI ID exceeds the maximum"); + return -EINVAL; + } + + if (!ice_is_dvm_ena(&vsi->adapter->hw)) { + PMD_DRV_LOG(ERR, "Single VLAN mode (SVM) does not support qinq"); + return -EOPNOTSUPP; + } + + if (on) { + err = ice_vsi_ena_outer_stripping(vsi, outer_ethertype); + if (!err) { + enum ice_l2tsel l2tsel = + ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG2_2ND; + + /* PF tells the VF that the outer VLAN tag is always + * extracted to VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 and + * inner is always extracted to + * VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1. This is needed to + * support outer stripping so the first tag always ends + * up in L2TAG2_2ND and the second/inner tag, if + * enabled, is extracted in L2TAG1. + */ + ice_vsi_update_l2tsel(vsi, l2tsel); + } } else { - if (ena) - ret = ice_vsi_ena_inner_stripping(vsi); - else - ret = ice_vsi_dis_inner_stripping(vsi); + err = ice_vsi_dis_outer_stripping(vsi); + if (!err) { + enum ice_l2tsel l2tsel = + ICE_L2TSEL_EXTRACT_FIRST_TAG_L2TAG1; + + /* PF tells the VF that the outer VLAN tag is always + * extracted to VIRTCHNL_VLAN_TAG_LOCATION_L2TAG2_2 and + * inner is always extracted to + * VIRTCHNL_VLAN_TAG_LOCATION_L2TAG1. This is needed to + * support inner stripping while outer stripping is + * disabled so that the first and only tag is extracted + * in L2TAG1. + */ + ice_vsi_update_l2tsel(vsi, l2tsel); + } } - return ret; + return err; } static int @@ -4543,6 +4732,14 @@ ice_vlan_offload_set(struct rte_eth_dev *dev, int mask) ice_vsi_config_vlan_stripping(vsi, false); } + if (mask & RTE_ETH_QINQ_STRIP_MASK) { + /* Enable or disable outer VLAN stripping */ + if (rxmode->offloads & RTE_ETH_RX_OFFLOAD_QINQ_STRIP) + ice_vsi_config_outer_vlan_stripping(vsi, true); + else + ice_vsi_config_outer_vlan_stripping(vsi, false); + } + return 0; } @@ -5019,6 +5216,130 @@ ice_vsi_vlan_pvid_set(struct ice_vsi *vsi, struct ice_vsi_vlan_pvid_info *info) return ret; } +/** + * __ice_vsi_set_outer_port_vlan - set the outer port VLAN and related settings + * @vsi: VSI to configure + * @vlan_info: packed u16 that contains the VLAN prio and ID + * @tpid: TPID of the port VLAN + * + * Set the port VLAN prio, ID, and TPID. + * + * Enable VLAN pruning so the VSI doesn't receive any traffic that doesn't match + * a VLAN prune rule. The caller should take care to add a VLAN prune rule that + * matches the port VLAN ID and TPID. + * + * Tell hardware to strip outer VLAN tagged packets on receive and don't put + * them in the receive descriptor. VSI(s) in port VLANs should not be aware of + * the port VLAN ID or TPID they are assigned to. + * + * Tell hardware to prevent outer VLAN tag insertion on transmit and only allow + * untagged outer packets from the transmit descriptor. + * + * Also, tell the hardware to insert the port VLAN on transmit. + */ +static int +ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid) +{ + struct ice_hw *hw = ICE_VSI_TO_HW(vsi); + struct ice_vsi_ctx ctxt; + enum ice_status status; + u8 tag_type; + int err = 0; + + if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type)) + return -EINVAL; + + memset(&ctxt, 0, sizeof(ctxt)); + + ctxt.info = vsi->info; + + ctxt.info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; + + ctxt.info.port_based_outer_vlan = rte_cpu_to_le_16(vlan_info); + ctxt.info.outer_vlan_flags = + (ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW << + ICE_AQ_VSI_OUTER_VLAN_EMODE_S) | + ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) & + ICE_AQ_VSI_OUTER_TAG_TYPE_M) | + ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC | + (ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED << + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) | + ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT; + ctxt.info.valid_sections = + rte_cpu_to_le_16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID | + ICE_AQ_VSI_PROP_SW_VALID); + + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); + if (status != ICE_SUCCESS) { + PMD_DRV_LOG(ERR, + "update VSI for setting outer port based VLAN failed, err %d", + status); + err = -EINVAL; + } else { + vsi->info.port_based_outer_vlan = ctxt.info.port_based_outer_vlan; + vsi->info.outer_vlan_flags = ctxt.info.outer_vlan_flags; + vsi->info.sw_flags2 = ctxt.info.sw_flags2; + } + + return err; +} + +/** + * ice_vsi_dis_outer_insertion - disable outer VLAN insertion + * @vsi: VSI to configure + * @info: vlan pvid info + * + * Disable outer VLAN insertion via VSI context. This function should only be + * used if DVM is supported. + * + * Only modify the outer VLAN insertion settings. The VLAN TPID and outer VLAN + * settings are unmodified. + * + * This tells the hardware to not allow VLAN tagged packets in the transmit + * descriptor. This enables software offloaded VLAN insertion and disables + * hardware offloaded VLAN insertion. + */ +static int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi, struct ice_vsi_vlan_pvid_info *info) +{ + struct ice_hw *hw = ICE_VSI_TO_HW(vsi); + struct ice_vsi_ctx ctxt; + enum ice_status status; + uint8_t vlan_flags = 0; + int err = 0; + + memset(&ctxt, 0, sizeof(ctxt)); + + ctxt.info.valid_sections = + rte_cpu_to_le_16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID); + ctxt.info.port_based_inner_vlan = 0; + /* clear current outer VLAN insertion settings */ + ctxt.info.outer_vlan_flags = vsi->info.outer_vlan_flags & + ~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT | + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M); + if (info->config.reject.tagged == 0) + vlan_flags |= ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTTAGGED; + if (info->config.reject.untagged == 0) + vlan_flags |= ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED; + ctxt.info.outer_vlan_flags |= + ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC | + ((vlan_flags << + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) & + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M); + + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); + if (!status) { + PMD_DRV_LOG(ERR, + "update VSI for disabling outer VLAN insertion failed, err %d", + status); + err = -EINVAL; + } else { + vsi->info.outer_vlan_flags = ctxt.info.outer_vlan_flags; + vsi->info.port_based_inner_vlan = ctxt.info.port_based_inner_vlan; + } + + return err; +} + static int ice_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on) { @@ -5039,6 +5360,13 @@ ice_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on) data->dev_conf.txmode.hw_vlan_reject_untagged; } + if (ice_is_dvm_ena(&vsi->adapter->hw)) { + if (on) + return ice_vsi_set_outer_port_vlan(vsi, pvid, pf->outer_ethertype); + else + return ice_vsi_dis_outer_insertion(vsi, &info); + } + ret = ice_vsi_vlan_pvid_set(vsi, &info); if (ret < 0) { PMD_DRV_LOG(ERR, "Failed to set pvid."); @@ -5048,6 +5376,77 @@ ice_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on) return 0; } +static int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, uint16_t tpid) +{ + struct ice_hw *hw = ICE_VSI_TO_HW(vsi); + struct ice_vsi_ctx ctxt; + enum ice_status status; + int err = 0; + u8 tag_type; + /* do not allow modifying VLAN stripping when a port VLAN is configured + * on this VSI + */ + if (vsi->info.port_based_outer_vlan) + return 0; + + if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type)) + return -EINVAL; + + memset(&ctxt, 0, sizeof(ctxt)); + ctxt.info.valid_sections = + rte_cpu_to_le_16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID); + /* clear current outer VLAN insertion settings */ + ctxt.info.outer_vlan_flags = vsi->info.outer_vlan_flags & + ~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT | + ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC | + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M | + ICE_AQ_VSI_OUTER_TAG_TYPE_M); + ctxt.info.outer_vlan_flags |= + ((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL << + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) & + ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M) | + ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) & + ICE_AQ_VSI_OUTER_TAG_TYPE_M); + + status = ice_update_vsi(hw, vsi->idx, &ctxt, NULL); + if (status) { + PMD_DRV_LOG(ERR, "Update VSI failed to enable outer VLAN stripping"); + err = -EIO; + } else { + vsi->info.outer_vlan_flags = ctxt.info.outer_vlan_flags; + } + + return err; +} + +static int +ice_vlan_tpid_set(struct rte_eth_dev *dev, + enum rte_vlan_type vlan_type, + uint16_t tpid) +{ + struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private); + struct ice_hw *hw = ICE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ice_vsi *vsi = pf->main_vsi; + uint64_t qinq = dev->data->dev_conf.rxmode.offloads & + RTE_ETH_RX_OFFLOAD_VLAN_EXTEND; + int err = 0; + + if ((vlan_type != RTE_ETH_VLAN_TYPE_INNER && + vlan_type != RTE_ETH_VLAN_TYPE_OUTER) || + (!qinq && vlan_type == RTE_ETH_VLAN_TYPE_INNER) || + !ice_is_supported_port_vlan_proto(hw, tpid)) { + PMD_DRV_LOG(ERR, + "Unsupported vlan type."); + return -EINVAL; + } + + err = ice_vsi_ena_outer_insertion(vsi, tpid); + if (!err) + pf->outer_ethertype = tpid; + + return err; +} + static int ice_get_eeprom_length(struct rte_eth_dev *dev) { diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h index 9140f3af79..f925231f34 100644 --- a/drivers/net/ice/ice_ethdev.h +++ b/drivers/net/ice/ice_ethdev.h @@ -550,6 +550,7 @@ struct ice_pf { uint64_t supported_rxdid; /* bitmap for supported RXDID */ uint64_t rss_hf; struct ice_tm_conf tm_conf; + uint16_t outer_ethertype; }; #define ICE_MAX_QUEUE_NUM 2048 -- 2.25.1