Imported Upstream version 16.04
[deb_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;
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                 u8 up, selector;
402
403                 app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
404                 for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
405                         if (app->prio_map & BIT(up))
406                                 break;
407                 }
408                 dcbcfg->app[i].priority = up;
409
410                 /* Get Selector from lower 2 bits, and convert to IEEE */
411                 selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
412                 switch (selector) {
413                 case I40E_CEE_APP_SEL_ETHTYPE:
414                         dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
415                         break;
416                 case I40E_CEE_APP_SEL_TCPIP:
417                         dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
418                         break;
419                 default:
420                         /* Keep selector as it is for unknown types */
421                         dcbcfg->app[i].selector = selector;
422                 }
423
424                 dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
425                 /* Move to next app */
426                 offset += sizeof(*app);
427         }
428 }
429
430 /**
431  * i40e_parse_cee_tlv
432  * @tlv: CEE DCBX TLV
433  * @dcbcfg: Local store to update DCBX config data
434  *
435  * Get the TLV subtype and send it to parsing function
436  * based on the subtype value
437  **/
438 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
439                                struct i40e_dcbx_config *dcbcfg)
440 {
441         u16 len, tlvlen, sublen, typelength;
442         struct i40e_cee_feat_tlv *sub_tlv;
443         u8 subtype, feat_tlv_count = 0;
444         u32 ouisubtype;
445
446         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
447         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
448                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
449         /* Return if not CEE DCBX */
450         if (subtype != I40E_CEE_DCBX_TYPE)
451                 return;
452
453         typelength = I40E_NTOHS(tlv->typelength);
454         tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
455                         I40E_LLDP_TLV_LEN_SHIFT);
456         len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
457               sizeof(struct i40e_cee_ctrl_tlv);
458         /* Return if no CEE DCBX Feature TLVs */
459         if (tlvlen <= len)
460                 return;
461
462         sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
463         while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
464                 typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
465                 sublen = (u16)((typelength &
466                                 I40E_LLDP_TLV_LEN_MASK) >>
467                                 I40E_LLDP_TLV_LEN_SHIFT);
468                 subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
469                                 I40E_LLDP_TLV_TYPE_SHIFT);
470                 switch (subtype) {
471                 case I40E_CEE_SUBTYPE_PG_CFG:
472                         i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
473                         break;
474                 case I40E_CEE_SUBTYPE_PFC_CFG:
475                         i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
476                         break;
477                 case I40E_CEE_SUBTYPE_APP_PRI:
478                         i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
479                         break;
480                 default:
481                         return; /* Invalid Sub-type return */
482                 }
483                 feat_tlv_count++;
484                 /* Move to next sub TLV */
485                 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
486                                                 sizeof(sub_tlv->hdr.typelen) +
487                                                 sublen);
488         }
489 }
490
491 /**
492  * i40e_parse_org_tlv
493  * @tlv: Organization specific TLV
494  * @dcbcfg: Local store to update ETS REC data
495  *
496  * Currently only IEEE 802.1Qaz TLV is supported, all others
497  * will be returned
498  **/
499 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
500                                struct i40e_dcbx_config *dcbcfg)
501 {
502         u32 ouisubtype;
503         u32 oui;
504
505         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
506         oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
507                     I40E_LLDP_TLV_OUI_SHIFT);
508         switch (oui) {
509         case I40E_IEEE_8021QAZ_OUI:
510                 i40e_parse_ieee_tlv(tlv, dcbcfg);
511                 break;
512         case I40E_CEE_DCBX_OUI:
513                 i40e_parse_cee_tlv(tlv, dcbcfg);
514                 break;
515         default:
516                 break;
517         }
518 }
519
520 /**
521  * i40e_lldp_to_dcb_config
522  * @lldpmib: LLDPDU to be parsed
523  * @dcbcfg: store for LLDPDU data
524  *
525  * Parse DCB configuration from the LLDPDU
526  **/
527 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
528                                     struct i40e_dcbx_config *dcbcfg)
529 {
530         enum i40e_status_code ret = I40E_SUCCESS;
531         struct i40e_lldp_org_tlv *tlv;
532         u16 type;
533         u16 length;
534         u16 typelength;
535         u16 offset = 0;
536
537         if (!lldpmib || !dcbcfg)
538                 return I40E_ERR_PARAM;
539
540         /* set to the start of LLDPDU */
541         lldpmib += I40E_LLDP_MIB_HLEN;
542         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
543         while (1) {
544                 typelength = I40E_NTOHS(tlv->typelength);
545                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
546                              I40E_LLDP_TLV_TYPE_SHIFT);
547                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
548                                I40E_LLDP_TLV_LEN_SHIFT);
549                 offset += sizeof(typelength) + length;
550
551                 /* END TLV or beyond LLDPDU size */
552                 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
553                         break;
554
555                 switch (type) {
556                 case I40E_TLV_TYPE_ORG:
557                         i40e_parse_org_tlv(tlv, dcbcfg);
558                         break;
559                 default:
560                         break;
561                 }
562
563                 /* Move to next TLV */
564                 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
565                                                     sizeof(tlv->typelength) +
566                                                     length);
567         }
568
569         return ret;
570 }
571
572 /**
573  * i40e_aq_get_dcb_config
574  * @hw: pointer to the hw struct
575  * @mib_type: mib type for the query
576  * @bridgetype: bridge type for the query (remote)
577  * @dcbcfg: store for LLDPDU data
578  *
579  * Query DCB configuration from the Firmware
580  **/
581 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
582                                    u8 bridgetype,
583                                    struct i40e_dcbx_config *dcbcfg)
584 {
585         enum i40e_status_code ret = I40E_SUCCESS;
586         struct i40e_virt_mem mem;
587         u8 *lldpmib;
588
589         /* Allocate the LLDPDU */
590         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
591         if (ret)
592                 return ret;
593
594         lldpmib = (u8 *)mem.va;
595         ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
596                                    (void *)lldpmib, I40E_LLDPDU_SIZE,
597                                    NULL, NULL, NULL);
598         if (ret)
599                 goto free_mem;
600
601         /* Parse LLDP MIB to get dcb configuration */
602         ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
603
604 free_mem:
605         i40e_free_virt_mem(hw, &mem);
606         return ret;
607 }
608
609 /**
610  * i40e_cee_to_dcb_v1_config
611  * @cee_cfg: pointer to CEE v1 response configuration struct
612  * @dcbcfg: DCB configuration struct
613  *
614  * Convert CEE v1 configuration from firmware to DCB configuration
615  **/
616 static void i40e_cee_to_dcb_v1_config(
617                         struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
618                         struct i40e_dcbx_config *dcbcfg)
619 {
620         u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
621         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
622         u8 i, tc, err;
623
624         /* CEE PG data to ETS config */
625         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
626
627         /* Note that the FW creates the oper_prio_tc nibbles reversed
628          * from those in the CEE Priority Group sub-TLV.
629          */
630         for (i = 0; i < 4; i++) {
631                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
632                          I40E_CEE_PGID_PRIO_0_MASK) >>
633                          I40E_CEE_PGID_PRIO_0_SHIFT);
634                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
635                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
636                          I40E_CEE_PGID_PRIO_1_MASK) >>
637                          I40E_CEE_PGID_PRIO_1_SHIFT);
638                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
639         }
640
641         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
642                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
643
644         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
645                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
646                         /* Map it to next empty TC */
647                         dcbcfg->etscfg.prioritytable[i] =
648                                                 cee_cfg->oper_num_tc - 1;
649                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
650                 } else {
651                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
652                 }
653         }
654
655         /* CEE PFC data to ETS config */
656         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
657         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
658
659         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
660                   I40E_AQC_CEE_APP_STATUS_SHIFT;
661         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
662         /* Add APPs if Error is False */
663         if (!err) {
664                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
665                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
666
667                 /* FCoE APP */
668                 dcbcfg->app[0].priority =
669                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
670                          I40E_AQC_CEE_APP_FCOE_SHIFT;
671                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
672                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
673
674                 /* iSCSI APP */
675                 dcbcfg->app[1].priority =
676                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
677                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
678                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
679                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
680
681                 /* FIP APP */
682                 dcbcfg->app[2].priority =
683                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
684                          I40E_AQC_CEE_APP_FIP_SHIFT;
685                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
686                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
687         }
688 }
689
690 /**
691  * i40e_cee_to_dcb_config
692  * @cee_cfg: pointer to CEE configuration struct
693  * @dcbcfg: DCB configuration struct
694  *
695  * Convert CEE configuration from firmware to DCB configuration
696  **/
697 static void i40e_cee_to_dcb_config(
698                                 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
699                                 struct i40e_dcbx_config *dcbcfg)
700 {
701         u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
702         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
703         u8 i, tc, err, sync, oper;
704
705         /* CEE PG data to ETS config */
706         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
707
708         /* Note that the FW creates the oper_prio_tc nibbles reversed
709          * from those in the CEE Priority Group sub-TLV.
710          */
711         for (i = 0; i < 4; i++) {
712                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
713                          I40E_CEE_PGID_PRIO_0_MASK) >>
714                          I40E_CEE_PGID_PRIO_0_SHIFT);
715                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
716                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
717                          I40E_CEE_PGID_PRIO_1_MASK) >>
718                          I40E_CEE_PGID_PRIO_1_SHIFT);
719                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
720         }
721
722         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
723                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
724
725         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
726                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
727                         /* Map it to next empty TC */
728                         dcbcfg->etscfg.prioritytable[i] =
729                                                 cee_cfg->oper_num_tc - 1;
730                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
731                 } else {
732                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
733                 }
734         }
735
736         /* CEE PFC data to ETS config */
737         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
738         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
739
740         i = 0;
741         status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
742                   I40E_AQC_CEE_FCOE_STATUS_SHIFT;
743         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
744         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
745         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
746         /* Add FCoE APP if Error is False and Oper/Sync is True */
747         if (!err && sync && oper) {
748                 /* FCoE APP */
749                 dcbcfg->app[i].priority =
750                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
751                          I40E_AQC_CEE_APP_FCOE_SHIFT;
752                 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
753                 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
754                 i++;
755         }
756
757         status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
758                   I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
759         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
760         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
761         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
762         /* Add iSCSI APP if Error is False and Oper/Sync is True */
763         if (!err && sync && oper) {
764                 /* iSCSI APP */
765                 dcbcfg->app[i].priority =
766                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
767                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
768                 dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
769                 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
770                 i++;
771         }
772
773         status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
774                   I40E_AQC_CEE_FIP_STATUS_SHIFT;
775         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
776         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
777         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
778         /* Add FIP APP if Error is False and Oper/Sync is True */
779         if (!err && sync && oper) {
780                 /* FIP APP */
781                 dcbcfg->app[i].priority =
782                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
783                          I40E_AQC_CEE_APP_FIP_SHIFT;
784                 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
785                 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
786                 i++;
787         }
788         dcbcfg->numapps = i;
789 }
790
791 /**
792  * i40e_get_ieee_dcb_config
793  * @hw: pointer to the hw struct
794  *
795  * Get IEEE mode DCB configuration from the Firmware
796  **/
797 STATIC enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw)
798 {
799         enum i40e_status_code ret = I40E_SUCCESS;
800
801         /* IEEE mode */
802         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
803         /* Get Local DCB Config */
804         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
805                                      &hw->local_dcbx_config);
806         if (ret)
807                 goto out;
808
809         /* Get Remote DCB Config */
810         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
811                                      I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
812                                      &hw->remote_dcbx_config);
813         /* Don't treat ENOENT as an error for Remote MIBs */
814         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
815                 ret = I40E_SUCCESS;
816
817 out:
818         return ret;
819 }
820
821 /**
822  * i40e_get_dcb_config
823  * @hw: pointer to the hw struct
824  *
825  * Get DCB configuration from the Firmware
826  **/
827 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
828 {
829         enum i40e_status_code ret = I40E_SUCCESS;
830         struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
831         struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
832
833         /* If Firmware version < v4.33 on X710/XL710, IEEE only */
834         if ((hw->mac.type == I40E_MAC_XL710) &&
835             (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
836               (hw->aq.fw_maj_ver < 4)))
837                 return i40e_get_ieee_dcb_config(hw);
838
839         /* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
840         if ((hw->mac.type == I40E_MAC_XL710) &&
841             ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
842                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
843                                                  sizeof(cee_v1_cfg), NULL);
844                 if (ret == I40E_SUCCESS) {
845                         /* CEE mode */
846                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
847                         hw->local_dcbx_config.tlv_status =
848                                         LE16_TO_CPU(cee_v1_cfg.tlv_status);
849                         i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
850                                                   &hw->local_dcbx_config);
851                 }
852         } else {
853                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
854                                                  sizeof(cee_cfg), NULL);
855                 if (ret == I40E_SUCCESS) {
856                         /* CEE mode */
857                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
858                         hw->local_dcbx_config.tlv_status =
859                                         LE32_TO_CPU(cee_cfg.tlv_status);
860                         i40e_cee_to_dcb_config(&cee_cfg,
861                                                &hw->local_dcbx_config);
862                 }
863         }
864
865         /* CEE mode not enabled try querying IEEE data */
866         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
867                 return i40e_get_ieee_dcb_config(hw);
868
869         if (ret != I40E_SUCCESS)
870                 goto out;
871
872         /* Get CEE DCB Desired Config */
873         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
874                                      &hw->desired_dcbx_config);
875         if (ret)
876                 goto out;
877
878         /* Get Remote DCB Config */
879         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
880                              I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
881                              &hw->remote_dcbx_config);
882         /* Don't treat ENOENT as an error for Remote MIBs */
883         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
884                 ret = I40E_SUCCESS;
885
886 out:
887         return ret;
888 }
889
890 /**
891  * i40e_init_dcb
892  * @hw: pointer to the hw struct
893  *
894  * Update DCB configuration from the Firmware
895  **/
896 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
897 {
898         enum i40e_status_code ret = I40E_SUCCESS;
899         struct i40e_lldp_variables lldp_cfg;
900         u8 adminstatus = 0;
901
902         if (!hw->func_caps.dcb)
903                 return ret;
904
905         /* Read LLDP NVM area */
906         ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
907         if (ret)
908                 return ret;
909
910         /* Get the LLDP AdminStatus for the current port */
911         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
912         adminstatus &= 0xF;
913
914         /* LLDP agent disabled */
915         if (!adminstatus) {
916                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
917                 return ret;
918         }
919
920         /* Get DCBX status */
921         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
922         if (ret)
923                 return ret;
924
925         /* Check the DCBX Status */
926         switch (hw->dcbx_status) {
927         case I40E_DCBX_STATUS_DONE:
928         case I40E_DCBX_STATUS_IN_PROGRESS:
929                 /* Get current DCBX configuration */
930                 ret = i40e_get_dcb_config(hw);
931                 if (ret)
932                         return ret;
933                 break;
934         case I40E_DCBX_STATUS_DISABLED:
935                 return ret;
936         case I40E_DCBX_STATUS_NOT_STARTED:
937         case I40E_DCBX_STATUS_MULTIPLE_PEERS:
938         default:
939                 break;
940         }
941
942         /* Configure the LLDP MIB change event */
943         ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
944         if (ret)
945                 return ret;
946
947         return ret;
948 }
949
950 /**
951  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
952  * @tlv: Fill the ETS config data in IEEE format
953  * @dcbcfg: Local store which holds the DCB Config
954  *
955  * Prepare IEEE 802.1Qaz ETS CFG TLV
956  **/
957 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
958                                   struct i40e_dcbx_config *dcbcfg)
959 {
960         u8 priority0, priority1, maxtcwilling = 0;
961         struct i40e_dcb_ets_config *etscfg;
962         u16 offset = 0, typelength, i;
963         u8 *buf = tlv->tlvinfo;
964         u32 ouisubtype;
965
966         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
967                         I40E_IEEE_ETS_TLV_LENGTH);
968         tlv->typelength = I40E_HTONS(typelength);
969
970         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
971                         I40E_IEEE_SUBTYPE_ETS_CFG);
972         tlv->ouisubtype = I40E_HTONL(ouisubtype);
973
974         /* First Octet post subtype
975          * --------------------------
976          * |will-|CBS  | Re-  | Max |
977          * |ing  |     |served| TCs |
978          * --------------------------
979          * |1bit | 1bit|3 bits|3bits|
980          */
981         etscfg = &dcbcfg->etscfg;
982         if (etscfg->willing)
983                 maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
984         maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
985         buf[offset] = maxtcwilling;
986
987         /* Move offset to Priority Assignment Table */
988         offset++;
989
990         /* Priority Assignment Table (4 octets)
991          * Octets:|    1    |    2    |    3    |    4    |
992          *        -----------------------------------------
993          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
994          *        -----------------------------------------
995          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
996          *        -----------------------------------------
997          */
998         for (i = 0; i < 4; i++) {
999                 priority0 = etscfg->prioritytable[i * 2] & 0xF;
1000                 priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
1001                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1002                                 priority1;
1003                 offset++;
1004         }
1005
1006         /* TC Bandwidth Table (8 octets)
1007          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1008          *        ---------------------------------
1009          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1010          *        ---------------------------------
1011          */
1012         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1013                 buf[offset++] = etscfg->tcbwtable[i];
1014
1015         /* TSA Assignment Table (8 octets)
1016          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1017          *        ---------------------------------
1018          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1019          *        ---------------------------------
1020          */
1021         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1022                 buf[offset++] = etscfg->tsatable[i];
1023 }
1024
1025 /**
1026  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1027  * @tlv: Fill ETS Recommended TLV in IEEE format
1028  * @dcbcfg: Local store which holds the DCB Config
1029  *
1030  * Prepare IEEE 802.1Qaz ETS REC TLV
1031  **/
1032 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
1033                                      struct i40e_dcbx_config *dcbcfg)
1034 {
1035         struct i40e_dcb_ets_config *etsrec;
1036         u16 offset = 0, typelength, i;
1037         u8 priority0, priority1;
1038         u8 *buf = tlv->tlvinfo;
1039         u32 ouisubtype;
1040
1041         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1042                         I40E_IEEE_ETS_TLV_LENGTH);
1043         tlv->typelength = I40E_HTONS(typelength);
1044
1045         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1046                         I40E_IEEE_SUBTYPE_ETS_REC);
1047         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1048
1049         etsrec = &dcbcfg->etsrec;
1050         /* First Octet is reserved */
1051         /* Move offset to Priority Assignment Table */
1052         offset++;
1053
1054         /* Priority Assignment Table (4 octets)
1055          * Octets:|    1    |    2    |    3    |    4    |
1056          *        -----------------------------------------
1057          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1058          *        -----------------------------------------
1059          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1060          *        -----------------------------------------
1061          */
1062         for (i = 0; i < 4; i++) {
1063                 priority0 = etsrec->prioritytable[i * 2] & 0xF;
1064                 priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
1065                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1066                                 priority1;
1067                 offset++;
1068         }
1069
1070         /* TC Bandwidth Table (8 octets)
1071          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1072          *        ---------------------------------
1073          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1074          *        ---------------------------------
1075          */
1076         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1077                 buf[offset++] = etsrec->tcbwtable[i];
1078
1079         /* TSA Assignment Table (8 octets)
1080          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1081          *        ---------------------------------
1082          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1083          *        ---------------------------------
1084          */
1085         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1086                 buf[offset++] = etsrec->tsatable[i];
1087 }
1088
1089  /**
1090  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1091  * @tlv: Fill PFC TLV in IEEE format
1092  * @dcbcfg: Local store to get PFC CFG data
1093  *
1094  * Prepare IEEE 802.1Qaz PFC CFG TLV
1095  **/
1096 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
1097                                   struct i40e_dcbx_config *dcbcfg)
1098 {
1099         u8 *buf = tlv->tlvinfo;
1100         u32 ouisubtype;
1101         u16 typelength;
1102
1103         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1104                         I40E_IEEE_PFC_TLV_LENGTH);
1105         tlv->typelength = I40E_HTONS(typelength);
1106
1107         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1108                         I40E_IEEE_SUBTYPE_PFC_CFG);
1109         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1110
1111         /* ----------------------------------------
1112          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1113          * |ing  |     |served| cap |              |
1114          * -----------------------------------------
1115          * |1bit | 1bit|2 bits|4bits| 1 octet      |
1116          */
1117         if (dcbcfg->pfc.willing)
1118                 buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
1119
1120         if (dcbcfg->pfc.mbc)
1121                 buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
1122
1123         buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1124         buf[1] = dcbcfg->pfc.pfcenable;
1125 }
1126
1127 /**
1128  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1129  * @tlv: Fill APP TLV in IEEE format
1130  * @dcbcfg: Local store to get APP CFG data
1131  *
1132  * Prepare IEEE 802.1Qaz APP CFG TLV
1133  **/
1134 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
1135                                       struct i40e_dcbx_config *dcbcfg)
1136 {
1137         u16 typelength, length, offset = 0;
1138         u8 priority, selector, i = 0;
1139         u8 *buf = tlv->tlvinfo;
1140         u32 ouisubtype;
1141
1142         /* No APP TLVs then just return */
1143         if (dcbcfg->numapps == 0)
1144                 return;
1145         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1146                         I40E_IEEE_SUBTYPE_APP_PRI);
1147         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1148
1149         /* Move offset to App Priority Table */
1150         offset++;
1151         /* Application Priority Table (3 octets)
1152          * Octets:|         1          |    2    |    3    |
1153          *        -----------------------------------------
1154          *        |Priority|Rsrvd| Sel |    Protocol ID    |
1155          *        -----------------------------------------
1156          *   Bits:|23    21|20 19|18 16|15                0|
1157          *        -----------------------------------------
1158          */
1159         while (i < dcbcfg->numapps) {
1160                 priority = dcbcfg->app[i].priority & 0x7;
1161                 selector = dcbcfg->app[i].selector & 0x7;
1162                 buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
1163                 buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
1164                 buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
1165                 /* Move to next app */
1166                 offset += 3;
1167                 i++;
1168                 if (i >= I40E_DCBX_MAX_APPS)
1169                         break;
1170         }
1171         /* length includes size of ouisubtype + 1 reserved + 3*numapps */
1172         length = sizeof(tlv->ouisubtype) + 1 + (i*3);
1173         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1174                 (length & 0x1FF));
1175         tlv->typelength = I40E_HTONS(typelength);
1176 }
1177
1178  /**
1179  * i40e_add_dcb_tlv - Add all IEEE TLVs
1180  * @tlv: pointer to org tlv
1181  *
1182  * add tlv information
1183  **/
1184 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
1185                              struct i40e_dcbx_config *dcbcfg,
1186                              u16 tlvid)
1187 {
1188         switch (tlvid) {
1189         case I40E_IEEE_TLV_ID_ETS_CFG:
1190                 i40e_add_ieee_ets_tlv(tlv, dcbcfg);
1191                 break;
1192         case I40E_IEEE_TLV_ID_ETS_REC:
1193                 i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
1194                 break;
1195         case I40E_IEEE_TLV_ID_PFC_CFG:
1196                 i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
1197                 break;
1198         case I40E_IEEE_TLV_ID_APP_PRI:
1199                 i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
1200                 break;
1201         default:
1202                 break;
1203         }
1204 }
1205
1206  /**
1207  * i40e_set_dcb_config - Set the local LLDP MIB to FW
1208  * @hw: pointer to the hw struct
1209  *
1210  * Set DCB configuration to the Firmware
1211  **/
1212 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
1213 {
1214         enum i40e_status_code ret = I40E_SUCCESS;
1215         struct i40e_dcbx_config *dcbcfg;
1216         struct i40e_virt_mem mem;
1217         u8 mib_type, *lldpmib;
1218         u16 miblen;
1219
1220         /* update the hw local config */
1221         dcbcfg = &hw->local_dcbx_config;
1222         /* Allocate the LLDPDU */
1223         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
1224         if (ret)
1225                 return ret;
1226
1227         mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
1228         if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
1229                 mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
1230                             SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
1231         }
1232         lldpmib = (u8 *)mem.va;
1233         ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
1234         ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
1235
1236         i40e_free_virt_mem(hw, &mem);
1237         return ret;
1238 }
1239
1240 /**
1241  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1242  * @hw: pointer to the hw struct
1243  * @dcbcfg: store for LLDPDU data
1244  *
1245  * send DCB configuration to FW
1246  **/
1247 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
1248                                               struct i40e_dcbx_config *dcbcfg)
1249 {
1250         u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
1251         enum i40e_status_code ret = I40E_SUCCESS;
1252         struct i40e_lldp_org_tlv *tlv;
1253         u16 typelength;
1254
1255         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
1256         while (1) {
1257                 i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1258                 typelength = I40E_NTOHS(tlv->typelength);
1259                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
1260                                 I40E_LLDP_TLV_LEN_SHIFT);
1261                 if (length)
1262                         offset += length + 2;
1263                 /* END TLV or beyond LLDPDU size */
1264                 if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
1265                     (offset > I40E_LLDPDU_SIZE))
1266                         break;
1267                 /* Move to next TLV */
1268                 if (length)
1269                         tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
1270                               sizeof(tlv->typelength) + length);
1271         }
1272         *miblen = offset;
1273         return ret;
1274 }
1275
1276
1277 /**
1278  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
1279  * @hw: pointer to the HW structure
1280  * @lldp_cfg: pointer to hold lldp configuration variables
1281  *
1282  * Reads the LLDP configuration data from NVM
1283  **/
1284 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
1285                                          struct i40e_lldp_variables *lldp_cfg)
1286 {
1287         enum i40e_status_code ret = I40E_SUCCESS;
1288         u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
1289
1290         if (!lldp_cfg)
1291                 return I40E_ERR_PARAM;
1292
1293         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1294         if (ret != I40E_SUCCESS)
1295                 goto err_lldp_cfg;
1296
1297         ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
1298                                sizeof(struct i40e_lldp_variables),
1299                                (u8 *)lldp_cfg,
1300                                true, NULL);
1301         i40e_release_nvm(hw);
1302
1303 err_lldp_cfg:
1304         return ret;
1305 }