i40e/base: support CEE DCBX
[dpdk.git] / lib / librte_pmd_i40e / i40e / i40e_dcb.c
1 /*******************************************************************************
2
3 Copyright (c) 2013 - 2015, Intel Corporation
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in the
14     documentation and/or other materials provided with the distribution.
15
16  3. Neither the name of the Intel Corporation nor the names of its
17     contributors may be used to endorse or promote products derived from
18     this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31
32 ***************************************************************************/
33
34 #include "i40e_adminq.h"
35 #include "i40e_prototype.h"
36 #include "i40e_dcb.h"
37
38 /**
39  * i40e_get_dcbx_status
40  * @hw: pointer to the hw struct
41  * @status: Embedded DCBX Engine Status
42  *
43  * Get the DCBX status from the Firmware
44  **/
45 enum i40e_status_code i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
46 {
47         u32 reg;
48
49         if (!status)
50                 return I40E_ERR_PARAM;
51
52         reg = rd32(hw, I40E_PRTDCB_GENS);
53         *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
54                         I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
55
56         return I40E_SUCCESS;
57 }
58
59 /**
60  * i40e_parse_ieee_etscfg_tlv
61  * @tlv: IEEE 802.1Qaz ETS CFG TLV
62  * @dcbcfg: Local store to update ETS CFG data
63  *
64  * Parses IEEE 802.1Qaz ETS CFG TLV
65  **/
66 static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
67                                        struct i40e_dcbx_config *dcbcfg)
68 {
69         struct i40e_dcb_ets_config *etscfg;
70         u8 *buf = tlv->tlvinfo;
71         u16 offset = 0;
72         u8 priority;
73         int i;
74
75         /* First Octet post subtype
76          * --------------------------
77          * |will-|CBS  | Re-  | Max |
78          * |ing  |     |served| TCs |
79          * --------------------------
80          * |1bit | 1bit|3 bits|3bits|
81          */
82         etscfg = &dcbcfg->etscfg;
83         etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
84                                I40E_IEEE_ETS_WILLING_SHIFT);
85         etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
86                            I40E_IEEE_ETS_CBS_SHIFT);
87         etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
88                               I40E_IEEE_ETS_MAXTC_SHIFT);
89
90         /* Move offset to Priority Assignment Table */
91         offset++;
92
93         /* Priority Assignment Table (4 octets)
94          * Octets:|    1    |    2    |    3    |    4    |
95          *        -----------------------------------------
96          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
97          *        -----------------------------------------
98          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
99          *        -----------------------------------------
100          */
101         for (i = 0; i < 4; i++) {
102                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
103                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
104                 etscfg->prioritytable[i * 2] =  priority;
105                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
106                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
107                 etscfg->prioritytable[i * 2 + 1] = priority;
108                 offset++;
109         }
110
111         /* TC Bandwidth Table (8 octets)
112          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
113          *        ---------------------------------
114          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
115          *        ---------------------------------
116          */
117         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
118                 etscfg->tcbwtable[i] = buf[offset++];
119
120         /* TSA Assignment Table (8 octets)
121          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
122          *        ---------------------------------
123          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
124          *        ---------------------------------
125          */
126         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
127                 etscfg->tsatable[i] = buf[offset++];
128 }
129
130 /**
131  * i40e_parse_ieee_etsrec_tlv
132  * @tlv: IEEE 802.1Qaz ETS REC TLV
133  * @dcbcfg: Local store to update ETS REC data
134  *
135  * Parses IEEE 802.1Qaz ETS REC TLV
136  **/
137 static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
138                                        struct i40e_dcbx_config *dcbcfg)
139 {
140         u8 *buf = tlv->tlvinfo;
141         u16 offset = 0;
142         u8 priority;
143         int i;
144
145         /* Move offset to priority table */
146         offset++;
147
148         /* Priority Assignment Table (4 octets)
149          * Octets:|    1    |    2    |    3    |    4    |
150          *        -----------------------------------------
151          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
152          *        -----------------------------------------
153          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
154          *        -----------------------------------------
155          */
156         for (i = 0; i < 4; i++) {
157                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
158                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
159                 dcbcfg->etsrec.prioritytable[i*2] =  priority;
160                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
161                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
162                 dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
163                 offset++;
164         }
165
166         /* TC Bandwidth Table (8 octets)
167          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
168          *        ---------------------------------
169          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
170          *        ---------------------------------
171          */
172         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
173                 dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
174
175         /* TSA Assignment Table (8 octets)
176          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
177          *        ---------------------------------
178          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
179          *        ---------------------------------
180          */
181         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
182                 dcbcfg->etsrec.tsatable[i] = buf[offset++];
183 }
184
185 /**
186  * i40e_parse_ieee_pfccfg_tlv
187  * @tlv: IEEE 802.1Qaz PFC CFG TLV
188  * @dcbcfg: Local store to update PFC CFG data
189  *
190  * Parses IEEE 802.1Qaz PFC CFG TLV
191  **/
192 static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
193                                        struct i40e_dcbx_config *dcbcfg)
194 {
195         u8 *buf = tlv->tlvinfo;
196
197         /* ----------------------------------------
198          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
199          * |ing  |     |served| cap |              |
200          * -----------------------------------------
201          * |1bit | 1bit|2 bits|4bits| 1 octet      |
202          */
203         dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
204                                    I40E_IEEE_PFC_WILLING_SHIFT);
205         dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
206                                I40E_IEEE_PFC_MBC_SHIFT);
207         dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
208                                   I40E_IEEE_PFC_CAP_SHIFT);
209         dcbcfg->pfc.pfcenable = buf[1];
210 }
211
212 /**
213  * i40e_parse_ieee_app_tlv
214  * @tlv: IEEE 802.1Qaz APP TLV
215  * @dcbcfg: Local store to update APP PRIO data
216  *
217  * Parses IEEE 802.1Qaz APP PRIO TLV
218  **/
219 static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
220                                     struct i40e_dcbx_config *dcbcfg)
221 {
222         u16 typelength;
223         u16 offset = 0;
224         u16 length;
225         int i = 0;
226         u8 *buf;
227
228         typelength = I40E_NTOHS(tlv->typelength);
229         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
230                        I40E_LLDP_TLV_LEN_SHIFT);
231         buf = tlv->tlvinfo;
232
233         /* The App priority table starts 5 octets after TLV header */
234         length -= (sizeof(tlv->ouisubtype) + 1);
235
236         /* Move offset to App Priority Table */
237         offset++;
238
239         /* Application Priority Table (3 octets)
240          * Octets:|         1          |    2    |    3    |
241          *        -----------------------------------------
242          *        |Priority|Rsrvd| Sel |    Protocol ID    |
243          *        -----------------------------------------
244          *   Bits:|23    21|20 19|18 16|15                0|
245          *        -----------------------------------------
246          */
247         while (offset < length) {
248                 dcbcfg->app[i].priority = (u8)((buf[offset] &
249                                                 I40E_IEEE_APP_PRIO_MASK) >>
250                                                I40E_IEEE_APP_PRIO_SHIFT);
251                 dcbcfg->app[i].selector = (u8)((buf[offset] &
252                                                 I40E_IEEE_APP_SEL_MASK) >>
253                                                I40E_IEEE_APP_SEL_SHIFT);
254                 dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
255                                              buf[offset + 2];
256                 /* Move to next app */
257                 offset += 3;
258                 i++;
259                 if (i >= I40E_DCBX_MAX_APPS)
260                         break;
261         }
262
263         dcbcfg->numapps = i;
264 }
265
266 /**
267  * i40e_parse_ieee_etsrec_tlv
268  * @tlv: IEEE 802.1Qaz TLV
269  * @dcbcfg: Local store to update ETS REC data
270  *
271  * Get the TLV subtype and send it to parsing function
272  * based on the subtype value
273  **/
274 static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
275                                 struct i40e_dcbx_config *dcbcfg)
276 {
277         u32 ouisubtype;
278         u8 subtype;
279
280         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
281         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
282                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
283         switch (subtype) {
284         case I40E_IEEE_SUBTYPE_ETS_CFG:
285                 i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
286                 break;
287         case I40E_IEEE_SUBTYPE_ETS_REC:
288                 i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
289                 break;
290         case I40E_IEEE_SUBTYPE_PFC_CFG:
291                 i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
292                 break;
293         case I40E_IEEE_SUBTYPE_APP_PRI:
294                 i40e_parse_ieee_app_tlv(tlv, dcbcfg);
295                 break;
296         default:
297                 break;
298         }
299 }
300
301 /**
302  * i40e_parse_org_tlv
303  * @tlv: Organization specific TLV
304  * @dcbcfg: Local store to update ETS REC data
305  *
306  * Currently only IEEE 802.1Qaz TLV is supported, all others
307  * will be returned
308  **/
309 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
310                                struct i40e_dcbx_config *dcbcfg)
311 {
312         u32 ouisubtype;
313         u32 oui;
314
315         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
316         oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
317                     I40E_LLDP_TLV_OUI_SHIFT);
318         switch (oui) {
319         case I40E_IEEE_8021QAZ_OUI:
320                 i40e_parse_ieee_tlv(tlv, dcbcfg);
321                 break;
322         default:
323                 break;
324         }
325 }
326
327 /**
328  * i40e_lldp_to_dcb_config
329  * @lldpmib: LLDPDU to be parsed
330  * @dcbcfg: store for LLDPDU data
331  *
332  * Parse DCB configuration from the LLDPDU
333  **/
334 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
335                                     struct i40e_dcbx_config *dcbcfg)
336 {
337         enum i40e_status_code ret = I40E_SUCCESS;
338         struct i40e_lldp_org_tlv *tlv;
339         u16 type;
340         u16 length;
341         u16 typelength;
342         u16 offset = 0;
343
344         if (!lldpmib || !dcbcfg)
345                 return I40E_ERR_PARAM;
346
347         /* set to the start of LLDPDU */
348         lldpmib += I40E_LLDP_MIB_HLEN;
349         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
350         while (1) {
351                 typelength = I40E_NTOHS(tlv->typelength);
352                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
353                              I40E_LLDP_TLV_TYPE_SHIFT);
354                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
355                                I40E_LLDP_TLV_LEN_SHIFT);
356                 offset += sizeof(typelength) + length;
357
358                 /* END TLV or beyond LLDPDU size */
359                 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
360                         break;
361
362                 switch (type) {
363                 case I40E_TLV_TYPE_ORG:
364                         i40e_parse_org_tlv(tlv, dcbcfg);
365                         break;
366                 default:
367                         break;
368                 }
369
370                 /* Move to next TLV */
371                 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
372                                                     sizeof(tlv->typelength) +
373                                                     length);
374         }
375
376         return ret;
377 }
378
379 /**
380  * i40e_aq_get_dcb_config
381  * @hw: pointer to the hw struct
382  * @mib_type: mib type for the query
383  * @bridgetype: bridge type for the query (remote)
384  * @dcbcfg: store for LLDPDU data
385  *
386  * Query DCB configuration from the Firmware
387  **/
388 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
389                                    u8 bridgetype,
390                                    struct i40e_dcbx_config *dcbcfg)
391 {
392         enum i40e_status_code ret = I40E_SUCCESS;
393         struct i40e_virt_mem mem;
394         u8 *lldpmib;
395
396         /* Allocate the LLDPDU */
397         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
398         if (ret)
399                 return ret;
400
401         lldpmib = (u8 *)mem.va;
402         ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
403                                    (void *)lldpmib, I40E_LLDPDU_SIZE,
404                                    NULL, NULL, NULL);
405         if (ret)
406                 goto free_mem;
407
408         /* Parse LLDP MIB to get dcb configuration */
409         ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
410
411 free_mem:
412         i40e_free_virt_mem(hw, &mem);
413         return ret;
414 }
415
416 /**
417  * i40e_cee_to_dcb_v1_config
418  * @cee_cfg: pointer to CEE v1 response configuration struct
419  * @dcbcfg: DCB configuration struct
420  *
421  * Convert CEE v1 configuration from firmware to DCB configuration
422  **/
423 static void i40e_cee_to_dcb_v1_config(
424                         struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
425                         struct i40e_dcbx_config *dcbcfg)
426 {
427         u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
428         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
429         u8 i, tc, err, sync, oper;
430
431         /* CEE PG data to ETS config */
432         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
433
434         /* Note that the FW creates the oper_prio_tc nibbles reversed
435          * from those in the CEE Priority Group sub-TLV.
436          */
437         for (i = 0; i < 4; i++) {
438                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
439                          I40E_CEE_PGID_PRIO_0_MASK) >>
440                          I40E_CEE_PGID_PRIO_0_SHIFT);
441                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
442                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
443                          I40E_CEE_PGID_PRIO_1_MASK) >>
444                          I40E_CEE_PGID_PRIO_1_SHIFT);
445                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
446         }
447
448         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
449                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
450
451         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
452                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
453                         /* Map it to next empty TC */
454                         dcbcfg->etscfg.prioritytable[i] =
455                                                 cee_cfg->oper_num_tc - 1;
456                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
457                 } else {
458                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
459                 }
460         }
461
462         /* CEE PFC data to ETS config */
463         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
464         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
465
466         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
467                   I40E_AQC_CEE_APP_STATUS_SHIFT;
468         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
469         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
470         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
471         /* Add APPs if Error is False and Oper/Sync is True */
472         if (!err) {
473                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
474                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
475
476                 /* FCoE APP */
477                 dcbcfg->app[0].priority =
478                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
479                          I40E_AQC_CEE_APP_FCOE_SHIFT;
480                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
481                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
482
483                 /* iSCSI APP */
484                 dcbcfg->app[1].priority =
485                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
486                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
487                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
488                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
489
490                 /* FIP APP */
491                 dcbcfg->app[2].priority =
492                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
493                          I40E_AQC_CEE_APP_FIP_SHIFT;
494                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
495                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
496         }
497 }
498
499 /**
500  * i40e_cee_to_dcb_config
501  * @cee_cfg: pointer to CEE configuration struct
502  * @dcbcfg: DCB configuration struct
503  *
504  * Convert CEE configuration from firmware to DCB configuration
505  **/
506 static void i40e_cee_to_dcb_config(
507                                 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
508                                 struct i40e_dcbx_config *dcbcfg)
509 {
510         u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
511         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
512         u8 i, tc, err, sync, oper;
513
514         /* CEE PG data to ETS config */
515         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
516
517         for (i = 0; i < 4; i++) {
518                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
519                          I40E_CEE_PGID_PRIO_1_MASK) >>
520                          I40E_CEE_PGID_PRIO_1_SHIFT);
521                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
522                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
523                          I40E_CEE_PGID_PRIO_0_MASK) >>
524                          I40E_CEE_PGID_PRIO_0_SHIFT);
525                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
526         }
527
528         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
529                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
530
531         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
532                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
533                         /* Map it to next empty TC */
534                         dcbcfg->etscfg.prioritytable[i] =
535                                                 cee_cfg->oper_num_tc - 1;
536                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
537                 } else {
538                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
539                 }
540         }
541
542         /* CEE PFC data to ETS config */
543         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
544         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
545
546         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
547                   I40E_AQC_CEE_APP_STATUS_SHIFT;
548         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
549         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
550         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
551         /* Add APPs if Error is False and Oper/Sync is True */
552         if (!err && sync && oper) {
553                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
554                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
555
556                 /* FCoE APP */
557                 dcbcfg->app[0].priority =
558                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
559                          I40E_AQC_CEE_APP_FCOE_SHIFT;
560                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
561                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
562
563                 /* iSCSI APP */
564                 dcbcfg->app[1].priority =
565                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
566                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
567                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
568                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
569
570                 /* FIP APP */
571                 dcbcfg->app[2].priority =
572                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
573                          I40E_AQC_CEE_APP_FIP_SHIFT;
574                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
575                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
576         }
577 }
578
579 /**
580  * i40e_get_dcb_config
581  * @hw: pointer to the hw struct
582  *
583  * Get DCB configuration from the Firmware
584  **/
585 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
586 {
587         enum i40e_status_code ret = I40E_SUCCESS;
588         struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
589         struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
590
591         /* If Firmware version < v4.33 IEEE only */
592         if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
593             (hw->aq.fw_maj_ver < 4))
594                 goto ieee;
595
596         /* If Firmware version == v4.33 use old CEE struct */
597         if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
598                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
599                                                  sizeof(cee_v1_cfg), NULL);
600                 if (ret == I40E_SUCCESS) {
601                         /* CEE mode */
602                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
603                         i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
604                                                   &hw->local_dcbx_config);
605                 }
606         } else {
607                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
608                                                  sizeof(cee_cfg), NULL);
609                 if (ret == I40E_SUCCESS) {
610                         /* CEE mode */
611                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
612                         i40e_cee_to_dcb_config(&cee_cfg,
613                                                &hw->local_dcbx_config);
614                 }
615         }
616
617         /* CEE mode not enabled try querying IEEE data */
618         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
619                 goto ieee;
620         else
621                 goto out;
622
623 ieee:
624         /* IEEE mode */
625         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
626         /* Get Local DCB Config */
627         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
628                                      &hw->local_dcbx_config);
629         if (ret)
630                 goto out;
631
632         /* Get Remote DCB Config */
633         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
634                              I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
635                              &hw->remote_dcbx_config);
636         /* Don't treat ENOENT as an error for Remote MIBs */
637         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
638                 ret = I40E_SUCCESS;
639
640 out:
641         return ret;
642 }
643
644 /**
645  * i40e_init_dcb
646  * @hw: pointer to the hw struct
647  *
648  * Update DCB configuration from the Firmware
649  **/
650 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
651 {
652         enum i40e_status_code ret = I40E_SUCCESS;
653         struct i40e_lldp_variables lldp_cfg;
654         u8 adminstatus = 0;
655
656         if (!hw->func_caps.dcb)
657                 return ret;
658
659         /* Read LLDP NVM area */
660         ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
661         if (ret)
662                 return ret;
663
664         /* Get the LLDP AdminStatus for the current port */
665         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
666         adminstatus &= 0xF;
667
668         /* LLDP agent disabled */
669         if (!adminstatus) {
670                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
671                 return ret;
672         }
673
674         /* Get DCBX status */
675         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
676         if (ret)
677                 return ret;
678
679         /* Check the DCBX Status */
680         switch (hw->dcbx_status) {
681         case I40E_DCBX_STATUS_DONE:
682         case I40E_DCBX_STATUS_IN_PROGRESS:
683                 /* Get current DCBX configuration */
684                 ret = i40e_get_dcb_config(hw);
685                 if (ret)
686                         return ret;
687                 break;
688         case I40E_DCBX_STATUS_DISABLED:
689                 return ret;
690         case I40E_DCBX_STATUS_NOT_STARTED:
691         case I40E_DCBX_STATUS_MULTIPLE_PEERS:
692         default:
693                 break;
694         }
695
696         /* Configure the LLDP MIB change event */
697         ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
698         if (ret)
699                 return ret;
700
701         return ret;
702 }
703
704
705
706 /**
707  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
708  * @hw: pointer to the HW structure
709  * @lldp_cfg: pointer to hold lldp configuration variables
710  *
711  * Reads the LLDP configuration data from NVM
712  **/
713 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
714                                          struct i40e_lldp_variables *lldp_cfg)
715 {
716         enum i40e_status_code ret = I40E_SUCCESS;
717         u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
718
719         if (!lldp_cfg)
720                 return I40E_ERR_PARAM;
721
722         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
723         if (ret != I40E_SUCCESS)
724                 goto err_lldp_cfg;
725
726         ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
727                                sizeof(struct i40e_lldp_variables),
728                                (u8 *)lldp_cfg,
729                                true, NULL);
730         i40e_release_nvm(hw);
731
732 err_lldp_cfg:
733         return ret;
734 }