Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) 2019-2021, Intel Corporation. */
0003 
0004 #include "ice_vsi_vlan_lib.h"
0005 #include "ice_lib.h"
0006 #include "ice_fltr.h"
0007 #include "ice.h"
0008 
0009 static void print_invalid_tpid(struct ice_vsi *vsi, u16 tpid)
0010 {
0011     dev_err(ice_pf_to_dev(vsi->back), "%s %d specified invalid VLAN tpid 0x%04x\n",
0012         ice_vsi_type_str(vsi->type), vsi->idx, tpid);
0013 }
0014 
0015 /**
0016  * validate_vlan - check if the ice_vlan passed in is valid
0017  * @vsi: VSI used for printing error message
0018  * @vlan: ice_vlan structure to validate
0019  *
0020  * Return true if the VLAN TPID is valid or if the VLAN TPID is 0 and the VLAN
0021  * VID is 0, which allows for non-zero VLAN filters with the specified VLAN TPID
0022  * and untagged VLAN 0 filters to be added to the prune list respectively.
0023  */
0024 static bool validate_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
0025 {
0026     if (vlan->tpid != ETH_P_8021Q && vlan->tpid != ETH_P_8021AD &&
0027         vlan->tpid != ETH_P_QINQ1 && (vlan->tpid || vlan->vid)) {
0028         print_invalid_tpid(vsi, vlan->tpid);
0029         return false;
0030     }
0031 
0032     return true;
0033 }
0034 
0035 /**
0036  * ice_vsi_add_vlan - default add VLAN implementation for all VSI types
0037  * @vsi: VSI being configured
0038  * @vlan: VLAN filter to add
0039  */
0040 int ice_vsi_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
0041 {
0042     int err;
0043 
0044     if (!validate_vlan(vsi, vlan))
0045         return -EINVAL;
0046 
0047     err = ice_fltr_add_vlan(vsi, vlan);
0048     if (err && err != -EEXIST) {
0049         dev_err(ice_pf_to_dev(vsi->back), "Failure Adding VLAN %d on VSI %i, status %d\n",
0050             vlan->vid, vsi->vsi_num, err);
0051         return err;
0052     }
0053 
0054     vsi->num_vlan++;
0055     return 0;
0056 }
0057 
0058 /**
0059  * ice_vsi_del_vlan - default del VLAN implementation for all VSI types
0060  * @vsi: VSI being configured
0061  * @vlan: VLAN filter to delete
0062  */
0063 int ice_vsi_del_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
0064 {
0065     struct ice_pf *pf = vsi->back;
0066     struct device *dev;
0067     int err;
0068 
0069     if (!validate_vlan(vsi, vlan))
0070         return -EINVAL;
0071 
0072     dev = ice_pf_to_dev(pf);
0073 
0074     err = ice_fltr_remove_vlan(vsi, vlan);
0075     if (!err)
0076         vsi->num_vlan--;
0077     else if (err == -ENOENT || err == -EBUSY)
0078         err = 0;
0079     else
0080         dev_err(dev, "Error removing VLAN %d on VSI %i error: %d\n",
0081             vlan->vid, vsi->vsi_num, err);
0082 
0083     return err;
0084 }
0085 
0086 /**
0087  * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx
0088  * @vsi: the VSI being changed
0089  */
0090 static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
0091 {
0092     struct ice_hw *hw = &vsi->back->hw;
0093     struct ice_vsi_ctx *ctxt;
0094     int err;
0095 
0096     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0097     if (!ctxt)
0098         return -ENOMEM;
0099 
0100     /* Here we are configuring the VSI to let the driver add VLAN tags by
0101      * setting inner_vlan_flags to ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL. The actual VLAN tag
0102      * insertion happens in the Tx hot path, in ice_tx_map.
0103      */
0104     ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
0105 
0106     /* Preserve existing VLAN strip setting */
0107     ctxt->info.inner_vlan_flags |= (vsi->info.inner_vlan_flags &
0108                     ICE_AQ_VSI_INNER_VLAN_EMODE_M);
0109 
0110     ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
0111 
0112     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0113     if (err) {
0114         dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN insert failed, err %d aq_err %s\n",
0115             err, ice_aq_str(hw->adminq.sq_last_status));
0116         goto out;
0117     }
0118 
0119     vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
0120 out:
0121     kfree(ctxt);
0122     return err;
0123 }
0124 
0125 /**
0126  * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx
0127  * @vsi: the VSI being changed
0128  * @ena: boolean value indicating if this is a enable or disable request
0129  */
0130 static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
0131 {
0132     struct ice_hw *hw = &vsi->back->hw;
0133     struct ice_vsi_ctx *ctxt;
0134     int err;
0135 
0136     /* do not allow modifying VLAN stripping when a port VLAN is configured
0137      * on this VSI
0138      */
0139     if (vsi->info.port_based_inner_vlan)
0140         return 0;
0141 
0142     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0143     if (!ctxt)
0144         return -ENOMEM;
0145 
0146     /* Here we are configuring what the VSI should do with the VLAN tag in
0147      * the Rx packet. We can either leave the tag in the packet or put it in
0148      * the Rx descriptor.
0149      */
0150     if (ena)
0151         /* Strip VLAN tag from Rx packet and put it in the desc */
0152         ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH;
0153     else
0154         /* Disable stripping. Leave tag in packet */
0155         ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING;
0156 
0157     /* Allow all packets untagged/tagged */
0158     ctxt->info.inner_vlan_flags |= ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
0159 
0160     ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
0161 
0162     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0163     if (err) {
0164         dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN strip failed, ena = %d err %d aq_err %s\n",
0165             ena, err, ice_aq_str(hw->adminq.sq_last_status));
0166         goto out;
0167     }
0168 
0169     vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
0170 out:
0171     kfree(ctxt);
0172     return err;
0173 }
0174 
0175 int ice_vsi_ena_inner_stripping(struct ice_vsi *vsi, const u16 tpid)
0176 {
0177     if (tpid != ETH_P_8021Q) {
0178         print_invalid_tpid(vsi, tpid);
0179         return -EINVAL;
0180     }
0181 
0182     return ice_vsi_manage_vlan_stripping(vsi, true);
0183 }
0184 
0185 int ice_vsi_dis_inner_stripping(struct ice_vsi *vsi)
0186 {
0187     return ice_vsi_manage_vlan_stripping(vsi, false);
0188 }
0189 
0190 int ice_vsi_ena_inner_insertion(struct ice_vsi *vsi, const u16 tpid)
0191 {
0192     if (tpid != ETH_P_8021Q) {
0193         print_invalid_tpid(vsi, tpid);
0194         return -EINVAL;
0195     }
0196 
0197     return ice_vsi_manage_vlan_insertion(vsi);
0198 }
0199 
0200 int ice_vsi_dis_inner_insertion(struct ice_vsi *vsi)
0201 {
0202     return ice_vsi_manage_vlan_insertion(vsi);
0203 }
0204 
0205 /**
0206  * __ice_vsi_set_inner_port_vlan - set port VLAN VSI context settings to enable a port VLAN
0207  * @vsi: the VSI to update
0208  * @pvid_info: VLAN ID and QoS used to set the PVID VSI context field
0209  */
0210 static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info)
0211 {
0212     struct ice_hw *hw = &vsi->back->hw;
0213     struct ice_aqc_vsi_props *info;
0214     struct ice_vsi_ctx *ctxt;
0215     int ret;
0216 
0217     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0218     if (!ctxt)
0219         return -ENOMEM;
0220 
0221     ctxt->info = vsi->info;
0222     info = &ctxt->info;
0223     info->inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ACCEPTUNTAGGED |
0224         ICE_AQ_VSI_INNER_VLAN_INSERT_PVID |
0225         ICE_AQ_VSI_INNER_VLAN_EMODE_STR;
0226     info->sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
0227 
0228     info->port_based_inner_vlan = cpu_to_le16(pvid_info);
0229     info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
0230                        ICE_AQ_VSI_PROP_SW_VALID);
0231 
0232     ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0233     if (ret) {
0234         dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n",
0235              ret, ice_aq_str(hw->adminq.sq_last_status));
0236         goto out;
0237     }
0238 
0239     vsi->info.inner_vlan_flags = info->inner_vlan_flags;
0240     vsi->info.sw_flags2 = info->sw_flags2;
0241     vsi->info.port_based_inner_vlan = info->port_based_inner_vlan;
0242 out:
0243     kfree(ctxt);
0244     return ret;
0245 }
0246 
0247 int ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
0248 {
0249     u16 port_vlan_info;
0250 
0251     if (vlan->tpid != ETH_P_8021Q)
0252         return -EINVAL;
0253 
0254     if (vlan->prio > 7)
0255         return -EINVAL;
0256 
0257     port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT);
0258 
0259     return __ice_vsi_set_inner_port_vlan(vsi, port_vlan_info);
0260 }
0261 
0262 /**
0263  * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI
0264  * @vsi: VSI to enable or disable VLAN pruning on
0265  * @ena: set to true to enable VLAN pruning and false to disable it
0266  *
0267  * returns 0 if VSI is updated, negative otherwise
0268  */
0269 static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena)
0270 {
0271     struct ice_vsi_ctx *ctxt;
0272     struct ice_pf *pf;
0273     int status;
0274 
0275     if (!vsi)
0276         return -EINVAL;
0277 
0278     /* Don't enable VLAN pruning if the netdev is currently in promiscuous
0279      * mode. VLAN pruning will be enabled when the interface exits
0280      * promiscuous mode if any VLAN filters are active.
0281      */
0282     if (vsi->netdev && vsi->netdev->flags & IFF_PROMISC && ena)
0283         return 0;
0284 
0285     pf = vsi->back;
0286     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0287     if (!ctxt)
0288         return -ENOMEM;
0289 
0290     ctxt->info = vsi->info;
0291 
0292     if (ena)
0293         ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
0294     else
0295         ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
0296 
0297     ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
0298 
0299     status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL);
0300     if (status) {
0301         netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %s\n",
0302                ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status,
0303                ice_aq_str(pf->hw.adminq.sq_last_status));
0304         goto err_out;
0305     }
0306 
0307     vsi->info.sw_flags2 = ctxt->info.sw_flags2;
0308 
0309     kfree(ctxt);
0310     return 0;
0311 
0312 err_out:
0313     kfree(ctxt);
0314     return status;
0315 }
0316 
0317 int ice_vsi_ena_rx_vlan_filtering(struct ice_vsi *vsi)
0318 {
0319     return ice_cfg_vlan_pruning(vsi, true);
0320 }
0321 
0322 int ice_vsi_dis_rx_vlan_filtering(struct ice_vsi *vsi)
0323 {
0324     return ice_cfg_vlan_pruning(vsi, false);
0325 }
0326 
0327 static int ice_cfg_vlan_antispoof(struct ice_vsi *vsi, bool enable)
0328 {
0329     struct ice_vsi_ctx *ctx;
0330     int err;
0331 
0332     ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
0333     if (!ctx)
0334         return -ENOMEM;
0335 
0336     ctx->info.sec_flags = vsi->info.sec_flags;
0337     ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
0338 
0339     if (enable)
0340         ctx->info.sec_flags |= ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
0341             ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S;
0342     else
0343         ctx->info.sec_flags &= ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
0344                      ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
0345 
0346     err = ice_update_vsi(&vsi->back->hw, vsi->idx, ctx, NULL);
0347     if (err)
0348         dev_err(ice_pf_to_dev(vsi->back), "Failed to configure Tx VLAN anti-spoof %s for VSI %d, error %d\n",
0349             enable ? "ON" : "OFF", vsi->vsi_num, err);
0350     else
0351         vsi->info.sec_flags = ctx->info.sec_flags;
0352 
0353     kfree(ctx);
0354 
0355     return err;
0356 }
0357 
0358 int ice_vsi_ena_tx_vlan_filtering(struct ice_vsi *vsi)
0359 {
0360     return ice_cfg_vlan_antispoof(vsi, true);
0361 }
0362 
0363 int ice_vsi_dis_tx_vlan_filtering(struct ice_vsi *vsi)
0364 {
0365     return ice_cfg_vlan_antispoof(vsi, false);
0366 }
0367 
0368 /**
0369  * tpid_to_vsi_outer_vlan_type - convert from TPID to VSI context based tag_type
0370  * @tpid: tpid used to translate into VSI context based tag_type
0371  * @tag_type: output variable to hold the VSI context based tag type
0372  */
0373 static int tpid_to_vsi_outer_vlan_type(u16 tpid, u8 *tag_type)
0374 {
0375     switch (tpid) {
0376     case ETH_P_8021Q:
0377         *tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_8100;
0378         break;
0379     case ETH_P_8021AD:
0380         *tag_type = ICE_AQ_VSI_OUTER_TAG_STAG;
0381         break;
0382     case ETH_P_QINQ1:
0383         *tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_9100;
0384         break;
0385     default:
0386         *tag_type = 0;
0387         return -EINVAL;
0388     }
0389 
0390     return 0;
0391 }
0392 
0393 /**
0394  * ice_vsi_ena_outer_stripping - enable outer VLAN stripping
0395  * @vsi: VSI to configure
0396  * @tpid: TPID to enable outer VLAN stripping for
0397  *
0398  * Enable outer VLAN stripping via VSI context. This function should only be
0399  * used if DVM is supported. Also, this function should never be called directly
0400  * as it should be part of ice_vsi_vlan_ops if it's needed.
0401  *
0402  * Since the VSI context only supports a single TPID for insertion and
0403  * stripping, setting the TPID for stripping will affect the TPID for insertion.
0404  * Callers need to be aware of this limitation.
0405  *
0406  * Only modify outer VLAN stripping settings and the VLAN TPID. Outer VLAN
0407  * insertion settings are unmodified.
0408  *
0409  * This enables hardware to strip a VLAN tag with the specified TPID to be
0410  * stripped from the packet and placed in the receive descriptor.
0411  */
0412 int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid)
0413 {
0414     struct ice_hw *hw = &vsi->back->hw;
0415     struct ice_vsi_ctx *ctxt;
0416     u8 tag_type;
0417     int err;
0418 
0419     /* do not allow modifying VLAN stripping when a port VLAN is configured
0420      * on this VSI
0421      */
0422     if (vsi->info.port_based_outer_vlan)
0423         return 0;
0424 
0425     if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
0426         return -EINVAL;
0427 
0428     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0429     if (!ctxt)
0430         return -ENOMEM;
0431 
0432     ctxt->info.valid_sections =
0433         cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
0434     /* clear current outer VLAN strip settings */
0435     ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
0436         ~(ICE_AQ_VSI_OUTER_VLAN_EMODE_M | ICE_AQ_VSI_OUTER_TAG_TYPE_M);
0437     ctxt->info.outer_vlan_flags |=
0438         ((ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW_BOTH <<
0439           ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
0440          ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
0441           ICE_AQ_VSI_OUTER_TAG_TYPE_M));
0442 
0443     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0444     if (err)
0445         dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN stripping failed, err %d aq_err %s\n",
0446             err, ice_aq_str(hw->adminq.sq_last_status));
0447     else
0448         vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
0449 
0450     kfree(ctxt);
0451     return err;
0452 }
0453 
0454 /**
0455  * ice_vsi_dis_outer_stripping - disable outer VLAN stripping
0456  * @vsi: VSI to configure
0457  *
0458  * Disable outer VLAN stripping via VSI context. This function should only be
0459  * used if DVM is supported. Also, this function should never be called directly
0460  * as it should be part of ice_vsi_vlan_ops if it's needed.
0461  *
0462  * Only modify the outer VLAN stripping settings. The VLAN TPID and outer VLAN
0463  * insertion settings are unmodified.
0464  *
0465  * This tells the hardware to not strip any VLAN tagged packets, thus leaving
0466  * them in the packet. This enables software offloaded VLAN stripping and
0467  * disables hardware offloaded VLAN stripping.
0468  */
0469 int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi)
0470 {
0471     struct ice_hw *hw = &vsi->back->hw;
0472     struct ice_vsi_ctx *ctxt;
0473     int err;
0474 
0475     if (vsi->info.port_based_outer_vlan)
0476         return 0;
0477 
0478     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0479     if (!ctxt)
0480         return -ENOMEM;
0481 
0482     ctxt->info.valid_sections =
0483         cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
0484     /* clear current outer VLAN strip settings */
0485     ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
0486         ~ICE_AQ_VSI_OUTER_VLAN_EMODE_M;
0487     ctxt->info.outer_vlan_flags |= ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING <<
0488         ICE_AQ_VSI_OUTER_VLAN_EMODE_S;
0489 
0490     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0491     if (err)
0492         dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN stripping failed, err %d aq_err %s\n",
0493             err, ice_aq_str(hw->adminq.sq_last_status));
0494     else
0495         vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
0496 
0497     kfree(ctxt);
0498     return err;
0499 }
0500 
0501 /**
0502  * ice_vsi_ena_outer_insertion - enable outer VLAN insertion
0503  * @vsi: VSI to configure
0504  * @tpid: TPID to enable outer VLAN insertion for
0505  *
0506  * Enable outer VLAN insertion via VSI context. This function should only be
0507  * used if DVM is supported. Also, this function should never be called directly
0508  * as it should be part of ice_vsi_vlan_ops if it's needed.
0509  *
0510  * Since the VSI context only supports a single TPID for insertion and
0511  * stripping, setting the TPID for insertion will affect the TPID for stripping.
0512  * Callers need to be aware of this limitation.
0513  *
0514  * Only modify outer VLAN insertion settings and the VLAN TPID. Outer VLAN
0515  * stripping settings are unmodified.
0516  *
0517  * This allows a VLAN tag with the specified TPID to be inserted in the transmit
0518  * descriptor.
0519  */
0520 int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid)
0521 {
0522     struct ice_hw *hw = &vsi->back->hw;
0523     struct ice_vsi_ctx *ctxt;
0524     u8 tag_type;
0525     int err;
0526 
0527     if (vsi->info.port_based_outer_vlan)
0528         return 0;
0529 
0530     if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
0531         return -EINVAL;
0532 
0533     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0534     if (!ctxt)
0535         return -ENOMEM;
0536 
0537     ctxt->info.valid_sections =
0538         cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
0539     /* clear current outer VLAN insertion settings */
0540     ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
0541         ~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT |
0542           ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
0543           ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M |
0544           ICE_AQ_VSI_OUTER_TAG_TYPE_M);
0545     ctxt->info.outer_vlan_flags |=
0546         ((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
0547           ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
0548          ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M) |
0549         ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
0550          ICE_AQ_VSI_OUTER_TAG_TYPE_M);
0551 
0552     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0553     if (err)
0554         dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN insertion failed, err %d aq_err %s\n",
0555             err, ice_aq_str(hw->adminq.sq_last_status));
0556     else
0557         vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
0558 
0559     kfree(ctxt);
0560     return err;
0561 }
0562 
0563 /**
0564  * ice_vsi_dis_outer_insertion - disable outer VLAN insertion
0565  * @vsi: VSI to configure
0566  *
0567  * Disable outer VLAN insertion via VSI context. This function should only be
0568  * used if DVM is supported. Also, this function should never be called directly
0569  * as it should be part of ice_vsi_vlan_ops if it's needed.
0570  *
0571  * Only modify the outer VLAN insertion settings. The VLAN TPID and outer VLAN
0572  * settings are unmodified.
0573  *
0574  * This tells the hardware to not allow any VLAN tagged packets in the transmit
0575  * descriptor. This enables software offloaded VLAN insertion and disables
0576  * hardware offloaded VLAN insertion.
0577  */
0578 int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi)
0579 {
0580     struct ice_hw *hw = &vsi->back->hw;
0581     struct ice_vsi_ctx *ctxt;
0582     int err;
0583 
0584     if (vsi->info.port_based_outer_vlan)
0585         return 0;
0586 
0587     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0588     if (!ctxt)
0589         return -ENOMEM;
0590 
0591     ctxt->info.valid_sections =
0592         cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
0593     /* clear current outer VLAN insertion settings */
0594     ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
0595         ~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT |
0596           ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
0597     ctxt->info.outer_vlan_flags |=
0598         ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
0599         ((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
0600           ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
0601          ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
0602 
0603     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0604     if (err)
0605         dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN insertion failed, err %d aq_err %s\n",
0606             err, ice_aq_str(hw->adminq.sq_last_status));
0607     else
0608         vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
0609 
0610     kfree(ctxt);
0611     return err;
0612 }
0613 
0614 /**
0615  * __ice_vsi_set_outer_port_vlan - set the outer port VLAN and related settings
0616  * @vsi: VSI to configure
0617  * @vlan_info: packed u16 that contains the VLAN prio and ID
0618  * @tpid: TPID of the port VLAN
0619  *
0620  * Set the port VLAN prio, ID, and TPID.
0621  *
0622  * Enable VLAN pruning so the VSI doesn't receive any traffic that doesn't match
0623  * a VLAN prune rule. The caller should take care to add a VLAN prune rule that
0624  * matches the port VLAN ID and TPID.
0625  *
0626  * Tell hardware to strip outer VLAN tagged packets on receive and don't put
0627  * them in the receive descriptor. VSI(s) in port VLANs should not be aware of
0628  * the port VLAN ID or TPID they are assigned to.
0629  *
0630  * Tell hardware to prevent outer VLAN tag insertion on transmit and only allow
0631  * untagged outer packets from the transmit descriptor.
0632  *
0633  * Also, tell the hardware to insert the port VLAN on transmit.
0634  */
0635 static int
0636 __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
0637 {
0638     struct ice_hw *hw = &vsi->back->hw;
0639     struct ice_vsi_ctx *ctxt;
0640     u8 tag_type;
0641     int err;
0642 
0643     if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
0644         return -EINVAL;
0645 
0646     ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
0647     if (!ctxt)
0648         return -ENOMEM;
0649 
0650     ctxt->info = vsi->info;
0651 
0652     ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
0653 
0654     ctxt->info.port_based_outer_vlan = cpu_to_le16(vlan_info);
0655     ctxt->info.outer_vlan_flags =
0656         (ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW <<
0657          ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
0658         ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
0659          ICE_AQ_VSI_OUTER_TAG_TYPE_M) |
0660         ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
0661         (ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED <<
0662          ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) |
0663         ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT;
0664 
0665     ctxt->info.valid_sections =
0666         cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID |
0667                 ICE_AQ_VSI_PROP_SW_VALID);
0668 
0669     err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
0670     if (err) {
0671         dev_err(ice_pf_to_dev(vsi->back), "update VSI for setting outer port based VLAN failed, err %d aq_err %s\n",
0672             err, ice_aq_str(hw->adminq.sq_last_status));
0673     } else {
0674         vsi->info.port_based_outer_vlan = ctxt->info.port_based_outer_vlan;
0675         vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
0676         vsi->info.sw_flags2 = ctxt->info.sw_flags2;
0677     }
0678 
0679     kfree(ctxt);
0680     return err;
0681 }
0682 
0683 /**
0684  * ice_vsi_set_outer_port_vlan - public version of __ice_vsi_set_outer_port_vlan
0685  * @vsi: VSI to configure
0686  * @vlan: ice_vlan structure used to set the port VLAN
0687  *
0688  * Set the outer port VLAN via VSI context. This function should only be
0689  * used if DVM is supported. Also, this function should never be called directly
0690  * as it should be part of ice_vsi_vlan_ops if it's needed.
0691  *
0692  * This function does not support clearing the port VLAN as there is currently
0693  * no use case for this.
0694  *
0695  * Use the ice_vlan structure passed in to set this VSI in a port VLAN.
0696  */
0697 int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
0698 {
0699     u16 port_vlan_info;
0700 
0701     if (vlan->prio > (VLAN_PRIO_MASK >> VLAN_PRIO_SHIFT))
0702         return -EINVAL;
0703 
0704     port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT);
0705 
0706     return __ice_vsi_set_outer_port_vlan(vsi, port_vlan_info, vlan->tpid);
0707 }