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