i40e/base: add parsing for CEE DCBX TLVs
[dpdk.git] / drivers / net / i40e / base / 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_cee_pgcfg_tlv
303  * @tlv: CEE DCBX PG CFG TLV
304  * @dcbcfg: Local store to update ETS CFG data
305  *
306  * Parses CEE DCBX PG CFG TLV
307  **/
308 static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
309                                      struct i40e_dcbx_config *dcbcfg)
310 {
311         struct i40e_dcb_ets_config *etscfg;
312         u8 *buf = tlv->tlvinfo;
313         u16 offset = 0;
314         u8 priority;
315         int i;
316
317         etscfg = &dcbcfg->etscfg;
318
319         if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
320                 etscfg->willing = 1;
321
322         etscfg->cbs = 0;
323         /* Priority Group Table (4 octets)
324          * Octets:|    1    |    2    |    3    |    4    |
325          *        -----------------------------------------
326          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
327          *        -----------------------------------------
328          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
329          *        -----------------------------------------
330          */
331         for (i = 0; i < 4; i++) {
332                 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
333                                  I40E_CEE_PGID_PRIO_1_SHIFT);
334                 etscfg->prioritytable[i * 2] =  priority;
335                 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
336                                  I40E_CEE_PGID_PRIO_0_SHIFT);
337                 etscfg->prioritytable[i * 2 + 1] = priority;
338                 offset++;
339         }
340
341         /* PG Percentage Table (8 octets)
342          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
343          *        ---------------------------------
344          *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
345          *        ---------------------------------
346          */
347         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
348                 etscfg->tcbwtable[i] = buf[offset++];
349
350         /* Number of TCs supported (1 octet) */
351         etscfg->maxtcs = buf[offset];
352 }
353
354 /**
355  * i40e_parse_cee_pfccfg_tlv
356  * @tlv: CEE DCBX PFC CFG TLV
357  * @dcbcfg: Local store to update PFC CFG data
358  *
359  * Parses CEE DCBX PFC CFG TLV
360  **/
361 static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
362                                       struct i40e_dcbx_config *dcbcfg)
363 {
364         u8 *buf = tlv->tlvinfo;
365
366         if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
367                 dcbcfg->pfc.willing = 1;
368
369         /* ------------------------
370          * | PFC Enable | PFC TCs |
371          * ------------------------
372          * | 1 octet    | 1 octet |
373          */
374         dcbcfg->pfc.pfcenable = buf[0];
375         dcbcfg->pfc.pfccap = buf[1];
376 }
377
378 /**
379  * i40e_parse_cee_app_tlv
380  * @tlv: CEE DCBX APP TLV
381  * @dcbcfg: Local store to update APP PRIO data
382  *
383  * Parses CEE DCBX APP PRIO TLV
384  **/
385 static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
386                                    struct i40e_dcbx_config *dcbcfg)
387 {
388         u16 length, typelength, offset = 0;
389         struct i40e_cee_app_prio *app;
390         u8 i, up, selector;
391
392         typelength = I40E_NTOHS(tlv->hdr.typelen);
393         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
394                        I40E_LLDP_TLV_LEN_SHIFT);
395
396         dcbcfg->numapps = length/sizeof(*app);
397         if (!dcbcfg->numapps)
398                 return;
399
400         for (i = 0; i < dcbcfg->numapps; i++) {
401                 app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
402                 for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
403                         if (app->prio_map & BIT(up))
404                                 break;
405                 }
406                 dcbcfg->app[i].priority = up;
407                 /* Get Selector from lower 2 bits, and convert to IEEE */
408                 selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
409                 if (selector == I40E_CEE_APP_SEL_ETHTYPE)
410                         dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
411                 else if (selector == I40E_CEE_APP_SEL_TCPIP)
412                         dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
413                 else
414                         /* Keep selector as it is for unknown types */
415                         dcbcfg->app[i].selector = selector;
416                 dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
417                 /* Move to next app */
418                 offset += sizeof(*app);
419         }
420 }
421
422 /**
423  * i40e_parse_cee_tlv
424  * @tlv: CEE DCBX TLV
425  * @dcbcfg: Local store to update DCBX config data
426  *
427  * Get the TLV subtype and send it to parsing function
428  * based on the subtype value
429  **/
430 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
431                                struct i40e_dcbx_config *dcbcfg)
432 {
433         u16 len, tlvlen, sublen, typelength;
434         struct i40e_cee_feat_tlv *sub_tlv;
435         u8 subtype, feat_tlv_count = 0;
436         u32 ouisubtype;
437
438         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
439         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
440                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
441         /* Return if not CEE DCBX */
442         if (subtype != I40E_CEE_DCBX_TYPE)
443                 return;
444
445         typelength = I40E_NTOHS(tlv->typelength);
446         tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
447                         I40E_LLDP_TLV_LEN_SHIFT);
448         len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
449               sizeof(struct i40e_cee_ctrl_tlv);
450         /* Return if no CEE DCBX Feature TLVs */
451         if (tlvlen <= len)
452                 return;
453
454         sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
455         while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
456                 typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
457                 sublen = (u16)((typelength &
458                                 I40E_LLDP_TLV_LEN_MASK) >>
459                                 I40E_LLDP_TLV_LEN_SHIFT);
460                 subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
461                                 I40E_LLDP_TLV_TYPE_SHIFT);
462                 switch (subtype) {
463                 case I40E_CEE_SUBTYPE_PG_CFG:
464                         i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
465                         break;
466                 case I40E_CEE_SUBTYPE_PFC_CFG:
467                         i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
468                         break;
469                 case I40E_CEE_SUBTYPE_APP_PRI:
470                         i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
471                         break;
472                 default:
473                         return; /* Invalid Sub-type return */
474                 }
475                 feat_tlv_count++;
476                 /* Move to next sub TLV */
477                 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
478                                                 sizeof(sub_tlv->hdr.typelen) +
479                                                 sublen);
480         }
481 }
482
483 /**
484  * i40e_parse_org_tlv
485  * @tlv: Organization specific TLV
486  * @dcbcfg: Local store to update ETS REC data
487  *
488  * Currently only IEEE 802.1Qaz TLV is supported, all others
489  * will be returned
490  **/
491 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
492                                struct i40e_dcbx_config *dcbcfg)
493 {
494         u32 ouisubtype;
495         u32 oui;
496
497         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
498         oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
499                     I40E_LLDP_TLV_OUI_SHIFT);
500         switch (oui) {
501         case I40E_IEEE_8021QAZ_OUI:
502                 i40e_parse_ieee_tlv(tlv, dcbcfg);
503                 break;
504         case I40E_CEE_DCBX_OUI:
505                 i40e_parse_cee_tlv(tlv, dcbcfg);
506                 break;
507         default:
508                 break;
509         }
510 }
511
512 /**
513  * i40e_lldp_to_dcb_config
514  * @lldpmib: LLDPDU to be parsed
515  * @dcbcfg: store for LLDPDU data
516  *
517  * Parse DCB configuration from the LLDPDU
518  **/
519 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
520                                     struct i40e_dcbx_config *dcbcfg)
521 {
522         enum i40e_status_code ret = I40E_SUCCESS;
523         struct i40e_lldp_org_tlv *tlv;
524         u16 type;
525         u16 length;
526         u16 typelength;
527         u16 offset = 0;
528
529         if (!lldpmib || !dcbcfg)
530                 return I40E_ERR_PARAM;
531
532         /* set to the start of LLDPDU */
533         lldpmib += I40E_LLDP_MIB_HLEN;
534         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
535         while (1) {
536                 typelength = I40E_NTOHS(tlv->typelength);
537                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
538                              I40E_LLDP_TLV_TYPE_SHIFT);
539                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
540                                I40E_LLDP_TLV_LEN_SHIFT);
541                 offset += sizeof(typelength) + length;
542
543                 /* END TLV or beyond LLDPDU size */
544                 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
545                         break;
546
547                 switch (type) {
548                 case I40E_TLV_TYPE_ORG:
549                         i40e_parse_org_tlv(tlv, dcbcfg);
550                         break;
551                 default:
552                         break;
553                 }
554
555                 /* Move to next TLV */
556                 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
557                                                     sizeof(tlv->typelength) +
558                                                     length);
559         }
560
561         return ret;
562 }
563
564 /**
565  * i40e_aq_get_dcb_config
566  * @hw: pointer to the hw struct
567  * @mib_type: mib type for the query
568  * @bridgetype: bridge type for the query (remote)
569  * @dcbcfg: store for LLDPDU data
570  *
571  * Query DCB configuration from the Firmware
572  **/
573 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
574                                    u8 bridgetype,
575                                    struct i40e_dcbx_config *dcbcfg)
576 {
577         enum i40e_status_code ret = I40E_SUCCESS;
578         struct i40e_virt_mem mem;
579         u8 *lldpmib;
580
581         /* Allocate the LLDPDU */
582         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
583         if (ret)
584                 return ret;
585
586         lldpmib = (u8 *)mem.va;
587         ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
588                                    (void *)lldpmib, I40E_LLDPDU_SIZE,
589                                    NULL, NULL, NULL);
590         if (ret)
591                 goto free_mem;
592
593         /* Parse LLDP MIB to get dcb configuration */
594         ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
595
596 free_mem:
597         i40e_free_virt_mem(hw, &mem);
598         return ret;
599 }
600
601 /**
602  * i40e_cee_to_dcb_v1_config
603  * @cee_cfg: pointer to CEE v1 response configuration struct
604  * @dcbcfg: DCB configuration struct
605  *
606  * Convert CEE v1 configuration from firmware to DCB configuration
607  **/
608 static void i40e_cee_to_dcb_v1_config(
609                         struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
610                         struct i40e_dcbx_config *dcbcfg)
611 {
612         u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
613         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
614         u8 i, tc, err;
615
616         /* CEE PG data to ETS config */
617         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
618
619         /* Note that the FW creates the oper_prio_tc nibbles reversed
620          * from those in the CEE Priority Group sub-TLV.
621          */
622         for (i = 0; i < 4; i++) {
623                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
624                          I40E_CEE_PGID_PRIO_0_MASK) >>
625                          I40E_CEE_PGID_PRIO_0_SHIFT);
626                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
627                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
628                          I40E_CEE_PGID_PRIO_1_MASK) >>
629                          I40E_CEE_PGID_PRIO_1_SHIFT);
630                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
631         }
632
633         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
634                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
635
636         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
637                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
638                         /* Map it to next empty TC */
639                         dcbcfg->etscfg.prioritytable[i] =
640                                                 cee_cfg->oper_num_tc - 1;
641                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
642                 } else {
643                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
644                 }
645         }
646
647         /* CEE PFC data to ETS config */
648         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
649         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
650
651         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
652                   I40E_AQC_CEE_APP_STATUS_SHIFT;
653         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
654         /* Add APPs if Error is False */
655         if (!err) {
656                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
657                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
658
659                 /* FCoE APP */
660                 dcbcfg->app[0].priority =
661                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
662                          I40E_AQC_CEE_APP_FCOE_SHIFT;
663                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
664                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
665
666                 /* iSCSI APP */
667                 dcbcfg->app[1].priority =
668                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
669                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
670                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
671                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
672
673                 /* FIP APP */
674                 dcbcfg->app[2].priority =
675                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
676                          I40E_AQC_CEE_APP_FIP_SHIFT;
677                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
678                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
679         }
680 }
681
682 /**
683  * i40e_cee_to_dcb_config
684  * @cee_cfg: pointer to CEE configuration struct
685  * @dcbcfg: DCB configuration struct
686  *
687  * Convert CEE configuration from firmware to DCB configuration
688  **/
689 static void i40e_cee_to_dcb_config(
690                                 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
691                                 struct i40e_dcbx_config *dcbcfg)
692 {
693         u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
694         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
695         u8 i, tc, err, sync, oper;
696
697         /* CEE PG data to ETS config */
698         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
699
700         for (i = 0; i < 4; i++) {
701                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
702                          I40E_CEE_PGID_PRIO_1_MASK) >>
703                          I40E_CEE_PGID_PRIO_1_SHIFT);
704                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
705                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
706                          I40E_CEE_PGID_PRIO_0_MASK) >>
707                          I40E_CEE_PGID_PRIO_0_SHIFT);
708                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
709         }
710
711         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
712                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
713
714         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
715                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
716                         /* Map it to next empty TC */
717                         dcbcfg->etscfg.prioritytable[i] =
718                                                 cee_cfg->oper_num_tc - 1;
719                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
720                 } else {
721                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
722                 }
723         }
724
725         /* CEE PFC data to ETS config */
726         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
727         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
728
729         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
730                   I40E_AQC_CEE_APP_STATUS_SHIFT;
731         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
732         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
733         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
734         /* Add APPs if Error is False and Oper/Sync is True */
735         if (!err && sync && oper) {
736                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
737                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
738
739                 /* FCoE APP */
740                 dcbcfg->app[0].priority =
741                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
742                          I40E_AQC_CEE_APP_FCOE_SHIFT;
743                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
744                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
745
746                 /* iSCSI APP */
747                 dcbcfg->app[1].priority =
748                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
749                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
750                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
751                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
752
753                 /* FIP APP */
754                 dcbcfg->app[2].priority =
755                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
756                          I40E_AQC_CEE_APP_FIP_SHIFT;
757                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
758                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
759         }
760 }
761
762 /**
763  * i40e_get_dcb_config
764  * @hw: pointer to the hw struct
765  *
766  * Get DCB configuration from the Firmware
767  **/
768 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
769 {
770         enum i40e_status_code ret = I40E_SUCCESS;
771         struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
772         struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
773
774         /* If Firmware version < v4.33 IEEE only */
775         if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
776             (hw->aq.fw_maj_ver < 4))
777                 goto ieee;
778
779         /* If Firmware version == v4.33 use old CEE struct */
780         if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
781                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
782                                                  sizeof(cee_v1_cfg), NULL);
783                 if (ret == I40E_SUCCESS) {
784                         /* CEE mode */
785                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
786                         i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
787                                                   &hw->local_dcbx_config);
788                 }
789         } else {
790                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
791                                                  sizeof(cee_cfg), NULL);
792                 if (ret == I40E_SUCCESS) {
793                         /* CEE mode */
794                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
795                         i40e_cee_to_dcb_config(&cee_cfg,
796                                                &hw->local_dcbx_config);
797                 }
798         }
799
800         /* CEE mode not enabled try querying IEEE data */
801         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
802                 goto ieee;
803         else
804                 goto out;
805
806 ieee:
807         /* IEEE mode */
808         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
809         /* Get Local DCB Config */
810         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
811                                      &hw->local_dcbx_config);
812         if (ret)
813                 goto out;
814
815         /* Get Remote DCB Config */
816         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
817                              I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
818                              &hw->remote_dcbx_config);
819         /* Don't treat ENOENT as an error for Remote MIBs */
820         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
821                 ret = I40E_SUCCESS;
822
823 out:
824         return ret;
825 }
826
827 /**
828  * i40e_init_dcb
829  * @hw: pointer to the hw struct
830  *
831  * Update DCB configuration from the Firmware
832  **/
833 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
834 {
835         enum i40e_status_code ret = I40E_SUCCESS;
836         struct i40e_lldp_variables lldp_cfg;
837         u8 adminstatus = 0;
838
839         if (!hw->func_caps.dcb)
840                 return ret;
841
842         /* Read LLDP NVM area */
843         ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
844         if (ret)
845                 return ret;
846
847         /* Get the LLDP AdminStatus for the current port */
848         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
849         adminstatus &= 0xF;
850
851         /* LLDP agent disabled */
852         if (!adminstatus) {
853                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
854                 return ret;
855         }
856
857         /* Get DCBX status */
858         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
859         if (ret)
860                 return ret;
861
862         /* Check the DCBX Status */
863         switch (hw->dcbx_status) {
864         case I40E_DCBX_STATUS_DONE:
865         case I40E_DCBX_STATUS_IN_PROGRESS:
866                 /* Get current DCBX configuration */
867                 ret = i40e_get_dcb_config(hw);
868                 if (ret)
869                         return ret;
870                 break;
871         case I40E_DCBX_STATUS_DISABLED:
872                 return ret;
873         case I40E_DCBX_STATUS_NOT_STARTED:
874         case I40E_DCBX_STATUS_MULTIPLE_PEERS:
875         default:
876                 break;
877         }
878
879         /* Configure the LLDP MIB change event */
880         ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
881         if (ret)
882                 return ret;
883
884         return ret;
885 }
886
887
888
889 /**
890  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
891  * @hw: pointer to the HW structure
892  * @lldp_cfg: pointer to hold lldp configuration variables
893  *
894  * Reads the LLDP configuration data from NVM
895  **/
896 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
897                                          struct i40e_lldp_variables *lldp_cfg)
898 {
899         enum i40e_status_code ret = I40E_SUCCESS;
900         u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
901
902         if (!lldp_cfg)
903                 return I40E_ERR_PARAM;
904
905         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
906         if (ret != I40E_SUCCESS)
907                 goto err_lldp_cfg;
908
909         ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
910                                sizeof(struct i40e_lldp_variables),
911                                (u8 *)lldp_cfg,
912                                true, NULL);
913         i40e_release_nvm(hw);
914
915 err_lldp_cfg:
916         return ret;
917 }