xref: /dpdk/drivers/net/ice/base/ice_vlan_mode.c (revision bb07d96d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2001-2021 Intel Corporation
3  */
4 
5 #include "ice_vlan_mode.h"
6 #include "ice_common.h"
7 
8 /**
9  * ice_pkg_supports_dvm - determine 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 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 	*dvm = false;
23 
24 	bld = ice_pkg_buf_alloc_single_section(hw,
25 					       ICE_SID_RXPARSER_METADATA_INIT,
26 					       meta_init_size, (void **)&sect);
27 	if (!bld)
28 		return ICE_ERR_NO_MEMORY;
29 
30 	/* only need to read a single section */
31 	sect->count = CPU_TO_LE16(1);
32 	sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
33 
34 	status = ice_aq_upload_section(hw,
35 				       (struct ice_buf_hdr *)ice_pkg_buf(bld),
36 				       ICE_PKG_BUF_SIZE, NULL);
37 	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 		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
44 			arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
45 
46 		ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
47 
48 		/* check if DVM is supported */
49 		*dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
50 	}
51 
52 	ice_pkg_buf_free(hw, bld);
53 
54 	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 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 	if (!get_params)
71 		return ICE_ERR_PARAM;
72 
73 	ice_fill_dflt_direct_cmd_desc(&desc,
74 				      ice_aqc_opc_get_vlan_mode_parameters);
75 
76 	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 static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
92 {
93 	struct ice_aqc_get_vlan_mode get_params = { 0 };
94 	enum ice_status status;
95 
96 	status = ice_aq_get_vlan_mode(hw, &get_params);
97 	if (status) {
98 		ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
99 			  status);
100 		return false;
101 	}
102 
103 	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 bool ice_is_dvm_ena(struct ice_hw *hw)
116 {
117 	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 void ice_cache_vlan_mode(struct ice_hw *hw)
129 {
130 	hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
131 }
132 
133 /**
134  * ice_is_dvm_supported - check if Double VLAN Mode is supported
135  * @hw: pointer to the hardware structure
136  *
137  * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
138  * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
139  * firmware must support it, otherwise only SVM is supported. This function
140  * should only be called while the global config lock is held and after the
141  * package has been successfully downloaded.
142  */
143 static bool ice_is_dvm_supported(struct ice_hw *hw)
144 {
145 	struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
146 	enum ice_status status;
147 	bool pkg_supports_dvm;
148 
149 	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
150 	if (status) {
151 		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
152 			  status);
153 		return false;
154 	}
155 
156 	if (!pkg_supports_dvm)
157 		return false;
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_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 #define ICE_EXTERNAL_VLAN_ID_FV_IDX			11
173 #define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX			1
174 #define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX		2
175 #define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX		2
176 #define ICE_PKT_FLAGS_0_TO_15_FV_IDX			1
177 #define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK		0xD000
178 static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = {
179 	{
180 		/* Update recipe ICE_SW_LKUP_VLAN to filter based on the
181 		 * outer/single VLAN in DVM
182 		 */
183 		.rid = ICE_SW_LKUP_VLAN,
184 		.fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,
185 		.ignore_valid = true,
186 		.mask = 0,
187 		.mask_valid = false, /* use pre-existing mask */
188 		.lkup_idx = ICE_SW_LKUP_VLAN_LOC_LKUP_IDX,
189 	},
190 	{
191 		/* Update recipe ICE_SW_LKUP_VLAN to filter based on the VLAN
192 		 * packet flags to support VLAN filtering on multiple VLAN
193 		 * ethertypes (i.e. 0x8100 and 0x88a8) in DVM
194 		 */
195 		.rid = ICE_SW_LKUP_VLAN,
196 		.fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX,
197 		.ignore_valid = false,
198 		.mask = ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK,
199 		.mask_valid = true,
200 		.lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX,
201 	},
202 	{
203 		/* Update recipe ICE_SW_LKUP_PROMISC_VLAN to filter based on the
204 		 * outer/single VLAN in DVM
205 		 */
206 		.rid = ICE_SW_LKUP_PROMISC_VLAN,
207 		.fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,
208 		.ignore_valid = true,
209 		.mask = 0,
210 		.mask_valid = false,  /* use pre-existing mask */
211 		.lkup_idx = ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX,
212 	},
213 };
214 
215 /**
216  * ice_dvm_update_dflt_recipes - update default switch recipes in DVM
217  * @hw: hardware structure used to update the recipes
218  */
219 static enum ice_status ice_dvm_update_dflt_recipes(struct ice_hw *hw)
220 {
221 	unsigned long i;
222 
223 	for (i = 0; i < ARRAY_SIZE(ice_dvm_dflt_recipes); i++) {
224 		struct ice_update_recipe_lkup_idx_params *params;
225 		enum ice_status status;
226 
227 		params = &ice_dvm_dflt_recipes[i];
228 
229 		status = ice_update_recipe_lkup_idx(hw, params);
230 		if (status) {
231 			ice_debug(hw, ICE_DBG_INIT, "Failed to update RID %d lkup_idx %d fv_idx %d mask_valid %s mask 0x%04x\n",
232 				  params->rid, params->lkup_idx, params->fv_idx,
233 				  params->mask_valid ? "true" : "false",
234 				  params->mask);
235 			return status;
236 		}
237 	}
238 
239 	return ICE_SUCCESS;
240 }
241 
242 /**
243  * ice_aq_set_vlan_mode - set the VLAN mode of the device
244  * @hw: pointer to the HW structure
245  * @set_params: requested VLAN mode configuration
246  *
247  * Set VLAN Mode Parameters (0x020C)
248  */
249 static enum ice_status
250 ice_aq_set_vlan_mode(struct ice_hw *hw,
251 		     struct ice_aqc_set_vlan_mode *set_params)
252 {
253 	u8 rdma_packet, mng_vlan_prot_id;
254 	struct ice_aq_desc desc;
255 
256 	if (!set_params)
257 		return ICE_ERR_PARAM;
258 
259 	if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
260 		return ICE_ERR_PARAM;
261 
262 	rdma_packet = set_params->rdma_packet;
263 	if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
264 	    rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
265 		return ICE_ERR_PARAM;
266 
267 	mng_vlan_prot_id = set_params->mng_vlan_prot_id;
268 	if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
269 	    mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
270 		return ICE_ERR_PARAM;
271 
272 	ice_fill_dflt_direct_cmd_desc(&desc,
273 				      ice_aqc_opc_set_vlan_mode_parameters);
274 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
275 
276 	return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),
277 			       NULL);
278 }
279 
280 /**
281  * ice_set_dvm - sets up software and hardware for double VLAN mode
282  * @hw: pointer to the hardware structure
283  */
284 static enum ice_status ice_set_dvm(struct ice_hw *hw)
285 {
286 	struct ice_aqc_set_vlan_mode params = { 0 };
287 	enum ice_status status;
288 
289 	params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG;
290 	params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING;
291 	params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER;
292 
293 	status = ice_aq_set_vlan_mode(hw, &params);
294 	if (status) {
295 		ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n",
296 			  status);
297 		return status;
298 	}
299 
300 	status = ice_dvm_update_dflt_recipes(hw);
301 	if (status) {
302 		ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n",
303 			  status);
304 		return status;
305 	}
306 
307 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, true,
308 					NULL);
309 	if (status) {
310 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n",
311 			  status);
312 		return status;
313 	}
314 
315 	status = ice_set_dvm_boost_entries(hw);
316 	if (status) {
317 		ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n",
318 			  status);
319 		return status;
320 	}
321 
322 	return ICE_SUCCESS;
323 }
324 
325 /**
326  * ice_set_svm - set single VLAN mode
327  * @hw: pointer to the HW structure
328  */
329 static enum ice_status ice_set_svm(struct ice_hw *hw)
330 {
331 	struct ice_aqc_set_vlan_mode *set_params;
332 	enum ice_status status;
333 
334 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
335 	if (status) {
336 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
337 		return status;
338 	}
339 
340 	set_params = (struct ice_aqc_set_vlan_mode *)
341 		ice_malloc(hw, sizeof(*set_params));
342 	if (!set_params)
343 		return ICE_ERR_NO_MEMORY;
344 
345 	/* default configuration for SVM configurations */
346 	set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
347 	set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
348 	set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
349 
350 	status = ice_aq_set_vlan_mode(hw, set_params);
351 	if (status)
352 		ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
353 
354 	ice_free(hw, set_params);
355 	return status;
356 }
357 
358 /**
359  * ice_set_vlan_mode
360  * @hw: pointer to the HW structure
361  */
362 enum ice_status ice_set_vlan_mode(struct ice_hw *hw)
363 {
364 	/* DCF only has the ability to query the VLAN mode. Setting the VLAN
365 	 * mode is done by the PF.
366 	 */
367 	if (hw->dcf_enabled)
368 		return ICE_SUCCESS;
369 
370 	if (!ice_is_dvm_supported(hw))
371 		return ICE_SUCCESS;
372 
373 	if (!ice_set_dvm(hw))
374 		return ICE_SUCCESS;
375 
376 	return ice_set_svm(hw);
377 }
378