xref: /dpdk/drivers/net/ice/base/ice_vlan_mode.c (revision daa2ca42)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2001-2021 Intel Corporation
3  */
4 
5 #include "ice_common.h"
6 
7 /**
8  * ice_pkg_get_supported_vlan_mode - chk if DDP supports Double VLAN mode (DVM)
9  * @hw: pointer to the HW struct
10  * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
11  */
12 static enum ice_status
ice_pkg_get_supported_vlan_mode(struct ice_hw * hw,bool * dvm)13 ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
14 {
15 	u16 meta_init_size = sizeof(struct ice_meta_init_section);
16 	struct ice_meta_init_section *sect;
17 	struct ice_buf_build *bld;
18 	enum ice_status status;
19 
20 	/* if anything fails, we assume there is no DVM support */
21 	*dvm = false;
22 
23 	bld = ice_pkg_buf_alloc_single_section(hw,
24 					       ICE_SID_RXPARSER_METADATA_INIT,
25 					       meta_init_size, (void **)&sect);
26 	if (!bld)
27 		return ICE_ERR_NO_MEMORY;
28 
29 	/* only need to read a single section */
30 	sect->count = CPU_TO_LE16(1);
31 	sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
32 
33 	status = ice_aq_upload_section(hw,
34 				       (struct ice_buf_hdr *)ice_pkg_buf(bld),
35 				       ICE_PKG_BUF_SIZE, NULL);
36 	if (!status) {
37 		ice_declare_bitmap(entry, ICE_META_INIT_BITS);
38 		u32 arr[ICE_META_INIT_DW_CNT];
39 		u16 i;
40 
41 		/* convert to host bitmap format */
42 		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
43 			arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
44 
45 		ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
46 
47 		/* check if DVM is supported */
48 		*dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
49 	}
50 
51 	ice_pkg_buf_free(hw, bld);
52 
53 	return status;
54 }
55 
56 /**
57  * ice_aq_get_vlan_mode - get the VLAN mode of the device
58  * @hw: pointer to the HW structure
59  * @get_params: structure FW fills in based on the current VLAN mode config
60  *
61  * Get VLAN Mode Parameters (0x020D)
62  */
63 static enum ice_status
ice_aq_get_vlan_mode(struct ice_hw * hw,struct ice_aqc_get_vlan_mode * get_params)64 ice_aq_get_vlan_mode(struct ice_hw *hw,
65 		     struct ice_aqc_get_vlan_mode *get_params)
66 {
67 	struct ice_aq_desc desc;
68 
69 	if (!get_params)
70 		return ICE_ERR_PARAM;
71 
72 	ice_fill_dflt_direct_cmd_desc(&desc,
73 				      ice_aqc_opc_get_vlan_mode_parameters);
74 
75 	return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params),
76 			       NULL);
77 }
78 
79 /**
80  * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled
81  * @hw: pointer to the HW structure
82  *
83  * Returns true if the hardware/firmware is configured in double VLAN mode,
84  * else return false signaling that the hardware/firmware is configured in
85  * single VLAN mode.
86  *
87  * Also, return false if this call fails for any reason (i.e. firmware doesn't
88  * support this AQ call).
89  */
ice_aq_is_dvm_ena(struct ice_hw * hw)90 static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
91 {
92 	struct ice_aqc_get_vlan_mode get_params = { 0 };
93 	enum ice_status status;
94 
95 	status = ice_aq_get_vlan_mode(hw, &get_params);
96 	if (status) {
97 		ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
98 			  status);
99 		return false;
100 	}
101 
102 	return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);
103 }
104 
105 /**
106  * ice_is_dvm_ena - check if double VLAN mode is enabled
107  * @hw: pointer to the HW structure
108  *
109  * The device is configured in single or double VLAN mode on initialization and
110  * this cannot be dynamically changed during runtime. Based on this there is no
111  * need to make an AQ call every time the driver needs to know the VLAN mode.
112  * Instead, use the cached VLAN mode.
113  */
ice_is_dvm_ena(struct ice_hw * hw)114 bool ice_is_dvm_ena(struct ice_hw *hw)
115 {
116 	return hw->dvm_ena;
117 }
118 
119 /**
120  * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded
121  * @hw: pointer to the HW structure
122  *
123  * This is only called after downloading the DDP and after the global
124  * configuration lock has been released because all ports on a device need to
125  * cache the VLAN mode.
126  */
ice_cache_vlan_mode(struct ice_hw * hw)127 static void ice_cache_vlan_mode(struct ice_hw *hw)
128 {
129 	hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
130 }
131 
132 /**
133  * ice_pkg_supports_dvm - find out if DDP supports DVM
134  * @hw: pointer to the HW structure
135  */
ice_pkg_supports_dvm(struct ice_hw * hw)136 static bool ice_pkg_supports_dvm(struct ice_hw *hw)
137 {
138 	enum ice_status status;
139 	bool pkg_supports_dvm;
140 
141 	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
142 	if (status) {
143 		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
144 			  status);
145 		return false;
146 	}
147 
148 	return pkg_supports_dvm;
149 }
150 
151 /**
152  * ice_fw_supports_dvm - find out if FW supports DVM
153  * @hw: pointer to the HW structure
154  */
ice_fw_supports_dvm(struct ice_hw * hw)155 static bool ice_fw_supports_dvm(struct ice_hw *hw)
156 {
157 	struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
158 	enum ice_status status;
159 
160 	/* If firmware returns success, then it supports DVM, else it only
161 	 * supports SVM
162 	 */
163 	status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);
164 	if (status) {
165 		ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
166 			  status);
167 		return false;
168 	}
169 
170 	return true;
171 }
172 
173 /**
174  * ice_is_dvm_supported - check if Double VLAN Mode is supported
175  * @hw: pointer to the hardware structure
176  *
177  * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
178  * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
179  * firmware must support it, otherwise only SVM is supported. This function
180  * should only be called while the global config lock is held and after the
181  * package has been successfully downloaded.
182  */
ice_is_dvm_supported(struct ice_hw * hw)183 static bool ice_is_dvm_supported(struct ice_hw *hw)
184 {
185 	if (!ice_pkg_supports_dvm(hw)) {
186 		ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");
187 		return false;
188 	}
189 
190 	if (!ice_fw_supports_dvm(hw)) {
191 		ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");
192 		return false;
193 	}
194 
195 	return true;
196 }
197 
198 #define ICE_EXTERNAL_VLAN_ID_FV_IDX			11
199 #define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX			1
200 #define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX		2
201 #define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX		2
202 #define ICE_PKT_FLAGS_0_TO_15_FV_IDX			1
203 #define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK		0xD000
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  */
ice_dvm_update_dflt_recipes(struct ice_hw * hw)245 static enum ice_status ice_dvm_update_dflt_recipes(struct ice_hw *hw)
246 {
247 	unsigned long i;
248 
249 	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 		params = &ice_dvm_dflt_recipes[i];
254 
255 		status = ice_update_recipe_lkup_idx(hw, params);
256 		if (status) {
257 			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 			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
ice_aq_set_vlan_mode(struct ice_hw * hw,struct ice_aqc_set_vlan_mode * set_params)276 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 	if (!set_params)
283 		return ICE_ERR_PARAM;
284 
285 	if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
286 		return ICE_ERR_PARAM;
287 
288 	rdma_packet = set_params->rdma_packet;
289 	if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
290 	    rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
291 		return ICE_ERR_PARAM;
292 
293 	mng_vlan_prot_id = set_params->mng_vlan_prot_id;
294 	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 	ice_fill_dflt_direct_cmd_desc(&desc,
299 				      ice_aqc_opc_set_vlan_mode_parameters);
300 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
301 
302 	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  */
ice_set_dvm(struct ice_hw * hw)310 static enum ice_status ice_set_dvm(struct ice_hw *hw)
311 {
312 	struct ice_aqc_set_vlan_mode params = { 0 };
313 	enum ice_status status;
314 
315 	params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG;
316 	params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING;
317 	params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER;
318 
319 	status = ice_aq_set_vlan_mode(hw, &params);
320 	if (status) {
321 		ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n",
322 			  status);
323 		return status;
324 	}
325 
326 	status = ice_dvm_update_dflt_recipes(hw);
327 	if (status) {
328 		ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n",
329 			  status);
330 		return status;
331 	}
332 
333 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, true,
334 					NULL);
335 	if (status) {
336 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n",
337 			  status);
338 		return status;
339 	}
340 
341 	status = ice_set_dvm_boost_entries(hw);
342 	if (status) {
343 		ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n",
344 			  status);
345 		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  */
ice_set_svm(struct ice_hw * hw)355 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 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
361 	if (status) {
362 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
363 		return status;
364 	}
365 
366 	set_params = (struct ice_aqc_set_vlan_mode *)
367 		ice_malloc(hw, sizeof(*set_params));
368 	if (!set_params)
369 		return ICE_ERR_NO_MEMORY;
370 
371 	/* default configuration for SVM configurations */
372 	set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
373 	set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
374 	set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
375 
376 	status = ice_aq_set_vlan_mode(hw, set_params);
377 	if (status)
378 		ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
379 
380 	ice_free(hw, set_params);
381 	return status;
382 }
383 
384 /**
385  * ice_set_vlan_mode
386  * @hw: pointer to the HW structure
387  */
ice_set_vlan_mode(struct ice_hw * hw)388 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 	if (hw->dcf_enabled)
394 		return ICE_SUCCESS;
395 
396 	if (!ice_is_dvm_supported(hw))
397 		return ICE_SUCCESS;
398 
399 	if (!ice_set_dvm(hw))
400 		return ICE_SUCCESS;
401 
402 	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  */
ice_print_dvm_not_supported(struct ice_hw * hw)413 static void ice_print_dvm_not_supported(struct ice_hw *hw)
414 {
415 	bool pkg_supports_dvm = ice_pkg_supports_dvm(hw);
416 	bool fw_supports_dvm = ice_fw_supports_dvm(hw);
417 
418 	if (!fw_supports_dvm && !pkg_supports_dvm)
419 		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 	else if (!pkg_supports_dvm)
422 		ice_info(hw, "QinQ functionality cannot be enabled on this device. "
423 			     "Update your DDP package to a version that supports QinQ.\n");
424 	else if (!fw_supports_dvm)
425 		ice_info(hw, "QinQ functionality cannot be enabled on this device. "
426 			     "Update your NVM to a version that supports QinQ.\n");
427 }
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  */
ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw * hw)442 void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)
443 {
444 	ice_cache_vlan_mode(hw);
445 
446 	if (ice_is_dvm_ena(hw))
447 		ice_change_proto_id_to_dvm();
448 	else
449 		ice_print_dvm_not_supported(hw);
450 }
451