1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (C) 2019-2021, Intel Corporation. */
3
4#include "ice_common.h"
5
6/**
7 * ice_pkg_get_supported_vlan_mode - determine if DDP supports Double VLAN mode
8 * @hw: pointer to the HW struct
9 * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
10 */
11static int
12ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
13{
14 u16 meta_init_size = sizeof(struct ice_meta_init_section);
15 struct ice_meta_init_section *sect;
16 struct ice_buf_build *bld;
17 int status;
18
19 /* if anything fails, we assume there is no DVM support */
20 *dvm = false;
21
22 bld = ice_pkg_buf_alloc_single_section(hw,
23 ICE_SID_RXPARSER_METADATA_INIT,
24 size: meta_init_size, section: (void **)&sect);
25 if (!bld)
26 return -ENOMEM;
27
28 /* only need to read a single section */
29 sect->count = cpu_to_le16(1);
30 sect->offset = cpu_to_le16(ICE_META_VLAN_MODE_ENTRY);
31
32 status = ice_aq_upload_section(hw,
33 pkg_buf: (struct ice_buf_hdr *)ice_pkg_buf(bld),
34 ICE_PKG_BUF_SIZE, NULL);
35 if (!status) {
36 DECLARE_BITMAP(entry, ICE_META_INIT_BITS);
37 u32 arr[ICE_META_INIT_DW_CNT];
38 u16 i;
39
40 /* convert to host bitmap format */
41 for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
42 arr[i] = le32_to_cpu(sect->entry.bm[i]);
43
44 bitmap_from_arr32(bitmap: entry, buf: arr, nbits: (u16)ICE_META_INIT_BITS);
45
46 /* check if DVM is supported */
47 *dvm = test_bit(ICE_META_VLAN_MODE_BIT, entry);
48 }
49
50 ice_pkg_buf_free(hw, bld);
51
52 return status;
53}
54
55/**
56 * ice_aq_get_vlan_mode - get the VLAN mode of the device
57 * @hw: pointer to the HW structure
58 * @get_params: structure FW fills in based on the current VLAN mode config
59 *
60 * Get VLAN Mode Parameters (0x020D)
61 */
62static int
63ice_aq_get_vlan_mode(struct ice_hw *hw,
64 struct ice_aqc_get_vlan_mode *get_params)
65{
66 struct ice_aq_desc desc;
67
68 if (!get_params)
69 return -EINVAL;
70
71 ice_fill_dflt_direct_cmd_desc(desc: &desc,
72 opcode: ice_aqc_opc_get_vlan_mode_parameters);
73
74 return ice_aq_send_cmd(hw, desc: &desc, buf: get_params, buf_size: sizeof(*get_params),
75 NULL);
76}
77
78/**
79 * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled
80 * @hw: pointer to the HW structure
81 *
82 * Returns true if the hardware/firmware is configured in double VLAN mode,
83 * else return false signaling that the hardware/firmware is configured in
84 * single VLAN mode.
85 *
86 * Also, return false if this call fails for any reason (i.e. firmware doesn't
87 * support this AQ call).
88 */
89static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
90{
91 struct ice_aqc_get_vlan_mode get_params = { 0 };
92 int status;
93
94 status = ice_aq_get_vlan_mode(hw, get_params: &get_params);
95 if (status) {
96 ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
97 status);
98 return false;
99 }
100
101 return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);
102}
103
104/**
105 * ice_is_dvm_ena - check if double VLAN mode is enabled
106 * @hw: pointer to the HW structure
107 *
108 * The device is configured in single or double VLAN mode on initialization and
109 * this cannot be dynamically changed during runtime. Based on this there is no
110 * need to make an AQ call every time the driver needs to know the VLAN mode.
111 * Instead, use the cached VLAN mode.
112 */
113bool ice_is_dvm_ena(struct ice_hw *hw)
114{
115 return hw->dvm_ena;
116}
117
118/**
119 * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded
120 * @hw: pointer to the HW structure
121 *
122 * This is only called after downloading the DDP and after the global
123 * configuration lock has been released because all ports on a device need to
124 * cache the VLAN mode.
125 */
126static void ice_cache_vlan_mode(struct ice_hw *hw)
127{
128 hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
129}
130
131/**
132 * ice_pkg_supports_dvm - find out if DDP supports DVM
133 * @hw: pointer to the HW structure
134 */
135static bool ice_pkg_supports_dvm(struct ice_hw *hw)
136{
137 bool pkg_supports_dvm;
138 int status;
139
140 status = ice_pkg_get_supported_vlan_mode(hw, dvm: &pkg_supports_dvm);
141 if (status) {
142 ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
143 status);
144 return false;
145 }
146
147 return pkg_supports_dvm;
148}
149
150/**
151 * ice_fw_supports_dvm - find out if FW supports DVM
152 * @hw: pointer to the HW structure
153 */
154static bool ice_fw_supports_dvm(struct ice_hw *hw)
155{
156 struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
157 int status;
158
159 /* If firmware returns success, then it supports DVM, else it only
160 * supports SVM
161 */
162 status = ice_aq_get_vlan_mode(hw, get_params: &get_vlan_mode);
163 if (status) {
164 ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
165 status);
166 return false;
167 }
168
169 return true;
170}
171
172/**
173 * ice_is_dvm_supported - check if Double VLAN Mode is supported
174 * @hw: pointer to the hardware structure
175 *
176 * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
177 * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
178 * firmware must support it, otherwise only SVM is supported. This function
179 * should only be called while the global config lock is held and after the
180 * package has been successfully downloaded.
181 */
182static bool ice_is_dvm_supported(struct ice_hw *hw)
183{
184 if (!ice_pkg_supports_dvm(hw)) {
185 ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");
186 return false;
187 }
188
189 if (!ice_fw_supports_dvm(hw)) {
190 ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");
191 return false;
192 }
193
194 return true;
195}
196
197#define ICE_EXTERNAL_VLAN_ID_FV_IDX 11
198#define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX 1
199#define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX 2
200#define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX 2
201#define ICE_PKT_FLAGS_0_TO_15_FV_IDX 1
202static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = {
203 {
204 /* Update recipe ICE_SW_LKUP_VLAN to filter based on the
205 * outer/single VLAN in DVM
206 */
207 .rid = ICE_SW_LKUP_VLAN,
208 .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,
209 .ignore_valid = true,
210 .mask = 0,
211 .mask_valid = false, /* use pre-existing mask */
212 .lkup_idx = ICE_SW_LKUP_VLAN_LOC_LKUP_IDX,
213 },
214 {
215 /* Update recipe ICE_SW_LKUP_VLAN to filter based on the VLAN
216 * packet flags to support VLAN filtering on multiple VLAN
217 * ethertypes (i.e. 0x8100 and 0x88a8) in DVM
218 */
219 .rid = ICE_SW_LKUP_VLAN,
220 .fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX,
221 .ignore_valid = false,
222 .mask = ICE_PKT_VLAN_MASK,
223 .mask_valid = true,
224 .lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX,
225 },
226 {
227 /* Update recipe ICE_SW_LKUP_PROMISC_VLAN to filter based on the
228 * outer/single VLAN in DVM
229 */
230 .rid = ICE_SW_LKUP_PROMISC_VLAN,
231 .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,
232 .ignore_valid = true,
233 .mask = 0,
234 .mask_valid = false, /* use pre-existing mask */
235 .lkup_idx = ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX,
236 },
237};
238
239/**
240 * ice_dvm_update_dflt_recipes - update default switch recipes in DVM
241 * @hw: hardware structure used to update the recipes
242 */
243static int ice_dvm_update_dflt_recipes(struct ice_hw *hw)
244{
245 unsigned long i;
246
247 for (i = 0; i < ARRAY_SIZE(ice_dvm_dflt_recipes); i++) {
248 struct ice_update_recipe_lkup_idx_params *params;
249 int status;
250
251 params = &ice_dvm_dflt_recipes[i];
252
253 status = ice_update_recipe_lkup_idx(hw, params);
254 if (status) {
255 ice_debug(hw, ICE_DBG_INIT, "Failed to update RID %d lkup_idx %d fv_idx %d mask_valid %s mask 0x%04x\n",
256 params->rid, params->lkup_idx, params->fv_idx,
257 params->mask_valid ? "true" : "false",
258 params->mask);
259 return status;
260 }
261 }
262
263 return 0;
264}
265
266/**
267 * ice_aq_set_vlan_mode - set the VLAN mode of the device
268 * @hw: pointer to the HW structure
269 * @set_params: requested VLAN mode configuration
270 *
271 * Set VLAN Mode Parameters (0x020C)
272 */
273static int
274ice_aq_set_vlan_mode(struct ice_hw *hw,
275 struct ice_aqc_set_vlan_mode *set_params)
276{
277 u8 rdma_packet, mng_vlan_prot_id;
278 struct ice_aq_desc desc;
279
280 if (!set_params)
281 return -EINVAL;
282
283 if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
284 return -EINVAL;
285
286 rdma_packet = set_params->rdma_packet;
287 if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
288 rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
289 return -EINVAL;
290
291 mng_vlan_prot_id = set_params->mng_vlan_prot_id;
292 if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
293 mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
294 return -EINVAL;
295
296 ice_fill_dflt_direct_cmd_desc(desc: &desc,
297 opcode: ice_aqc_opc_set_vlan_mode_parameters);
298 desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);
299
300 return ice_aq_send_cmd(hw, desc: &desc, buf: set_params, buf_size: sizeof(*set_params),
301 NULL);
302}
303
304/**
305 * ice_set_dvm - sets up software and hardware for double VLAN mode
306 * @hw: pointer to the hardware structure
307 */
308static int ice_set_dvm(struct ice_hw *hw)
309{
310 struct ice_aqc_set_vlan_mode params = { 0 };
311 int status;
312
313 params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG;
314 params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING;
315 params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER;
316
317 status = ice_aq_set_vlan_mode(hw, set_params: &params);
318 if (status) {
319 ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n",
320 status);
321 return status;
322 }
323
324 status = ice_dvm_update_dflt_recipes(hw);
325 if (status) {
326 ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n",
327 status);
328 return status;
329 }
330
331 status = ice_aq_set_port_params(pi: hw->port_info, double_vlan: true, NULL);
332 if (status) {
333 ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n",
334 status);
335 return status;
336 }
337
338 status = ice_set_dvm_boost_entries(hw);
339 if (status) {
340 ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n",
341 status);
342 return status;
343 }
344
345 return 0;
346}
347
348/**
349 * ice_set_svm - set single VLAN mode
350 * @hw: pointer to the HW structure
351 */
352static int ice_set_svm(struct ice_hw *hw)
353{
354 struct ice_aqc_set_vlan_mode *set_params;
355 int status;
356
357 status = ice_aq_set_port_params(pi: hw->port_info, double_vlan: false, NULL);
358 if (status) {
359 ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
360 return status;
361 }
362
363 set_params = devm_kzalloc(dev: ice_hw_to_dev(hw), size: sizeof(*set_params),
364 GFP_KERNEL);
365 if (!set_params)
366 return -ENOMEM;
367
368 /* default configuration for SVM configurations */
369 set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
370 set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
371 set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
372
373 status = ice_aq_set_vlan_mode(hw, set_params);
374 if (status)
375 ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
376
377 devm_kfree(dev: ice_hw_to_dev(hw), p: set_params);
378 return status;
379}
380
381/**
382 * ice_set_vlan_mode
383 * @hw: pointer to the HW structure
384 */
385int ice_set_vlan_mode(struct ice_hw *hw)
386{
387 if (!ice_is_dvm_supported(hw))
388 return 0;
389
390 if (!ice_set_dvm(hw))
391 return 0;
392
393 return ice_set_svm(hw);
394}
395
396/**
397 * ice_print_dvm_not_supported - print if DDP and/or FW doesn't support DVM
398 * @hw: pointer to the HW structure
399 *
400 * The purpose of this function is to print that QinQ is not supported due to
401 * incompatibilty from the DDP and/or FW. This will give a hint to the user to
402 * update one and/or both components if they expect QinQ functionality.
403 */
404static void ice_print_dvm_not_supported(struct ice_hw *hw)
405{
406 bool pkg_supports_dvm = ice_pkg_supports_dvm(hw);
407 bool fw_supports_dvm = ice_fw_supports_dvm(hw);
408
409 if (!fw_supports_dvm && !pkg_supports_dvm)
410 dev_info(ice_hw_to_dev(hw), "QinQ functionality cannot be enabled on this device. Update your DDP package and NVM to versions that support QinQ.\n");
411 else if (!pkg_supports_dvm)
412 dev_info(ice_hw_to_dev(hw), "QinQ functionality cannot be enabled on this device. Update your DDP package to a version that supports QinQ.\n");
413 else if (!fw_supports_dvm)
414 dev_info(ice_hw_to_dev(hw), "QinQ functionality cannot be enabled on this device. Update your NVM to a version that supports QinQ.\n");
415}
416
417/**
418 * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download
419 * @hw: pointer to the HW structure
420 *
421 * This function is meant to configure any VLAN mode specific functionality
422 * after the global configuration lock has been released and the DDP has been
423 * downloaded.
424 *
425 * Since only one PF downloads the DDP and configures the VLAN mode there needs
426 * to be a way to configure the other PFs after the DDP has been downloaded and
427 * the global configuration lock has been released. All such code should go in
428 * this function.
429 */
430void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)
431{
432 ice_cache_vlan_mode(hw);
433
434 if (ice_is_dvm_ena(hw))
435 ice_change_proto_id_to_dvm();
436 else
437 ice_print_dvm_not_supported(hw);
438}
439

source code of linux/drivers/net/ethernet/intel/ice/ice_vlan_mode.c