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