cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ice_vsi_vlan_lib.c (20626B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (C) 2019-2021, Intel Corporation. */
      3
      4#include "ice_vsi_vlan_lib.h"
      5#include "ice_lib.h"
      6#include "ice_fltr.h"
      7#include "ice.h"
      8
      9static void print_invalid_tpid(struct ice_vsi *vsi, u16 tpid)
     10{
     11	dev_err(ice_pf_to_dev(vsi->back), "%s %d specified invalid VLAN tpid 0x%04x\n",
     12		ice_vsi_type_str(vsi->type), vsi->idx, tpid);
     13}
     14
     15/**
     16 * validate_vlan - check if the ice_vlan passed in is valid
     17 * @vsi: VSI used for printing error message
     18 * @vlan: ice_vlan structure to validate
     19 *
     20 * Return true if the VLAN TPID is valid or if the VLAN TPID is 0 and the VLAN
     21 * VID is 0, which allows for non-zero VLAN filters with the specified VLAN TPID
     22 * and untagged VLAN 0 filters to be added to the prune list respectively.
     23 */
     24static bool validate_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
     25{
     26	if (vlan->tpid != ETH_P_8021Q && vlan->tpid != ETH_P_8021AD &&
     27	    vlan->tpid != ETH_P_QINQ1 && (vlan->tpid || vlan->vid)) {
     28		print_invalid_tpid(vsi, vlan->tpid);
     29		return false;
     30	}
     31
     32	return true;
     33}
     34
     35/**
     36 * ice_vsi_add_vlan - default add VLAN implementation for all VSI types
     37 * @vsi: VSI being configured
     38 * @vlan: VLAN filter to add
     39 */
     40int ice_vsi_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
     41{
     42	int err;
     43
     44	if (!validate_vlan(vsi, vlan))
     45		return -EINVAL;
     46
     47	err = ice_fltr_add_vlan(vsi, vlan);
     48	if (err && err != -EEXIST) {
     49		dev_err(ice_pf_to_dev(vsi->back), "Failure Adding VLAN %d on VSI %i, status %d\n",
     50			vlan->vid, vsi->vsi_num, err);
     51		return err;
     52	}
     53
     54	vsi->num_vlan++;
     55	return 0;
     56}
     57
     58/**
     59 * ice_vsi_del_vlan - default del VLAN implementation for all VSI types
     60 * @vsi: VSI being configured
     61 * @vlan: VLAN filter to delete
     62 */
     63int ice_vsi_del_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
     64{
     65	struct ice_pf *pf = vsi->back;
     66	struct device *dev;
     67	int err;
     68
     69	if (!validate_vlan(vsi, vlan))
     70		return -EINVAL;
     71
     72	dev = ice_pf_to_dev(pf);
     73
     74	err = ice_fltr_remove_vlan(vsi, vlan);
     75	if (!err)
     76		vsi->num_vlan--;
     77	else if (err == -ENOENT || err == -EBUSY)
     78		err = 0;
     79	else
     80		dev_err(dev, "Error removing VLAN %d on VSI %i error: %d\n",
     81			vlan->vid, vsi->vsi_num, err);
     82
     83	return err;
     84}
     85
     86/**
     87 * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx
     88 * @vsi: the VSI being changed
     89 */
     90static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
     91{
     92	struct ice_hw *hw = &vsi->back->hw;
     93	struct ice_vsi_ctx *ctxt;
     94	int err;
     95
     96	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
     97	if (!ctxt)
     98		return -ENOMEM;
     99
    100	/* Here we are configuring the VSI to let the driver add VLAN tags by
    101	 * setting inner_vlan_flags to ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL. The actual VLAN tag
    102	 * insertion happens in the Tx hot path, in ice_tx_map.
    103	 */
    104	ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
    105
    106	/* Preserve existing VLAN strip setting */
    107	ctxt->info.inner_vlan_flags |= (vsi->info.inner_vlan_flags &
    108					ICE_AQ_VSI_INNER_VLAN_EMODE_M);
    109
    110	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
    111
    112	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    113	if (err) {
    114		dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN insert failed, err %d aq_err %s\n",
    115			err, ice_aq_str(hw->adminq.sq_last_status));
    116		goto out;
    117	}
    118
    119	vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
    120out:
    121	kfree(ctxt);
    122	return err;
    123}
    124
    125/**
    126 * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx
    127 * @vsi: the VSI being changed
    128 * @ena: boolean value indicating if this is a enable or disable request
    129 */
    130static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
    131{
    132	struct ice_hw *hw = &vsi->back->hw;
    133	struct ice_vsi_ctx *ctxt;
    134	int err;
    135
    136	/* do not allow modifying VLAN stripping when a port VLAN is configured
    137	 * on this VSI
    138	 */
    139	if (vsi->info.port_based_inner_vlan)
    140		return 0;
    141
    142	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    143	if (!ctxt)
    144		return -ENOMEM;
    145
    146	/* Here we are configuring what the VSI should do with the VLAN tag in
    147	 * the Rx packet. We can either leave the tag in the packet or put it in
    148	 * the Rx descriptor.
    149	 */
    150	if (ena)
    151		/* Strip VLAN tag from Rx packet and put it in the desc */
    152		ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH;
    153	else
    154		/* Disable stripping. Leave tag in packet */
    155		ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING;
    156
    157	/* Allow all packets untagged/tagged */
    158	ctxt->info.inner_vlan_flags |= ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
    159
    160	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
    161
    162	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    163	if (err) {
    164		dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN strip failed, ena = %d err %d aq_err %s\n",
    165			ena, err, ice_aq_str(hw->adminq.sq_last_status));
    166		goto out;
    167	}
    168
    169	vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
    170out:
    171	kfree(ctxt);
    172	return err;
    173}
    174
    175int ice_vsi_ena_inner_stripping(struct ice_vsi *vsi, const u16 tpid)
    176{
    177	if (tpid != ETH_P_8021Q) {
    178		print_invalid_tpid(vsi, tpid);
    179		return -EINVAL;
    180	}
    181
    182	return ice_vsi_manage_vlan_stripping(vsi, true);
    183}
    184
    185int ice_vsi_dis_inner_stripping(struct ice_vsi *vsi)
    186{
    187	return ice_vsi_manage_vlan_stripping(vsi, false);
    188}
    189
    190int ice_vsi_ena_inner_insertion(struct ice_vsi *vsi, const u16 tpid)
    191{
    192	if (tpid != ETH_P_8021Q) {
    193		print_invalid_tpid(vsi, tpid);
    194		return -EINVAL;
    195	}
    196
    197	return ice_vsi_manage_vlan_insertion(vsi);
    198}
    199
    200int ice_vsi_dis_inner_insertion(struct ice_vsi *vsi)
    201{
    202	return ice_vsi_manage_vlan_insertion(vsi);
    203}
    204
    205/**
    206 * __ice_vsi_set_inner_port_vlan - set port VLAN VSI context settings to enable a port VLAN
    207 * @vsi: the VSI to update
    208 * @pvid_info: VLAN ID and QoS used to set the PVID VSI context field
    209 */
    210static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info)
    211{
    212	struct ice_hw *hw = &vsi->back->hw;
    213	struct ice_aqc_vsi_props *info;
    214	struct ice_vsi_ctx *ctxt;
    215	int ret;
    216
    217	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    218	if (!ctxt)
    219		return -ENOMEM;
    220
    221	ctxt->info = vsi->info;
    222	info = &ctxt->info;
    223	info->inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ACCEPTUNTAGGED |
    224		ICE_AQ_VSI_INNER_VLAN_INSERT_PVID |
    225		ICE_AQ_VSI_INNER_VLAN_EMODE_STR;
    226	info->sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
    227
    228	info->port_based_inner_vlan = cpu_to_le16(pvid_info);
    229	info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
    230					   ICE_AQ_VSI_PROP_SW_VALID);
    231
    232	ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    233	if (ret) {
    234		dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n",
    235			 ret, ice_aq_str(hw->adminq.sq_last_status));
    236		goto out;
    237	}
    238
    239	vsi->info.inner_vlan_flags = info->inner_vlan_flags;
    240	vsi->info.sw_flags2 = info->sw_flags2;
    241	vsi->info.port_based_inner_vlan = info->port_based_inner_vlan;
    242out:
    243	kfree(ctxt);
    244	return ret;
    245}
    246
    247int ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
    248{
    249	u16 port_vlan_info;
    250
    251	if (vlan->tpid != ETH_P_8021Q)
    252		return -EINVAL;
    253
    254	if (vlan->prio > 7)
    255		return -EINVAL;
    256
    257	port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT);
    258
    259	return __ice_vsi_set_inner_port_vlan(vsi, port_vlan_info);
    260}
    261
    262/**
    263 * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI
    264 * @vsi: VSI to enable or disable VLAN pruning on
    265 * @ena: set to true to enable VLAN pruning and false to disable it
    266 *
    267 * returns 0 if VSI is updated, negative otherwise
    268 */
    269static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena)
    270{
    271	struct ice_vsi_ctx *ctxt;
    272	struct ice_pf *pf;
    273	int status;
    274
    275	if (!vsi)
    276		return -EINVAL;
    277
    278	/* Don't enable VLAN pruning if the netdev is currently in promiscuous
    279	 * mode. VLAN pruning will be enabled when the interface exits
    280	 * promiscuous mode if any VLAN filters are active.
    281	 */
    282	if (vsi->netdev && vsi->netdev->flags & IFF_PROMISC && ena)
    283		return 0;
    284
    285	pf = vsi->back;
    286	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    287	if (!ctxt)
    288		return -ENOMEM;
    289
    290	ctxt->info = vsi->info;
    291
    292	if (ena)
    293		ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
    294	else
    295		ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
    296
    297	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
    298
    299	status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL);
    300	if (status) {
    301		netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %s\n",
    302			   ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status,
    303			   ice_aq_str(pf->hw.adminq.sq_last_status));
    304		goto err_out;
    305	}
    306
    307	vsi->info.sw_flags2 = ctxt->info.sw_flags2;
    308
    309	kfree(ctxt);
    310	return 0;
    311
    312err_out:
    313	kfree(ctxt);
    314	return status;
    315}
    316
    317int ice_vsi_ena_rx_vlan_filtering(struct ice_vsi *vsi)
    318{
    319	return ice_cfg_vlan_pruning(vsi, true);
    320}
    321
    322int ice_vsi_dis_rx_vlan_filtering(struct ice_vsi *vsi)
    323{
    324	return ice_cfg_vlan_pruning(vsi, false);
    325}
    326
    327static int ice_cfg_vlan_antispoof(struct ice_vsi *vsi, bool enable)
    328{
    329	struct ice_vsi_ctx *ctx;
    330	int err;
    331
    332	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
    333	if (!ctx)
    334		return -ENOMEM;
    335
    336	ctx->info.sec_flags = vsi->info.sec_flags;
    337	ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
    338
    339	if (enable)
    340		ctx->info.sec_flags |= ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
    341			ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S;
    342	else
    343		ctx->info.sec_flags &= ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
    344					 ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
    345
    346	err = ice_update_vsi(&vsi->back->hw, vsi->idx, ctx, NULL);
    347	if (err)
    348		dev_err(ice_pf_to_dev(vsi->back), "Failed to configure Tx VLAN anti-spoof %s for VSI %d, error %d\n",
    349			enable ? "ON" : "OFF", vsi->vsi_num, err);
    350	else
    351		vsi->info.sec_flags = ctx->info.sec_flags;
    352
    353	kfree(ctx);
    354
    355	return err;
    356}
    357
    358int ice_vsi_ena_tx_vlan_filtering(struct ice_vsi *vsi)
    359{
    360	return ice_cfg_vlan_antispoof(vsi, true);
    361}
    362
    363int ice_vsi_dis_tx_vlan_filtering(struct ice_vsi *vsi)
    364{
    365	return ice_cfg_vlan_antispoof(vsi, false);
    366}
    367
    368/**
    369 * tpid_to_vsi_outer_vlan_type - convert from TPID to VSI context based tag_type
    370 * @tpid: tpid used to translate into VSI context based tag_type
    371 * @tag_type: output variable to hold the VSI context based tag type
    372 */
    373static int tpid_to_vsi_outer_vlan_type(u16 tpid, u8 *tag_type)
    374{
    375	switch (tpid) {
    376	case ETH_P_8021Q:
    377		*tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_8100;
    378		break;
    379	case ETH_P_8021AD:
    380		*tag_type = ICE_AQ_VSI_OUTER_TAG_STAG;
    381		break;
    382	case ETH_P_QINQ1:
    383		*tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_9100;
    384		break;
    385	default:
    386		*tag_type = 0;
    387		return -EINVAL;
    388	}
    389
    390	return 0;
    391}
    392
    393/**
    394 * ice_vsi_ena_outer_stripping - enable outer VLAN stripping
    395 * @vsi: VSI to configure
    396 * @tpid: TPID to enable outer VLAN stripping for
    397 *
    398 * Enable outer VLAN stripping via VSI context. This function should only be
    399 * used if DVM is supported. Also, this function should never be called directly
    400 * as it should be part of ice_vsi_vlan_ops if it's needed.
    401 *
    402 * Since the VSI context only supports a single TPID for insertion and
    403 * stripping, setting the TPID for stripping will affect the TPID for insertion.
    404 * Callers need to be aware of this limitation.
    405 *
    406 * Only modify outer VLAN stripping settings and the VLAN TPID. Outer VLAN
    407 * insertion settings are unmodified.
    408 *
    409 * This enables hardware to strip a VLAN tag with the specified TPID to be
    410 * stripped from the packet and placed in the receive descriptor.
    411 */
    412int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid)
    413{
    414	struct ice_hw *hw = &vsi->back->hw;
    415	struct ice_vsi_ctx *ctxt;
    416	u8 tag_type;
    417	int err;
    418
    419	/* do not allow modifying VLAN stripping when a port VLAN is configured
    420	 * on this VSI
    421	 */
    422	if (vsi->info.port_based_outer_vlan)
    423		return 0;
    424
    425	if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
    426		return -EINVAL;
    427
    428	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    429	if (!ctxt)
    430		return -ENOMEM;
    431
    432	ctxt->info.valid_sections =
    433		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
    434	/* clear current outer VLAN strip settings */
    435	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
    436		~(ICE_AQ_VSI_OUTER_VLAN_EMODE_M | ICE_AQ_VSI_OUTER_TAG_TYPE_M);
    437	ctxt->info.outer_vlan_flags |=
    438		((ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW_BOTH <<
    439		  ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
    440		 ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
    441		  ICE_AQ_VSI_OUTER_TAG_TYPE_M));
    442
    443	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    444	if (err)
    445		dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN stripping failed, err %d aq_err %s\n",
    446			err, ice_aq_str(hw->adminq.sq_last_status));
    447	else
    448		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
    449
    450	kfree(ctxt);
    451	return err;
    452}
    453
    454/**
    455 * ice_vsi_dis_outer_stripping - disable outer VLAN stripping
    456 * @vsi: VSI to configure
    457 *
    458 * Disable outer VLAN stripping via VSI context. This function should only be
    459 * used if DVM is supported. Also, this function should never be called directly
    460 * as it should be part of ice_vsi_vlan_ops if it's needed.
    461 *
    462 * Only modify the outer VLAN stripping settings. The VLAN TPID and outer VLAN
    463 * insertion settings are unmodified.
    464 *
    465 * This tells the hardware to not strip any VLAN tagged packets, thus leaving
    466 * them in the packet. This enables software offloaded VLAN stripping and
    467 * disables hardware offloaded VLAN stripping.
    468 */
    469int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi)
    470{
    471	struct ice_hw *hw = &vsi->back->hw;
    472	struct ice_vsi_ctx *ctxt;
    473	int err;
    474
    475	if (vsi->info.port_based_outer_vlan)
    476		return 0;
    477
    478	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    479	if (!ctxt)
    480		return -ENOMEM;
    481
    482	ctxt->info.valid_sections =
    483		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
    484	/* clear current outer VLAN strip settings */
    485	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
    486		~ICE_AQ_VSI_OUTER_VLAN_EMODE_M;
    487	ctxt->info.outer_vlan_flags |= ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING <<
    488		ICE_AQ_VSI_OUTER_VLAN_EMODE_S;
    489
    490	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    491	if (err)
    492		dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN stripping failed, err %d aq_err %s\n",
    493			err, ice_aq_str(hw->adminq.sq_last_status));
    494	else
    495		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
    496
    497	kfree(ctxt);
    498	return err;
    499}
    500
    501/**
    502 * ice_vsi_ena_outer_insertion - enable outer VLAN insertion
    503 * @vsi: VSI to configure
    504 * @tpid: TPID to enable outer VLAN insertion for
    505 *
    506 * Enable outer VLAN insertion via VSI context. This function should only be
    507 * used if DVM is supported. Also, this function should never be called directly
    508 * as it should be part of ice_vsi_vlan_ops if it's needed.
    509 *
    510 * Since the VSI context only supports a single TPID for insertion and
    511 * stripping, setting the TPID for insertion will affect the TPID for stripping.
    512 * Callers need to be aware of this limitation.
    513 *
    514 * Only modify outer VLAN insertion settings and the VLAN TPID. Outer VLAN
    515 * stripping settings are unmodified.
    516 *
    517 * This allows a VLAN tag with the specified TPID to be inserted in the transmit
    518 * descriptor.
    519 */
    520int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid)
    521{
    522	struct ice_hw *hw = &vsi->back->hw;
    523	struct ice_vsi_ctx *ctxt;
    524	u8 tag_type;
    525	int err;
    526
    527	if (vsi->info.port_based_outer_vlan)
    528		return 0;
    529
    530	if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
    531		return -EINVAL;
    532
    533	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    534	if (!ctxt)
    535		return -ENOMEM;
    536
    537	ctxt->info.valid_sections =
    538		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
    539	/* clear current outer VLAN insertion settings */
    540	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
    541		~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT |
    542		  ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
    543		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M |
    544		  ICE_AQ_VSI_OUTER_TAG_TYPE_M);
    545	ctxt->info.outer_vlan_flags |=
    546		((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
    547		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
    548		 ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M) |
    549		((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
    550		 ICE_AQ_VSI_OUTER_TAG_TYPE_M);
    551
    552	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    553	if (err)
    554		dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN insertion failed, err %d aq_err %s\n",
    555			err, ice_aq_str(hw->adminq.sq_last_status));
    556	else
    557		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
    558
    559	kfree(ctxt);
    560	return err;
    561}
    562
    563/**
    564 * ice_vsi_dis_outer_insertion - disable outer VLAN insertion
    565 * @vsi: VSI to configure
    566 *
    567 * Disable outer VLAN insertion via VSI context. This function should only be
    568 * used if DVM is supported. Also, this function should never be called directly
    569 * as it should be part of ice_vsi_vlan_ops if it's needed.
    570 *
    571 * Only modify the outer VLAN insertion settings. The VLAN TPID and outer VLAN
    572 * settings are unmodified.
    573 *
    574 * This tells the hardware to not allow any VLAN tagged packets in the transmit
    575 * descriptor. This enables software offloaded VLAN insertion and disables
    576 * hardware offloaded VLAN insertion.
    577 */
    578int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi)
    579{
    580	struct ice_hw *hw = &vsi->back->hw;
    581	struct ice_vsi_ctx *ctxt;
    582	int err;
    583
    584	if (vsi->info.port_based_outer_vlan)
    585		return 0;
    586
    587	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    588	if (!ctxt)
    589		return -ENOMEM;
    590
    591	ctxt->info.valid_sections =
    592		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
    593	/* clear current outer VLAN insertion settings */
    594	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
    595		~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT |
    596		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
    597	ctxt->info.outer_vlan_flags |=
    598		ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
    599		((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
    600		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
    601		 ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
    602
    603	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    604	if (err)
    605		dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN insertion failed, err %d aq_err %s\n",
    606			err, ice_aq_str(hw->adminq.sq_last_status));
    607	else
    608		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
    609
    610	kfree(ctxt);
    611	return err;
    612}
    613
    614/**
    615 * __ice_vsi_set_outer_port_vlan - set the outer port VLAN and related settings
    616 * @vsi: VSI to configure
    617 * @vlan_info: packed u16 that contains the VLAN prio and ID
    618 * @tpid: TPID of the port VLAN
    619 *
    620 * Set the port VLAN prio, ID, and TPID.
    621 *
    622 * Enable VLAN pruning so the VSI doesn't receive any traffic that doesn't match
    623 * a VLAN prune rule. The caller should take care to add a VLAN prune rule that
    624 * matches the port VLAN ID and TPID.
    625 *
    626 * Tell hardware to strip outer VLAN tagged packets on receive and don't put
    627 * them in the receive descriptor. VSI(s) in port VLANs should not be aware of
    628 * the port VLAN ID or TPID they are assigned to.
    629 *
    630 * Tell hardware to prevent outer VLAN tag insertion on transmit and only allow
    631 * untagged outer packets from the transmit descriptor.
    632 *
    633 * Also, tell the hardware to insert the port VLAN on transmit.
    634 */
    635static int
    636__ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
    637{
    638	struct ice_hw *hw = &vsi->back->hw;
    639	struct ice_vsi_ctx *ctxt;
    640	u8 tag_type;
    641	int err;
    642
    643	if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
    644		return -EINVAL;
    645
    646	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
    647	if (!ctxt)
    648		return -ENOMEM;
    649
    650	ctxt->info = vsi->info;
    651
    652	ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
    653
    654	ctxt->info.port_based_outer_vlan = cpu_to_le16(vlan_info);
    655	ctxt->info.outer_vlan_flags =
    656		(ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW <<
    657		 ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
    658		((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
    659		 ICE_AQ_VSI_OUTER_TAG_TYPE_M) |
    660		ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
    661		(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED <<
    662		 ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) |
    663		ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT;
    664
    665	ctxt->info.valid_sections =
    666		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID |
    667			    ICE_AQ_VSI_PROP_SW_VALID);
    668
    669	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
    670	if (err) {
    671		dev_err(ice_pf_to_dev(vsi->back), "update VSI for setting outer port based VLAN failed, err %d aq_err %s\n",
    672			err, ice_aq_str(hw->adminq.sq_last_status));
    673	} else {
    674		vsi->info.port_based_outer_vlan = ctxt->info.port_based_outer_vlan;
    675		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
    676		vsi->info.sw_flags2 = ctxt->info.sw_flags2;
    677	}
    678
    679	kfree(ctxt);
    680	return err;
    681}
    682
    683/**
    684 * ice_vsi_set_outer_port_vlan - public version of __ice_vsi_set_outer_port_vlan
    685 * @vsi: VSI to configure
    686 * @vlan: ice_vlan structure used to set the port VLAN
    687 *
    688 * Set the outer port VLAN via VSI context. This function should only be
    689 * used if DVM is supported. Also, this function should never be called directly
    690 * as it should be part of ice_vsi_vlan_ops if it's needed.
    691 *
    692 * This function does not support clearing the port VLAN as there is currently
    693 * no use case for this.
    694 *
    695 * Use the ice_vlan structure passed in to set this VSI in a port VLAN.
    696 */
    697int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
    698{
    699	u16 port_vlan_info;
    700
    701	if (vlan->prio > (VLAN_PRIO_MASK >> VLAN_PRIO_SHIFT))
    702		return -EINVAL;
    703
    704	port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT);
    705
    706	return __ice_vsi_set_outer_port_vlan(vsi, port_vlan_info, vlan->tpid);
    707}