i40e/base: store CEE DCBX config
[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_ieee_dcb_config
764  * @hw: pointer to the hw struct
765  *
766  * Get IEEE mode DCB configuration from the Firmware
767  **/
768 STATIC enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw)
769 {
770         enum i40e_status_code ret = I40E_SUCCESS;
771
772         /* IEEE mode */
773         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
774         /* Get Local DCB Config */
775         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
776                                      &hw->local_dcbx_config);
777         if (ret)
778                 goto out;
779
780         /* Get Remote DCB Config */
781         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
782                                      I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
783                                      &hw->remote_dcbx_config);
784         /* Don't treat ENOENT as an error for Remote MIBs */
785         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
786                 ret = I40E_SUCCESS;
787
788 out:
789         return ret;
790 }
791
792 /**
793  * i40e_get_dcb_config
794  * @hw: pointer to the hw struct
795  *
796  * Get DCB configuration from the Firmware
797  **/
798 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
799 {
800         enum i40e_status_code ret = I40E_SUCCESS;
801         struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
802         struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
803
804         /* If Firmware version < v4.33 IEEE only */
805         if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
806             (hw->aq.fw_maj_ver < 4))
807                 return i40e_get_ieee_dcb_config(hw);
808
809         /* If Firmware version == v4.33 use old CEE struct */
810         if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
811                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
812                                                  sizeof(cee_v1_cfg), NULL);
813                 if (ret == I40E_SUCCESS) {
814                         /* CEE mode */
815                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
816                         hw->local_dcbx_config.tlv_status =
817                                         LE16_TO_CPU(cee_v1_cfg.tlv_status);
818                         i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
819                                                   &hw->local_dcbx_config);
820                 }
821         } else {
822                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
823                                                  sizeof(cee_cfg), NULL);
824                 if (ret == I40E_SUCCESS) {
825                         /* CEE mode */
826                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
827                         hw->local_dcbx_config.tlv_status =
828                                         LE32_TO_CPU(cee_cfg.tlv_status);
829                         i40e_cee_to_dcb_config(&cee_cfg,
830                                                &hw->local_dcbx_config);
831                 }
832         }
833
834         /* CEE mode not enabled try querying IEEE data */
835         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
836                 return i40e_get_ieee_dcb_config(hw);
837
838         if (ret != I40E_SUCCESS)
839                 goto out;
840
841         /* Get CEE DCB Desired Config */
842         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
843                                      &hw->desired_dcbx_config);
844         if (ret)
845                 goto out;
846
847         /* Get Remote DCB Config */
848         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
849                              I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
850                              &hw->remote_dcbx_config);
851         /* Don't treat ENOENT as an error for Remote MIBs */
852         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
853                 ret = I40E_SUCCESS;
854
855 out:
856         return ret;
857 }
858
859 /**
860  * i40e_init_dcb
861  * @hw: pointer to the hw struct
862  *
863  * Update DCB configuration from the Firmware
864  **/
865 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
866 {
867         enum i40e_status_code ret = I40E_SUCCESS;
868         struct i40e_lldp_variables lldp_cfg;
869         u8 adminstatus = 0;
870
871         if (!hw->func_caps.dcb)
872                 return ret;
873
874         /* Read LLDP NVM area */
875         ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
876         if (ret)
877                 return ret;
878
879         /* Get the LLDP AdminStatus for the current port */
880         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
881         adminstatus &= 0xF;
882
883         /* LLDP agent disabled */
884         if (!adminstatus) {
885                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
886                 return ret;
887         }
888
889         /* Get DCBX status */
890         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
891         if (ret)
892                 return ret;
893
894         /* Check the DCBX Status */
895         switch (hw->dcbx_status) {
896         case I40E_DCBX_STATUS_DONE:
897         case I40E_DCBX_STATUS_IN_PROGRESS:
898                 /* Get current DCBX configuration */
899                 ret = i40e_get_dcb_config(hw);
900                 if (ret)
901                         return ret;
902                 break;
903         case I40E_DCBX_STATUS_DISABLED:
904                 return ret;
905         case I40E_DCBX_STATUS_NOT_STARTED:
906         case I40E_DCBX_STATUS_MULTIPLE_PEERS:
907         default:
908                 break;
909         }
910
911         /* Configure the LLDP MIB change event */
912         ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
913         if (ret)
914                 return ret;
915
916         return ret;
917 }
918
919 /**
920  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
921  * @tlv: Fill the ETS config data in IEEE format
922  * @dcbcfg: Local store which holds the DCB Config
923  *
924  * Prepare IEEE 802.1Qaz ETS CFG TLV
925  **/
926 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
927                                   struct i40e_dcbx_config *dcbcfg)
928 {
929         u8 priority0, priority1, maxtcwilling = 0;
930         struct i40e_dcb_ets_config *etscfg;
931         u16 offset = 0, typelength, i;
932         u8 *buf = tlv->tlvinfo;
933         u32 ouisubtype;
934
935         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
936                         I40E_IEEE_ETS_TLV_LENGTH);
937         tlv->typelength = I40E_HTONS(typelength);
938
939         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
940                         I40E_IEEE_SUBTYPE_ETS_CFG);
941         tlv->ouisubtype = I40E_HTONL(ouisubtype);
942
943         /* First Octet post subtype
944          * --------------------------
945          * |will-|CBS  | Re-  | Max |
946          * |ing  |     |served| TCs |
947          * --------------------------
948          * |1bit | 1bit|3 bits|3bits|
949          */
950         etscfg = &dcbcfg->etscfg;
951         if (etscfg->willing)
952                 maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
953         maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
954         buf[offset] = maxtcwilling;
955
956         /* Move offset to Priority Assignment Table */
957         offset++;
958
959         /* Priority Assignment Table (4 octets)
960          * Octets:|    1    |    2    |    3    |    4    |
961          *        -----------------------------------------
962          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
963          *        -----------------------------------------
964          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
965          *        -----------------------------------------
966          */
967         for (i = 0; i < 4; i++) {
968                 priority0 = etscfg->prioritytable[i * 2] & 0xF;
969                 priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
970                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
971                                 priority1;
972                 offset++;
973         }
974
975         /* TC Bandwidth Table (8 octets)
976          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
977          *        ---------------------------------
978          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
979          *        ---------------------------------
980          */
981         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
982                 buf[offset++] = etscfg->tcbwtable[i];
983
984         /* TSA Assignment Table (8 octets)
985          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
986          *        ---------------------------------
987          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
988          *        ---------------------------------
989          */
990         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
991                 buf[offset++] = etscfg->tsatable[i];
992 }
993
994 /**
995  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
996  * @tlv: Fill ETS Recommended TLV in IEEE format
997  * @dcbcfg: Local store which holds the DCB Config
998  *
999  * Prepare IEEE 802.1Qaz ETS REC TLV
1000  **/
1001 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
1002                                      struct i40e_dcbx_config *dcbcfg)
1003 {
1004         struct i40e_dcb_ets_config *etsrec;
1005         u16 offset = 0, typelength, i;
1006         u8 priority0, priority1;
1007         u8 *buf = tlv->tlvinfo;
1008         u32 ouisubtype;
1009
1010         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1011                         I40E_IEEE_ETS_TLV_LENGTH);
1012         tlv->typelength = I40E_HTONS(typelength);
1013
1014         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1015                         I40E_IEEE_SUBTYPE_ETS_REC);
1016         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1017
1018         etsrec = &dcbcfg->etsrec;
1019         /* First Octet is reserved */
1020         /* Move offset to Priority Assignment Table */
1021         offset++;
1022
1023         /* Priority Assignment Table (4 octets)
1024          * Octets:|    1    |    2    |    3    |    4    |
1025          *        -----------------------------------------
1026          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1027          *        -----------------------------------------
1028          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1029          *        -----------------------------------------
1030          */
1031         for (i = 0; i < 4; i++) {
1032                 priority0 = etsrec->prioritytable[i * 2] & 0xF;
1033                 priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
1034                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1035                                 priority1;
1036                 offset++;
1037         }
1038
1039         /* TC Bandwidth Table (8 octets)
1040          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1041          *        ---------------------------------
1042          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1043          *        ---------------------------------
1044          */
1045         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1046                 buf[offset++] = etsrec->tcbwtable[i];
1047
1048         /* TSA Assignment Table (8 octets)
1049          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1050          *        ---------------------------------
1051          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1052          *        ---------------------------------
1053          */
1054         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1055                 buf[offset++] = etsrec->tsatable[i];
1056 }
1057
1058  /**
1059  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1060  * @tlv: Fill PFC TLV in IEEE format
1061  * @dcbcfg: Local store to get PFC CFG data
1062  *
1063  * Prepare IEEE 802.1Qaz PFC CFG TLV
1064  **/
1065 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
1066                                   struct i40e_dcbx_config *dcbcfg)
1067 {
1068         u8 *buf = tlv->tlvinfo;
1069         u32 ouisubtype;
1070         u16 typelength;
1071
1072         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1073                         I40E_IEEE_PFC_TLV_LENGTH);
1074         tlv->typelength = I40E_HTONS(typelength);
1075
1076         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1077                         I40E_IEEE_SUBTYPE_PFC_CFG);
1078         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1079
1080         /* ----------------------------------------
1081          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1082          * |ing  |     |served| cap |              |
1083          * -----------------------------------------
1084          * |1bit | 1bit|2 bits|4bits| 1 octet      |
1085          */
1086         if (dcbcfg->pfc.willing)
1087                 buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
1088
1089         if (dcbcfg->pfc.mbc)
1090                 buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
1091
1092         buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1093         buf[1] = dcbcfg->pfc.pfcenable;
1094 }
1095
1096 /**
1097  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1098  * @tlv: Fill APP TLV in IEEE format
1099  * @dcbcfg: Local store to get APP CFG data
1100  *
1101  * Prepare IEEE 802.1Qaz APP CFG TLV
1102  **/
1103 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
1104                                       struct i40e_dcbx_config *dcbcfg)
1105 {
1106         u16 typelength, length, offset = 0;
1107         u8 priority, selector, i = 0;
1108         u8 *buf = tlv->tlvinfo;
1109         u32 ouisubtype;
1110
1111         /* No APP TLVs then just return */
1112         if (dcbcfg->numapps == 0)
1113                 return;
1114         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1115                         I40E_IEEE_SUBTYPE_APP_PRI);
1116         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1117
1118         /* Move offset to App Priority Table */
1119         offset++;
1120         /* Application Priority Table (3 octets)
1121          * Octets:|         1          |    2    |    3    |
1122          *        -----------------------------------------
1123          *        |Priority|Rsrvd| Sel |    Protocol ID    |
1124          *        -----------------------------------------
1125          *   Bits:|23    21|20 19|18 16|15                0|
1126          *        -----------------------------------------
1127          */
1128         while (i < dcbcfg->numapps) {
1129                 priority = dcbcfg->app[i].priority & 0x7;
1130                 selector = dcbcfg->app[i].selector & 0x7;
1131                 buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
1132                 buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
1133                 buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
1134                 /* Move to next app */
1135                 offset += 3;
1136                 i++;
1137                 if (i >= I40E_DCBX_MAX_APPS)
1138                         break;
1139         }
1140         /* length includes size of ouisubtype + 1 reserved + 3*numapps */
1141         length = sizeof(tlv->ouisubtype) + 1 + (i*3);
1142         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1143                 (length & 0x1FF));
1144         tlv->typelength = I40E_HTONS(typelength);
1145 }
1146
1147  /**
1148  * i40e_add_dcb_tlv - Add all IEEE TLVs
1149  * @tlv: pointer to org tlv
1150  *
1151  * add tlv information
1152  **/
1153 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
1154                              struct i40e_dcbx_config *dcbcfg,
1155                              u16 tlvid)
1156 {
1157         switch (tlvid) {
1158         case I40E_IEEE_TLV_ID_ETS_CFG:
1159                 i40e_add_ieee_ets_tlv(tlv, dcbcfg);
1160                 break;
1161         case I40E_IEEE_TLV_ID_ETS_REC:
1162                 i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
1163                 break;
1164         case I40E_IEEE_TLV_ID_PFC_CFG:
1165                 i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
1166                 break;
1167         case I40E_IEEE_TLV_ID_APP_PRI:
1168                 i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
1169                 break;
1170         default:
1171                 break;
1172         }
1173 }
1174
1175  /**
1176  * i40e_set_dcb_config - Set the local LLDP MIB to FW
1177  * @hw: pointer to the hw struct
1178  *
1179  * Set DCB configuration to the Firmware
1180  **/
1181 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
1182 {
1183         enum i40e_status_code ret = I40E_SUCCESS;
1184         struct i40e_dcbx_config *dcbcfg;
1185         struct i40e_virt_mem mem;
1186         u8 mib_type, *lldpmib;
1187         u16 miblen;
1188
1189         /* update the hw local config */
1190         dcbcfg = &hw->local_dcbx_config;
1191         /* Allocate the LLDPDU */
1192         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
1193         if (ret)
1194                 return ret;
1195
1196         mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
1197         if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
1198                 mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
1199                             SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
1200         }
1201         lldpmib = (u8 *)mem.va;
1202         ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
1203         ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
1204
1205         i40e_free_virt_mem(hw, &mem);
1206         return ret;
1207 }
1208
1209 /**
1210  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1211  * @hw: pointer to the hw struct
1212  * @dcbcfg: store for LLDPDU data
1213  *
1214  * send DCB configuration to FW
1215  **/
1216 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
1217                                               struct i40e_dcbx_config *dcbcfg)
1218 {
1219         u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
1220         enum i40e_status_code ret = I40E_SUCCESS;
1221         struct i40e_lldp_org_tlv *tlv;
1222         u16 type, typelength;
1223
1224         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
1225         while (1) {
1226                 i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1227                 typelength = I40E_NTOHS(tlv->typelength);
1228                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
1229                                 I40E_LLDP_TLV_TYPE_SHIFT);
1230                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
1231                                 I40E_LLDP_TLV_LEN_SHIFT);
1232                 if (length)
1233                         offset += length + 2;
1234                 /* END TLV or beyond LLDPDU size */
1235                 if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
1236                     (offset > I40E_LLDPDU_SIZE))
1237                         break;
1238                 /* Move to next TLV */
1239                 if (length)
1240                         tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
1241                               sizeof(tlv->typelength) + length);
1242         }
1243         *miblen = offset;
1244         return ret;
1245 }
1246
1247
1248 /**
1249  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
1250  * @hw: pointer to the HW structure
1251  * @lldp_cfg: pointer to hold lldp configuration variables
1252  *
1253  * Reads the LLDP configuration data from NVM
1254  **/
1255 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
1256                                          struct i40e_lldp_variables *lldp_cfg)
1257 {
1258         enum i40e_status_code ret = I40E_SUCCESS;
1259         u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
1260
1261         if (!lldp_cfg)
1262                 return I40E_ERR_PARAM;
1263
1264         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1265         if (ret != I40E_SUCCESS)
1266                 goto err_lldp_cfg;
1267
1268         ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
1269                                sizeof(struct i40e_lldp_variables),
1270                                (u8 *)lldp_cfg,
1271                                true, NULL);
1272         i40e_release_nvm(hw);
1273
1274 err_lldp_cfg:
1275         return ret;
1276 }