xref: /freebsd/sys/dev/ice/ice_vlan_mode.c (revision 7ee6b0f125a092ed99d327bb8d608dd2ff77b7aa)
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*  Copyright (c) 2023, Intel Corporation
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above copyright notice,
9  *      this list of conditions and the following disclaimer.
10  *
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *
15  *   3. Neither the name of the Intel Corporation nor the names of its
16  *      contributors may be used to endorse or promote products derived from
17  *      this software without specific prior written permission.
18  *
19  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  *  POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*$FreeBSD$*/
32 
33 #include "ice_common.h"
34 
35 #include "ice_ddp_common.h"
36 /**
37  * ice_pkg_get_supported_vlan_mode - chk if DDP supports Double VLAN mode (DVM)
38  * @hw: pointer to the HW struct
39  * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
40  */
41 static enum ice_status
42 ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
43 {
44 	u16 meta_init_size = sizeof(struct ice_meta_init_section);
45 	struct ice_meta_init_section *sect;
46 	struct ice_buf_build *bld;
47 	enum ice_status status;
48 
49 	/* if anything fails, we assume there is no DVM support */
50 	*dvm = false;
51 
52 	bld = ice_pkg_buf_alloc_single_section(hw,
53 					       ICE_SID_RXPARSER_METADATA_INIT,
54 					       meta_init_size, (void **)&sect);
55 	if (!bld)
56 		return ICE_ERR_NO_MEMORY;
57 
58 	/* only need to read a single section */
59 	sect->count = CPU_TO_LE16(1);
60 	sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
61 
62 	status = ice_aq_upload_section(hw,
63 				       (struct ice_buf_hdr *)ice_pkg_buf(bld),
64 				       ICE_PKG_BUF_SIZE, NULL);
65 	if (!status) {
66 		ice_declare_bitmap(entry, ICE_META_INIT_BITS);
67 		u32 arr[ICE_META_INIT_DW_CNT];
68 		u16 i;
69 
70 		/* convert to host bitmap format */
71 		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
72 			arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
73 
74 		ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
75 
76 		/* check if DVM is supported */
77 		*dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
78 	}
79 
80 	ice_pkg_buf_free(hw, bld);
81 
82 	return status;
83 }
84 
85 /**
86  * ice_aq_get_vlan_mode - get the VLAN mode of the device
87  * @hw: pointer to the HW structure
88  * @get_params: structure FW fills in based on the current VLAN mode config
89  *
90  * Get VLAN Mode Parameters (0x020D)
91  */
92 static enum ice_status
93 ice_aq_get_vlan_mode(struct ice_hw *hw,
94 		     struct ice_aqc_get_vlan_mode *get_params)
95 {
96 	struct ice_aq_desc desc;
97 
98 	if (!get_params)
99 		return ICE_ERR_PARAM;
100 
101 	ice_fill_dflt_direct_cmd_desc(&desc,
102 				      ice_aqc_opc_get_vlan_mode_parameters);
103 
104 	return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params),
105 			       NULL);
106 }
107 
108 /**
109  * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled
110  * @hw: pointer to the HW structure
111  *
112  * Returns true if the hardware/firmware is configured in double VLAN mode,
113  * else return false signaling that the hardware/firmware is configured in
114  * single VLAN mode.
115  *
116  * Also, return false if this call fails for any reason (i.e. firmware doesn't
117  * support this AQ call).
118  */
119 static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
120 {
121 	struct ice_aqc_get_vlan_mode get_params = { 0 };
122 	enum ice_status status;
123 
124 	status = ice_aq_get_vlan_mode(hw, &get_params);
125 	if (status) {
126 		ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
127 			  status);
128 		return false;
129 	}
130 
131 	return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);
132 }
133 
134 /**
135  * ice_is_dvm_ena - check if double VLAN mode is enabled
136  * @hw: pointer to the HW structure
137  *
138  * The device is configured in single or double VLAN mode on initialization and
139  * this cannot be dynamically changed during runtime. Based on this there is no
140  * need to make an AQ call every time the driver needs to know the VLAN mode.
141  * Instead, use the cached VLAN mode.
142  */
143 bool ice_is_dvm_ena(struct ice_hw *hw)
144 {
145 	return hw->dvm_ena;
146 }
147 
148 /**
149  * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded
150  * @hw: pointer to the HW structure
151  *
152  * This is only called after downloading the DDP and after the global
153  * configuration lock has been released because all ports on a device need to
154  * cache the VLAN mode.
155  */
156 static void ice_cache_vlan_mode(struct ice_hw *hw)
157 {
158 	hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
159 }
160 
161 /**
162  * ice_pkg_supports_dvm - find out if DDP supports DVM
163  * @hw: pointer to the HW structure
164  */
165 static bool ice_pkg_supports_dvm(struct ice_hw *hw)
166 {
167 	enum ice_status status;
168 	bool pkg_supports_dvm;
169 
170 	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
171 	if (status) {
172 		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
173 			  status);
174 		return false;
175 	}
176 
177 	return pkg_supports_dvm;
178 }
179 
180 /**
181  * ice_fw_supports_dvm - find out if FW supports DVM
182  * @hw: pointer to the HW structure
183  */
184 static bool ice_fw_supports_dvm(struct ice_hw *hw)
185 {
186 	struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
187 	enum ice_status status;
188 
189 	/* If firmware returns success, then it supports DVM, else it only
190 	 * supports SVM
191 	 */
192 	status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);
193 	if (status) {
194 		ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
195 			  status);
196 		return false;
197 	}
198 
199 	return true;
200 }
201 
202 /**
203  * ice_is_dvm_supported - check if Double VLAN Mode is supported
204  * @hw: pointer to the hardware structure
205  *
206  * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
207  * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
208  * firmware must support it, otherwise only SVM is supported. This function
209  * should only be called while the global config lock is held and after the
210  * package has been successfully downloaded.
211  */
212 static bool ice_is_dvm_supported(struct ice_hw *hw)
213 {
214 	if (!ice_pkg_supports_dvm(hw)) {
215 		ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");
216 		return false;
217 	}
218 
219 	if (!ice_fw_supports_dvm(hw)) {
220 		ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");
221 		return false;
222 	}
223 
224 	return true;
225 }
226 
227 /**
228  * ice_aq_set_vlan_mode - set the VLAN mode of the device
229  * @hw: pointer to the HW structure
230  * @set_params: requested VLAN mode configuration
231  *
232  * Set VLAN Mode Parameters (0x020C)
233  */
234 static enum ice_status
235 ice_aq_set_vlan_mode(struct ice_hw *hw,
236 		     struct ice_aqc_set_vlan_mode *set_params)
237 {
238 	u8 rdma_packet, mng_vlan_prot_id;
239 	struct ice_aq_desc desc;
240 
241 	if (!set_params)
242 		return ICE_ERR_PARAM;
243 
244 	if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
245 		return ICE_ERR_PARAM;
246 
247 	rdma_packet = set_params->rdma_packet;
248 	if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
249 	    rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
250 		return ICE_ERR_PARAM;
251 
252 	mng_vlan_prot_id = set_params->mng_vlan_prot_id;
253 	if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
254 	    mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
255 		return ICE_ERR_PARAM;
256 
257 	ice_fill_dflt_direct_cmd_desc(&desc,
258 				      ice_aqc_opc_set_vlan_mode_parameters);
259 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
260 
261 	return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),
262 			       NULL);
263 }
264 
265 /**
266  * ice_set_svm - set single VLAN mode
267  * @hw: pointer to the HW structure
268  */
269 static enum ice_status ice_set_svm(struct ice_hw *hw)
270 {
271 	struct ice_aqc_set_vlan_mode *set_params;
272 	enum ice_status status;
273 
274 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
275 	if (status) {
276 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
277 		return status;
278 	}
279 
280 	set_params = (struct ice_aqc_set_vlan_mode *)
281 		ice_malloc(hw, sizeof(*set_params));
282 	if (!set_params)
283 		return ICE_ERR_NO_MEMORY;
284 
285 	/* default configuration for SVM configurations */
286 	set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
287 	set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
288 	set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
289 
290 	status = ice_aq_set_vlan_mode(hw, set_params);
291 	if (status)
292 		ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
293 
294 	ice_free(hw, set_params);
295 	return status;
296 }
297 
298 /**
299  * ice_set_vlan_mode
300  * @hw: pointer to the HW structure
301  */
302 enum ice_status ice_set_vlan_mode(struct ice_hw *hw)
303 {
304 	if (!ice_is_dvm_supported(hw))
305 		return ICE_SUCCESS;
306 
307 	return ice_set_svm(hw);
308 }
309 
310 /**
311  * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download
312  * @hw: pointer to the HW structure
313  *
314  * This function is meant to configure any VLAN mode specific functionality
315  * after the global configuration lock has been released and the DDP has been
316  * downloaded.
317  *
318  * Since only one PF downloads the DDP and configures the VLAN mode there needs
319  * to be a way to configure the other PFs after the DDP has been downloaded and
320  * the global configuration lock has been released. All such code should go in
321  * this function.
322  */
323 void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)
324 {
325 	ice_cache_vlan_mode(hw);
326 }
327