i40e/base: prepare local LLDP MIB in TLV
[dpdk.git] / drivers / net / i40e / base / i40e_dcb.c
1 /*******************************************************************************
2
3 Copyright (c) 2013 - 2015, Intel Corporation
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9  1. Redistributions of source code must retain the above copyright notice,
10     this list of conditions and the following disclaimer.
11
12  2. Redistributions in binary form must reproduce the above copyright
13     notice, this list of conditions and the following disclaimer in the
14     documentation and/or other materials provided with the distribution.
15
16  3. Neither the name of the Intel Corporation nor the names of its
17     contributors may be used to endorse or promote products derived from
18     this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 POSSIBILITY OF SUCH DAMAGE.
31
32 ***************************************************************************/
33
34 #include "i40e_adminq.h"
35 #include "i40e_prototype.h"
36 #include "i40e_dcb.h"
37
38 /**
39  * i40e_get_dcbx_status
40  * @hw: pointer to the hw struct
41  * @status: Embedded DCBX Engine Status
42  *
43  * Get the DCBX status from the Firmware
44  **/
45 enum i40e_status_code i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
46 {
47         u32 reg;
48
49         if (!status)
50                 return I40E_ERR_PARAM;
51
52         reg = rd32(hw, I40E_PRTDCB_GENS);
53         *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
54                         I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
55
56         return I40E_SUCCESS;
57 }
58
59 /**
60  * i40e_parse_ieee_etscfg_tlv
61  * @tlv: IEEE 802.1Qaz ETS CFG TLV
62  * @dcbcfg: Local store to update ETS CFG data
63  *
64  * Parses IEEE 802.1Qaz ETS CFG TLV
65  **/
66 static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
67                                        struct i40e_dcbx_config *dcbcfg)
68 {
69         struct i40e_dcb_ets_config *etscfg;
70         u8 *buf = tlv->tlvinfo;
71         u16 offset = 0;
72         u8 priority;
73         int i;
74
75         /* First Octet post subtype
76          * --------------------------
77          * |will-|CBS  | Re-  | Max |
78          * |ing  |     |served| TCs |
79          * --------------------------
80          * |1bit | 1bit|3 bits|3bits|
81          */
82         etscfg = &dcbcfg->etscfg;
83         etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
84                                I40E_IEEE_ETS_WILLING_SHIFT);
85         etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
86                            I40E_IEEE_ETS_CBS_SHIFT);
87         etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
88                               I40E_IEEE_ETS_MAXTC_SHIFT);
89
90         /* Move offset to Priority Assignment Table */
91         offset++;
92
93         /* Priority Assignment Table (4 octets)
94          * Octets:|    1    |    2    |    3    |    4    |
95          *        -----------------------------------------
96          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
97          *        -----------------------------------------
98          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
99          *        -----------------------------------------
100          */
101         for (i = 0; i < 4; i++) {
102                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
103                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
104                 etscfg->prioritytable[i * 2] =  priority;
105                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
106                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
107                 etscfg->prioritytable[i * 2 + 1] = priority;
108                 offset++;
109         }
110
111         /* TC Bandwidth Table (8 octets)
112          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
113          *        ---------------------------------
114          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
115          *        ---------------------------------
116          */
117         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
118                 etscfg->tcbwtable[i] = buf[offset++];
119
120         /* TSA Assignment Table (8 octets)
121          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
122          *        ---------------------------------
123          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
124          *        ---------------------------------
125          */
126         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
127                 etscfg->tsatable[i] = buf[offset++];
128 }
129
130 /**
131  * i40e_parse_ieee_etsrec_tlv
132  * @tlv: IEEE 802.1Qaz ETS REC TLV
133  * @dcbcfg: Local store to update ETS REC data
134  *
135  * Parses IEEE 802.1Qaz ETS REC TLV
136  **/
137 static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
138                                        struct i40e_dcbx_config *dcbcfg)
139 {
140         u8 *buf = tlv->tlvinfo;
141         u16 offset = 0;
142         u8 priority;
143         int i;
144
145         /* Move offset to priority table */
146         offset++;
147
148         /* Priority Assignment Table (4 octets)
149          * Octets:|    1    |    2    |    3    |    4    |
150          *        -----------------------------------------
151          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
152          *        -----------------------------------------
153          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
154          *        -----------------------------------------
155          */
156         for (i = 0; i < 4; i++) {
157                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
158                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
159                 dcbcfg->etsrec.prioritytable[i*2] =  priority;
160                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
161                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
162                 dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
163                 offset++;
164         }
165
166         /* TC Bandwidth Table (8 octets)
167          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
168          *        ---------------------------------
169          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
170          *        ---------------------------------
171          */
172         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
173                 dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
174
175         /* TSA Assignment Table (8 octets)
176          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
177          *        ---------------------------------
178          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
179          *        ---------------------------------
180          */
181         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
182                 dcbcfg->etsrec.tsatable[i] = buf[offset++];
183 }
184
185 /**
186  * i40e_parse_ieee_pfccfg_tlv
187  * @tlv: IEEE 802.1Qaz PFC CFG TLV
188  * @dcbcfg: Local store to update PFC CFG data
189  *
190  * Parses IEEE 802.1Qaz PFC CFG TLV
191  **/
192 static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
193                                        struct i40e_dcbx_config *dcbcfg)
194 {
195         u8 *buf = tlv->tlvinfo;
196
197         /* ----------------------------------------
198          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
199          * |ing  |     |served| cap |              |
200          * -----------------------------------------
201          * |1bit | 1bit|2 bits|4bits| 1 octet      |
202          */
203         dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
204                                    I40E_IEEE_PFC_WILLING_SHIFT);
205         dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
206                                I40E_IEEE_PFC_MBC_SHIFT);
207         dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
208                                   I40E_IEEE_PFC_CAP_SHIFT);
209         dcbcfg->pfc.pfcenable = buf[1];
210 }
211
212 /**
213  * i40e_parse_ieee_app_tlv
214  * @tlv: IEEE 802.1Qaz APP TLV
215  * @dcbcfg: Local store to update APP PRIO data
216  *
217  * Parses IEEE 802.1Qaz APP PRIO TLV
218  **/
219 static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
220                                     struct i40e_dcbx_config *dcbcfg)
221 {
222         u16 typelength;
223         u16 offset = 0;
224         u16 length;
225         int i = 0;
226         u8 *buf;
227
228         typelength = I40E_NTOHS(tlv->typelength);
229         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
230                        I40E_LLDP_TLV_LEN_SHIFT);
231         buf = tlv->tlvinfo;
232
233         /* The App priority table starts 5 octets after TLV header */
234         length -= (sizeof(tlv->ouisubtype) + 1);
235
236         /* Move offset to App Priority Table */
237         offset++;
238
239         /* Application Priority Table (3 octets)
240          * Octets:|         1          |    2    |    3    |
241          *        -----------------------------------------
242          *        |Priority|Rsrvd| Sel |    Protocol ID    |
243          *        -----------------------------------------
244          *   Bits:|23    21|20 19|18 16|15                0|
245          *        -----------------------------------------
246          */
247         while (offset < length) {
248                 dcbcfg->app[i].priority = (u8)((buf[offset] &
249                                                 I40E_IEEE_APP_PRIO_MASK) >>
250                                                I40E_IEEE_APP_PRIO_SHIFT);
251                 dcbcfg->app[i].selector = (u8)((buf[offset] &
252                                                 I40E_IEEE_APP_SEL_MASK) >>
253                                                I40E_IEEE_APP_SEL_SHIFT);
254                 dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
255                                              buf[offset + 2];
256                 /* Move to next app */
257                 offset += 3;
258                 i++;
259                 if (i >= I40E_DCBX_MAX_APPS)
260                         break;
261         }
262
263         dcbcfg->numapps = i;
264 }
265
266 /**
267  * i40e_parse_ieee_etsrec_tlv
268  * @tlv: IEEE 802.1Qaz TLV
269  * @dcbcfg: Local store to update ETS REC data
270  *
271  * Get the TLV subtype and send it to parsing function
272  * based on the subtype value
273  **/
274 static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
275                                 struct i40e_dcbx_config *dcbcfg)
276 {
277         u32 ouisubtype;
278         u8 subtype;
279
280         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
281         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
282                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
283         switch (subtype) {
284         case I40E_IEEE_SUBTYPE_ETS_CFG:
285                 i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
286                 break;
287         case I40E_IEEE_SUBTYPE_ETS_REC:
288                 i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
289                 break;
290         case I40E_IEEE_SUBTYPE_PFC_CFG:
291                 i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
292                 break;
293         case I40E_IEEE_SUBTYPE_APP_PRI:
294                 i40e_parse_ieee_app_tlv(tlv, dcbcfg);
295                 break;
296         default:
297                 break;
298         }
299 }
300
301 /**
302  * i40e_parse_cee_pgcfg_tlv
303  * @tlv: CEE DCBX PG CFG TLV
304  * @dcbcfg: Local store to update ETS CFG data
305  *
306  * Parses CEE DCBX PG CFG TLV
307  **/
308 static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
309                                      struct i40e_dcbx_config *dcbcfg)
310 {
311         struct i40e_dcb_ets_config *etscfg;
312         u8 *buf = tlv->tlvinfo;
313         u16 offset = 0;
314         u8 priority;
315         int i;
316
317         etscfg = &dcbcfg->etscfg;
318
319         if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
320                 etscfg->willing = 1;
321
322         etscfg->cbs = 0;
323         /* Priority Group Table (4 octets)
324          * Octets:|    1    |    2    |    3    |    4    |
325          *        -----------------------------------------
326          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
327          *        -----------------------------------------
328          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
329          *        -----------------------------------------
330          */
331         for (i = 0; i < 4; i++) {
332                 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
333                                  I40E_CEE_PGID_PRIO_1_SHIFT);
334                 etscfg->prioritytable[i * 2] =  priority;
335                 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
336                                  I40E_CEE_PGID_PRIO_0_SHIFT);
337                 etscfg->prioritytable[i * 2 + 1] = priority;
338                 offset++;
339         }
340
341         /* PG Percentage Table (8 octets)
342          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
343          *        ---------------------------------
344          *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
345          *        ---------------------------------
346          */
347         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
348                 etscfg->tcbwtable[i] = buf[offset++];
349
350         /* Number of TCs supported (1 octet) */
351         etscfg->maxtcs = buf[offset];
352 }
353
354 /**
355  * i40e_parse_cee_pfccfg_tlv
356  * @tlv: CEE DCBX PFC CFG TLV
357  * @dcbcfg: Local store to update PFC CFG data
358  *
359  * Parses CEE DCBX PFC CFG TLV
360  **/
361 static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
362                                       struct i40e_dcbx_config *dcbcfg)
363 {
364         u8 *buf = tlv->tlvinfo;
365
366         if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
367                 dcbcfg->pfc.willing = 1;
368
369         /* ------------------------
370          * | PFC Enable | PFC TCs |
371          * ------------------------
372          * | 1 octet    | 1 octet |
373          */
374         dcbcfg->pfc.pfcenable = buf[0];
375         dcbcfg->pfc.pfccap = buf[1];
376 }
377
378 /**
379  * i40e_parse_cee_app_tlv
380  * @tlv: CEE DCBX APP TLV
381  * @dcbcfg: Local store to update APP PRIO data
382  *
383  * Parses CEE DCBX APP PRIO TLV
384  **/
385 static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
386                                    struct i40e_dcbx_config *dcbcfg)
387 {
388         u16 length, typelength, offset = 0;
389         struct i40e_cee_app_prio *app;
390         u8 i, up, selector;
391
392         typelength = I40E_NTOHS(tlv->hdr.typelen);
393         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
394                        I40E_LLDP_TLV_LEN_SHIFT);
395
396         dcbcfg->numapps = length/sizeof(*app);
397         if (!dcbcfg->numapps)
398                 return;
399
400         for (i = 0; i < dcbcfg->numapps; i++) {
401                 app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
402                 for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
403                         if (app->prio_map & BIT(up))
404                                 break;
405                 }
406                 dcbcfg->app[i].priority = up;
407                 /* Get Selector from lower 2 bits, and convert to IEEE */
408                 selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
409                 if (selector == I40E_CEE_APP_SEL_ETHTYPE)
410                         dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
411                 else if (selector == I40E_CEE_APP_SEL_TCPIP)
412                         dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
413                 else
414                         /* Keep selector as it is for unknown types */
415                         dcbcfg->app[i].selector = selector;
416                 dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
417                 /* Move to next app */
418                 offset += sizeof(*app);
419         }
420 }
421
422 /**
423  * i40e_parse_cee_tlv
424  * @tlv: CEE DCBX TLV
425  * @dcbcfg: Local store to update DCBX config data
426  *
427  * Get the TLV subtype and send it to parsing function
428  * based on the subtype value
429  **/
430 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
431                                struct i40e_dcbx_config *dcbcfg)
432 {
433         u16 len, tlvlen, sublen, typelength;
434         struct i40e_cee_feat_tlv *sub_tlv;
435         u8 subtype, feat_tlv_count = 0;
436         u32 ouisubtype;
437
438         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
439         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
440                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
441         /* Return if not CEE DCBX */
442         if (subtype != I40E_CEE_DCBX_TYPE)
443                 return;
444
445         typelength = I40E_NTOHS(tlv->typelength);
446         tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
447                         I40E_LLDP_TLV_LEN_SHIFT);
448         len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
449               sizeof(struct i40e_cee_ctrl_tlv);
450         /* Return if no CEE DCBX Feature TLVs */
451         if (tlvlen <= len)
452                 return;
453
454         sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
455         while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
456                 typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
457                 sublen = (u16)((typelength &
458                                 I40E_LLDP_TLV_LEN_MASK) >>
459                                 I40E_LLDP_TLV_LEN_SHIFT);
460                 subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
461                                 I40E_LLDP_TLV_TYPE_SHIFT);
462                 switch (subtype) {
463                 case I40E_CEE_SUBTYPE_PG_CFG:
464                         i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
465                         break;
466                 case I40E_CEE_SUBTYPE_PFC_CFG:
467                         i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
468                         break;
469                 case I40E_CEE_SUBTYPE_APP_PRI:
470                         i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
471                         break;
472                 default:
473                         return; /* Invalid Sub-type return */
474                 }
475                 feat_tlv_count++;
476                 /* Move to next sub TLV */
477                 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
478                                                 sizeof(sub_tlv->hdr.typelen) +
479                                                 sublen);
480         }
481 }
482
483 /**
484  * i40e_parse_org_tlv
485  * @tlv: Organization specific TLV
486  * @dcbcfg: Local store to update ETS REC data
487  *
488  * Currently only IEEE 802.1Qaz TLV is supported, all others
489  * will be returned
490  **/
491 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
492                                struct i40e_dcbx_config *dcbcfg)
493 {
494         u32 ouisubtype;
495         u32 oui;
496
497         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
498         oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
499                     I40E_LLDP_TLV_OUI_SHIFT);
500         switch (oui) {
501         case I40E_IEEE_8021QAZ_OUI:
502                 i40e_parse_ieee_tlv(tlv, dcbcfg);
503                 break;
504         case I40E_CEE_DCBX_OUI:
505                 i40e_parse_cee_tlv(tlv, dcbcfg);
506                 break;
507         default:
508                 break;
509         }
510 }
511
512 /**
513  * i40e_lldp_to_dcb_config
514  * @lldpmib: LLDPDU to be parsed
515  * @dcbcfg: store for LLDPDU data
516  *
517  * Parse DCB configuration from the LLDPDU
518  **/
519 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
520                                     struct i40e_dcbx_config *dcbcfg)
521 {
522         enum i40e_status_code ret = I40E_SUCCESS;
523         struct i40e_lldp_org_tlv *tlv;
524         u16 type;
525         u16 length;
526         u16 typelength;
527         u16 offset = 0;
528
529         if (!lldpmib || !dcbcfg)
530                 return I40E_ERR_PARAM;
531
532         /* set to the start of LLDPDU */
533         lldpmib += I40E_LLDP_MIB_HLEN;
534         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
535         while (1) {
536                 typelength = I40E_NTOHS(tlv->typelength);
537                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
538                              I40E_LLDP_TLV_TYPE_SHIFT);
539                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
540                                I40E_LLDP_TLV_LEN_SHIFT);
541                 offset += sizeof(typelength) + length;
542
543                 /* END TLV or beyond LLDPDU size */
544                 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
545                         break;
546
547                 switch (type) {
548                 case I40E_TLV_TYPE_ORG:
549                         i40e_parse_org_tlv(tlv, dcbcfg);
550                         break;
551                 default:
552                         break;
553                 }
554
555                 /* Move to next TLV */
556                 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
557                                                     sizeof(tlv->typelength) +
558                                                     length);
559         }
560
561         return ret;
562 }
563
564 /**
565  * i40e_aq_get_dcb_config
566  * @hw: pointer to the hw struct
567  * @mib_type: mib type for the query
568  * @bridgetype: bridge type for the query (remote)
569  * @dcbcfg: store for LLDPDU data
570  *
571  * Query DCB configuration from the Firmware
572  **/
573 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
574                                    u8 bridgetype,
575                                    struct i40e_dcbx_config *dcbcfg)
576 {
577         enum i40e_status_code ret = I40E_SUCCESS;
578         struct i40e_virt_mem mem;
579         u8 *lldpmib;
580
581         /* Allocate the LLDPDU */
582         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
583         if (ret)
584                 return ret;
585
586         lldpmib = (u8 *)mem.va;
587         ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
588                                    (void *)lldpmib, I40E_LLDPDU_SIZE,
589                                    NULL, NULL, NULL);
590         if (ret)
591                 goto free_mem;
592
593         /* Parse LLDP MIB to get dcb configuration */
594         ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
595
596 free_mem:
597         i40e_free_virt_mem(hw, &mem);
598         return ret;
599 }
600
601 /**
602  * i40e_cee_to_dcb_v1_config
603  * @cee_cfg: pointer to CEE v1 response configuration struct
604  * @dcbcfg: DCB configuration struct
605  *
606  * Convert CEE v1 configuration from firmware to DCB configuration
607  **/
608 static void i40e_cee_to_dcb_v1_config(
609                         struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
610                         struct i40e_dcbx_config *dcbcfg)
611 {
612         u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
613         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
614         u8 i, tc, err;
615
616         /* CEE PG data to ETS config */
617         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
618
619         /* Note that the FW creates the oper_prio_tc nibbles reversed
620          * from those in the CEE Priority Group sub-TLV.
621          */
622         for (i = 0; i < 4; i++) {
623                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
624                          I40E_CEE_PGID_PRIO_0_MASK) >>
625                          I40E_CEE_PGID_PRIO_0_SHIFT);
626                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
627                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
628                          I40E_CEE_PGID_PRIO_1_MASK) >>
629                          I40E_CEE_PGID_PRIO_1_SHIFT);
630                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
631         }
632
633         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
634                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
635
636         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
637                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
638                         /* Map it to next empty TC */
639                         dcbcfg->etscfg.prioritytable[i] =
640                                                 cee_cfg->oper_num_tc - 1;
641                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
642                 } else {
643                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
644                 }
645         }
646
647         /* CEE PFC data to ETS config */
648         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
649         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
650
651         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
652                   I40E_AQC_CEE_APP_STATUS_SHIFT;
653         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
654         /* Add APPs if Error is False */
655         if (!err) {
656                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
657                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
658
659                 /* FCoE APP */
660                 dcbcfg->app[0].priority =
661                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
662                          I40E_AQC_CEE_APP_FCOE_SHIFT;
663                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
664                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
665
666                 /* iSCSI APP */
667                 dcbcfg->app[1].priority =
668                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
669                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
670                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
671                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
672
673                 /* FIP APP */
674                 dcbcfg->app[2].priority =
675                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
676                          I40E_AQC_CEE_APP_FIP_SHIFT;
677                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
678                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
679         }
680 }
681
682 /**
683  * i40e_cee_to_dcb_config
684  * @cee_cfg: pointer to CEE configuration struct
685  * @dcbcfg: DCB configuration struct
686  *
687  * Convert CEE configuration from firmware to DCB configuration
688  **/
689 static void i40e_cee_to_dcb_config(
690                                 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
691                                 struct i40e_dcbx_config *dcbcfg)
692 {
693         u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
694         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
695         u8 i, tc, err, sync, oper;
696
697         /* CEE PG data to ETS config */
698         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
699
700         for (i = 0; i < 4; i++) {
701                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
702                          I40E_CEE_PGID_PRIO_1_MASK) >>
703                          I40E_CEE_PGID_PRIO_1_SHIFT);
704                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
705                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
706                          I40E_CEE_PGID_PRIO_0_MASK) >>
707                          I40E_CEE_PGID_PRIO_0_SHIFT);
708                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
709         }
710
711         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
712                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
713
714         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
715                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
716                         /* Map it to next empty TC */
717                         dcbcfg->etscfg.prioritytable[i] =
718                                                 cee_cfg->oper_num_tc - 1;
719                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
720                 } else {
721                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
722                 }
723         }
724
725         /* CEE PFC data to ETS config */
726         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
727         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
728
729         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
730                   I40E_AQC_CEE_APP_STATUS_SHIFT;
731         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
732         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
733         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
734         /* Add APPs if Error is False and Oper/Sync is True */
735         if (!err && sync && oper) {
736                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
737                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
738
739                 /* FCoE APP */
740                 dcbcfg->app[0].priority =
741                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
742                          I40E_AQC_CEE_APP_FCOE_SHIFT;
743                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
744                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
745
746                 /* iSCSI APP */
747                 dcbcfg->app[1].priority =
748                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
749                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
750                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
751                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
752
753                 /* FIP APP */
754                 dcbcfg->app[2].priority =
755                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
756                          I40E_AQC_CEE_APP_FIP_SHIFT;
757                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
758                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
759         }
760 }
761
762 /**
763  * i40e_get_dcb_config
764  * @hw: pointer to the hw struct
765  *
766  * Get DCB configuration from the Firmware
767  **/
768 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
769 {
770         enum i40e_status_code ret = I40E_SUCCESS;
771         struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
772         struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
773
774         /* If Firmware version < v4.33 IEEE only */
775         if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
776             (hw->aq.fw_maj_ver < 4))
777                 goto ieee;
778
779         /* If Firmware version == v4.33 use old CEE struct */
780         if ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33)) {
781                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
782                                                  sizeof(cee_v1_cfg), NULL);
783                 if (ret == I40E_SUCCESS) {
784                         /* CEE mode */
785                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
786                         i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
787                                                   &hw->local_dcbx_config);
788                 }
789         } else {
790                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
791                                                  sizeof(cee_cfg), NULL);
792                 if (ret == I40E_SUCCESS) {
793                         /* CEE mode */
794                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
795                         i40e_cee_to_dcb_config(&cee_cfg,
796                                                &hw->local_dcbx_config);
797                 }
798         }
799
800         /* CEE mode not enabled try querying IEEE data */
801         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
802                 goto ieee;
803         else
804                 goto out;
805
806 ieee:
807         /* IEEE mode */
808         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
809         /* Get Local DCB Config */
810         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
811                                      &hw->local_dcbx_config);
812         if (ret)
813                 goto out;
814
815         /* Get Remote DCB Config */
816         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
817                              I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
818                              &hw->remote_dcbx_config);
819         /* Don't treat ENOENT as an error for Remote MIBs */
820         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
821                 ret = I40E_SUCCESS;
822
823 out:
824         return ret;
825 }
826
827 /**
828  * i40e_init_dcb
829  * @hw: pointer to the hw struct
830  *
831  * Update DCB configuration from the Firmware
832  **/
833 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
834 {
835         enum i40e_status_code ret = I40E_SUCCESS;
836         struct i40e_lldp_variables lldp_cfg;
837         u8 adminstatus = 0;
838
839         if (!hw->func_caps.dcb)
840                 return ret;
841
842         /* Read LLDP NVM area */
843         ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
844         if (ret)
845                 return ret;
846
847         /* Get the LLDP AdminStatus for the current port */
848         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
849         adminstatus &= 0xF;
850
851         /* LLDP agent disabled */
852         if (!adminstatus) {
853                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
854                 return ret;
855         }
856
857         /* Get DCBX status */
858         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
859         if (ret)
860                 return ret;
861
862         /* Check the DCBX Status */
863         switch (hw->dcbx_status) {
864         case I40E_DCBX_STATUS_DONE:
865         case I40E_DCBX_STATUS_IN_PROGRESS:
866                 /* Get current DCBX configuration */
867                 ret = i40e_get_dcb_config(hw);
868                 if (ret)
869                         return ret;
870                 break;
871         case I40E_DCBX_STATUS_DISABLED:
872                 return ret;
873         case I40E_DCBX_STATUS_NOT_STARTED:
874         case I40E_DCBX_STATUS_MULTIPLE_PEERS:
875         default:
876                 break;
877         }
878
879         /* Configure the LLDP MIB change event */
880         ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
881         if (ret)
882                 return ret;
883
884         return ret;
885 }
886
887 /**
888  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
889  * @tlv: Fill the ETS config data in IEEE format
890  * @dcbcfg: Local store which holds the DCB Config
891  *
892  * Prepare IEEE 802.1Qaz ETS CFG TLV
893  **/
894 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
895                                   struct i40e_dcbx_config *dcbcfg)
896 {
897         u8 priority0, priority1, maxtcwilling = 0;
898         struct i40e_dcb_ets_config *etscfg;
899         u16 offset = 0, typelength, i;
900         u8 *buf = tlv->tlvinfo;
901         u32 ouisubtype;
902
903         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
904                         I40E_IEEE_ETS_TLV_LENGTH);
905         tlv->typelength = I40E_HTONS(typelength);
906
907         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
908                         I40E_IEEE_SUBTYPE_ETS_CFG);
909         tlv->ouisubtype = I40E_HTONL(ouisubtype);
910
911         /* First Octet post subtype
912          * --------------------------
913          * |will-|CBS  | Re-  | Max |
914          * |ing  |     |served| TCs |
915          * --------------------------
916          * |1bit | 1bit|3 bits|3bits|
917          */
918         etscfg = &dcbcfg->etscfg;
919         if (etscfg->willing)
920                 maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
921         maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
922         buf[offset] = maxtcwilling;
923
924         /* Move offset to Priority Assignment Table */
925         offset++;
926
927         /* Priority Assignment Table (4 octets)
928          * Octets:|    1    |    2    |    3    |    4    |
929          *        -----------------------------------------
930          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
931          *        -----------------------------------------
932          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
933          *        -----------------------------------------
934          */
935         for (i = 0; i < 4; i++) {
936                 priority0 = etscfg->prioritytable[i * 2] & 0xF;
937                 priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
938                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
939                                 priority1;
940                 offset++;
941         }
942
943         /* TC Bandwidth Table (8 octets)
944          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
945          *        ---------------------------------
946          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
947          *        ---------------------------------
948          */
949         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
950                 buf[offset++] = etscfg->tcbwtable[i];
951
952         /* TSA Assignment Table (8 octets)
953          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
954          *        ---------------------------------
955          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
956          *        ---------------------------------
957          */
958         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
959                 buf[offset++] = etscfg->tsatable[i];
960 }
961
962 /**
963  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
964  * @tlv: Fill ETS Recommended TLV in IEEE format
965  * @dcbcfg: Local store which holds the DCB Config
966  *
967  * Prepare IEEE 802.1Qaz ETS REC TLV
968  **/
969 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
970                                      struct i40e_dcbx_config *dcbcfg)
971 {
972         struct i40e_dcb_ets_config *etsrec;
973         u16 offset = 0, typelength, i;
974         u8 priority0, priority1;
975         u8 *buf = tlv->tlvinfo;
976         u32 ouisubtype;
977
978         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
979                         I40E_IEEE_ETS_TLV_LENGTH);
980         tlv->typelength = I40E_HTONS(typelength);
981
982         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
983                         I40E_IEEE_SUBTYPE_ETS_REC);
984         tlv->ouisubtype = I40E_HTONL(ouisubtype);
985
986         etsrec = &dcbcfg->etsrec;
987         /* First Octet is reserved */
988         /* Move offset to Priority Assignment Table */
989         offset++;
990
991         /* Priority Assignment Table (4 octets)
992          * Octets:|    1    |    2    |    3    |    4    |
993          *        -----------------------------------------
994          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
995          *        -----------------------------------------
996          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
997          *        -----------------------------------------
998          */
999         for (i = 0; i < 4; i++) {
1000                 priority0 = etsrec->prioritytable[i * 2] & 0xF;
1001                 priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
1002                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1003                                 priority1;
1004                 offset++;
1005         }
1006
1007         /* TC Bandwidth Table (8 octets)
1008          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1009          *        ---------------------------------
1010          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1011          *        ---------------------------------
1012          */
1013         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1014                 buf[offset++] = etsrec->tcbwtable[i];
1015
1016         /* TSA Assignment Table (8 octets)
1017          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1018          *        ---------------------------------
1019          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1020          *        ---------------------------------
1021          */
1022         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1023                 buf[offset++] = etsrec->tsatable[i];
1024 }
1025
1026  /**
1027  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1028  * @tlv: Fill PFC TLV in IEEE format
1029  * @dcbcfg: Local store to get PFC CFG data
1030  *
1031  * Prepare IEEE 802.1Qaz PFC CFG TLV
1032  **/
1033 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
1034                                   struct i40e_dcbx_config *dcbcfg)
1035 {
1036         u8 *buf = tlv->tlvinfo;
1037         u32 ouisubtype;
1038         u16 typelength;
1039
1040         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1041                         I40E_IEEE_PFC_TLV_LENGTH);
1042         tlv->typelength = I40E_HTONS(typelength);
1043
1044         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1045                         I40E_IEEE_SUBTYPE_PFC_CFG);
1046         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1047
1048         /* ----------------------------------------
1049          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1050          * |ing  |     |served| cap |              |
1051          * -----------------------------------------
1052          * |1bit | 1bit|2 bits|4bits| 1 octet      |
1053          */
1054         if (dcbcfg->pfc.willing)
1055                 buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
1056
1057         if (dcbcfg->pfc.mbc)
1058                 buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
1059
1060         buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1061         buf[1] = dcbcfg->pfc.pfcenable;
1062 }
1063
1064 /**
1065  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1066  * @tlv: Fill APP TLV in IEEE format
1067  * @dcbcfg: Local store to get APP CFG data
1068  *
1069  * Prepare IEEE 802.1Qaz APP CFG TLV
1070  **/
1071 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
1072                                       struct i40e_dcbx_config *dcbcfg)
1073 {
1074         u16 typelength, length, offset = 0;
1075         u8 priority, selector, i = 0;
1076         u8 *buf = tlv->tlvinfo;
1077         u32 ouisubtype;
1078
1079         /* No APP TLVs then just return */
1080         if (dcbcfg->numapps == 0)
1081                 return;
1082         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1083                         I40E_IEEE_SUBTYPE_APP_PRI);
1084         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1085
1086         /* Move offset to App Priority Table */
1087         offset++;
1088         /* Application Priority Table (3 octets)
1089          * Octets:|         1          |    2    |    3    |
1090          *        -----------------------------------------
1091          *        |Priority|Rsrvd| Sel |    Protocol ID    |
1092          *        -----------------------------------------
1093          *   Bits:|23    21|20 19|18 16|15                0|
1094          *        -----------------------------------------
1095          */
1096         while (i < dcbcfg->numapps) {
1097                 priority = dcbcfg->app[i].priority & 0x7;
1098                 selector = dcbcfg->app[i].selector & 0x7;
1099                 buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
1100                 buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
1101                 buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
1102                 /* Move to next app */
1103                 offset += 3;
1104                 i++;
1105                 if (i >= I40E_DCBX_MAX_APPS)
1106                         break;
1107         }
1108         /* length includes size of ouisubtype + 1 reserved + 3*numapps */
1109         length = sizeof(tlv->ouisubtype) + 1 + (i*3);
1110         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1111                 (length & 0x1FF));
1112         tlv->typelength = I40E_HTONS(typelength);
1113 }
1114
1115  /**
1116  * i40e_add_dcb_tlv - Add all IEEE TLVs
1117  * @tlv: pointer to org tlv
1118  *
1119  * add tlv information
1120  **/
1121 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
1122                              struct i40e_dcbx_config *dcbcfg,
1123                              u16 tlvid)
1124 {
1125         switch (tlvid) {
1126         case I40E_IEEE_TLV_ID_ETS_CFG:
1127                 i40e_add_ieee_ets_tlv(tlv, dcbcfg);
1128                 break;
1129         case I40E_IEEE_TLV_ID_ETS_REC:
1130                 i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
1131                 break;
1132         case I40E_IEEE_TLV_ID_PFC_CFG:
1133                 i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
1134                 break;
1135         case I40E_IEEE_TLV_ID_APP_PRI:
1136                 i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
1137                 break;
1138         default:
1139                 break;
1140         }
1141 }
1142
1143  /**
1144  * i40e_set_dcb_config - Set the local LLDP MIB to FW
1145  * @hw: pointer to the hw struct
1146  *
1147  * Set DCB configuration to the Firmware
1148  **/
1149 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
1150 {
1151         enum i40e_status_code ret = I40E_SUCCESS;
1152         struct i40e_dcbx_config *dcbcfg;
1153         struct i40e_virt_mem mem;
1154         u8 mib_type, *lldpmib;
1155         u16 miblen;
1156
1157         /* update the hw local config */
1158         dcbcfg = &hw->local_dcbx_config;
1159         /* Allocate the LLDPDU */
1160         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
1161         if (ret)
1162                 return ret;
1163
1164         mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
1165         if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
1166                 mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
1167                             SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
1168         }
1169         lldpmib = (u8 *)mem.va;
1170         ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
1171         ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
1172
1173         i40e_free_virt_mem(hw, &mem);
1174         return ret;
1175 }
1176
1177 /**
1178  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1179  * @hw: pointer to the hw struct
1180  * @dcbcfg: store for LLDPDU data
1181  *
1182  * send DCB configuration to FW
1183  **/
1184 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
1185                                               struct i40e_dcbx_config *dcbcfg)
1186 {
1187         u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
1188         enum i40e_status_code ret = I40E_SUCCESS;
1189         struct i40e_lldp_org_tlv *tlv;
1190         u16 type, typelength;
1191
1192         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
1193         while (1) {
1194                 i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1195                 typelength = I40E_NTOHS(tlv->typelength);
1196                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
1197                                 I40E_LLDP_TLV_TYPE_SHIFT);
1198                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
1199                                 I40E_LLDP_TLV_LEN_SHIFT);
1200                 if (length)
1201                         offset += length + 2;
1202                 /* END TLV or beyond LLDPDU size */
1203                 if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
1204                     (offset > I40E_LLDPDU_SIZE))
1205                         break;
1206                 /* Move to next TLV */
1207                 if (length)
1208                         tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
1209                               sizeof(tlv->typelength) + length);
1210         }
1211         *miblen = offset;
1212         return ret;
1213 }
1214
1215
1216 /**
1217  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
1218  * @hw: pointer to the HW structure
1219  * @lldp_cfg: pointer to hold lldp configuration variables
1220  *
1221  * Reads the LLDP configuration data from NVM
1222  **/
1223 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
1224                                          struct i40e_lldp_variables *lldp_cfg)
1225 {
1226         enum i40e_status_code ret = I40E_SUCCESS;
1227         u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
1228
1229         if (!lldp_cfg)
1230                 return I40E_ERR_PARAM;
1231
1232         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1233         if (ret != I40E_SUCCESS)
1234                 goto err_lldp_cfg;
1235
1236         ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
1237                                sizeof(struct i40e_lldp_variables),
1238                                (u8 *)lldp_cfg,
1239                                true, NULL);
1240         i40e_release_nvm(hw);
1241
1242 err_lldp_cfg:
1243         return ret;
1244 }