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