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