1bc42afa9SBrett Creeley // SPDX-License-Identifier: GPL-2.0
2bc42afa9SBrett Creeley /* Copyright (C) 2019-2021, Intel Corporation. */
3bc42afa9SBrett Creeley 
4bc42afa9SBrett Creeley #include "ice_vsi_vlan_lib.h"
5bc42afa9SBrett Creeley #include "ice_lib.h"
6bc42afa9SBrett Creeley #include "ice_fltr.h"
7bc42afa9SBrett Creeley #include "ice.h"
8bc42afa9SBrett Creeley 
print_invalid_tpid(struct ice_vsi * vsi,u16 tpid)92bfefa2dSBrett Creeley static void print_invalid_tpid(struct ice_vsi *vsi, u16 tpid)
102bfefa2dSBrett Creeley {
112bfefa2dSBrett Creeley 	dev_err(ice_pf_to_dev(vsi->back), "%s %d specified invalid VLAN tpid 0x%04x\n",
122bfefa2dSBrett Creeley 		ice_vsi_type_str(vsi->type), vsi->idx, tpid);
132bfefa2dSBrett Creeley }
142bfefa2dSBrett Creeley 
152bfefa2dSBrett Creeley /**
162bfefa2dSBrett Creeley  * validate_vlan - check if the ice_vlan passed in is valid
172bfefa2dSBrett Creeley  * @vsi: VSI used for printing error message
182bfefa2dSBrett Creeley  * @vlan: ice_vlan structure to validate
192bfefa2dSBrett Creeley  *
202bfefa2dSBrett Creeley  * Return true if the VLAN TPID is valid or if the VLAN TPID is 0 and the VLAN
212bfefa2dSBrett Creeley  * VID is 0, which allows for non-zero VLAN filters with the specified VLAN TPID
222bfefa2dSBrett Creeley  * and untagged VLAN 0 filters to be added to the prune list respectively.
232bfefa2dSBrett Creeley  */
validate_vlan(struct ice_vsi * vsi,struct ice_vlan * vlan)242bfefa2dSBrett Creeley static bool validate_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
252bfefa2dSBrett Creeley {
26c31af68aSBrett Creeley 	if (vlan->tpid != ETH_P_8021Q && vlan->tpid != ETH_P_8021AD &&
27c31af68aSBrett Creeley 	    vlan->tpid != ETH_P_QINQ1 && (vlan->tpid || vlan->vid)) {
282bfefa2dSBrett Creeley 		print_invalid_tpid(vsi, vlan->tpid);
292bfefa2dSBrett Creeley 		return false;
302bfefa2dSBrett Creeley 	}
312bfefa2dSBrett Creeley 
322bfefa2dSBrett Creeley 	return true;
332bfefa2dSBrett Creeley }
342bfefa2dSBrett Creeley 
35bc42afa9SBrett Creeley /**
36bc42afa9SBrett Creeley  * ice_vsi_add_vlan - default add VLAN implementation for all VSI types
37bc42afa9SBrett Creeley  * @vsi: VSI being configured
38fb05ba12SBrett Creeley  * @vlan: VLAN filter to add
39bc42afa9SBrett Creeley  */
ice_vsi_add_vlan(struct ice_vsi * vsi,struct ice_vlan * vlan)40fb05ba12SBrett Creeley int ice_vsi_add_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
41bc42afa9SBrett Creeley {
42a1ffafb0SBrett Creeley 	int err;
43bc42afa9SBrett Creeley 
442bfefa2dSBrett Creeley 	if (!validate_vlan(vsi, vlan))
452bfefa2dSBrett Creeley 		return -EINVAL;
462bfefa2dSBrett Creeley 
47a1ffafb0SBrett Creeley 	err = ice_fltr_add_vlan(vsi, vlan);
4871e61511SJacob Keller 	if (!err)
4971e61511SJacob Keller 		vsi->num_vlan++;
5071e61511SJacob Keller 	else if (err == -EEXIST)
5171e61511SJacob Keller 		err = 0;
5271e61511SJacob Keller 	else
53a1ffafb0SBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "Failure Adding VLAN %d on VSI %i, status %d\n",
54a1ffafb0SBrett Creeley 			vlan->vid, vsi->vsi_num, err);
55bc42afa9SBrett Creeley 
5671e61511SJacob Keller 	return err;
57bc42afa9SBrett Creeley }
58bc42afa9SBrett Creeley 
59bc42afa9SBrett Creeley /**
60bc42afa9SBrett Creeley  * ice_vsi_del_vlan - default del VLAN implementation for all VSI types
61bc42afa9SBrett Creeley  * @vsi: VSI being configured
62fb05ba12SBrett Creeley  * @vlan: VLAN filter to delete
63bc42afa9SBrett Creeley  */
ice_vsi_del_vlan(struct ice_vsi * vsi,struct ice_vlan * vlan)64fb05ba12SBrett Creeley int ice_vsi_del_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
65bc42afa9SBrett Creeley {
66bc42afa9SBrett Creeley 	struct ice_pf *pf = vsi->back;
67bc42afa9SBrett Creeley 	struct device *dev;
68bc42afa9SBrett Creeley 	int err;
69bc42afa9SBrett Creeley 
702bfefa2dSBrett Creeley 	if (!validate_vlan(vsi, vlan))
712bfefa2dSBrett Creeley 		return -EINVAL;
722bfefa2dSBrett Creeley 
73bc42afa9SBrett Creeley 	dev = ice_pf_to_dev(pf);
74bc42afa9SBrett Creeley 
75fb05ba12SBrett Creeley 	err = ice_fltr_remove_vlan(vsi, vlan);
76a1ffafb0SBrett Creeley 	if (!err)
77bc42afa9SBrett Creeley 		vsi->num_vlan--;
78a1ffafb0SBrett Creeley 	else if (err == -ENOENT || err == -EBUSY)
79bc42afa9SBrett Creeley 		err = 0;
80a1ffafb0SBrett Creeley 	else
81bc42afa9SBrett Creeley 		dev_err(dev, "Error removing VLAN %d on VSI %i error: %d\n",
82fb05ba12SBrett Creeley 			vlan->vid, vsi->vsi_num, err);
83bc42afa9SBrett Creeley 
84bc42afa9SBrett Creeley 	return err;
85bc42afa9SBrett Creeley }
86bc42afa9SBrett Creeley 
87bc42afa9SBrett Creeley /**
88bc42afa9SBrett Creeley  * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx
89bc42afa9SBrett Creeley  * @vsi: the VSI being changed
90bc42afa9SBrett Creeley  */
ice_vsi_manage_vlan_insertion(struct ice_vsi * vsi)91bc42afa9SBrett Creeley static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi)
92bc42afa9SBrett Creeley {
93bc42afa9SBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
94bc42afa9SBrett Creeley 	struct ice_vsi_ctx *ctxt;
95bc42afa9SBrett Creeley 	int err;
96bc42afa9SBrett Creeley 
97bc42afa9SBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
98bc42afa9SBrett Creeley 	if (!ctxt)
99bc42afa9SBrett Creeley 		return -ENOMEM;
100bc42afa9SBrett Creeley 
101bc42afa9SBrett Creeley 	/* Here we are configuring the VSI to let the driver add VLAN tags by
1027bd527aaSBrett Creeley 	 * setting inner_vlan_flags to ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL. The actual VLAN tag
103bc42afa9SBrett Creeley 	 * insertion happens in the Tx hot path, in ice_tx_map.
104bc42afa9SBrett Creeley 	 */
1057bd527aaSBrett Creeley 	ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
106bc42afa9SBrett Creeley 
107bc42afa9SBrett Creeley 	/* Preserve existing VLAN strip setting */
1087bd527aaSBrett Creeley 	ctxt->info.inner_vlan_flags |= (vsi->info.inner_vlan_flags &
1097bd527aaSBrett Creeley 					ICE_AQ_VSI_INNER_VLAN_EMODE_M);
110bc42afa9SBrett Creeley 
111bc42afa9SBrett Creeley 	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
112bc42afa9SBrett Creeley 
113bc42afa9SBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
114bc42afa9SBrett Creeley 	if (err) {
115bc42afa9SBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN insert failed, err %d aq_err %s\n",
116bc42afa9SBrett Creeley 			err, ice_aq_str(hw->adminq.sq_last_status));
117bc42afa9SBrett Creeley 		goto out;
118bc42afa9SBrett Creeley 	}
119bc42afa9SBrett Creeley 
1207bd527aaSBrett Creeley 	vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
121bc42afa9SBrett Creeley out:
122bc42afa9SBrett Creeley 	kfree(ctxt);
123bc42afa9SBrett Creeley 	return err;
124bc42afa9SBrett Creeley }
125bc42afa9SBrett Creeley 
126bc42afa9SBrett Creeley /**
127bc42afa9SBrett Creeley  * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx
128bc42afa9SBrett Creeley  * @vsi: the VSI being changed
129bc42afa9SBrett Creeley  * @ena: boolean value indicating if this is a enable or disable request
130bc42afa9SBrett Creeley  */
ice_vsi_manage_vlan_stripping(struct ice_vsi * vsi,bool ena)131bc42afa9SBrett Creeley static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena)
132bc42afa9SBrett Creeley {
133bc42afa9SBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
134bc42afa9SBrett Creeley 	struct ice_vsi_ctx *ctxt;
1356bc0e112SJesse Brandeburg 	u8 *ivf;
136bc42afa9SBrett Creeley 	int err;
137bc42afa9SBrett Creeley 
138bc42afa9SBrett Creeley 	/* do not allow modifying VLAN stripping when a port VLAN is configured
139bc42afa9SBrett Creeley 	 * on this VSI
140bc42afa9SBrett Creeley 	 */
1417bd527aaSBrett Creeley 	if (vsi->info.port_based_inner_vlan)
142bc42afa9SBrett Creeley 		return 0;
143bc42afa9SBrett Creeley 
144bc42afa9SBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
145bc42afa9SBrett Creeley 	if (!ctxt)
146bc42afa9SBrett Creeley 		return -ENOMEM;
147bc42afa9SBrett Creeley 
1486bc0e112SJesse Brandeburg 	ivf = &ctxt->info.inner_vlan_flags;
1496bc0e112SJesse Brandeburg 
150bc42afa9SBrett Creeley 	/* Here we are configuring what the VSI should do with the VLAN tag in
151bc42afa9SBrett Creeley 	 * the Rx packet. We can either leave the tag in the packet or put it in
152bc42afa9SBrett Creeley 	 * the Rx descriptor.
153bc42afa9SBrett Creeley 	 */
1546bc0e112SJesse Brandeburg 	if (ena) {
155bc42afa9SBrett Creeley 		/* Strip VLAN tag from Rx packet and put it in the desc */
1566bc0e112SJesse Brandeburg 		*ivf = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M,
1576bc0e112SJesse Brandeburg 				  ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH);
1586bc0e112SJesse Brandeburg 	} else {
159bc42afa9SBrett Creeley 		/* Disable stripping. Leave tag in packet */
1606bc0e112SJesse Brandeburg 		*ivf = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M,
1616bc0e112SJesse Brandeburg 				  ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING);
1626bc0e112SJesse Brandeburg 	}
163bc42afa9SBrett Creeley 
164bc42afa9SBrett Creeley 	/* Allow all packets untagged/tagged */
1656bc0e112SJesse Brandeburg 	*ivf |= ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL;
166bc42afa9SBrett Creeley 
167bc42afa9SBrett Creeley 	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID);
168bc42afa9SBrett Creeley 
169bc42afa9SBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
170bc42afa9SBrett Creeley 	if (err) {
171bc42afa9SBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN strip failed, ena = %d err %d aq_err %s\n",
172bc42afa9SBrett Creeley 			ena, err, ice_aq_str(hw->adminq.sq_last_status));
173bc42afa9SBrett Creeley 		goto out;
174bc42afa9SBrett Creeley 	}
175bc42afa9SBrett Creeley 
1767bd527aaSBrett Creeley 	vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
177bc42afa9SBrett Creeley out:
178bc42afa9SBrett Creeley 	kfree(ctxt);
179bc42afa9SBrett Creeley 	return err;
180bc42afa9SBrett Creeley }
181bc42afa9SBrett Creeley 
ice_vsi_ena_inner_stripping(struct ice_vsi * vsi,const u16 tpid)1827bd527aaSBrett Creeley int ice_vsi_ena_inner_stripping(struct ice_vsi *vsi, const u16 tpid)
183bc42afa9SBrett Creeley {
1842bfefa2dSBrett Creeley 	if (tpid != ETH_P_8021Q) {
1852bfefa2dSBrett Creeley 		print_invalid_tpid(vsi, tpid);
1862bfefa2dSBrett Creeley 		return -EINVAL;
1872bfefa2dSBrett Creeley 	}
1882bfefa2dSBrett Creeley 
189bc42afa9SBrett Creeley 	return ice_vsi_manage_vlan_stripping(vsi, true);
190bc42afa9SBrett Creeley }
191bc42afa9SBrett Creeley 
ice_vsi_dis_inner_stripping(struct ice_vsi * vsi)1927bd527aaSBrett Creeley int ice_vsi_dis_inner_stripping(struct ice_vsi *vsi)
193bc42afa9SBrett Creeley {
194bc42afa9SBrett Creeley 	return ice_vsi_manage_vlan_stripping(vsi, false);
195bc42afa9SBrett Creeley }
196bc42afa9SBrett Creeley 
ice_vsi_ena_inner_insertion(struct ice_vsi * vsi,const u16 tpid)1977bd527aaSBrett Creeley int ice_vsi_ena_inner_insertion(struct ice_vsi *vsi, const u16 tpid)
198bc42afa9SBrett Creeley {
1992bfefa2dSBrett Creeley 	if (tpid != ETH_P_8021Q) {
2002bfefa2dSBrett Creeley 		print_invalid_tpid(vsi, tpid);
2012bfefa2dSBrett Creeley 		return -EINVAL;
2022bfefa2dSBrett Creeley 	}
2032bfefa2dSBrett Creeley 
204bc42afa9SBrett Creeley 	return ice_vsi_manage_vlan_insertion(vsi);
205bc42afa9SBrett Creeley }
206bc42afa9SBrett Creeley 
ice_vsi_dis_inner_insertion(struct ice_vsi * vsi)2077bd527aaSBrett Creeley int ice_vsi_dis_inner_insertion(struct ice_vsi *vsi)
208bc42afa9SBrett Creeley {
209bc42afa9SBrett Creeley 	return ice_vsi_manage_vlan_insertion(vsi);
210bc42afa9SBrett Creeley }
211bc42afa9SBrett Creeley 
2122946204bSMichal Swiatkowski static void
ice_save_vlan_info(struct ice_aqc_vsi_props * info,struct ice_vsi_vlan_info * vlan)2132946204bSMichal Swiatkowski ice_save_vlan_info(struct ice_aqc_vsi_props *info,
2142946204bSMichal Swiatkowski 		   struct ice_vsi_vlan_info *vlan)
2152946204bSMichal Swiatkowski {
2162946204bSMichal Swiatkowski 	vlan->sw_flags2 = info->sw_flags2;
2172946204bSMichal Swiatkowski 	vlan->inner_vlan_flags = info->inner_vlan_flags;
2182946204bSMichal Swiatkowski 	vlan->outer_vlan_flags = info->outer_vlan_flags;
2192946204bSMichal Swiatkowski }
2202946204bSMichal Swiatkowski 
2212946204bSMichal Swiatkowski static void
ice_restore_vlan_info(struct ice_aqc_vsi_props * info,struct ice_vsi_vlan_info * vlan)2222946204bSMichal Swiatkowski ice_restore_vlan_info(struct ice_aqc_vsi_props *info,
2232946204bSMichal Swiatkowski 		      struct ice_vsi_vlan_info *vlan)
2242946204bSMichal Swiatkowski {
2252946204bSMichal Swiatkowski 	info->sw_flags2 = vlan->sw_flags2;
2262946204bSMichal Swiatkowski 	info->inner_vlan_flags = vlan->inner_vlan_flags;
2272946204bSMichal Swiatkowski 	info->outer_vlan_flags = vlan->outer_vlan_flags;
2282946204bSMichal Swiatkowski }
2292946204bSMichal Swiatkowski 
230bc42afa9SBrett Creeley /**
2317bd527aaSBrett Creeley  * __ice_vsi_set_inner_port_vlan - set port VLAN VSI context settings to enable a port VLAN
232bc42afa9SBrett Creeley  * @vsi: the VSI to update
233bc42afa9SBrett Creeley  * @pvid_info: VLAN ID and QoS used to set the PVID VSI context field
234bc42afa9SBrett Creeley  */
__ice_vsi_set_inner_port_vlan(struct ice_vsi * vsi,u16 pvid_info)2357bd527aaSBrett Creeley static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info)
236bc42afa9SBrett Creeley {
237bc42afa9SBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
238bc42afa9SBrett Creeley 	struct ice_aqc_vsi_props *info;
239bc42afa9SBrett Creeley 	struct ice_vsi_ctx *ctxt;
240bc42afa9SBrett Creeley 	int ret;
241bc42afa9SBrett Creeley 
242bc42afa9SBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
243bc42afa9SBrett Creeley 	if (!ctxt)
244bc42afa9SBrett Creeley 		return -ENOMEM;
245bc42afa9SBrett Creeley 
2462946204bSMichal Swiatkowski 	ice_save_vlan_info(&vsi->info, &vsi->vlan_info);
247bc42afa9SBrett Creeley 	ctxt->info = vsi->info;
248bc42afa9SBrett Creeley 	info = &ctxt->info;
2497bd527aaSBrett Creeley 	info->inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ACCEPTUNTAGGED |
2507bd527aaSBrett Creeley 		ICE_AQ_VSI_INNER_VLAN_INSERT_PVID |
2517bd527aaSBrett Creeley 		ICE_AQ_VSI_INNER_VLAN_EMODE_STR;
252bc42afa9SBrett Creeley 	info->sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
253bc42afa9SBrett Creeley 
2547bd527aaSBrett Creeley 	info->port_based_inner_vlan = cpu_to_le16(pvid_info);
255bc42afa9SBrett Creeley 	info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
256bc42afa9SBrett Creeley 					   ICE_AQ_VSI_PROP_SW_VALID);
257bc42afa9SBrett Creeley 
258bc42afa9SBrett Creeley 	ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
259bc42afa9SBrett Creeley 	if (ret) {
260bc42afa9SBrett Creeley 		dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n",
261bc42afa9SBrett Creeley 			 ret, ice_aq_str(hw->adminq.sq_last_status));
262bc42afa9SBrett Creeley 		goto out;
263bc42afa9SBrett Creeley 	}
264bc42afa9SBrett Creeley 
2657bd527aaSBrett Creeley 	vsi->info.inner_vlan_flags = info->inner_vlan_flags;
266bc42afa9SBrett Creeley 	vsi->info.sw_flags2 = info->sw_flags2;
2677bd527aaSBrett Creeley 	vsi->info.port_based_inner_vlan = info->port_based_inner_vlan;
268bc42afa9SBrett Creeley out:
269bc42afa9SBrett Creeley 	kfree(ctxt);
270bc42afa9SBrett Creeley 	return ret;
271bc42afa9SBrett Creeley }
272bc42afa9SBrett Creeley 
ice_vsi_set_inner_port_vlan(struct ice_vsi * vsi,struct ice_vlan * vlan)2737bd527aaSBrett Creeley int ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
274bc42afa9SBrett Creeley {
275fb05ba12SBrett Creeley 	u16 port_vlan_info;
276fb05ba12SBrett Creeley 
2772bfefa2dSBrett Creeley 	if (vlan->tpid != ETH_P_8021Q)
2782bfefa2dSBrett Creeley 		return -EINVAL;
2792bfefa2dSBrett Creeley 
280fb05ba12SBrett Creeley 	if (vlan->prio > 7)
281fb05ba12SBrett Creeley 		return -EINVAL;
282fb05ba12SBrett Creeley 
283fb05ba12SBrett Creeley 	port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT);
284fb05ba12SBrett Creeley 
2857bd527aaSBrett Creeley 	return __ice_vsi_set_inner_port_vlan(vsi, port_vlan_info);
286bc42afa9SBrett Creeley }
287bc42afa9SBrett Creeley 
ice_vsi_clear_inner_port_vlan(struct ice_vsi * vsi)2882946204bSMichal Swiatkowski int ice_vsi_clear_inner_port_vlan(struct ice_vsi *vsi)
2892946204bSMichal Swiatkowski {
2902946204bSMichal Swiatkowski 	struct ice_hw *hw = &vsi->back->hw;
2912946204bSMichal Swiatkowski 	struct ice_aqc_vsi_props *info;
2922946204bSMichal Swiatkowski 	struct ice_vsi_ctx *ctxt;
2932946204bSMichal Swiatkowski 	int ret;
2942946204bSMichal Swiatkowski 
2952946204bSMichal Swiatkowski 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
2962946204bSMichal Swiatkowski 	if (!ctxt)
2972946204bSMichal Swiatkowski 		return -ENOMEM;
2982946204bSMichal Swiatkowski 
2992946204bSMichal Swiatkowski 	ice_restore_vlan_info(&vsi->info, &vsi->vlan_info);
3002946204bSMichal Swiatkowski 	vsi->info.port_based_inner_vlan = 0;
3012946204bSMichal Swiatkowski 	ctxt->info = vsi->info;
3022946204bSMichal Swiatkowski 	info = &ctxt->info;
3032946204bSMichal Swiatkowski 	info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
3042946204bSMichal Swiatkowski 					   ICE_AQ_VSI_PROP_SW_VALID);
3052946204bSMichal Swiatkowski 
3062946204bSMichal Swiatkowski 	ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
3072946204bSMichal Swiatkowski 	if (ret)
3082946204bSMichal Swiatkowski 		dev_err(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n",
3092946204bSMichal Swiatkowski 			ret, ice_aq_str(hw->adminq.sq_last_status));
3102946204bSMichal Swiatkowski 
3112946204bSMichal Swiatkowski 	kfree(ctxt);
3122946204bSMichal Swiatkowski 	return ret;
3132946204bSMichal Swiatkowski }
3142946204bSMichal Swiatkowski 
315bc42afa9SBrett Creeley /**
316bc42afa9SBrett Creeley  * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI
317bc42afa9SBrett Creeley  * @vsi: VSI to enable or disable VLAN pruning on
318bc42afa9SBrett Creeley  * @ena: set to true to enable VLAN pruning and false to disable it
319bc42afa9SBrett Creeley  *
320bc42afa9SBrett Creeley  * returns 0 if VSI is updated, negative otherwise
321bc42afa9SBrett Creeley  */
ice_cfg_vlan_pruning(struct ice_vsi * vsi,bool ena)322bc42afa9SBrett Creeley static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena)
323bc42afa9SBrett Creeley {
324bc42afa9SBrett Creeley 	struct ice_vsi_ctx *ctxt;
325bc42afa9SBrett Creeley 	struct ice_pf *pf;
326bc42afa9SBrett Creeley 	int status;
327bc42afa9SBrett Creeley 
328bc42afa9SBrett Creeley 	if (!vsi)
329bc42afa9SBrett Creeley 		return -EINVAL;
330bc42afa9SBrett Creeley 
331bc42afa9SBrett Creeley 	/* Don't enable VLAN pruning if the netdev is currently in promiscuous
332bc42afa9SBrett Creeley 	 * mode. VLAN pruning will be enabled when the interface exits
333bc42afa9SBrett Creeley 	 * promiscuous mode if any VLAN filters are active.
334bc42afa9SBrett Creeley 	 */
335bc42afa9SBrett Creeley 	if (vsi->netdev && vsi->netdev->flags & IFF_PROMISC && ena)
336bc42afa9SBrett Creeley 		return 0;
337bc42afa9SBrett Creeley 
338bc42afa9SBrett Creeley 	pf = vsi->back;
339bc42afa9SBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
340bc42afa9SBrett Creeley 	if (!ctxt)
341bc42afa9SBrett Creeley 		return -ENOMEM;
342bc42afa9SBrett Creeley 
343bc42afa9SBrett Creeley 	ctxt->info = vsi->info;
344bc42afa9SBrett Creeley 
345bc42afa9SBrett Creeley 	if (ena)
346bc42afa9SBrett Creeley 		ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
347bc42afa9SBrett Creeley 	else
348bc42afa9SBrett Creeley 		ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
349bc42afa9SBrett Creeley 
350bc42afa9SBrett Creeley 	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
351bc42afa9SBrett Creeley 
352bc42afa9SBrett Creeley 	status = ice_update_vsi(&pf->hw, vsi->idx, ctxt, NULL);
353bc42afa9SBrett Creeley 	if (status) {
354bc42afa9SBrett Creeley 		netdev_err(vsi->netdev, "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %s\n",
355bc42afa9SBrett Creeley 			   ena ? "En" : "Dis", vsi->idx, vsi->vsi_num, status,
356bc42afa9SBrett Creeley 			   ice_aq_str(pf->hw.adminq.sq_last_status));
357bc42afa9SBrett Creeley 		goto err_out;
358bc42afa9SBrett Creeley 	}
359bc42afa9SBrett Creeley 
360bc42afa9SBrett Creeley 	vsi->info.sw_flags2 = ctxt->info.sw_flags2;
361bc42afa9SBrett Creeley 
362bc42afa9SBrett Creeley 	kfree(ctxt);
363bc42afa9SBrett Creeley 	return 0;
364bc42afa9SBrett Creeley 
365bc42afa9SBrett Creeley err_out:
366bc42afa9SBrett Creeley 	kfree(ctxt);
367bc42afa9SBrett Creeley 	return status;
368bc42afa9SBrett Creeley }
369bc42afa9SBrett Creeley 
ice_vsi_ena_rx_vlan_filtering(struct ice_vsi * vsi)370bc42afa9SBrett Creeley int ice_vsi_ena_rx_vlan_filtering(struct ice_vsi *vsi)
371bc42afa9SBrett Creeley {
372bc42afa9SBrett Creeley 	return ice_cfg_vlan_pruning(vsi, true);
373bc42afa9SBrett Creeley }
374bc42afa9SBrett Creeley 
ice_vsi_dis_rx_vlan_filtering(struct ice_vsi * vsi)375bc42afa9SBrett Creeley int ice_vsi_dis_rx_vlan_filtering(struct ice_vsi *vsi)
376bc42afa9SBrett Creeley {
377bc42afa9SBrett Creeley 	return ice_cfg_vlan_pruning(vsi, false);
378bc42afa9SBrett Creeley }
379bc42afa9SBrett Creeley 
ice_cfg_vlan_antispoof(struct ice_vsi * vsi,bool enable)380bc42afa9SBrett Creeley static int ice_cfg_vlan_antispoof(struct ice_vsi *vsi, bool enable)
381bc42afa9SBrett Creeley {
382bc42afa9SBrett Creeley 	struct ice_vsi_ctx *ctx;
383bc42afa9SBrett Creeley 	int err;
384bc42afa9SBrett Creeley 
385bc42afa9SBrett Creeley 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
386bc42afa9SBrett Creeley 	if (!ctx)
387bc42afa9SBrett Creeley 		return -ENOMEM;
388bc42afa9SBrett Creeley 
389bc42afa9SBrett Creeley 	ctx->info.sec_flags = vsi->info.sec_flags;
390bc42afa9SBrett Creeley 	ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID);
391bc42afa9SBrett Creeley 
392bc42afa9SBrett Creeley 	if (enable)
393bc42afa9SBrett Creeley 		ctx->info.sec_flags |= ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
394bc42afa9SBrett Creeley 			ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S;
395bc42afa9SBrett Creeley 	else
396bc42afa9SBrett Creeley 		ctx->info.sec_flags &= ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
397bc42afa9SBrett Creeley 					 ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
398bc42afa9SBrett Creeley 
399bc42afa9SBrett Creeley 	err = ice_update_vsi(&vsi->back->hw, vsi->idx, ctx, NULL);
400bc42afa9SBrett Creeley 	if (err)
401bc42afa9SBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "Failed to configure Tx VLAN anti-spoof %s for VSI %d, error %d\n",
402bc42afa9SBrett Creeley 			enable ? "ON" : "OFF", vsi->vsi_num, err);
403bc42afa9SBrett Creeley 	else
404bc42afa9SBrett Creeley 		vsi->info.sec_flags = ctx->info.sec_flags;
405bc42afa9SBrett Creeley 
406bc42afa9SBrett Creeley 	kfree(ctx);
407bc42afa9SBrett Creeley 
408bc42afa9SBrett Creeley 	return err;
409bc42afa9SBrett Creeley }
410bc42afa9SBrett Creeley 
ice_vsi_ena_tx_vlan_filtering(struct ice_vsi * vsi)411bc42afa9SBrett Creeley int ice_vsi_ena_tx_vlan_filtering(struct ice_vsi *vsi)
412bc42afa9SBrett Creeley {
413bc42afa9SBrett Creeley 	return ice_cfg_vlan_antispoof(vsi, true);
414bc42afa9SBrett Creeley }
415bc42afa9SBrett Creeley 
ice_vsi_dis_tx_vlan_filtering(struct ice_vsi * vsi)416bc42afa9SBrett Creeley int ice_vsi_dis_tx_vlan_filtering(struct ice_vsi *vsi)
417bc42afa9SBrett Creeley {
418bc42afa9SBrett Creeley 	return ice_cfg_vlan_antispoof(vsi, false);
419bc42afa9SBrett Creeley }
420c31af68aSBrett Creeley 
421c31af68aSBrett Creeley /**
422c31af68aSBrett Creeley  * tpid_to_vsi_outer_vlan_type - convert from TPID to VSI context based tag_type
423c31af68aSBrett Creeley  * @tpid: tpid used to translate into VSI context based tag_type
424c31af68aSBrett Creeley  * @tag_type: output variable to hold the VSI context based tag type
425c31af68aSBrett Creeley  */
tpid_to_vsi_outer_vlan_type(u16 tpid,u8 * tag_type)426c31af68aSBrett Creeley static int tpid_to_vsi_outer_vlan_type(u16 tpid, u8 *tag_type)
427c31af68aSBrett Creeley {
428c31af68aSBrett Creeley 	switch (tpid) {
429c31af68aSBrett Creeley 	case ETH_P_8021Q:
430c31af68aSBrett Creeley 		*tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_8100;
431c31af68aSBrett Creeley 		break;
432c31af68aSBrett Creeley 	case ETH_P_8021AD:
433c31af68aSBrett Creeley 		*tag_type = ICE_AQ_VSI_OUTER_TAG_STAG;
434c31af68aSBrett Creeley 		break;
435c31af68aSBrett Creeley 	case ETH_P_QINQ1:
436c31af68aSBrett Creeley 		*tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_9100;
437c31af68aSBrett Creeley 		break;
438c31af68aSBrett Creeley 	default:
439c31af68aSBrett Creeley 		*tag_type = 0;
440c31af68aSBrett Creeley 		return -EINVAL;
441c31af68aSBrett Creeley 	}
442c31af68aSBrett Creeley 
443c31af68aSBrett Creeley 	return 0;
444c31af68aSBrett Creeley }
445c31af68aSBrett Creeley 
446c31af68aSBrett Creeley /**
447c31af68aSBrett Creeley  * ice_vsi_ena_outer_stripping - enable outer VLAN stripping
448c31af68aSBrett Creeley  * @vsi: VSI to configure
449c31af68aSBrett Creeley  * @tpid: TPID to enable outer VLAN stripping for
450c31af68aSBrett Creeley  *
451c31af68aSBrett Creeley  * Enable outer VLAN stripping via VSI context. This function should only be
452c31af68aSBrett Creeley  * used if DVM is supported. Also, this function should never be called directly
453c31af68aSBrett Creeley  * as it should be part of ice_vsi_vlan_ops if it's needed.
454c31af68aSBrett Creeley  *
455c31af68aSBrett Creeley  * Since the VSI context only supports a single TPID for insertion and
456c31af68aSBrett Creeley  * stripping, setting the TPID for stripping will affect the TPID for insertion.
457c31af68aSBrett Creeley  * Callers need to be aware of this limitation.
458c31af68aSBrett Creeley  *
459c31af68aSBrett Creeley  * Only modify outer VLAN stripping settings and the VLAN TPID. Outer VLAN
460c31af68aSBrett Creeley  * insertion settings are unmodified.
461c31af68aSBrett Creeley  *
462c31af68aSBrett Creeley  * This enables hardware to strip a VLAN tag with the specified TPID to be
463c31af68aSBrett Creeley  * stripped from the packet and placed in the receive descriptor.
464c31af68aSBrett Creeley  */
ice_vsi_ena_outer_stripping(struct ice_vsi * vsi,u16 tpid)465c31af68aSBrett Creeley int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid)
466c31af68aSBrett Creeley {
467c31af68aSBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
468c31af68aSBrett Creeley 	struct ice_vsi_ctx *ctxt;
469c31af68aSBrett Creeley 	u8 tag_type;
470c31af68aSBrett Creeley 	int err;
471c31af68aSBrett Creeley 
472c31af68aSBrett Creeley 	/* do not allow modifying VLAN stripping when a port VLAN is configured
473c31af68aSBrett Creeley 	 * on this VSI
474c31af68aSBrett Creeley 	 */
475c31af68aSBrett Creeley 	if (vsi->info.port_based_outer_vlan)
476c31af68aSBrett Creeley 		return 0;
477c31af68aSBrett Creeley 
478c31af68aSBrett Creeley 	if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
479c31af68aSBrett Creeley 		return -EINVAL;
480c31af68aSBrett Creeley 
481c31af68aSBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
482c31af68aSBrett Creeley 	if (!ctxt)
483c31af68aSBrett Creeley 		return -ENOMEM;
484c31af68aSBrett Creeley 
485c31af68aSBrett Creeley 	ctxt->info.valid_sections =
486c31af68aSBrett Creeley 		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
487c31af68aSBrett Creeley 	/* clear current outer VLAN strip settings */
488c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
489c31af68aSBrett Creeley 		~(ICE_AQ_VSI_OUTER_VLAN_EMODE_M | ICE_AQ_VSI_OUTER_TAG_TYPE_M);
490c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags |=
491c31af68aSBrett Creeley 		((ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW_BOTH <<
492c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
493c31af68aSBrett Creeley 		 ((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
494c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_TAG_TYPE_M));
495c31af68aSBrett Creeley 
496c31af68aSBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
497c31af68aSBrett Creeley 	if (err)
498c31af68aSBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN stripping failed, err %d aq_err %s\n",
499c31af68aSBrett Creeley 			err, ice_aq_str(hw->adminq.sq_last_status));
500c31af68aSBrett Creeley 	else
501c31af68aSBrett Creeley 		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
502c31af68aSBrett Creeley 
503c31af68aSBrett Creeley 	kfree(ctxt);
504c31af68aSBrett Creeley 	return err;
505c31af68aSBrett Creeley }
506c31af68aSBrett Creeley 
507c31af68aSBrett Creeley /**
508c31af68aSBrett Creeley  * ice_vsi_dis_outer_stripping - disable outer VLAN stripping
509c31af68aSBrett Creeley  * @vsi: VSI to configure
510c31af68aSBrett Creeley  *
511c31af68aSBrett Creeley  * Disable outer VLAN stripping via VSI context. This function should only be
512c31af68aSBrett Creeley  * used if DVM is supported. Also, this function should never be called directly
513c31af68aSBrett Creeley  * as it should be part of ice_vsi_vlan_ops if it's needed.
514c31af68aSBrett Creeley  *
515c31af68aSBrett Creeley  * Only modify the outer VLAN stripping settings. The VLAN TPID and outer VLAN
516c31af68aSBrett Creeley  * insertion settings are unmodified.
517c31af68aSBrett Creeley  *
518c31af68aSBrett Creeley  * This tells the hardware to not strip any VLAN tagged packets, thus leaving
519c31af68aSBrett Creeley  * them in the packet. This enables software offloaded VLAN stripping and
520c31af68aSBrett Creeley  * disables hardware offloaded VLAN stripping.
521c31af68aSBrett Creeley  */
ice_vsi_dis_outer_stripping(struct ice_vsi * vsi)522c31af68aSBrett Creeley int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi)
523c31af68aSBrett Creeley {
524c31af68aSBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
525c31af68aSBrett Creeley 	struct ice_vsi_ctx *ctxt;
526c31af68aSBrett Creeley 	int err;
527c31af68aSBrett Creeley 
528c31af68aSBrett Creeley 	if (vsi->info.port_based_outer_vlan)
529c31af68aSBrett Creeley 		return 0;
530c31af68aSBrett Creeley 
531c31af68aSBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
532c31af68aSBrett Creeley 	if (!ctxt)
533c31af68aSBrett Creeley 		return -ENOMEM;
534c31af68aSBrett Creeley 
535c31af68aSBrett Creeley 	ctxt->info.valid_sections =
536c31af68aSBrett Creeley 		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
537c31af68aSBrett Creeley 	/* clear current outer VLAN strip settings */
538c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
539c31af68aSBrett Creeley 		~ICE_AQ_VSI_OUTER_VLAN_EMODE_M;
540c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags |= ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING <<
541c31af68aSBrett Creeley 		ICE_AQ_VSI_OUTER_VLAN_EMODE_S;
542c31af68aSBrett Creeley 
543c31af68aSBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
544c31af68aSBrett Creeley 	if (err)
545c31af68aSBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN stripping failed, err %d aq_err %s\n",
546c31af68aSBrett Creeley 			err, ice_aq_str(hw->adminq.sq_last_status));
547c31af68aSBrett Creeley 	else
548c31af68aSBrett Creeley 		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
549c31af68aSBrett Creeley 
550c31af68aSBrett Creeley 	kfree(ctxt);
551c31af68aSBrett Creeley 	return err;
552c31af68aSBrett Creeley }
553c31af68aSBrett Creeley 
554c31af68aSBrett Creeley /**
555c31af68aSBrett Creeley  * ice_vsi_ena_outer_insertion - enable outer VLAN insertion
556c31af68aSBrett Creeley  * @vsi: VSI to configure
557c31af68aSBrett Creeley  * @tpid: TPID to enable outer VLAN insertion for
558c31af68aSBrett Creeley  *
559c31af68aSBrett Creeley  * Enable outer VLAN insertion via VSI context. This function should only be
560c31af68aSBrett Creeley  * used if DVM is supported. Also, this function should never be called directly
561c31af68aSBrett Creeley  * as it should be part of ice_vsi_vlan_ops if it's needed.
562c31af68aSBrett Creeley  *
563c31af68aSBrett Creeley  * Since the VSI context only supports a single TPID for insertion and
564c31af68aSBrett Creeley  * stripping, setting the TPID for insertion will affect the TPID for stripping.
565c31af68aSBrett Creeley  * Callers need to be aware of this limitation.
566c31af68aSBrett Creeley  *
567c31af68aSBrett Creeley  * Only modify outer VLAN insertion settings and the VLAN TPID. Outer VLAN
568c31af68aSBrett Creeley  * stripping settings are unmodified.
569c31af68aSBrett Creeley  *
570c31af68aSBrett Creeley  * This allows a VLAN tag with the specified TPID to be inserted in the transmit
571c31af68aSBrett Creeley  * descriptor.
572c31af68aSBrett Creeley  */
ice_vsi_ena_outer_insertion(struct ice_vsi * vsi,u16 tpid)573c31af68aSBrett Creeley int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid)
574c31af68aSBrett Creeley {
575c31af68aSBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
576c31af68aSBrett Creeley 	struct ice_vsi_ctx *ctxt;
577c31af68aSBrett Creeley 	u8 tag_type;
578c31af68aSBrett Creeley 	int err;
579c31af68aSBrett Creeley 
580c31af68aSBrett Creeley 	if (vsi->info.port_based_outer_vlan)
581c31af68aSBrett Creeley 		return 0;
582c31af68aSBrett Creeley 
583c31af68aSBrett Creeley 	if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
584c31af68aSBrett Creeley 		return -EINVAL;
585c31af68aSBrett Creeley 
586c31af68aSBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
587c31af68aSBrett Creeley 	if (!ctxt)
588c31af68aSBrett Creeley 		return -ENOMEM;
589c31af68aSBrett Creeley 
590c31af68aSBrett Creeley 	ctxt->info.valid_sections =
591c31af68aSBrett Creeley 		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
592c31af68aSBrett Creeley 	/* clear current outer VLAN insertion settings */
593c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
594c31af68aSBrett Creeley 		~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT |
595c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
596c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M |
597c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_TAG_TYPE_M);
598c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags |=
599c31af68aSBrett Creeley 		((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
600c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
601c31af68aSBrett Creeley 		 ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M) |
602c31af68aSBrett Creeley 		((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
603c31af68aSBrett Creeley 		 ICE_AQ_VSI_OUTER_TAG_TYPE_M);
604c31af68aSBrett Creeley 
605c31af68aSBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
606c31af68aSBrett Creeley 	if (err)
607c31af68aSBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN insertion failed, err %d aq_err %s\n",
608c31af68aSBrett Creeley 			err, ice_aq_str(hw->adminq.sq_last_status));
609c31af68aSBrett Creeley 	else
610c31af68aSBrett Creeley 		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
611c31af68aSBrett Creeley 
612c31af68aSBrett Creeley 	kfree(ctxt);
613c31af68aSBrett Creeley 	return err;
614c31af68aSBrett Creeley }
615c31af68aSBrett Creeley 
616c31af68aSBrett Creeley /**
617c31af68aSBrett Creeley  * ice_vsi_dis_outer_insertion - disable outer VLAN insertion
618c31af68aSBrett Creeley  * @vsi: VSI to configure
619c31af68aSBrett Creeley  *
620c31af68aSBrett Creeley  * Disable outer VLAN insertion via VSI context. This function should only be
621c31af68aSBrett Creeley  * used if DVM is supported. Also, this function should never be called directly
622c31af68aSBrett Creeley  * as it should be part of ice_vsi_vlan_ops if it's needed.
623c31af68aSBrett Creeley  *
624c31af68aSBrett Creeley  * Only modify the outer VLAN insertion settings. The VLAN TPID and outer VLAN
625c31af68aSBrett Creeley  * settings are unmodified.
626c31af68aSBrett Creeley  *
627c31af68aSBrett Creeley  * This tells the hardware to not allow any VLAN tagged packets in the transmit
628c31af68aSBrett Creeley  * descriptor. This enables software offloaded VLAN insertion and disables
629c31af68aSBrett Creeley  * hardware offloaded VLAN insertion.
630c31af68aSBrett Creeley  */
ice_vsi_dis_outer_insertion(struct ice_vsi * vsi)631c31af68aSBrett Creeley int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi)
632c31af68aSBrett Creeley {
633c31af68aSBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
634c31af68aSBrett Creeley 	struct ice_vsi_ctx *ctxt;
635c31af68aSBrett Creeley 	int err;
636c31af68aSBrett Creeley 
637c31af68aSBrett Creeley 	if (vsi->info.port_based_outer_vlan)
638c31af68aSBrett Creeley 		return 0;
639c31af68aSBrett Creeley 
640c31af68aSBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
641c31af68aSBrett Creeley 	if (!ctxt)
642c31af68aSBrett Creeley 		return -ENOMEM;
643c31af68aSBrett Creeley 
644c31af68aSBrett Creeley 	ctxt->info.valid_sections =
645c31af68aSBrett Creeley 		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID);
646c31af68aSBrett Creeley 	/* clear current outer VLAN insertion settings */
647c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags &
648c31af68aSBrett Creeley 		~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT |
649c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
650c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags |=
651c31af68aSBrett Creeley 		ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
652c31af68aSBrett Creeley 		((ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL <<
653c31af68aSBrett Creeley 		  ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) &
654c31af68aSBrett Creeley 		 ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M);
655c31af68aSBrett Creeley 
656c31af68aSBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
657c31af68aSBrett Creeley 	if (err)
658c31af68aSBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN insertion failed, err %d aq_err %s\n",
659c31af68aSBrett Creeley 			err, ice_aq_str(hw->adminq.sq_last_status));
660c31af68aSBrett Creeley 	else
661c31af68aSBrett Creeley 		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
662c31af68aSBrett Creeley 
663c31af68aSBrett Creeley 	kfree(ctxt);
664c31af68aSBrett Creeley 	return err;
665c31af68aSBrett Creeley }
666c31af68aSBrett Creeley 
667c31af68aSBrett Creeley /**
668c31af68aSBrett Creeley  * __ice_vsi_set_outer_port_vlan - set the outer port VLAN and related settings
669c31af68aSBrett Creeley  * @vsi: VSI to configure
670c31af68aSBrett Creeley  * @vlan_info: packed u16 that contains the VLAN prio and ID
671c31af68aSBrett Creeley  * @tpid: TPID of the port VLAN
672c31af68aSBrett Creeley  *
673c31af68aSBrett Creeley  * Set the port VLAN prio, ID, and TPID.
674c31af68aSBrett Creeley  *
675c31af68aSBrett Creeley  * Enable VLAN pruning so the VSI doesn't receive any traffic that doesn't match
676c31af68aSBrett Creeley  * a VLAN prune rule. The caller should take care to add a VLAN prune rule that
677c31af68aSBrett Creeley  * matches the port VLAN ID and TPID.
678c31af68aSBrett Creeley  *
679c31af68aSBrett Creeley  * Tell hardware to strip outer VLAN tagged packets on receive and don't put
680c31af68aSBrett Creeley  * them in the receive descriptor. VSI(s) in port VLANs should not be aware of
681c31af68aSBrett Creeley  * the port VLAN ID or TPID they are assigned to.
682c31af68aSBrett Creeley  *
683c31af68aSBrett Creeley  * Tell hardware to prevent outer VLAN tag insertion on transmit and only allow
684c31af68aSBrett Creeley  * untagged outer packets from the transmit descriptor.
685c31af68aSBrett Creeley  *
686c31af68aSBrett Creeley  * Also, tell the hardware to insert the port VLAN on transmit.
687c31af68aSBrett Creeley  */
688c31af68aSBrett Creeley static int
__ice_vsi_set_outer_port_vlan(struct ice_vsi * vsi,u16 vlan_info,u16 tpid)689c31af68aSBrett Creeley __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid)
690c31af68aSBrett Creeley {
691c31af68aSBrett Creeley 	struct ice_hw *hw = &vsi->back->hw;
692c31af68aSBrett Creeley 	struct ice_vsi_ctx *ctxt;
693c31af68aSBrett Creeley 	u8 tag_type;
694c31af68aSBrett Creeley 	int err;
695c31af68aSBrett Creeley 
696c31af68aSBrett Creeley 	if (tpid_to_vsi_outer_vlan_type(tpid, &tag_type))
697c31af68aSBrett Creeley 		return -EINVAL;
698c31af68aSBrett Creeley 
699c31af68aSBrett Creeley 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
700c31af68aSBrett Creeley 	if (!ctxt)
701c31af68aSBrett Creeley 		return -ENOMEM;
702c31af68aSBrett Creeley 
7032946204bSMichal Swiatkowski 	ice_save_vlan_info(&vsi->info, &vsi->vlan_info);
704c31af68aSBrett Creeley 	ctxt->info = vsi->info;
705c31af68aSBrett Creeley 
706c31af68aSBrett Creeley 	ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
707c31af68aSBrett Creeley 
708c31af68aSBrett Creeley 	ctxt->info.port_based_outer_vlan = cpu_to_le16(vlan_info);
709c31af68aSBrett Creeley 	ctxt->info.outer_vlan_flags =
710c31af68aSBrett Creeley 		(ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW <<
711c31af68aSBrett Creeley 		 ICE_AQ_VSI_OUTER_VLAN_EMODE_S) |
712c31af68aSBrett Creeley 		((tag_type << ICE_AQ_VSI_OUTER_TAG_TYPE_S) &
713c31af68aSBrett Creeley 		 ICE_AQ_VSI_OUTER_TAG_TYPE_M) |
714c31af68aSBrett Creeley 		ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC |
715c31af68aSBrett Creeley 		(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED <<
716c31af68aSBrett Creeley 		 ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) |
717c31af68aSBrett Creeley 		ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT;
718c31af68aSBrett Creeley 
719c31af68aSBrett Creeley 	ctxt->info.valid_sections =
720c31af68aSBrett Creeley 		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID |
721c31af68aSBrett Creeley 			    ICE_AQ_VSI_PROP_SW_VALID);
722c31af68aSBrett Creeley 
723c31af68aSBrett Creeley 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
724c31af68aSBrett Creeley 	if (err) {
725c31af68aSBrett Creeley 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for setting outer port based VLAN failed, err %d aq_err %s\n",
726c31af68aSBrett Creeley 			err, ice_aq_str(hw->adminq.sq_last_status));
727c31af68aSBrett Creeley 	} else {
728c31af68aSBrett Creeley 		vsi->info.port_based_outer_vlan = ctxt->info.port_based_outer_vlan;
729c31af68aSBrett Creeley 		vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags;
730c31af68aSBrett Creeley 		vsi->info.sw_flags2 = ctxt->info.sw_flags2;
731c31af68aSBrett Creeley 	}
732c31af68aSBrett Creeley 
733c31af68aSBrett Creeley 	kfree(ctxt);
734c31af68aSBrett Creeley 	return err;
735c31af68aSBrett Creeley }
736c31af68aSBrett Creeley 
737c31af68aSBrett Creeley /**
738c31af68aSBrett Creeley  * ice_vsi_set_outer_port_vlan - public version of __ice_vsi_set_outer_port_vlan
739c31af68aSBrett Creeley  * @vsi: VSI to configure
740c31af68aSBrett Creeley  * @vlan: ice_vlan structure used to set the port VLAN
741c31af68aSBrett Creeley  *
742c31af68aSBrett Creeley  * Set the outer port VLAN via VSI context. This function should only be
743c31af68aSBrett Creeley  * used if DVM is supported. Also, this function should never be called directly
744c31af68aSBrett Creeley  * as it should be part of ice_vsi_vlan_ops if it's needed.
745c31af68aSBrett Creeley  *
746c31af68aSBrett Creeley  * Use the ice_vlan structure passed in to set this VSI in a port VLAN.
747c31af68aSBrett Creeley  */
ice_vsi_set_outer_port_vlan(struct ice_vsi * vsi,struct ice_vlan * vlan)748c31af68aSBrett Creeley int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan)
749c31af68aSBrett Creeley {
750c31af68aSBrett Creeley 	u16 port_vlan_info;
751c31af68aSBrett Creeley 
752c31af68aSBrett Creeley 	if (vlan->prio > (VLAN_PRIO_MASK >> VLAN_PRIO_SHIFT))
753c31af68aSBrett Creeley 		return -EINVAL;
754c31af68aSBrett Creeley 
755c31af68aSBrett Creeley 	port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT);
756c31af68aSBrett Creeley 
757c31af68aSBrett Creeley 	return __ice_vsi_set_outer_port_vlan(vsi, port_vlan_info, vlan->tpid);
758c31af68aSBrett Creeley }
7592946204bSMichal Swiatkowski 
7602946204bSMichal Swiatkowski /**
7612946204bSMichal Swiatkowski  * ice_vsi_clear_outer_port_vlan - clear outer port vlan
7622946204bSMichal Swiatkowski  * @vsi: VSI to configure
7632946204bSMichal Swiatkowski  *
7642946204bSMichal Swiatkowski  * The function is restoring previously set vlan config (saved in
7652946204bSMichal Swiatkowski  * vsi->vlan_info). Setting happens in port vlan configuration.
7662946204bSMichal Swiatkowski  */
ice_vsi_clear_outer_port_vlan(struct ice_vsi * vsi)7672946204bSMichal Swiatkowski int ice_vsi_clear_outer_port_vlan(struct ice_vsi *vsi)
7682946204bSMichal Swiatkowski {
7692946204bSMichal Swiatkowski 	struct ice_hw *hw = &vsi->back->hw;
7702946204bSMichal Swiatkowski 	struct ice_vsi_ctx *ctxt;
7712946204bSMichal Swiatkowski 	int err;
7722946204bSMichal Swiatkowski 
7732946204bSMichal Swiatkowski 	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
7742946204bSMichal Swiatkowski 	if (!ctxt)
7752946204bSMichal Swiatkowski 		return -ENOMEM;
7762946204bSMichal Swiatkowski 
7772946204bSMichal Swiatkowski 	ice_restore_vlan_info(&vsi->info, &vsi->vlan_info);
7782946204bSMichal Swiatkowski 	vsi->info.port_based_outer_vlan = 0;
7792946204bSMichal Swiatkowski 	ctxt->info = vsi->info;
7802946204bSMichal Swiatkowski 
7812946204bSMichal Swiatkowski 	ctxt->info.valid_sections =
7822946204bSMichal Swiatkowski 		cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID |
7832946204bSMichal Swiatkowski 			    ICE_AQ_VSI_PROP_SW_VALID);
7842946204bSMichal Swiatkowski 
7852946204bSMichal Swiatkowski 	err = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
7862946204bSMichal Swiatkowski 	if (err)
7872946204bSMichal Swiatkowski 		dev_err(ice_pf_to_dev(vsi->back), "update VSI for clearing outer port based VLAN failed, err %d aq_err %s\n",
7882946204bSMichal Swiatkowski 			err, ice_aq_str(hw->adminq.sq_last_status));
7892946204bSMichal Swiatkowski 
7902946204bSMichal Swiatkowski 	kfree(ctxt);
7912946204bSMichal Swiatkowski 	return err;
7922946204bSMichal Swiatkowski }
793