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 | |
9 | static 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 | */ |
24 | static 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, tpid: 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 | */ |
40 | int 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) |
49 | vsi->num_vlan++; |
50 | else if (err == -EEXIST) |
51 | err = 0; |
52 | else |
53 | dev_err(ice_pf_to_dev(vsi->back), "Failure Adding VLAN %d on VSI %i, status %d\n", |
54 | vlan->vid, vsi->vsi_num, err); |
55 | |
56 | return err; |
57 | } |
58 | |
59 | /** |
60 | * ice_vsi_del_vlan - default del VLAN implementation for all VSI types |
61 | * @vsi: VSI being configured |
62 | * @vlan: VLAN filter to delete |
63 | */ |
64 | int ice_vsi_del_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan) |
65 | { |
66 | struct ice_pf *pf = vsi->back; |
67 | struct device *dev; |
68 | int err; |
69 | |
70 | if (!validate_vlan(vsi, vlan)) |
71 | return -EINVAL; |
72 | |
73 | dev = ice_pf_to_dev(pf); |
74 | |
75 | err = ice_fltr_remove_vlan(vsi, vlan); |
76 | if (!err) |
77 | vsi->num_vlan--; |
78 | else if (err == -ENOENT || err == -EBUSY) |
79 | err = 0; |
80 | else |
81 | dev_err(dev, "Error removing VLAN %d on VSI %i error: %d\n", |
82 | vlan->vid, vsi->vsi_num, err); |
83 | |
84 | return err; |
85 | } |
86 | |
87 | /** |
88 | * ice_vsi_manage_vlan_insertion - Manage VLAN insertion for the VSI for Tx |
89 | * @vsi: the VSI being changed |
90 | */ |
91 | static int ice_vsi_manage_vlan_insertion(struct ice_vsi *vsi) |
92 | { |
93 | struct ice_hw *hw = &vsi->back->hw; |
94 | struct ice_vsi_ctx *ctxt; |
95 | int err; |
96 | |
97 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
98 | if (!ctxt) |
99 | return -ENOMEM; |
100 | |
101 | /* Here we are configuring the VSI to let the driver add VLAN tags by |
102 | * setting inner_vlan_flags to ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL. The actual VLAN tag |
103 | * insertion happens in the Tx hot path, in ice_tx_map. |
104 | */ |
105 | ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL; |
106 | |
107 | /* Preserve existing VLAN strip setting */ |
108 | ctxt->info.inner_vlan_flags |= (vsi->info.inner_vlan_flags & |
109 | ICE_AQ_VSI_INNER_VLAN_EMODE_M); |
110 | |
111 | ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); |
112 | |
113 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
114 | if (err) { |
115 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN insert failed, err %d aq_err %s\n", |
116 | err, ice_aq_str(hw->adminq.sq_last_status)); |
117 | goto out; |
118 | } |
119 | |
120 | vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags; |
121 | out: |
122 | kfree(objp: ctxt); |
123 | return err; |
124 | } |
125 | |
126 | /** |
127 | * ice_vsi_manage_vlan_stripping - Manage VLAN stripping for the VSI for Rx |
128 | * @vsi: the VSI being changed |
129 | * @ena: boolean value indicating if this is a enable or disable request |
130 | */ |
131 | static int ice_vsi_manage_vlan_stripping(struct ice_vsi *vsi, bool ena) |
132 | { |
133 | struct ice_hw *hw = &vsi->back->hw; |
134 | struct ice_vsi_ctx *ctxt; |
135 | u8 *ivf; |
136 | int err; |
137 | |
138 | /* do not allow modifying VLAN stripping when a port VLAN is configured |
139 | * on this VSI |
140 | */ |
141 | if (vsi->info.port_based_inner_vlan) |
142 | return 0; |
143 | |
144 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
145 | if (!ctxt) |
146 | return -ENOMEM; |
147 | |
148 | ivf = &ctxt->info.inner_vlan_flags; |
149 | |
150 | /* Here we are configuring what the VSI should do with the VLAN tag in |
151 | * the Rx packet. We can either leave the tag in the packet or put it in |
152 | * the Rx descriptor. |
153 | */ |
154 | if (ena) { |
155 | /* Strip VLAN tag from Rx packet and put it in the desc */ |
156 | *ivf = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M, |
157 | ICE_AQ_VSI_INNER_VLAN_EMODE_STR_BOTH); |
158 | } else { |
159 | /* Disable stripping. Leave tag in packet */ |
160 | *ivf = FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M, |
161 | ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING); |
162 | } |
163 | |
164 | /* Allow all packets untagged/tagged */ |
165 | *ivf |= ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL; |
166 | |
167 | ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID); |
168 | |
169 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
170 | if (err) { |
171 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for VLAN strip failed, ena = %d err %d aq_err %s\n", |
172 | ena, err, ice_aq_str(hw->adminq.sq_last_status)); |
173 | goto out; |
174 | } |
175 | |
176 | vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags; |
177 | out: |
178 | kfree(objp: ctxt); |
179 | return err; |
180 | } |
181 | |
182 | int ice_vsi_ena_inner_stripping(struct ice_vsi *vsi, const u16 tpid) |
183 | { |
184 | if (tpid != ETH_P_8021Q) { |
185 | print_invalid_tpid(vsi, tpid); |
186 | return -EINVAL; |
187 | } |
188 | |
189 | return ice_vsi_manage_vlan_stripping(vsi, ena: true); |
190 | } |
191 | |
192 | int ice_vsi_dis_inner_stripping(struct ice_vsi *vsi) |
193 | { |
194 | return ice_vsi_manage_vlan_stripping(vsi, ena: false); |
195 | } |
196 | |
197 | int ice_vsi_ena_inner_insertion(struct ice_vsi *vsi, const u16 tpid) |
198 | { |
199 | if (tpid != ETH_P_8021Q) { |
200 | print_invalid_tpid(vsi, tpid); |
201 | return -EINVAL; |
202 | } |
203 | |
204 | return ice_vsi_manage_vlan_insertion(vsi); |
205 | } |
206 | |
207 | int ice_vsi_dis_inner_insertion(struct ice_vsi *vsi) |
208 | { |
209 | return ice_vsi_manage_vlan_insertion(vsi); |
210 | } |
211 | |
212 | static void |
213 | ice_save_vlan_info(struct ice_aqc_vsi_props *info, |
214 | struct ice_vsi_vlan_info *vlan) |
215 | { |
216 | vlan->sw_flags2 = info->sw_flags2; |
217 | vlan->inner_vlan_flags = info->inner_vlan_flags; |
218 | vlan->outer_vlan_flags = info->outer_vlan_flags; |
219 | } |
220 | |
221 | static void |
222 | ice_restore_vlan_info(struct ice_aqc_vsi_props *info, |
223 | struct ice_vsi_vlan_info *vlan) |
224 | { |
225 | info->sw_flags2 = vlan->sw_flags2; |
226 | info->inner_vlan_flags = vlan->inner_vlan_flags; |
227 | info->outer_vlan_flags = vlan->outer_vlan_flags; |
228 | } |
229 | |
230 | /** |
231 | * __ice_vsi_set_inner_port_vlan - set port VLAN VSI context settings to enable a port VLAN |
232 | * @vsi: the VSI to update |
233 | * @pvid_info: VLAN ID and QoS used to set the PVID VSI context field |
234 | */ |
235 | static int __ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, u16 pvid_info) |
236 | { |
237 | struct ice_hw *hw = &vsi->back->hw; |
238 | struct ice_aqc_vsi_props *info; |
239 | struct ice_vsi_ctx *ctxt; |
240 | int ret; |
241 | |
242 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
243 | if (!ctxt) |
244 | return -ENOMEM; |
245 | |
246 | ice_save_vlan_info(info: &vsi->info, vlan: &vsi->vlan_info); |
247 | ctxt->info = vsi->info; |
248 | info = &ctxt->info; |
249 | info->inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ACCEPTUNTAGGED | |
250 | ICE_AQ_VSI_INNER_VLAN_INSERT_PVID | |
251 | ICE_AQ_VSI_INNER_VLAN_EMODE_STR; |
252 | info->sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; |
253 | |
254 | info->port_based_inner_vlan = cpu_to_le16(pvid_info); |
255 | info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID | |
256 | ICE_AQ_VSI_PROP_SW_VALID); |
257 | |
258 | ret = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
259 | if (ret) { |
260 | dev_info(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n", |
261 | ret, ice_aq_str(hw->adminq.sq_last_status)); |
262 | goto out; |
263 | } |
264 | |
265 | vsi->info.inner_vlan_flags = info->inner_vlan_flags; |
266 | vsi->info.sw_flags2 = info->sw_flags2; |
267 | vsi->info.port_based_inner_vlan = info->port_based_inner_vlan; |
268 | out: |
269 | kfree(objp: ctxt); |
270 | return ret; |
271 | } |
272 | |
273 | int ice_vsi_set_inner_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan) |
274 | { |
275 | u16 port_vlan_info; |
276 | |
277 | if (vlan->tpid != ETH_P_8021Q) |
278 | return -EINVAL; |
279 | |
280 | if (vlan->prio > 7) |
281 | return -EINVAL; |
282 | |
283 | port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT); |
284 | |
285 | return __ice_vsi_set_inner_port_vlan(vsi, pvid_info: port_vlan_info); |
286 | } |
287 | |
288 | int ice_vsi_clear_inner_port_vlan(struct ice_vsi *vsi) |
289 | { |
290 | struct ice_hw *hw = &vsi->back->hw; |
291 | struct ice_aqc_vsi_props *info; |
292 | struct ice_vsi_ctx *ctxt; |
293 | int ret; |
294 | |
295 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
296 | if (!ctxt) |
297 | return -ENOMEM; |
298 | |
299 | ice_restore_vlan_info(info: &vsi->info, vlan: &vsi->vlan_info); |
300 | vsi->info.port_based_inner_vlan = 0; |
301 | ctxt->info = vsi->info; |
302 | info = &ctxt->info; |
303 | info->valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID | |
304 | ICE_AQ_VSI_PROP_SW_VALID); |
305 | |
306 | ret = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
307 | if (ret) |
308 | dev_err(ice_hw_to_dev(hw), "update VSI for port VLAN failed, err %d aq_err %s\n", |
309 | ret, ice_aq_str(hw->adminq.sq_last_status)); |
310 | |
311 | kfree(objp: ctxt); |
312 | return ret; |
313 | } |
314 | |
315 | /** |
316 | * ice_cfg_vlan_pruning - enable or disable VLAN pruning on the VSI |
317 | * @vsi: VSI to enable or disable VLAN pruning on |
318 | * @ena: set to true to enable VLAN pruning and false to disable it |
319 | * |
320 | * returns 0 if VSI is updated, negative otherwise |
321 | */ |
322 | static int ice_cfg_vlan_pruning(struct ice_vsi *vsi, bool ena) |
323 | { |
324 | struct ice_vsi_ctx *ctxt; |
325 | struct ice_pf *pf; |
326 | int status; |
327 | |
328 | if (!vsi) |
329 | return -EINVAL; |
330 | |
331 | /* Don't enable VLAN pruning if the netdev is currently in promiscuous |
332 | * mode. VLAN pruning will be enabled when the interface exits |
333 | * promiscuous mode if any VLAN filters are active. |
334 | */ |
335 | if (vsi->netdev && vsi->netdev->flags & IFF_PROMISC && ena) |
336 | return 0; |
337 | |
338 | pf = vsi->back; |
339 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
340 | if (!ctxt) |
341 | return -ENOMEM; |
342 | |
343 | ctxt->info = vsi->info; |
344 | |
345 | if (ena) |
346 | ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; |
347 | else |
348 | ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; |
349 | |
350 | ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); |
351 | |
352 | status = ice_update_vsi(hw: &pf->hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
353 | if (status) { |
354 | netdev_err(dev: vsi->netdev, format: "%sabling VLAN pruning on VSI handle: %d, VSI HW ID: %d failed, err = %d, aq_err = %s\n", |
355 | ena ? "En": "Dis", vsi->idx, vsi->vsi_num, status, |
356 | ice_aq_str(aq_err: pf->hw.adminq.sq_last_status)); |
357 | goto err_out; |
358 | } |
359 | |
360 | vsi->info.sw_flags2 = ctxt->info.sw_flags2; |
361 | |
362 | kfree(objp: ctxt); |
363 | return 0; |
364 | |
365 | err_out: |
366 | kfree(objp: ctxt); |
367 | return status; |
368 | } |
369 | |
370 | int ice_vsi_ena_rx_vlan_filtering(struct ice_vsi *vsi) |
371 | { |
372 | return ice_cfg_vlan_pruning(vsi, ena: true); |
373 | } |
374 | |
375 | int ice_vsi_dis_rx_vlan_filtering(struct ice_vsi *vsi) |
376 | { |
377 | return ice_cfg_vlan_pruning(vsi, ena: false); |
378 | } |
379 | |
380 | static int ice_cfg_vlan_antispoof(struct ice_vsi *vsi, bool enable) |
381 | { |
382 | struct ice_vsi_ctx *ctx; |
383 | int err; |
384 | |
385 | ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); |
386 | if (!ctx) |
387 | return -ENOMEM; |
388 | |
389 | ctx->info.sec_flags = vsi->info.sec_flags; |
390 | ctx->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SECURITY_VALID); |
391 | |
392 | if (enable) |
393 | ctx->info.sec_flags |= ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << |
394 | ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S; |
395 | else |
396 | ctx->info.sec_flags &= ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << |
397 | ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); |
398 | |
399 | err = ice_update_vsi(hw: &vsi->back->hw, vsi_handle: vsi->idx, vsi_ctx: ctx, NULL); |
400 | if (err) |
401 | dev_err(ice_pf_to_dev(vsi->back), "Failed to configure Tx VLAN anti-spoof %s for VSI %d, error %d\n", |
402 | enable ? "ON": "OFF", vsi->vsi_num, err); |
403 | else |
404 | vsi->info.sec_flags = ctx->info.sec_flags; |
405 | |
406 | kfree(objp: ctx); |
407 | |
408 | return err; |
409 | } |
410 | |
411 | int ice_vsi_ena_tx_vlan_filtering(struct ice_vsi *vsi) |
412 | { |
413 | return ice_cfg_vlan_antispoof(vsi, enable: true); |
414 | } |
415 | |
416 | int ice_vsi_dis_tx_vlan_filtering(struct ice_vsi *vsi) |
417 | { |
418 | return ice_cfg_vlan_antispoof(vsi, enable: false); |
419 | } |
420 | |
421 | /** |
422 | * tpid_to_vsi_outer_vlan_type - convert from TPID to VSI context based tag_type |
423 | * @tpid: tpid used to translate into VSI context based tag_type |
424 | * @tag_type: output variable to hold the VSI context based tag type |
425 | */ |
426 | static int tpid_to_vsi_outer_vlan_type(u16 tpid, u8 *tag_type) |
427 | { |
428 | switch (tpid) { |
429 | case ETH_P_8021Q: |
430 | *tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_8100; |
431 | break; |
432 | case ETH_P_8021AD: |
433 | *tag_type = ICE_AQ_VSI_OUTER_TAG_STAG; |
434 | break; |
435 | case ETH_P_QINQ1: |
436 | *tag_type = ICE_AQ_VSI_OUTER_TAG_VLAN_9100; |
437 | break; |
438 | default: |
439 | *tag_type = 0; |
440 | return -EINVAL; |
441 | } |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | /** |
447 | * ice_vsi_ena_outer_stripping - enable outer VLAN stripping |
448 | * @vsi: VSI to configure |
449 | * @tpid: TPID to enable outer VLAN stripping for |
450 | * |
451 | * Enable outer VLAN stripping via VSI context. This function should only be |
452 | * used if DVM is supported. Also, this function should never be called directly |
453 | * as it should be part of ice_vsi_vlan_ops if it's needed. |
454 | * |
455 | * Since the VSI context only supports a single TPID for insertion and |
456 | * stripping, setting the TPID for stripping will affect the TPID for insertion. |
457 | * Callers need to be aware of this limitation. |
458 | * |
459 | * Only modify outer VLAN stripping settings and the VLAN TPID. Outer VLAN |
460 | * insertion settings are unmodified. |
461 | * |
462 | * This enables hardware to strip a VLAN tag with the specified TPID to be |
463 | * stripped from the packet and placed in the receive descriptor. |
464 | */ |
465 | int ice_vsi_ena_outer_stripping(struct ice_vsi *vsi, u16 tpid) |
466 | { |
467 | struct ice_hw *hw = &vsi->back->hw; |
468 | struct ice_vsi_ctx *ctxt; |
469 | u8 tag_type; |
470 | int err; |
471 | |
472 | /* do not allow modifying VLAN stripping when a port VLAN is configured |
473 | * on this VSI |
474 | */ |
475 | if (vsi->info.port_based_outer_vlan) |
476 | return 0; |
477 | |
478 | if (tpid_to_vsi_outer_vlan_type(tpid, tag_type: &tag_type)) |
479 | return -EINVAL; |
480 | |
481 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
482 | if (!ctxt) |
483 | return -ENOMEM; |
484 | |
485 | ctxt->info.valid_sections = |
486 | cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID); |
487 | /* clear current outer VLAN strip settings */ |
488 | ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags & |
489 | ~(ICE_AQ_VSI_OUTER_VLAN_EMODE_M | ICE_AQ_VSI_OUTER_TAG_TYPE_M); |
490 | ctxt->info.outer_vlan_flags |= |
491 | /* we want EMODE_SHOW_BOTH, but that value is zero, so the line |
492 | * above clears it well enough that we don't need to try to set |
493 | * zero here, so just do the tag type |
494 | */ |
495 | FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, tag_type); |
496 | |
497 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
498 | if (err) |
499 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN stripping failed, err %d aq_err %s\n", |
500 | err, ice_aq_str(hw->adminq.sq_last_status)); |
501 | else |
502 | vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; |
503 | |
504 | kfree(objp: ctxt); |
505 | return err; |
506 | } |
507 | |
508 | /** |
509 | * ice_vsi_dis_outer_stripping - disable outer VLAN stripping |
510 | * @vsi: VSI to configure |
511 | * |
512 | * Disable outer VLAN stripping via VSI context. This function should only be |
513 | * used if DVM is supported. Also, this function should never be called directly |
514 | * as it should be part of ice_vsi_vlan_ops if it's needed. |
515 | * |
516 | * Only modify the outer VLAN stripping settings. The VLAN TPID and outer VLAN |
517 | * insertion settings are unmodified. |
518 | * |
519 | * This tells the hardware to not strip any VLAN tagged packets, thus leaving |
520 | * them in the packet. This enables software offloaded VLAN stripping and |
521 | * disables hardware offloaded VLAN stripping. |
522 | */ |
523 | int ice_vsi_dis_outer_stripping(struct ice_vsi *vsi) |
524 | { |
525 | struct ice_hw *hw = &vsi->back->hw; |
526 | struct ice_vsi_ctx *ctxt; |
527 | int err; |
528 | |
529 | if (vsi->info.port_based_outer_vlan) |
530 | return 0; |
531 | |
532 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
533 | if (!ctxt) |
534 | return -ENOMEM; |
535 | |
536 | ctxt->info.valid_sections = |
537 | cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID); |
538 | /* clear current outer VLAN strip settings */ |
539 | ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags & |
540 | ~ICE_AQ_VSI_OUTER_VLAN_EMODE_M; |
541 | ctxt->info.outer_vlan_flags |= ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING << |
542 | ICE_AQ_VSI_OUTER_VLAN_EMODE_S; |
543 | |
544 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
545 | if (err) |
546 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN stripping failed, err %d aq_err %s\n", |
547 | err, ice_aq_str(hw->adminq.sq_last_status)); |
548 | else |
549 | vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; |
550 | |
551 | kfree(objp: ctxt); |
552 | return err; |
553 | } |
554 | |
555 | /** |
556 | * ice_vsi_ena_outer_insertion - enable outer VLAN insertion |
557 | * @vsi: VSI to configure |
558 | * @tpid: TPID to enable outer VLAN insertion for |
559 | * |
560 | * Enable outer VLAN insertion via VSI context. This function should only be |
561 | * used if DVM is supported. Also, this function should never be called directly |
562 | * as it should be part of ice_vsi_vlan_ops if it's needed. |
563 | * |
564 | * Since the VSI context only supports a single TPID for insertion and |
565 | * stripping, setting the TPID for insertion will affect the TPID for stripping. |
566 | * Callers need to be aware of this limitation. |
567 | * |
568 | * Only modify outer VLAN insertion settings and the VLAN TPID. Outer VLAN |
569 | * stripping settings are unmodified. |
570 | * |
571 | * This allows a VLAN tag with the specified TPID to be inserted in the transmit |
572 | * descriptor. |
573 | */ |
574 | int ice_vsi_ena_outer_insertion(struct ice_vsi *vsi, u16 tpid) |
575 | { |
576 | struct ice_hw *hw = &vsi->back->hw; |
577 | struct ice_vsi_ctx *ctxt; |
578 | u8 tag_type; |
579 | int err; |
580 | |
581 | if (vsi->info.port_based_outer_vlan) |
582 | return 0; |
583 | |
584 | if (tpid_to_vsi_outer_vlan_type(tpid, tag_type: &tag_type)) |
585 | return -EINVAL; |
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_BLOCK_TX_DESC | |
597 | ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M | |
598 | ICE_AQ_VSI_OUTER_TAG_TYPE_M); |
599 | ctxt->info.outer_vlan_flags |= |
600 | FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M, |
601 | ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL) | |
602 | FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, tag_type); |
603 | |
604 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
605 | if (err) |
606 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for enabling outer VLAN insertion failed, err %d aq_err %s\n", |
607 | err, ice_aq_str(hw->adminq.sq_last_status)); |
608 | else |
609 | vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; |
610 | |
611 | kfree(objp: ctxt); |
612 | return err; |
613 | } |
614 | |
615 | /** |
616 | * ice_vsi_dis_outer_insertion - disable outer VLAN insertion |
617 | * @vsi: VSI to configure |
618 | * |
619 | * Disable outer VLAN insertion via VSI context. This function should only be |
620 | * used if DVM is supported. Also, this function should never be called directly |
621 | * as it should be part of ice_vsi_vlan_ops if it's needed. |
622 | * |
623 | * Only modify the outer VLAN insertion settings. The VLAN TPID and outer VLAN |
624 | * settings are unmodified. |
625 | * |
626 | * This tells the hardware to not allow any VLAN tagged packets in the transmit |
627 | * descriptor. This enables software offloaded VLAN insertion and disables |
628 | * hardware offloaded VLAN insertion. |
629 | */ |
630 | int ice_vsi_dis_outer_insertion(struct ice_vsi *vsi) |
631 | { |
632 | struct ice_hw *hw = &vsi->back->hw; |
633 | struct ice_vsi_ctx *ctxt; |
634 | int err; |
635 | |
636 | if (vsi->info.port_based_outer_vlan) |
637 | return 0; |
638 | |
639 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
640 | if (!ctxt) |
641 | return -ENOMEM; |
642 | |
643 | ctxt->info.valid_sections = |
644 | cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID); |
645 | /* clear current outer VLAN insertion settings */ |
646 | ctxt->info.outer_vlan_flags = vsi->info.outer_vlan_flags & |
647 | ~(ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT | |
648 | ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M); |
649 | ctxt->info.outer_vlan_flags |= |
650 | ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC | |
651 | FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M, |
652 | ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL); |
653 | |
654 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
655 | if (err) |
656 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for disabling outer VLAN insertion failed, err %d aq_err %s\n", |
657 | err, ice_aq_str(hw->adminq.sq_last_status)); |
658 | else |
659 | vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; |
660 | |
661 | kfree(objp: ctxt); |
662 | return err; |
663 | } |
664 | |
665 | /** |
666 | * __ice_vsi_set_outer_port_vlan - set the outer port VLAN and related settings |
667 | * @vsi: VSI to configure |
668 | * @vlan_info: packed u16 that contains the VLAN prio and ID |
669 | * @tpid: TPID of the port VLAN |
670 | * |
671 | * Set the port VLAN prio, ID, and TPID. |
672 | * |
673 | * Enable VLAN pruning so the VSI doesn't receive any traffic that doesn't match |
674 | * a VLAN prune rule. The caller should take care to add a VLAN prune rule that |
675 | * matches the port VLAN ID and TPID. |
676 | * |
677 | * Tell hardware to strip outer VLAN tagged packets on receive and don't put |
678 | * them in the receive descriptor. VSI(s) in port VLANs should not be aware of |
679 | * the port VLAN ID or TPID they are assigned to. |
680 | * |
681 | * Tell hardware to prevent outer VLAN tag insertion on transmit and only allow |
682 | * untagged outer packets from the transmit descriptor. |
683 | * |
684 | * Also, tell the hardware to insert the port VLAN on transmit. |
685 | */ |
686 | static int |
687 | __ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, u16 vlan_info, u16 tpid) |
688 | { |
689 | struct ice_hw *hw = &vsi->back->hw; |
690 | struct ice_vsi_ctx *ctxt; |
691 | u8 tag_type; |
692 | int err; |
693 | |
694 | if (tpid_to_vsi_outer_vlan_type(tpid, tag_type: &tag_type)) |
695 | return -EINVAL; |
696 | |
697 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
698 | if (!ctxt) |
699 | return -ENOMEM; |
700 | |
701 | ice_save_vlan_info(info: &vsi->info, vlan: &vsi->vlan_info); |
702 | ctxt->info = vsi->info; |
703 | |
704 | ctxt->info.sw_flags2 |= ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; |
705 | |
706 | ctxt->info.port_based_outer_vlan = cpu_to_le16(vlan_info); |
707 | ctxt->info.outer_vlan_flags = |
708 | (ICE_AQ_VSI_OUTER_VLAN_EMODE_SHOW << |
709 | ICE_AQ_VSI_OUTER_VLAN_EMODE_S) | |
710 | FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, tag_type) | |
711 | ICE_AQ_VSI_OUTER_VLAN_BLOCK_TX_DESC | |
712 | (ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ACCEPTUNTAGGED << |
713 | ICE_AQ_VSI_OUTER_VLAN_TX_MODE_S) | |
714 | ICE_AQ_VSI_OUTER_VLAN_PORT_BASED_INSERT; |
715 | |
716 | ctxt->info.valid_sections = |
717 | cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID | |
718 | ICE_AQ_VSI_PROP_SW_VALID); |
719 | |
720 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
721 | if (err) { |
722 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for setting outer port based VLAN failed, err %d aq_err %s\n", |
723 | err, ice_aq_str(hw->adminq.sq_last_status)); |
724 | } else { |
725 | vsi->info.port_based_outer_vlan = ctxt->info.port_based_outer_vlan; |
726 | vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; |
727 | vsi->info.sw_flags2 = ctxt->info.sw_flags2; |
728 | } |
729 | |
730 | kfree(objp: ctxt); |
731 | return err; |
732 | } |
733 | |
734 | /** |
735 | * ice_vsi_set_outer_port_vlan - public version of __ice_vsi_set_outer_port_vlan |
736 | * @vsi: VSI to configure |
737 | * @vlan: ice_vlan structure used to set the port VLAN |
738 | * |
739 | * Set the outer port VLAN via VSI context. This function should only be |
740 | * used if DVM is supported. Also, this function should never be called directly |
741 | * as it should be part of ice_vsi_vlan_ops if it's needed. |
742 | * |
743 | * Use the ice_vlan structure passed in to set this VSI in a port VLAN. |
744 | */ |
745 | int ice_vsi_set_outer_port_vlan(struct ice_vsi *vsi, struct ice_vlan *vlan) |
746 | { |
747 | u16 port_vlan_info; |
748 | |
749 | if (vlan->prio > (VLAN_PRIO_MASK >> VLAN_PRIO_SHIFT)) |
750 | return -EINVAL; |
751 | |
752 | port_vlan_info = vlan->vid | (vlan->prio << VLAN_PRIO_SHIFT); |
753 | |
754 | return __ice_vsi_set_outer_port_vlan(vsi, vlan_info: port_vlan_info, tpid: vlan->tpid); |
755 | } |
756 | |
757 | /** |
758 | * ice_vsi_clear_outer_port_vlan - clear outer port vlan |
759 | * @vsi: VSI to configure |
760 | * |
761 | * The function is restoring previously set vlan config (saved in |
762 | * vsi->vlan_info). Setting happens in port vlan configuration. |
763 | */ |
764 | int ice_vsi_clear_outer_port_vlan(struct ice_vsi *vsi) |
765 | { |
766 | struct ice_hw *hw = &vsi->back->hw; |
767 | struct ice_vsi_ctx *ctxt; |
768 | int err; |
769 | |
770 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
771 | if (!ctxt) |
772 | return -ENOMEM; |
773 | |
774 | ice_restore_vlan_info(info: &vsi->info, vlan: &vsi->vlan_info); |
775 | vsi->info.port_based_outer_vlan = 0; |
776 | ctxt->info = vsi->info; |
777 | |
778 | ctxt->info.valid_sections = |
779 | cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID | |
780 | ICE_AQ_VSI_PROP_SW_VALID); |
781 | |
782 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
783 | if (err) |
784 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for clearing outer port based VLAN failed, err %d aq_err %s\n", |
785 | err, ice_aq_str(hw->adminq.sq_last_status)); |
786 | |
787 | kfree(objp: ctxt); |
788 | return err; |
789 | } |
790 | |
791 | int ice_vsi_clear_port_vlan(struct ice_vsi *vsi) |
792 | { |
793 | struct ice_hw *hw = &vsi->back->hw; |
794 | struct ice_vsi_ctx *ctxt; |
795 | int err; |
796 | |
797 | ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); |
798 | if (!ctxt) |
799 | return -ENOMEM; |
800 | |
801 | ctxt->info = vsi->info; |
802 | |
803 | ctxt->info.port_based_outer_vlan = 0; |
804 | ctxt->info.port_based_inner_vlan = 0; |
805 | |
806 | ctxt->info.inner_vlan_flags = |
807 | FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_TX_MODE_M, |
808 | ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL); |
809 | if (ice_is_dvm_ena(hw)) { |
810 | ctxt->info.inner_vlan_flags |= |
811 | FIELD_PREP(ICE_AQ_VSI_INNER_VLAN_EMODE_M, |
812 | ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING); |
813 | ctxt->info.outer_vlan_flags = |
814 | FIELD_PREP(ICE_AQ_VSI_OUTER_VLAN_TX_MODE_M, |
815 | ICE_AQ_VSI_OUTER_VLAN_TX_MODE_ALL); |
816 | ctxt->info.outer_vlan_flags |= |
817 | FIELD_PREP(ICE_AQ_VSI_OUTER_TAG_TYPE_M, |
818 | ICE_AQ_VSI_OUTER_TAG_VLAN_8100); |
819 | ctxt->info.outer_vlan_flags |= |
820 | ICE_AQ_VSI_OUTER_VLAN_EMODE_NOTHING << |
821 | ICE_AQ_VSI_OUTER_VLAN_EMODE_S; |
822 | } |
823 | |
824 | ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; |
825 | ctxt->info.valid_sections = |
826 | cpu_to_le16(ICE_AQ_VSI_PROP_OUTER_TAG_VALID | |
827 | ICE_AQ_VSI_PROP_VLAN_VALID | |
828 | ICE_AQ_VSI_PROP_SW_VALID); |
829 | |
830 | err = ice_update_vsi(hw, vsi_handle: vsi->idx, vsi_ctx: ctxt, NULL); |
831 | if (err) { |
832 | dev_err(ice_pf_to_dev(vsi->back), "update VSI for clearing port based VLAN failed, err %d aq_err %s\n", |
833 | err, ice_aq_str(hw->adminq.sq_last_status)); |
834 | } else { |
835 | vsi->info.port_based_outer_vlan = |
836 | ctxt->info.port_based_outer_vlan; |
837 | vsi->info.port_based_inner_vlan = |
838 | ctxt->info.port_based_inner_vlan; |
839 | vsi->info.outer_vlan_flags = ctxt->info.outer_vlan_flags; |
840 | vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags; |
841 | vsi->info.sw_flags2 = ctxt->info.sw_flags2; |
842 | } |
843 | |
844 | kfree(objp: ctxt); |
845 | return err; |
846 | } |
847 |
Definitions
- print_invalid_tpid
- validate_vlan
- ice_vsi_add_vlan
- ice_vsi_del_vlan
- ice_vsi_manage_vlan_insertion
- ice_vsi_manage_vlan_stripping
- ice_vsi_ena_inner_stripping
- ice_vsi_dis_inner_stripping
- ice_vsi_ena_inner_insertion
- ice_vsi_dis_inner_insertion
- ice_save_vlan_info
- ice_restore_vlan_info
- __ice_vsi_set_inner_port_vlan
- ice_vsi_set_inner_port_vlan
- ice_vsi_clear_inner_port_vlan
- ice_cfg_vlan_pruning
- ice_vsi_ena_rx_vlan_filtering
- ice_vsi_dis_rx_vlan_filtering
- ice_cfg_vlan_antispoof
- ice_vsi_ena_tx_vlan_filtering
- ice_vsi_dis_tx_vlan_filtering
- tpid_to_vsi_outer_vlan_type
- ice_vsi_ena_outer_stripping
- ice_vsi_dis_outer_stripping
- ice_vsi_ena_outer_insertion
- ice_vsi_dis_outer_insertion
- __ice_vsi_set_outer_port_vlan
- ice_vsi_set_outer_port_vlan
- ice_vsi_clear_outer_port_vlan
Improve your Profiling and Debugging skills
Find out more