net/i40e: move private APIs to a specific file
[dpdk.git] / drivers / net / i40e / rte_pmd_i40e.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <rte_malloc.h>
35 #include <rte_tailq.h>
36
37 #include "base/i40e_prototype.h"
38 #include "i40e_ethdev.h"
39 #include "i40e_pf.h"
40 #include "rte_pmd_i40e.h"
41
42 /* The max bandwidth of i40e is 40Gbps. */
43 #define I40E_QOS_BW_MAX 40000
44 /* The bandwidth should be the multiple of 50Mbps. */
45 #define I40E_QOS_BW_GRANULARITY 50
46 /* The min bandwidth weight is 1. */
47 #define I40E_QOS_BW_WEIGHT_MIN 1
48 /* The max bandwidth weight is 127. */
49 #define I40E_QOS_BW_WEIGHT_MAX 127
50
51 int
52 rte_pmd_i40e_ping_vfs(uint8_t port, uint16_t vf)
53 {
54         struct rte_eth_dev *dev;
55         struct i40e_pf *pf;
56
57         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
58
59         dev = &rte_eth_devices[port];
60
61         if (!is_i40e_supported(dev))
62                 return -ENOTSUP;
63
64         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
65
66         if (vf >= pf->vf_num || !pf->vfs) {
67                 PMD_DRV_LOG(ERR, "Invalid argument.");
68                 return -EINVAL;
69         }
70
71         i40e_notify_vf_link_status(dev, &pf->vfs[vf]);
72
73         return 0;
74 }
75
76 int
77 rte_pmd_i40e_set_vf_mac_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on)
78 {
79         struct rte_eth_dev *dev;
80         struct i40e_pf *pf;
81         struct i40e_vsi *vsi;
82         struct i40e_hw *hw;
83         struct i40e_vsi_context ctxt;
84         int ret;
85
86         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
87
88         dev = &rte_eth_devices[port];
89
90         if (!is_i40e_supported(dev))
91                 return -ENOTSUP;
92
93         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
94
95         if (vf_id >= pf->vf_num || !pf->vfs) {
96                 PMD_DRV_LOG(ERR, "Invalid argument.");
97                 return -EINVAL;
98         }
99
100         vsi = pf->vfs[vf_id].vsi;
101         if (!vsi) {
102                 PMD_DRV_LOG(ERR, "Invalid VSI.");
103                 return -EINVAL;
104         }
105
106         /* Check if it has been already on or off */
107         if (vsi->info.valid_sections &
108                 rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SECURITY_VALID)) {
109                 if (on) {
110                         if ((vsi->info.sec_flags &
111                              I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) ==
112                             I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK)
113                                 return 0; /* already on */
114                 } else {
115                         if ((vsi->info.sec_flags &
116                              I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK) == 0)
117                                 return 0; /* already off */
118                 }
119         }
120
121         vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
122         if (on)
123                 vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
124         else
125                 vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK;
126
127         memset(&ctxt, 0, sizeof(ctxt));
128         (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
129         ctxt.seid = vsi->seid;
130
131         hw = I40E_VSI_TO_HW(vsi);
132         ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
133         if (ret != I40E_SUCCESS) {
134                 ret = -ENOTSUP;
135                 PMD_DRV_LOG(ERR, "Failed to update VSI params");
136         }
137
138         return ret;
139 }
140
141 static int
142 i40e_add_rm_all_vlan_filter(struct i40e_vsi *vsi, uint8_t add)
143 {
144         uint32_t j, k;
145         uint16_t vlan_id;
146         struct i40e_hw *hw = I40E_VSI_TO_HW(vsi);
147         struct i40e_aqc_add_remove_vlan_element_data vlan_data = {0};
148         int ret;
149
150         for (j = 0; j < I40E_VFTA_SIZE; j++) {
151                 if (!vsi->vfta[j])
152                         continue;
153
154                 for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) {
155                         if (!(vsi->vfta[j] & (1 << k)))
156                                 continue;
157
158                         vlan_id = j * I40E_UINT32_BIT_SIZE + k;
159                         if (!vlan_id)
160                                 continue;
161
162                         vlan_data.vlan_tag = rte_cpu_to_le_16(vlan_id);
163                         if (add)
164                                 ret = i40e_aq_add_vlan(hw, vsi->seid,
165                                                        &vlan_data, 1, NULL);
166                         else
167                                 ret = i40e_aq_remove_vlan(hw, vsi->seid,
168                                                           &vlan_data, 1, NULL);
169                         if (ret != I40E_SUCCESS) {
170                                 PMD_DRV_LOG(ERR,
171                                             "Failed to add/rm vlan filter");
172                                 return ret;
173                         }
174                 }
175         }
176
177         return I40E_SUCCESS;
178 }
179
180 int
181 rte_pmd_i40e_set_vf_vlan_anti_spoof(uint8_t port, uint16_t vf_id, uint8_t on)
182 {
183         struct rte_eth_dev *dev;
184         struct i40e_pf *pf;
185         struct i40e_vsi *vsi;
186         struct i40e_hw *hw;
187         struct i40e_vsi_context ctxt;
188         int ret;
189
190         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
191
192         dev = &rte_eth_devices[port];
193
194         if (!is_i40e_supported(dev))
195                 return -ENOTSUP;
196
197         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
198
199         if (vf_id >= pf->vf_num || !pf->vfs) {
200                 PMD_DRV_LOG(ERR, "Invalid argument.");
201                 return -EINVAL;
202         }
203
204         vsi = pf->vfs[vf_id].vsi;
205         if (!vsi) {
206                 PMD_DRV_LOG(ERR, "Invalid VSI.");
207                 return -EINVAL;
208         }
209
210         /* Check if it has been already on or off */
211         if (vsi->vlan_anti_spoof_on == on)
212                 return 0; /* already on or off */
213
214         vsi->vlan_anti_spoof_on = on;
215         if (!vsi->vlan_filter_on) {
216                 ret = i40e_add_rm_all_vlan_filter(vsi, on);
217                 if (ret) {
218                         PMD_DRV_LOG(ERR, "Failed to add/remove VLAN filters.");
219                         return -ENOTSUP;
220                 }
221         }
222
223         vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SECURITY_VALID);
224         if (on)
225                 vsi->info.sec_flags |= I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
226         else
227                 vsi->info.sec_flags &= ~I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK;
228
229         memset(&ctxt, 0, sizeof(ctxt));
230         (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
231         ctxt.seid = vsi->seid;
232
233         hw = I40E_VSI_TO_HW(vsi);
234         ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
235         if (ret != I40E_SUCCESS) {
236                 ret = -ENOTSUP;
237                 PMD_DRV_LOG(ERR, "Failed to update VSI params");
238         }
239
240         return ret;
241 }
242
243 static int
244 i40e_vsi_rm_mac_filter(struct i40e_vsi *vsi)
245 {
246         struct i40e_mac_filter *f;
247         struct i40e_macvlan_filter *mv_f;
248         int i, vlan_num;
249         enum rte_mac_filter_type filter_type;
250         int ret = I40E_SUCCESS;
251         void *temp;
252
253         /* remove all the MACs */
254         TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
255                 vlan_num = vsi->vlan_num;
256                 filter_type = f->mac_info.filter_type;
257                 if (filter_type == RTE_MACVLAN_PERFECT_MATCH ||
258                     filter_type == RTE_MACVLAN_HASH_MATCH) {
259                         if (vlan_num == 0) {
260                                 PMD_DRV_LOG(ERR, "VLAN number shouldn't be 0");
261                                 return I40E_ERR_PARAM;
262                         }
263                 } else if (filter_type == RTE_MAC_PERFECT_MATCH ||
264                            filter_type == RTE_MAC_HASH_MATCH)
265                         vlan_num = 1;
266
267                 mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0);
268                 if (!mv_f) {
269                         PMD_DRV_LOG(ERR, "failed to allocate memory");
270                         return I40E_ERR_NO_MEMORY;
271                 }
272
273                 for (i = 0; i < vlan_num; i++) {
274                         mv_f[i].filter_type = filter_type;
275                         (void)rte_memcpy(&mv_f[i].macaddr,
276                                          &f->mac_info.mac_addr,
277                                          ETH_ADDR_LEN);
278                 }
279                 if (filter_type == RTE_MACVLAN_PERFECT_MATCH ||
280                     filter_type == RTE_MACVLAN_HASH_MATCH) {
281                         ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num,
282                                                          &f->mac_info.mac_addr);
283                         if (ret != I40E_SUCCESS) {
284                                 rte_free(mv_f);
285                                 return ret;
286                         }
287                 }
288
289                 ret = i40e_remove_macvlan_filters(vsi, mv_f, vlan_num);
290                 if (ret != I40E_SUCCESS) {
291                         rte_free(mv_f);
292                         return ret;
293                 }
294
295                 rte_free(mv_f);
296                 ret = I40E_SUCCESS;
297         }
298
299         return ret;
300 }
301
302 static int
303 i40e_vsi_restore_mac_filter(struct i40e_vsi *vsi)
304 {
305         struct i40e_mac_filter *f;
306         struct i40e_macvlan_filter *mv_f;
307         int i, vlan_num = 0;
308         int ret = I40E_SUCCESS;
309         void *temp;
310
311         /* restore all the MACs */
312         TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp) {
313                 if ((f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH) ||
314                     (f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH)) {
315                         /**
316                          * If vlan_num is 0, that's the first time to add mac,
317                          * set mask for vlan_id 0.
318                          */
319                         if (vsi->vlan_num == 0) {
320                                 i40e_set_vlan_filter(vsi, 0, 1);
321                                 vsi->vlan_num = 1;
322                         }
323                         vlan_num = vsi->vlan_num;
324                 } else if ((f->mac_info.filter_type == RTE_MAC_PERFECT_MATCH) ||
325                            (f->mac_info.filter_type == RTE_MAC_HASH_MATCH))
326                         vlan_num = 1;
327
328                 mv_f = rte_zmalloc("macvlan_data", vlan_num * sizeof(*mv_f), 0);
329                 if (!mv_f) {
330                         PMD_DRV_LOG(ERR, "failed to allocate memory");
331                         return I40E_ERR_NO_MEMORY;
332                 }
333
334                 for (i = 0; i < vlan_num; i++) {
335                         mv_f[i].filter_type = f->mac_info.filter_type;
336                         (void)rte_memcpy(&mv_f[i].macaddr,
337                                          &f->mac_info.mac_addr,
338                                          ETH_ADDR_LEN);
339                 }
340
341                 if (f->mac_info.filter_type == RTE_MACVLAN_PERFECT_MATCH ||
342                     f->mac_info.filter_type == RTE_MACVLAN_HASH_MATCH) {
343                         ret = i40e_find_all_vlan_for_mac(vsi, mv_f, vlan_num,
344                                                          &f->mac_info.mac_addr);
345                         if (ret != I40E_SUCCESS) {
346                                 rte_free(mv_f);
347                                 return ret;
348                         }
349                 }
350
351                 ret = i40e_add_macvlan_filters(vsi, mv_f, vlan_num);
352                 if (ret != I40E_SUCCESS) {
353                         rte_free(mv_f);
354                         return ret;
355                 }
356
357                 rte_free(mv_f);
358                 ret = I40E_SUCCESS;
359         }
360
361         return ret;
362 }
363
364 static int
365 i40e_vsi_set_tx_loopback(struct i40e_vsi *vsi, uint8_t on)
366 {
367         struct i40e_vsi_context ctxt;
368         struct i40e_hw *hw;
369         int ret;
370
371         if (!vsi)
372                 return -EINVAL;
373
374         hw = I40E_VSI_TO_HW(vsi);
375
376         /* Use the FW API if FW >= v5.0 */
377         if (hw->aq.fw_maj_ver < 5) {
378                 PMD_INIT_LOG(ERR, "FW < v5.0, cannot enable loopback");
379                 return -ENOTSUP;
380         }
381
382         /* Check if it has been already on or off */
383         if (vsi->info.valid_sections &
384                 rte_cpu_to_le_16(I40E_AQ_VSI_PROP_SWITCH_VALID)) {
385                 if (on) {
386                         if ((vsi->info.switch_id &
387                              I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) ==
388                             I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB)
389                                 return 0; /* already on */
390                 } else {
391                         if ((vsi->info.switch_id &
392                              I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB) == 0)
393                                 return 0; /* already off */
394                 }
395         }
396
397         /* remove all the MAC and VLAN first */
398         ret = i40e_vsi_rm_mac_filter(vsi);
399         if (ret) {
400                 PMD_INIT_LOG(ERR, "Failed to remove MAC filters.");
401                 return ret;
402         }
403         if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) {
404                 ret = i40e_add_rm_all_vlan_filter(vsi, 0);
405                 if (ret) {
406                         PMD_INIT_LOG(ERR, "Failed to remove VLAN filters.");
407                         return ret;
408                 }
409         }
410
411         vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
412         if (on)
413                 vsi->info.switch_id |= I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB;
414         else
415                 vsi->info.switch_id &= ~I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB;
416
417         memset(&ctxt, 0, sizeof(ctxt));
418         (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
419         ctxt.seid = vsi->seid;
420
421         ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
422         if (ret != I40E_SUCCESS) {
423                 PMD_DRV_LOG(ERR, "Failed to update VSI params");
424                 return ret;
425         }
426
427         /* add all the MAC and VLAN back */
428         ret = i40e_vsi_restore_mac_filter(vsi);
429         if (ret)
430                 return ret;
431         if (vsi->vlan_anti_spoof_on || vsi->vlan_filter_on) {
432                 ret = i40e_add_rm_all_vlan_filter(vsi, 1);
433                 if (ret)
434                         return ret;
435         }
436
437         return ret;
438 }
439
440 int
441 rte_pmd_i40e_set_tx_loopback(uint8_t port, uint8_t on)
442 {
443         struct rte_eth_dev *dev;
444         struct i40e_pf *pf;
445         struct i40e_pf_vf *vf;
446         struct i40e_vsi *vsi;
447         uint16_t vf_id;
448         int ret;
449
450         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
451
452         dev = &rte_eth_devices[port];
453
454         if (!is_i40e_supported(dev))
455                 return -ENOTSUP;
456
457         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
458
459         /* setup PF TX loopback */
460         vsi = pf->main_vsi;
461         ret = i40e_vsi_set_tx_loopback(vsi, on);
462         if (ret)
463                 return -ENOTSUP;
464
465         /* setup TX loopback for all the VFs */
466         if (!pf->vfs) {
467                 /* if no VF, do nothing. */
468                 return 0;
469         }
470
471         for (vf_id = 0; vf_id < pf->vf_num; vf_id++) {
472                 vf = &pf->vfs[vf_id];
473                 vsi = vf->vsi;
474
475                 ret = i40e_vsi_set_tx_loopback(vsi, on);
476                 if (ret)
477                         return -ENOTSUP;
478         }
479
480         return ret;
481 }
482
483 int
484 rte_pmd_i40e_set_vf_unicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on)
485 {
486         struct rte_eth_dev *dev;
487         struct i40e_pf *pf;
488         struct i40e_vsi *vsi;
489         struct i40e_hw *hw;
490         int ret;
491
492         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
493
494         dev = &rte_eth_devices[port];
495
496         if (!is_i40e_supported(dev))
497                 return -ENOTSUP;
498
499         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
500
501         if (vf_id >= pf->vf_num || !pf->vfs) {
502                 PMD_DRV_LOG(ERR, "Invalid argument.");
503                 return -EINVAL;
504         }
505
506         vsi = pf->vfs[vf_id].vsi;
507         if (!vsi) {
508                 PMD_DRV_LOG(ERR, "Invalid VSI.");
509                 return -EINVAL;
510         }
511
512         hw = I40E_VSI_TO_HW(vsi);
513
514         ret = i40e_aq_set_vsi_unicast_promiscuous(hw, vsi->seid,
515                                                   on, NULL, true);
516         if (ret != I40E_SUCCESS) {
517                 ret = -ENOTSUP;
518                 PMD_DRV_LOG(ERR, "Failed to set unicast promiscuous mode");
519         }
520
521         return ret;
522 }
523
524 int
525 rte_pmd_i40e_set_vf_multicast_promisc(uint8_t port, uint16_t vf_id, uint8_t on)
526 {
527         struct rte_eth_dev *dev;
528         struct i40e_pf *pf;
529         struct i40e_vsi *vsi;
530         struct i40e_hw *hw;
531         int ret;
532
533         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
534
535         dev = &rte_eth_devices[port];
536
537         if (!is_i40e_supported(dev))
538                 return -ENOTSUP;
539
540         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
541
542         if (vf_id >= pf->vf_num || !pf->vfs) {
543                 PMD_DRV_LOG(ERR, "Invalid argument.");
544                 return -EINVAL;
545         }
546
547         vsi = pf->vfs[vf_id].vsi;
548         if (!vsi) {
549                 PMD_DRV_LOG(ERR, "Invalid VSI.");
550                 return -EINVAL;
551         }
552
553         hw = I40E_VSI_TO_HW(vsi);
554
555         ret = i40e_aq_set_vsi_multicast_promiscuous(hw, vsi->seid,
556                                                     on, NULL);
557         if (ret != I40E_SUCCESS) {
558                 ret = -ENOTSUP;
559                 PMD_DRV_LOG(ERR, "Failed to set multicast promiscuous mode");
560         }
561
562         return ret;
563 }
564
565 int
566 rte_pmd_i40e_set_vf_mac_addr(uint8_t port, uint16_t vf_id,
567                              struct ether_addr *mac_addr)
568 {
569         struct i40e_mac_filter *f;
570         struct rte_eth_dev *dev;
571         struct i40e_pf_vf *vf;
572         struct i40e_vsi *vsi;
573         struct i40e_pf *pf;
574         void *temp;
575
576         if (i40e_validate_mac_addr((u8 *)mac_addr) != I40E_SUCCESS)
577                 return -EINVAL;
578
579         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
580
581         dev = &rte_eth_devices[port];
582
583         if (!is_i40e_supported(dev))
584                 return -ENOTSUP;
585
586         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
587
588         if (vf_id >= pf->vf_num || !pf->vfs)
589                 return -EINVAL;
590
591         vf = &pf->vfs[vf_id];
592         vsi = vf->vsi;
593         if (!vsi) {
594                 PMD_DRV_LOG(ERR, "Invalid VSI.");
595                 return -EINVAL;
596         }
597
598         ether_addr_copy(mac_addr, &vf->mac_addr);
599
600         /* Remove all existing mac */
601         TAILQ_FOREACH_SAFE(f, &vsi->mac_list, next, temp)
602                 i40e_vsi_delete_mac(vsi, &f->mac_info.mac_addr);
603
604         return 0;
605 }
606
607 /* Set vlan strip on/off for specific VF from host */
608 int
609 rte_pmd_i40e_set_vf_vlan_stripq(uint8_t port, uint16_t vf_id, uint8_t on)
610 {
611         struct rte_eth_dev *dev;
612         struct i40e_pf *pf;
613         struct i40e_vsi *vsi;
614         int ret;
615
616         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
617
618         dev = &rte_eth_devices[port];
619
620         if (!is_i40e_supported(dev))
621                 return -ENOTSUP;
622
623         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
624
625         if (vf_id >= pf->vf_num || !pf->vfs) {
626                 PMD_DRV_LOG(ERR, "Invalid argument.");
627                 return -EINVAL;
628         }
629
630         vsi = pf->vfs[vf_id].vsi;
631
632         if (!vsi)
633                 return -EINVAL;
634
635         ret = i40e_vsi_config_vlan_stripping(vsi, !!on);
636         if (ret != I40E_SUCCESS) {
637                 ret = -ENOTSUP;
638                 PMD_DRV_LOG(ERR, "Failed to set VLAN stripping!");
639         }
640
641         return ret;
642 }
643
644 int rte_pmd_i40e_set_vf_vlan_insert(uint8_t port, uint16_t vf_id,
645                                     uint16_t vlan_id)
646 {
647         struct rte_eth_dev *dev;
648         struct i40e_pf *pf;
649         struct i40e_hw *hw;
650         struct i40e_vsi *vsi;
651         struct i40e_vsi_context ctxt;
652         int ret;
653
654         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
655
656         if (vlan_id > ETHER_MAX_VLAN_ID) {
657                 PMD_DRV_LOG(ERR, "Invalid VLAN ID.");
658                 return -EINVAL;
659         }
660
661         dev = &rte_eth_devices[port];
662
663         if (!is_i40e_supported(dev))
664                 return -ENOTSUP;
665
666         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
667         hw = I40E_PF_TO_HW(pf);
668
669         /**
670          * return -ENODEV if SRIOV not enabled, VF number not configured
671          * or no queue assigned.
672          */
673         if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
674             pf->vf_nb_qps == 0)
675                 return -ENODEV;
676
677         if (vf_id >= pf->vf_num || !pf->vfs) {
678                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
679                 return -EINVAL;
680         }
681
682         vsi = pf->vfs[vf_id].vsi;
683         if (!vsi) {
684                 PMD_DRV_LOG(ERR, "Invalid VSI.");
685                 return -EINVAL;
686         }
687
688         vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
689         vsi->info.pvid = vlan_id;
690         if (vlan_id > 0)
691                 vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID;
692         else
693                 vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_INSERT_PVID;
694
695         memset(&ctxt, 0, sizeof(ctxt));
696         (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
697         ctxt.seid = vsi->seid;
698
699         hw = I40E_VSI_TO_HW(vsi);
700         ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
701         if (ret != I40E_SUCCESS) {
702                 ret = -ENOTSUP;
703                 PMD_DRV_LOG(ERR, "Failed to update VSI params");
704         }
705
706         return ret;
707 }
708
709 int rte_pmd_i40e_set_vf_broadcast(uint8_t port, uint16_t vf_id,
710                                   uint8_t on)
711 {
712         struct rte_eth_dev *dev;
713         struct i40e_pf *pf;
714         struct i40e_vsi *vsi;
715         struct i40e_hw *hw;
716         struct i40e_mac_filter_info filter;
717         struct ether_addr broadcast = {
718                 .addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
719         int ret;
720
721         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
722
723         if (on > 1) {
724                 PMD_DRV_LOG(ERR, "on should be 0 or 1.");
725                 return -EINVAL;
726         }
727
728         dev = &rte_eth_devices[port];
729
730         if (!is_i40e_supported(dev))
731                 return -ENOTSUP;
732
733         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
734         hw = I40E_PF_TO_HW(pf);
735
736         if (vf_id >= pf->vf_num || !pf->vfs) {
737                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
738                 return -EINVAL;
739         }
740
741         /**
742          * return -ENODEV if SRIOV not enabled, VF number not configured
743          * or no queue assigned.
744          */
745         if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
746             pf->vf_nb_qps == 0) {
747                 PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue.");
748                 return -ENODEV;
749         }
750
751         vsi = pf->vfs[vf_id].vsi;
752         if (!vsi) {
753                 PMD_DRV_LOG(ERR, "Invalid VSI.");
754                 return -EINVAL;
755         }
756
757         if (on) {
758                 (void)rte_memcpy(&filter.mac_addr, &broadcast, ETHER_ADDR_LEN);
759                 filter.filter_type = RTE_MACVLAN_PERFECT_MATCH;
760                 ret = i40e_vsi_add_mac(vsi, &filter);
761         } else {
762                 ret = i40e_vsi_delete_mac(vsi, &broadcast);
763         }
764
765         if (ret != I40E_SUCCESS && ret != I40E_ERR_PARAM) {
766                 ret = -ENOTSUP;
767                 PMD_DRV_LOG(ERR, "Failed to set VSI broadcast");
768         } else {
769                 ret = 0;
770         }
771
772         return ret;
773 }
774
775 int rte_pmd_i40e_set_vf_vlan_tag(uint8_t port, uint16_t vf_id, uint8_t on)
776 {
777         struct rte_eth_dev *dev;
778         struct i40e_pf *pf;
779         struct i40e_hw *hw;
780         struct i40e_vsi *vsi;
781         struct i40e_vsi_context ctxt;
782         int ret;
783
784         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
785
786         if (on > 1) {
787                 PMD_DRV_LOG(ERR, "on should be 0 or 1.");
788                 return -EINVAL;
789         }
790
791         dev = &rte_eth_devices[port];
792
793         if (!is_i40e_supported(dev))
794                 return -ENOTSUP;
795
796         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
797         hw = I40E_PF_TO_HW(pf);
798
799         /**
800          * return -ENODEV if SRIOV not enabled, VF number not configured
801          * or no queue assigned.
802          */
803         if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
804             pf->vf_nb_qps == 0) {
805                 PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue.");
806                 return -ENODEV;
807         }
808
809         if (vf_id >= pf->vf_num || !pf->vfs) {
810                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
811                 return -EINVAL;
812         }
813
814         vsi = pf->vfs[vf_id].vsi;
815         if (!vsi) {
816                 PMD_DRV_LOG(ERR, "Invalid VSI.");
817                 return -EINVAL;
818         }
819
820         vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
821         if (on) {
822                 vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_TAGGED;
823                 vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
824         } else {
825                 vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
826                 vsi->info.port_vlan_flags &= ~I40E_AQ_VSI_PVLAN_MODE_TAGGED;
827         }
828
829         memset(&ctxt, 0, sizeof(ctxt));
830         (void)rte_memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
831         ctxt.seid = vsi->seid;
832
833         hw = I40E_VSI_TO_HW(vsi);
834         ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
835         if (ret != I40E_SUCCESS) {
836                 ret = -ENOTSUP;
837                 PMD_DRV_LOG(ERR, "Failed to update VSI params");
838         }
839
840         return ret;
841 }
842
843 static int
844 i40e_vlan_filter_count(struct i40e_vsi *vsi)
845 {
846         uint32_t j, k;
847         uint16_t vlan_id;
848         int count = 0;
849
850         for (j = 0; j < I40E_VFTA_SIZE; j++) {
851                 if (!vsi->vfta[j])
852                         continue;
853
854                 for (k = 0; k < I40E_UINT32_BIT_SIZE; k++) {
855                         if (!(vsi->vfta[j] & (1 << k)))
856                                 continue;
857
858                         vlan_id = j * I40E_UINT32_BIT_SIZE + k;
859                         if (!vlan_id)
860                                 continue;
861
862                         count++;
863                 }
864         }
865
866         return count;
867 }
868
869 int rte_pmd_i40e_set_vf_vlan_filter(uint8_t port, uint16_t vlan_id,
870                                     uint64_t vf_mask, uint8_t on)
871 {
872         struct rte_eth_dev *dev;
873         struct i40e_pf *pf;
874         struct i40e_hw *hw;
875         struct i40e_vsi *vsi;
876         uint16_t vf_idx;
877         int ret = I40E_SUCCESS;
878
879         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
880
881         dev = &rte_eth_devices[port];
882
883         if (!is_i40e_supported(dev))
884                 return -ENOTSUP;
885
886         if (vlan_id > ETHER_MAX_VLAN_ID || !vlan_id) {
887                 PMD_DRV_LOG(ERR, "Invalid VLAN ID.");
888                 return -EINVAL;
889         }
890
891         if (vf_mask == 0) {
892                 PMD_DRV_LOG(ERR, "No VF.");
893                 return -EINVAL;
894         }
895
896         if (on > 1) {
897                 PMD_DRV_LOG(ERR, "on is should be 0 or 1.");
898                 return -EINVAL;
899         }
900
901         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
902         hw = I40E_PF_TO_HW(pf);
903
904         /**
905          * return -ENODEV if SRIOV not enabled, VF number not configured
906          * or no queue assigned.
907          */
908         if (!hw->func_caps.sr_iov_1_1 || pf->vf_num == 0 ||
909             pf->vf_nb_qps == 0) {
910                 PMD_DRV_LOG(ERR, "SRIOV is not enabled or no queue.");
911                 return -ENODEV;
912         }
913
914         for (vf_idx = 0; vf_idx < pf->vf_num && ret == I40E_SUCCESS; vf_idx++) {
915                 if (vf_mask & ((uint64_t)(1ULL << vf_idx))) {
916                         vsi = pf->vfs[vf_idx].vsi;
917                         if (on) {
918                                 if (!vsi->vlan_filter_on) {
919                                         vsi->vlan_filter_on = true;
920                                         i40e_aq_set_vsi_vlan_promisc(hw,
921                                                                      vsi->seid,
922                                                                      false,
923                                                                      NULL);
924                                         if (!vsi->vlan_anti_spoof_on)
925                                                 i40e_add_rm_all_vlan_filter(
926                                                         vsi, true);
927                                 }
928                                 ret = i40e_vsi_add_vlan(vsi, vlan_id);
929                         } else {
930                                 ret = i40e_vsi_delete_vlan(vsi, vlan_id);
931
932                                 if (!i40e_vlan_filter_count(vsi)) {
933                                         vsi->vlan_filter_on = false;
934                                         i40e_aq_set_vsi_vlan_promisc(hw,
935                                                                      vsi->seid,
936                                                                      true,
937                                                                      NULL);
938                                 }
939                         }
940                 }
941         }
942
943         if (ret != I40E_SUCCESS) {
944                 ret = -ENOTSUP;
945                 PMD_DRV_LOG(ERR, "Failed to set VF VLAN filter, on = %d", on);
946         }
947
948         return ret;
949 }
950
951 int
952 rte_pmd_i40e_get_vf_stats(uint8_t port,
953                           uint16_t vf_id,
954                           struct rte_eth_stats *stats)
955 {
956         struct rte_eth_dev *dev;
957         struct i40e_pf *pf;
958         struct i40e_vsi *vsi;
959
960         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
961
962         dev = &rte_eth_devices[port];
963
964         if (!is_i40e_supported(dev))
965                 return -ENOTSUP;
966
967         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
968
969         if (vf_id >= pf->vf_num || !pf->vfs) {
970                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
971                 return -EINVAL;
972         }
973
974         vsi = pf->vfs[vf_id].vsi;
975         if (!vsi) {
976                 PMD_DRV_LOG(ERR, "Invalid VSI.");
977                 return -EINVAL;
978         }
979
980         i40e_update_vsi_stats(vsi);
981
982         stats->ipackets = vsi->eth_stats.rx_unicast +
983                         vsi->eth_stats.rx_multicast +
984                         vsi->eth_stats.rx_broadcast;
985         stats->opackets = vsi->eth_stats.tx_unicast +
986                         vsi->eth_stats.tx_multicast +
987                         vsi->eth_stats.tx_broadcast;
988         stats->ibytes   = vsi->eth_stats.rx_bytes;
989         stats->obytes   = vsi->eth_stats.tx_bytes;
990         stats->ierrors  = vsi->eth_stats.rx_discards;
991         stats->oerrors  = vsi->eth_stats.tx_errors + vsi->eth_stats.tx_discards;
992
993         return 0;
994 }
995
996 int
997 rte_pmd_i40e_reset_vf_stats(uint8_t port,
998                             uint16_t vf_id)
999 {
1000         struct rte_eth_dev *dev;
1001         struct i40e_pf *pf;
1002         struct i40e_vsi *vsi;
1003
1004         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1005
1006         dev = &rte_eth_devices[port];
1007
1008         if (!is_i40e_supported(dev))
1009                 return -ENOTSUP;
1010
1011         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
1012
1013         if (vf_id >= pf->vf_num || !pf->vfs) {
1014                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
1015                 return -EINVAL;
1016         }
1017
1018         vsi = pf->vfs[vf_id].vsi;
1019         if (!vsi) {
1020                 PMD_DRV_LOG(ERR, "Invalid VSI.");
1021                 return -EINVAL;
1022         }
1023
1024         vsi->offset_loaded = false;
1025         i40e_update_vsi_stats(vsi);
1026
1027         return 0;
1028 }
1029
1030 int
1031 rte_pmd_i40e_set_vf_max_bw(uint8_t port, uint16_t vf_id, uint32_t bw)
1032 {
1033         struct rte_eth_dev *dev;
1034         struct i40e_pf *pf;
1035         struct i40e_vsi *vsi;
1036         struct i40e_hw *hw;
1037         int ret = 0;
1038         int i;
1039
1040         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1041
1042         dev = &rte_eth_devices[port];
1043
1044         if (!is_i40e_supported(dev))
1045                 return -ENOTSUP;
1046
1047         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
1048
1049         if (vf_id >= pf->vf_num || !pf->vfs) {
1050                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
1051                 return -EINVAL;
1052         }
1053
1054         vsi = pf->vfs[vf_id].vsi;
1055         if (!vsi) {
1056                 PMD_DRV_LOG(ERR, "Invalid VSI.");
1057                 return -EINVAL;
1058         }
1059
1060         if (bw > I40E_QOS_BW_MAX) {
1061                 PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.",
1062                             I40E_QOS_BW_MAX);
1063                 return -EINVAL;
1064         }
1065
1066         if (bw % I40E_QOS_BW_GRANULARITY) {
1067                 PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.",
1068                             I40E_QOS_BW_GRANULARITY);
1069                 return -EINVAL;
1070         }
1071
1072         bw /= I40E_QOS_BW_GRANULARITY;
1073
1074         hw = I40E_VSI_TO_HW(vsi);
1075
1076         /* No change. */
1077         if (bw == vsi->bw_info.bw_limit) {
1078                 PMD_DRV_LOG(INFO,
1079                             "No change for VF max bandwidth. Nothing to do.");
1080                 return 0;
1081         }
1082
1083         /**
1084          * VF bandwidth limitation and TC bandwidth limitation cannot be
1085          * enabled in parallel, quit if TC bandwidth limitation is enabled.
1086          *
1087          * If bw is 0, means disable bandwidth limitation. Then no need to
1088          * check TC bandwidth limitation.
1089          */
1090         if (bw) {
1091                 for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
1092                         if ((vsi->enabled_tc & BIT_ULL(i)) &&
1093                             vsi->bw_info.bw_ets_credits[i])
1094                                 break;
1095                 }
1096                 if (i != I40E_MAX_TRAFFIC_CLASS) {
1097                         PMD_DRV_LOG(ERR,
1098                                     "TC max bandwidth has been set on this VF,"
1099                                     " please disable it first.");
1100                         return -EINVAL;
1101                 }
1102         }
1103
1104         ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, (uint16_t)bw, 0, NULL);
1105         if (ret) {
1106                 PMD_DRV_LOG(ERR,
1107                             "Failed to set VF %d bandwidth, err(%d).",
1108                             vf_id, ret);
1109                 return -EINVAL;
1110         }
1111
1112         /* Store the configuration. */
1113         vsi->bw_info.bw_limit = (uint16_t)bw;
1114         vsi->bw_info.bw_max = 0;
1115
1116         return 0;
1117 }
1118
1119 int
1120 rte_pmd_i40e_set_vf_tc_bw_alloc(uint8_t port, uint16_t vf_id,
1121                                 uint8_t tc_num, uint8_t *bw_weight)
1122 {
1123         struct rte_eth_dev *dev;
1124         struct i40e_pf *pf;
1125         struct i40e_vsi *vsi;
1126         struct i40e_hw *hw;
1127         struct i40e_aqc_configure_vsi_tc_bw_data tc_bw;
1128         int ret = 0;
1129         int i, j;
1130         uint16_t sum;
1131         bool b_change = false;
1132
1133         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1134
1135         dev = &rte_eth_devices[port];
1136
1137         if (!is_i40e_supported(dev))
1138                 return -ENOTSUP;
1139
1140         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
1141
1142         if (vf_id >= pf->vf_num || !pf->vfs) {
1143                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
1144                 return -EINVAL;
1145         }
1146
1147         vsi = pf->vfs[vf_id].vsi;
1148         if (!vsi) {
1149                 PMD_DRV_LOG(ERR, "Invalid VSI.");
1150                 return -EINVAL;
1151         }
1152
1153         if (tc_num > I40E_MAX_TRAFFIC_CLASS) {
1154                 PMD_DRV_LOG(ERR, "TCs should be no more than %d.",
1155                             I40E_MAX_TRAFFIC_CLASS);
1156                 return -EINVAL;
1157         }
1158
1159         sum = 0;
1160         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
1161                 if (vsi->enabled_tc & BIT_ULL(i))
1162                         sum++;
1163         }
1164         if (sum != tc_num) {
1165                 PMD_DRV_LOG(ERR,
1166                             "Weight should be set for all %d enabled TCs.",
1167                             sum);
1168                 return -EINVAL;
1169         }
1170
1171         sum = 0;
1172         for (i = 0; i < tc_num; i++) {
1173                 if (!bw_weight[i]) {
1174                         PMD_DRV_LOG(ERR,
1175                                     "The weight should be 1 at least.");
1176                         return -EINVAL;
1177                 }
1178                 sum += bw_weight[i];
1179         }
1180         if (sum != 100) {
1181                 PMD_DRV_LOG(ERR,
1182                             "The summary of the TC weight should be 100.");
1183                 return -EINVAL;
1184         }
1185
1186         /**
1187          * Create the configuration for all the TCs.
1188          */
1189         memset(&tc_bw, 0, sizeof(tc_bw));
1190         tc_bw.tc_valid_bits = vsi->enabled_tc;
1191         j = 0;
1192         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
1193                 if (vsi->enabled_tc & BIT_ULL(i)) {
1194                         if (bw_weight[j] !=
1195                                 vsi->bw_info.bw_ets_share_credits[i])
1196                                 b_change = true;
1197
1198                         tc_bw.tc_bw_credits[i] = bw_weight[j];
1199                         j++;
1200                 }
1201         }
1202
1203         /* No change. */
1204         if (!b_change) {
1205                 PMD_DRV_LOG(INFO,
1206                             "No change for TC allocated bandwidth."
1207                             " Nothing to do.");
1208                 return 0;
1209         }
1210
1211         hw = I40E_VSI_TO_HW(vsi);
1212
1213         ret = i40e_aq_config_vsi_tc_bw(hw, vsi->seid, &tc_bw, NULL);
1214         if (ret) {
1215                 PMD_DRV_LOG(ERR,
1216                             "Failed to set VF %d TC bandwidth weight, err(%d).",
1217                             vf_id, ret);
1218                 return -EINVAL;
1219         }
1220
1221         /* Store the configuration. */
1222         j = 0;
1223         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
1224                 if (vsi->enabled_tc & BIT_ULL(i)) {
1225                         vsi->bw_info.bw_ets_share_credits[i] = bw_weight[j];
1226                         j++;
1227                 }
1228         }
1229
1230         return 0;
1231 }
1232
1233 int
1234 rte_pmd_i40e_set_vf_tc_max_bw(uint8_t port, uint16_t vf_id,
1235                               uint8_t tc_no, uint32_t bw)
1236 {
1237         struct rte_eth_dev *dev;
1238         struct i40e_pf *pf;
1239         struct i40e_vsi *vsi;
1240         struct i40e_hw *hw;
1241         struct i40e_aqc_configure_vsi_ets_sla_bw_data tc_bw;
1242         int ret = 0;
1243         int i;
1244
1245         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1246
1247         dev = &rte_eth_devices[port];
1248
1249         if (!is_i40e_supported(dev))
1250                 return -ENOTSUP;
1251
1252         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
1253
1254         if (vf_id >= pf->vf_num || !pf->vfs) {
1255                 PMD_DRV_LOG(ERR, "Invalid VF ID.");
1256                 return -EINVAL;
1257         }
1258
1259         vsi = pf->vfs[vf_id].vsi;
1260         if (!vsi) {
1261                 PMD_DRV_LOG(ERR, "Invalid VSI.");
1262                 return -EINVAL;
1263         }
1264
1265         if (bw > I40E_QOS_BW_MAX) {
1266                 PMD_DRV_LOG(ERR, "Bandwidth should not be larger than %dMbps.",
1267                             I40E_QOS_BW_MAX);
1268                 return -EINVAL;
1269         }
1270
1271         if (bw % I40E_QOS_BW_GRANULARITY) {
1272                 PMD_DRV_LOG(ERR, "Bandwidth should be the multiple of %dMbps.",
1273                             I40E_QOS_BW_GRANULARITY);
1274                 return -EINVAL;
1275         }
1276
1277         bw /= I40E_QOS_BW_GRANULARITY;
1278
1279         if (tc_no >= I40E_MAX_TRAFFIC_CLASS) {
1280                 PMD_DRV_LOG(ERR, "TC No. should be less than %d.",
1281                             I40E_MAX_TRAFFIC_CLASS);
1282                 return -EINVAL;
1283         }
1284
1285         hw = I40E_VSI_TO_HW(vsi);
1286
1287         if (!(vsi->enabled_tc & BIT_ULL(tc_no))) {
1288                 PMD_DRV_LOG(ERR, "VF %d TC %d isn't enabled.",
1289                             vf_id, tc_no);
1290                 return -EINVAL;
1291         }
1292
1293         /* No change. */
1294         if (bw == vsi->bw_info.bw_ets_credits[tc_no]) {
1295                 PMD_DRV_LOG(INFO,
1296                             "No change for TC max bandwidth. Nothing to do.");
1297                 return 0;
1298         }
1299
1300         /**
1301          * VF bandwidth limitation and TC bandwidth limitation cannot be
1302          * enabled in parallel, disable VF bandwidth limitation if it's
1303          * enabled.
1304          * If bw is 0, means disable bandwidth limitation. Then no need to
1305          * care about VF bandwidth limitation configuration.
1306          */
1307         if (bw && vsi->bw_info.bw_limit) {
1308                 ret = i40e_aq_config_vsi_bw_limit(hw, vsi->seid, 0, 0, NULL);
1309                 if (ret) {
1310                         PMD_DRV_LOG(ERR,
1311                                     "Failed to disable VF(%d)"
1312                                     " bandwidth limitation, err(%d).",
1313                                     vf_id, ret);
1314                         return -EINVAL;
1315                 }
1316
1317                 PMD_DRV_LOG(INFO,
1318                             "VF max bandwidth is disabled according"
1319                             " to TC max bandwidth setting.");
1320         }
1321
1322         /**
1323          * Get all the TCs' info to create a whole picture.
1324          * Because the incremental change isn't permitted.
1325          */
1326         memset(&tc_bw, 0, sizeof(tc_bw));
1327         tc_bw.tc_valid_bits = vsi->enabled_tc;
1328         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
1329                 if (vsi->enabled_tc & BIT_ULL(i)) {
1330                         tc_bw.tc_bw_credits[i] =
1331                                 rte_cpu_to_le_16(
1332                                         vsi->bw_info.bw_ets_credits[i]);
1333                 }
1334         }
1335         tc_bw.tc_bw_credits[tc_no] = rte_cpu_to_le_16((uint16_t)bw);
1336
1337         ret = i40e_aq_config_vsi_ets_sla_bw_limit(hw, vsi->seid, &tc_bw, NULL);
1338         if (ret) {
1339                 PMD_DRV_LOG(ERR,
1340                             "Failed to set VF %d TC %d max bandwidth, err(%d).",
1341                             vf_id, tc_no, ret);
1342                 return -EINVAL;
1343         }
1344
1345         /* Store the configuration. */
1346         vsi->bw_info.bw_ets_credits[tc_no] = (uint16_t)bw;
1347
1348         return 0;
1349 }
1350
1351 int
1352 rte_pmd_i40e_set_tc_strict_prio(uint8_t port, uint8_t tc_map)
1353 {
1354         struct rte_eth_dev *dev;
1355         struct i40e_pf *pf;
1356         struct i40e_vsi *vsi;
1357         struct i40e_veb *veb;
1358         struct i40e_hw *hw;
1359         struct i40e_aqc_configure_switching_comp_ets_data ets_data;
1360         int i;
1361         int ret;
1362
1363         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1364
1365         dev = &rte_eth_devices[port];
1366
1367         if (!is_i40e_supported(dev))
1368                 return -ENOTSUP;
1369
1370         pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
1371
1372         vsi = pf->main_vsi;
1373         if (!vsi) {
1374                 PMD_DRV_LOG(ERR, "Invalid VSI.");
1375                 return -EINVAL;
1376         }
1377
1378         veb = vsi->veb;
1379         if (!veb) {
1380                 PMD_DRV_LOG(ERR, "Invalid VEB.");
1381                 return -EINVAL;
1382         }
1383
1384         if ((tc_map & veb->enabled_tc) != tc_map) {
1385                 PMD_DRV_LOG(ERR,
1386                             "TC bitmap isn't the subset of enabled TCs 0x%x.",
1387                             veb->enabled_tc);
1388                 return -EINVAL;
1389         }
1390
1391         if (tc_map == veb->strict_prio_tc) {
1392                 PMD_DRV_LOG(INFO, "No change for TC bitmap. Nothing to do.");
1393                 return 0;
1394         }
1395
1396         hw = I40E_VSI_TO_HW(vsi);
1397
1398         /* Disable DCBx if it's the first time to set strict priority. */
1399         if (!veb->strict_prio_tc) {
1400                 ret = i40e_aq_stop_lldp(hw, true, NULL);
1401                 if (ret)
1402                         PMD_DRV_LOG(INFO,
1403                                     "Failed to disable DCBx as it's already"
1404                                     " disabled.");
1405                 else
1406                         PMD_DRV_LOG(INFO,
1407                                     "DCBx is disabled according to strict"
1408                                     " priority setting.");
1409         }
1410
1411         memset(&ets_data, 0, sizeof(ets_data));
1412         ets_data.tc_valid_bits = veb->enabled_tc;
1413         ets_data.seepage = I40E_AQ_ETS_SEEPAGE_EN_MASK;
1414         ets_data.tc_strict_priority_flags = tc_map;
1415         /* Get all TCs' bandwidth. */
1416         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
1417                 if (veb->enabled_tc & BIT_ULL(i)) {
1418                         /* For rubust, if bandwidth is 0, use 1 instead. */
1419                         if (veb->bw_info.bw_ets_share_credits[i])
1420                                 ets_data.tc_bw_share_credits[i] =
1421                                         veb->bw_info.bw_ets_share_credits[i];
1422                         else
1423                                 ets_data.tc_bw_share_credits[i] =
1424                                         I40E_QOS_BW_WEIGHT_MIN;
1425                 }
1426         }
1427
1428         if (!veb->strict_prio_tc)
1429                 ret = i40e_aq_config_switch_comp_ets(
1430                         hw, veb->uplink_seid,
1431                         &ets_data, i40e_aqc_opc_enable_switching_comp_ets,
1432                         NULL);
1433         else if (tc_map)
1434                 ret = i40e_aq_config_switch_comp_ets(
1435                         hw, veb->uplink_seid,
1436                         &ets_data, i40e_aqc_opc_modify_switching_comp_ets,
1437                         NULL);
1438         else
1439                 ret = i40e_aq_config_switch_comp_ets(
1440                         hw, veb->uplink_seid,
1441                         &ets_data, i40e_aqc_opc_disable_switching_comp_ets,
1442                         NULL);
1443
1444         if (ret) {
1445                 PMD_DRV_LOG(ERR,
1446                             "Failed to set TCs' strict priority mode."
1447                             " err (%d)", ret);
1448                 return -EINVAL;
1449         }
1450
1451         veb->strict_prio_tc = tc_map;
1452
1453         /* Enable DCBx again, if all the TCs' strict priority disabled. */
1454         if (!tc_map) {
1455                 ret = i40e_aq_start_lldp(hw, NULL);
1456                 if (ret) {
1457                         PMD_DRV_LOG(ERR,
1458                                     "Failed to enable DCBx, err(%d).", ret);
1459                         return -EINVAL;
1460                 }
1461
1462                 PMD_DRV_LOG(INFO,
1463                             "DCBx is enabled again according to strict"
1464                             " priority setting.");
1465         }
1466
1467         return ret;
1468 }
1469
1470 #define I40E_PROFILE_INFO_SIZE 48
1471 #define I40E_MAX_PROFILE_NUM 16
1472
1473 static void
1474 i40e_generate_profile_info_sec(char *name, struct i40e_ddp_version *version,
1475                                uint32_t track_id, uint8_t *profile_info_sec,
1476                                bool add)
1477 {
1478         struct i40e_profile_section_header *sec = NULL;
1479         struct i40e_profile_info *pinfo;
1480
1481         sec = (struct i40e_profile_section_header *)profile_info_sec;
1482         sec->tbl_size = 1;
1483         sec->data_end = sizeof(struct i40e_profile_section_header) +
1484                 sizeof(struct i40e_profile_info);
1485         sec->section.type = SECTION_TYPE_INFO;
1486         sec->section.offset = sizeof(struct i40e_profile_section_header);
1487         sec->section.size = sizeof(struct i40e_profile_info);
1488         pinfo = (struct i40e_profile_info *)(profile_info_sec +
1489                                              sec->section.offset);
1490         pinfo->track_id = track_id;
1491         memcpy(pinfo->name, name, I40E_DDP_NAME_SIZE);
1492         memcpy(&pinfo->version, version, sizeof(struct i40e_ddp_version));
1493         if (add)
1494                 pinfo->op = I40E_DDP_ADD_TRACKID;
1495         else
1496                 pinfo->op = I40E_DDP_REMOVE_TRACKID;
1497 }
1498
1499 static enum i40e_status_code
1500 i40e_add_rm_profile_info(struct i40e_hw *hw, uint8_t *profile_info_sec)
1501 {
1502         enum i40e_status_code status = I40E_SUCCESS;
1503         struct i40e_profile_section_header *sec;
1504         uint32_t track_id;
1505         uint32_t offset = 0;
1506         uint32_t info = 0;
1507
1508         sec = (struct i40e_profile_section_header *)profile_info_sec;
1509         track_id = ((struct i40e_profile_info *)(profile_info_sec +
1510                                          sec->section.offset))->track_id;
1511
1512         status = i40e_aq_write_ddp(hw, (void *)sec, sec->data_end,
1513                                    track_id, &offset, &info, NULL);
1514         if (status)
1515                 PMD_DRV_LOG(ERR, "Failed to add/remove profile info: "
1516                             "offset %d, info %d",
1517                             offset, info);
1518
1519         return status;
1520 }
1521
1522 #define I40E_PROFILE_INFO_SIZE 48
1523 #define I40E_MAX_PROFILE_NUM 16
1524
1525 /* Check if the profile info exists */
1526 static int
1527 i40e_check_profile_info(uint8_t port, uint8_t *profile_info_sec)
1528 {
1529         struct rte_eth_dev *dev = &rte_eth_devices[port];
1530         struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
1531         uint8_t *buff;
1532         struct rte_pmd_i40e_profile_list *p_list;
1533         struct rte_pmd_i40e_profile_info *pinfo, *p;
1534         uint32_t i;
1535         int ret;
1536
1537         buff = rte_zmalloc("pinfo_list",
1538                            (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4),
1539                            0);
1540         if (!buff) {
1541                 PMD_DRV_LOG(ERR, "failed to allocate memory");
1542                 return -1;
1543         }
1544
1545         ret = i40e_aq_get_ddp_list(
1546                 hw, (void *)buff,
1547                 (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4),
1548                 0, NULL);
1549         if (ret) {
1550                 PMD_DRV_LOG(ERR, "Failed to get profile info list.");
1551                 rte_free(buff);
1552                 return -1;
1553         }
1554         p_list = (struct rte_pmd_i40e_profile_list *)buff;
1555         pinfo = (struct rte_pmd_i40e_profile_info *)(profile_info_sec +
1556                              sizeof(struct i40e_profile_section_header));
1557         for (i = 0; i < p_list->p_count; i++) {
1558                 p = &p_list->p_info[i];
1559                 if ((pinfo->track_id == p->track_id) &&
1560                     !memcmp(&pinfo->version, &p->version,
1561                             sizeof(struct i40e_ddp_version)) &&
1562                     !memcmp(&pinfo->name, &p->name,
1563                             I40E_DDP_NAME_SIZE)) {
1564                         PMD_DRV_LOG(INFO, "Profile exists.");
1565                         rte_free(buff);
1566                         return 1;
1567                 }
1568         }
1569
1570         rte_free(buff);
1571         return 0;
1572 }
1573
1574 int
1575 rte_pmd_i40e_process_ddp_package(uint8_t port, uint8_t *buff,
1576                                  uint32_t size,
1577                                  enum rte_pmd_i40e_package_op op)
1578 {
1579         struct rte_eth_dev *dev;
1580         struct i40e_hw *hw;
1581         struct i40e_package_header *pkg_hdr;
1582         struct i40e_generic_seg_header *profile_seg_hdr;
1583         struct i40e_generic_seg_header *metadata_seg_hdr;
1584         uint32_t track_id;
1585         uint8_t *profile_info_sec;
1586         int is_exist;
1587         enum i40e_status_code status = I40E_SUCCESS;
1588
1589         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1590
1591         dev = &rte_eth_devices[port];
1592
1593         if (!is_i40e_supported(dev))
1594                 return -ENOTSUP;
1595
1596         hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
1597
1598         if (size < (sizeof(struct i40e_package_header) +
1599                     sizeof(struct i40e_metadata_segment) +
1600                     sizeof(uint32_t) * 2)) {
1601                 PMD_DRV_LOG(ERR, "Buff is invalid.");
1602                 return -EINVAL;
1603         }
1604
1605         pkg_hdr = (struct i40e_package_header *)buff;
1606
1607         if (!pkg_hdr) {
1608                 PMD_DRV_LOG(ERR, "Failed to fill the package structure");
1609                 return -EINVAL;
1610         }
1611
1612         if (pkg_hdr->segment_count < 2) {
1613                 PMD_DRV_LOG(ERR, "Segment_count should be 2 at least.");
1614                 return -EINVAL;
1615         }
1616
1617         /* Find metadata segment */
1618         metadata_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_METADATA,
1619                                                         pkg_hdr);
1620         if (!metadata_seg_hdr) {
1621                 PMD_DRV_LOG(ERR, "Failed to find metadata segment header");
1622                 return -EINVAL;
1623         }
1624         track_id = ((struct i40e_metadata_segment *)metadata_seg_hdr)->track_id;
1625
1626         /* Find profile segment */
1627         profile_seg_hdr = i40e_find_segment_in_package(SEGMENT_TYPE_I40E,
1628                                                        pkg_hdr);
1629         if (!profile_seg_hdr) {
1630                 PMD_DRV_LOG(ERR, "Failed to find profile segment header");
1631                 return -EINVAL;
1632         }
1633
1634         profile_info_sec = rte_zmalloc(
1635                 "i40e_profile_info",
1636                 sizeof(struct i40e_profile_section_header) +
1637                 sizeof(struct i40e_profile_info),
1638                 0);
1639         if (!profile_info_sec) {
1640                 PMD_DRV_LOG(ERR, "Failed to allocate memory");
1641                 return -EINVAL;
1642         }
1643
1644         if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) {
1645                 /* Check if the profile exists */
1646                 i40e_generate_profile_info_sec(
1647                      ((struct i40e_profile_segment *)profile_seg_hdr)->name,
1648                      &((struct i40e_profile_segment *)profile_seg_hdr)->version,
1649                      track_id, profile_info_sec, 1);
1650                 is_exist = i40e_check_profile_info(port, profile_info_sec);
1651                 if (is_exist > 0) {
1652                         PMD_DRV_LOG(ERR, "Profile already exists.");
1653                         rte_free(profile_info_sec);
1654                         return 1;
1655                 } else if (is_exist < 0) {
1656                         PMD_DRV_LOG(ERR, "Failed to check profile.");
1657                         rte_free(profile_info_sec);
1658                         return -EINVAL;
1659                 }
1660
1661                 /* Write profile to HW */
1662                 status = i40e_write_profile(
1663                                 hw,
1664                                 (struct i40e_profile_segment *)profile_seg_hdr,
1665                                 track_id);
1666                 if (status) {
1667                         PMD_DRV_LOG(ERR, "Failed to write profile.");
1668                         rte_free(profile_info_sec);
1669                         return status;
1670                 }
1671
1672                 /* Add profile info to info list */
1673                 status = i40e_add_rm_profile_info(hw, profile_info_sec);
1674                 if (status)
1675                         PMD_DRV_LOG(ERR, "Failed to add profile info.");
1676         } else {
1677                 PMD_DRV_LOG(ERR, "Operation not supported.");
1678         }
1679
1680         rte_free(profile_info_sec);
1681         return status;
1682 }
1683
1684 int
1685 rte_pmd_i40e_get_ddp_list(uint8_t port, uint8_t *buff, uint32_t size)
1686 {
1687         struct rte_eth_dev *dev;
1688         struct i40e_hw *hw;
1689         enum i40e_status_code status = I40E_SUCCESS;
1690
1691         RTE_ETH_VALID_PORTID_OR_ERR_RET(port, -ENODEV);
1692
1693         dev = &rte_eth_devices[port];
1694
1695         if (!is_i40e_supported(dev))
1696                 return -ENOTSUP;
1697
1698         if (size < (I40E_PROFILE_INFO_SIZE * I40E_MAX_PROFILE_NUM + 4))
1699                 return -EINVAL;
1700
1701         hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
1702
1703         status = i40e_aq_get_ddp_list(hw, (void *)buff,
1704                                       size, 0, NULL);
1705
1706         return status;
1707 }