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_get_supported_vlan_mode - chk 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 **)§);
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 static 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_pkg_supports_dvm - find out if DDP supports DVM
162 * @hw: pointer to the HW structure
163 */
164 static bool ice_pkg_supports_dvm(struct ice_hw *hw)
165 {
166 enum ice_status status;
167 bool pkg_supports_dvm;
168
169 status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
170 if (status) {
171 ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
172 status);
173 return false;
174 }
175
176 return pkg_supports_dvm;
177 }
178
179 /**
180 * ice_fw_supports_dvm - find out if FW supports DVM
181 * @hw: pointer to the HW structure
182 */
183 static bool ice_fw_supports_dvm(struct ice_hw *hw)
184 {
185 struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
186 enum ice_status status;
187
188 /* If firmware returns success, then it supports DVM, else it only
189 * supports SVM
190 */
191 status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);
192 if (status) {
193 ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
194 status);
195 return false;
196 }
197
198 return true;
199 }
200
201 /**
202 * ice_is_dvm_supported - check if Double VLAN Mode is supported
203 * @hw: pointer to the hardware structure
204 *
205 * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
206 * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
207 * firmware must support it, otherwise only SVM is supported. This function
208 * should only be called while the global config lock is held and after the
209 * package has been successfully downloaded.
210 */
211 static bool ice_is_dvm_supported(struct ice_hw *hw)
212 {
213 if (!ice_pkg_supports_dvm(hw)) {
214 ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");
215 return false;
216 }
217
218 if (!ice_fw_supports_dvm(hw)) {
219 ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");
220 return false;
221 }
222
223 return true;
224 }
225
226 /**
227 * ice_aq_set_vlan_mode - set the VLAN mode of the device
228 * @hw: pointer to the HW structure
229 * @set_params: requested VLAN mode configuration
230 *
231 * Set VLAN Mode Parameters (0x020C)
232 */
233 static enum ice_status
234 ice_aq_set_vlan_mode(struct ice_hw *hw,
235 struct ice_aqc_set_vlan_mode *set_params)
236 {
237 u8 rdma_packet, mng_vlan_prot_id;
238 struct ice_aq_desc desc;
239
240 if (!set_params)
241 return ICE_ERR_PARAM;
242
243 if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
244 return ICE_ERR_PARAM;
245
246 rdma_packet = set_params->rdma_packet;
247 if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
248 rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
249 return ICE_ERR_PARAM;
250
251 mng_vlan_prot_id = set_params->mng_vlan_prot_id;
252 if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
253 mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
254 return ICE_ERR_PARAM;
255
256 ice_fill_dflt_direct_cmd_desc(&desc,
257 ice_aqc_opc_set_vlan_mode_parameters);
258 desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
259
260 return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),
261 NULL);
262 }
263
264 /**
265 * ice_set_svm - set single VLAN mode
266 * @hw: pointer to the HW structure
267 */
268 static enum ice_status ice_set_svm(struct ice_hw *hw)
269 {
270 struct ice_aqc_set_vlan_mode *set_params;
271 enum ice_status status;
272
273 status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
274 if (status) {
275 ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
276 return status;
277 }
278
279 set_params = (struct ice_aqc_set_vlan_mode *)
280 ice_malloc(hw, sizeof(*set_params));
281 if (!set_params)
282 return ICE_ERR_NO_MEMORY;
283
284 /* default configuration for SVM configurations */
285 set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
286 set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
287 set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
288
289 status = ice_aq_set_vlan_mode(hw, set_params);
290 if (status)
291 ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
292
293 ice_free(hw, set_params);
294 return status;
295 }
296
297 /**
298 * ice_set_vlan_mode
299 * @hw: pointer to the HW structure
300 */
301 enum ice_status ice_set_vlan_mode(struct ice_hw *hw)
302 {
303 if (!ice_is_dvm_supported(hw))
304 return ICE_SUCCESS;
305
306 return ice_set_svm(hw);
307 }
308
309 /**
310 * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download
311 * @hw: pointer to the HW structure
312 *
313 * This function is meant to configure any VLAN mode specific functionality
314 * after the global configuration lock has been released and the DDP has been
315 * downloaded.
316 *
317 * Since only one PF downloads the DDP and configures the VLAN mode there needs
318 * to be a way to configure the other PFs after the DDP has been downloaded and
319 * the global configuration lock has been released. All such code should go in
320 * this function.
321 */
322 void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)
323 {
324 ice_cache_vlan_mode(hw);
325 }
Cache object: b2c4d6c680651a804436fdf4c79b56b2
|