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