xref: /freebsd/sys/dev/ice/ice_vlan_mode.c (revision 4731124cace5e7a0224e29784617d2856e5c59ab)
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*  Copyright (c) 2021, 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 /**
36  * ice_pkg_supports_dvm - determine if DDP supports Double VLAN mode (DVM)
37  * @hw: pointer to the HW struct
38  * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
39  */
40 static enum ice_status
41 ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
42 {
43 	u16 meta_init_size = sizeof(struct ice_meta_init_section);
44 	struct ice_meta_init_section *sect;
45 	struct ice_buf_build *bld;
46 	enum ice_status status;
47 
48 	/* if anything fails, we assume there is no DVM support */
49 	*dvm = false;
50 
51 	bld = ice_pkg_buf_alloc_single_section(hw,
52 					       ICE_SID_RXPARSER_METADATA_INIT,
53 					       meta_init_size, (void **)&sect);
54 	if (!bld)
55 		return ICE_ERR_NO_MEMORY;
56 
57 	/* only need to read a single section */
58 	sect->count = CPU_TO_LE16(1);
59 	sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
60 
61 	status = ice_aq_upload_section(hw,
62 				       (struct ice_buf_hdr *)ice_pkg_buf(bld),
63 				       ICE_PKG_BUF_SIZE, NULL);
64 	if (!status) {
65 		ice_declare_bitmap(entry, ICE_META_INIT_BITS);
66 		u32 arr[ICE_META_INIT_DW_CNT];
67 		u16 i;
68 
69 		/* convert to host bitmap format */
70 		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
71 			arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
72 
73 		ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
74 
75 		/* check if DVM is supported */
76 		*dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
77 	}
78 
79 	ice_pkg_buf_free(hw, bld);
80 
81 	return status;
82 }
83 
84 /**
85  * ice_aq_get_vlan_mode - get the VLAN mode of the device
86  * @hw: pointer to the HW structure
87  * @get_params: structure FW fills in based on the current VLAN mode config
88  *
89  * Get VLAN Mode Parameters (0x020D)
90  */
91 static enum ice_status
92 ice_aq_get_vlan_mode(struct ice_hw *hw,
93 		     struct ice_aqc_get_vlan_mode *get_params)
94 {
95 	struct ice_aq_desc desc;
96 
97 	if (!get_params)
98 		return ICE_ERR_PARAM;
99 
100 	ice_fill_dflt_direct_cmd_desc(&desc,
101 				      ice_aqc_opc_get_vlan_mode_parameters);
102 
103 	return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params),
104 			       NULL);
105 }
106 
107 /**
108  * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled
109  * @hw: pointer to the HW structure
110  *
111  * Returns true if the hardware/firmware is configured in double VLAN mode,
112  * else return false signaling that the hardware/firmware is configured in
113  * single VLAN mode.
114  *
115  * Also, return false if this call fails for any reason (i.e. firmware doesn't
116  * support this AQ call).
117  */
118 static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
119 {
120 	struct ice_aqc_get_vlan_mode get_params = { 0 };
121 	enum ice_status status;
122 
123 	status = ice_aq_get_vlan_mode(hw, &get_params);
124 	if (status) {
125 		ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
126 			  status);
127 		return false;
128 	}
129 
130 	return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);
131 }
132 
133 /**
134  * ice_is_dvm_ena - check if double VLAN mode is enabled
135  * @hw: pointer to the HW structure
136  *
137  * The device is configured in single or double VLAN mode on initialization and
138  * this cannot be dynamically changed during runtime. Based on this there is no
139  * need to make an AQ call every time the driver needs to know the VLAN mode.
140  * Instead, use the cached VLAN mode.
141  */
142 bool ice_is_dvm_ena(struct ice_hw *hw)
143 {
144 	return hw->dvm_ena;
145 }
146 
147 /**
148  * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded
149  * @hw: pointer to the HW structure
150  *
151  * This is only called after downloading the DDP and after the global
152  * configuration lock has been released because all ports on a device need to
153  * cache the VLAN mode.
154  */
155 void ice_cache_vlan_mode(struct ice_hw *hw)
156 {
157 	hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
158 }
159 
160 /**
161  * ice_is_dvm_supported - check if Double VLAN Mode is supported
162  * @hw: pointer to the hardware structure
163  *
164  * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
165  * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
166  * firmware must support it, otherwise only SVM is supported. This function
167  * should only be called while the global config lock is held and after the
168  * package has been successfully downloaded.
169  */
170 static bool ice_is_dvm_supported(struct ice_hw *hw)
171 {
172 	struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
173 	enum ice_status status;
174 	bool pkg_supports_dvm;
175 
176 	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
177 	if (status) {
178 		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
179 			  status);
180 		return false;
181 	}
182 
183 	if (!pkg_supports_dvm)
184 		return false;
185 
186 	/* If firmware returns success, then it supports DVM, else it only
187 	 * supports SVM
188 	 */
189 	status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);
190 	if (status) {
191 		ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
192 			  status);
193 		return false;
194 	}
195 
196 	return true;
197 }
198 
199 /**
200  * ice_aq_set_vlan_mode - set the VLAN mode of the device
201  * @hw: pointer to the HW structure
202  * @set_params: requested VLAN mode configuration
203  *
204  * Set VLAN Mode Parameters (0x020C)
205  */
206 static enum ice_status
207 ice_aq_set_vlan_mode(struct ice_hw *hw,
208 		     struct ice_aqc_set_vlan_mode *set_params)
209 {
210 	u8 rdma_packet, mng_vlan_prot_id;
211 	struct ice_aq_desc desc;
212 
213 	if (!set_params)
214 		return ICE_ERR_PARAM;
215 
216 	if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
217 		return ICE_ERR_PARAM;
218 
219 	rdma_packet = set_params->rdma_packet;
220 	if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
221 	    rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
222 		return ICE_ERR_PARAM;
223 
224 	mng_vlan_prot_id = set_params->mng_vlan_prot_id;
225 	if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
226 	    mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
227 		return ICE_ERR_PARAM;
228 
229 	ice_fill_dflt_direct_cmd_desc(&desc,
230 				      ice_aqc_opc_set_vlan_mode_parameters);
231 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
232 
233 	return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),
234 			       NULL);
235 }
236 
237 /**
238  * ice_set_svm - set single VLAN mode
239  * @hw: pointer to the HW structure
240  */
241 static enum ice_status ice_set_svm(struct ice_hw *hw)
242 {
243 	struct ice_aqc_set_vlan_mode *set_params;
244 	enum ice_status status;
245 
246 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
247 	if (status) {
248 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
249 		return status;
250 	}
251 
252 	set_params = (struct ice_aqc_set_vlan_mode *)
253 		ice_malloc(hw, sizeof(*set_params));
254 	if (!set_params)
255 		return ICE_ERR_NO_MEMORY;
256 
257 	/* default configuration for SVM configurations */
258 	set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
259 	set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
260 	set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
261 
262 	status = ice_aq_set_vlan_mode(hw, set_params);
263 	if (status)
264 		ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
265 
266 	ice_free(hw, set_params);
267 	return status;
268 }
269 
270 /**
271  * ice_set_vlan_mode
272  * @hw: pointer to the HW structure
273  */
274 enum ice_status ice_set_vlan_mode(struct ice_hw *hw)
275 {
276 
277 	if (!ice_is_dvm_supported(hw))
278 		return ICE_SUCCESS;
279 
280 	return ice_set_svm(hw);
281 }
282