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