]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ixl/i40e_dcb.c
dmar: reserve memory windows of PCIe root port
[FreeBSD/FreeBSD.git] / sys / dev / ixl / i40e_dcb.c
1 /******************************************************************************
2
3   Copyright (c) 2013-2018, 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 /*$FreeBSD$*/
34
35 #include "i40e_adminq.h"
36 #include "i40e_prototype.h"
37 #include "i40e_dcb.h"
38
39 /**
40  * i40e_get_dcbx_status
41  * @hw: pointer to the hw struct
42  * @status: Embedded DCBX Engine Status
43  *
44  * Get the DCBX status from the Firmware
45  **/
46 enum i40e_status_code i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
47 {
48         u32 reg;
49
50         if (!status)
51                 return I40E_ERR_PARAM;
52
53         reg = rd32(hw, I40E_PRTDCB_GENS);
54         *status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
55                         I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
56
57         return I40E_SUCCESS;
58 }
59
60 /**
61  * i40e_parse_ieee_etscfg_tlv
62  * @tlv: IEEE 802.1Qaz ETS CFG TLV
63  * @dcbcfg: Local store to update ETS CFG data
64  *
65  * Parses IEEE 802.1Qaz ETS CFG TLV
66  **/
67 static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
68                                        struct i40e_dcbx_config *dcbcfg)
69 {
70         struct i40e_dcb_ets_config *etscfg;
71         u8 *buf = tlv->tlvinfo;
72         u16 offset = 0;
73         u8 priority;
74         int i;
75
76         /* First Octet post subtype
77          * --------------------------
78          * |will-|CBS  | Re-  | Max |
79          * |ing  |     |served| TCs |
80          * --------------------------
81          * |1bit | 1bit|3 bits|3bits|
82          */
83         etscfg = &dcbcfg->etscfg;
84         etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
85                                I40E_IEEE_ETS_WILLING_SHIFT);
86         etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
87                            I40E_IEEE_ETS_CBS_SHIFT);
88         etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
89                               I40E_IEEE_ETS_MAXTC_SHIFT);
90
91         /* Move offset to Priority Assignment Table */
92         offset++;
93
94         /* Priority Assignment Table (4 octets)
95          * Octets:|    1    |    2    |    3    |    4    |
96          *        -----------------------------------------
97          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
98          *        -----------------------------------------
99          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
100          *        -----------------------------------------
101          */
102         for (i = 0; i < 4; i++) {
103                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
104                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
105                 etscfg->prioritytable[i * 2] =  priority;
106                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
107                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
108                 etscfg->prioritytable[i * 2 + 1] = priority;
109                 offset++;
110         }
111
112         /* TC Bandwidth Table (8 octets)
113          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
114          *        ---------------------------------
115          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
116          *        ---------------------------------
117          */
118         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
119                 etscfg->tcbwtable[i] = buf[offset++];
120
121         /* TSA Assignment Table (8 octets)
122          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
123          *        ---------------------------------
124          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
125          *        ---------------------------------
126          */
127         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
128                 etscfg->tsatable[i] = buf[offset++];
129 }
130
131 /**
132  * i40e_parse_ieee_etsrec_tlv
133  * @tlv: IEEE 802.1Qaz ETS REC TLV
134  * @dcbcfg: Local store to update ETS REC data
135  *
136  * Parses IEEE 802.1Qaz ETS REC TLV
137  **/
138 static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
139                                        struct i40e_dcbx_config *dcbcfg)
140 {
141         u8 *buf = tlv->tlvinfo;
142         u16 offset = 0;
143         u8 priority;
144         int i;
145
146         /* Move offset to priority table */
147         offset++;
148
149         /* Priority Assignment Table (4 octets)
150          * Octets:|    1    |    2    |    3    |    4    |
151          *        -----------------------------------------
152          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
153          *        -----------------------------------------
154          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
155          *        -----------------------------------------
156          */
157         for (i = 0; i < 4; i++) {
158                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
159                                 I40E_IEEE_ETS_PRIO_1_SHIFT);
160                 dcbcfg->etsrec.prioritytable[i*2] =  priority;
161                 priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
162                                 I40E_IEEE_ETS_PRIO_0_SHIFT);
163                 dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
164                 offset++;
165         }
166
167         /* TC Bandwidth Table (8 octets)
168          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
169          *        ---------------------------------
170          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
171          *        ---------------------------------
172          */
173         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
174                 dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
175
176         /* TSA Assignment Table (8 octets)
177          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
178          *        ---------------------------------
179          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
180          *        ---------------------------------
181          */
182         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
183                 dcbcfg->etsrec.tsatable[i] = buf[offset++];
184 }
185
186 /**
187  * i40e_parse_ieee_pfccfg_tlv
188  * @tlv: IEEE 802.1Qaz PFC CFG TLV
189  * @dcbcfg: Local store to update PFC CFG data
190  *
191  * Parses IEEE 802.1Qaz PFC CFG TLV
192  **/
193 static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
194                                        struct i40e_dcbx_config *dcbcfg)
195 {
196         u8 *buf = tlv->tlvinfo;
197
198         /* ----------------------------------------
199          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
200          * |ing  |     |served| cap |              |
201          * -----------------------------------------
202          * |1bit | 1bit|2 bits|4bits| 1 octet      |
203          */
204         dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
205                                    I40E_IEEE_PFC_WILLING_SHIFT);
206         dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
207                                I40E_IEEE_PFC_MBC_SHIFT);
208         dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
209                                   I40E_IEEE_PFC_CAP_SHIFT);
210         dcbcfg->pfc.pfcenable = buf[1];
211 }
212
213 /**
214  * i40e_parse_ieee_app_tlv
215  * @tlv: IEEE 802.1Qaz APP TLV
216  * @dcbcfg: Local store to update APP PRIO data
217  *
218  * Parses IEEE 802.1Qaz APP PRIO TLV
219  **/
220 static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
221                                     struct i40e_dcbx_config *dcbcfg)
222 {
223         u16 typelength;
224         u16 offset = 0;
225         u16 length;
226         int i = 0;
227         u8 *buf;
228
229         typelength = I40E_NTOHS(tlv->typelength);
230         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
231                        I40E_LLDP_TLV_LEN_SHIFT);
232         buf = tlv->tlvinfo;
233
234         /* The App priority table starts 5 octets after TLV header */
235         length -= (sizeof(tlv->ouisubtype) + 1);
236
237         /* Move offset to App Priority Table */
238         offset++;
239
240         /* Application Priority Table (3 octets)
241          * Octets:|         1          |    2    |    3    |
242          *        -----------------------------------------
243          *        |Priority|Rsrvd| Sel |    Protocol ID    |
244          *        -----------------------------------------
245          *   Bits:|23    21|20 19|18 16|15                0|
246          *        -----------------------------------------
247          */
248         while (offset < length) {
249                 dcbcfg->app[i].priority = (u8)((buf[offset] &
250                                                 I40E_IEEE_APP_PRIO_MASK) >>
251                                                I40E_IEEE_APP_PRIO_SHIFT);
252                 dcbcfg->app[i].selector = (u8)((buf[offset] &
253                                                 I40E_IEEE_APP_SEL_MASK) >>
254                                                I40E_IEEE_APP_SEL_SHIFT);
255                 dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
256                                              buf[offset + 2];
257                 /* Move to next app */
258                 offset += 3;
259                 i++;
260                 if (i >= I40E_DCBX_MAX_APPS)
261                         break;
262         }
263
264         dcbcfg->numapps = i;
265 }
266
267 /**
268  * i40e_parse_ieee_etsrec_tlv
269  * @tlv: IEEE 802.1Qaz TLV
270  * @dcbcfg: Local store to update ETS REC data
271  *
272  * Get the TLV subtype and send it to parsing function
273  * based on the subtype value
274  **/
275 static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
276                                 struct i40e_dcbx_config *dcbcfg)
277 {
278         u32 ouisubtype;
279         u8 subtype;
280
281         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
282         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
283                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
284         switch (subtype) {
285         case I40E_IEEE_SUBTYPE_ETS_CFG:
286                 i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
287                 break;
288         case I40E_IEEE_SUBTYPE_ETS_REC:
289                 i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
290                 break;
291         case I40E_IEEE_SUBTYPE_PFC_CFG:
292                 i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
293                 break;
294         case I40E_IEEE_SUBTYPE_APP_PRI:
295                 i40e_parse_ieee_app_tlv(tlv, dcbcfg);
296                 break;
297         default:
298                 break;
299         }
300 }
301
302 /**
303  * i40e_parse_cee_pgcfg_tlv
304  * @tlv: CEE DCBX PG CFG TLV
305  * @dcbcfg: Local store to update ETS CFG data
306  *
307  * Parses CEE DCBX PG CFG TLV
308  **/
309 static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
310                                      struct i40e_dcbx_config *dcbcfg)
311 {
312         struct i40e_dcb_ets_config *etscfg;
313         u8 *buf = tlv->tlvinfo;
314         u16 offset = 0;
315         u8 priority;
316         int i;
317
318         etscfg = &dcbcfg->etscfg;
319
320         if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
321                 etscfg->willing = 1;
322
323         etscfg->cbs = 0;
324         /* Priority Group Table (4 octets)
325          * Octets:|    1    |    2    |    3    |    4    |
326          *        -----------------------------------------
327          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
328          *        -----------------------------------------
329          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
330          *        -----------------------------------------
331          */
332         for (i = 0; i < 4; i++) {
333                 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
334                                  I40E_CEE_PGID_PRIO_1_SHIFT);
335                 etscfg->prioritytable[i * 2] =  priority;
336                 priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
337                                  I40E_CEE_PGID_PRIO_0_SHIFT);
338                 etscfg->prioritytable[i * 2 + 1] = priority;
339                 offset++;
340         }
341
342         /* PG Percentage Table (8 octets)
343          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
344          *        ---------------------------------
345          *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
346          *        ---------------------------------
347          */
348         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
349                 etscfg->tcbwtable[i] = buf[offset++];
350
351         /* Number of TCs supported (1 octet) */
352         etscfg->maxtcs = buf[offset];
353 }
354
355 /**
356  * i40e_parse_cee_pfccfg_tlv
357  * @tlv: CEE DCBX PFC CFG TLV
358  * @dcbcfg: Local store to update PFC CFG data
359  *
360  * Parses CEE DCBX PFC CFG TLV
361  **/
362 static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
363                                       struct i40e_dcbx_config *dcbcfg)
364 {
365         u8 *buf = tlv->tlvinfo;
366
367         if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
368                 dcbcfg->pfc.willing = 1;
369
370         /* ------------------------
371          * | PFC Enable | PFC TCs |
372          * ------------------------
373          * | 1 octet    | 1 octet |
374          */
375         dcbcfg->pfc.pfcenable = buf[0];
376         dcbcfg->pfc.pfccap = buf[1];
377 }
378
379 /**
380  * i40e_parse_cee_app_tlv
381  * @tlv: CEE DCBX APP TLV
382  * @dcbcfg: Local store to update APP PRIO data
383  *
384  * Parses CEE DCBX APP PRIO TLV
385  **/
386 static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
387                                    struct i40e_dcbx_config *dcbcfg)
388 {
389         u16 length, typelength, offset = 0;
390         struct i40e_cee_app_prio *app;
391         u8 i;
392
393         typelength = I40E_NTOHS(tlv->hdr.typelen);
394         length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
395                        I40E_LLDP_TLV_LEN_SHIFT);
396
397         dcbcfg->numapps = length / sizeof(*app);
398         if (!dcbcfg->numapps)
399                 return;
400         if (dcbcfg->numapps > I40E_DCBX_MAX_APPS)
401                 dcbcfg->numapps = I40E_DCBX_MAX_APPS;
402
403         for (i = 0; i < dcbcfg->numapps; i++) {
404                 u8 up, selector;
405
406                 app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
407                 for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
408                         if (app->prio_map & BIT(up))
409                                 break;
410                 }
411                 dcbcfg->app[i].priority = up;
412
413                 /* Get Selector from lower 2 bits, and convert to IEEE */
414                 selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
415                 switch (selector) {
416                 case I40E_CEE_APP_SEL_ETHTYPE:
417                         dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
418                         break;
419                 case I40E_CEE_APP_SEL_TCPIP:
420                         dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
421                         break;
422                 default:
423                         /* Keep selector as it is for unknown types */
424                         dcbcfg->app[i].selector = selector;
425                 }
426
427                 dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
428                 /* Move to next app */
429                 offset += sizeof(*app);
430         }
431 }
432
433 /**
434  * i40e_parse_cee_tlv
435  * @tlv: CEE DCBX TLV
436  * @dcbcfg: Local store to update DCBX config data
437  *
438  * Get the TLV subtype and send it to parsing function
439  * based on the subtype value
440  **/
441 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
442                                struct i40e_dcbx_config *dcbcfg)
443 {
444         u16 len, tlvlen, sublen, typelength;
445         struct i40e_cee_feat_tlv *sub_tlv;
446         u8 subtype, feat_tlv_count = 0;
447         u32 ouisubtype;
448
449         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
450         subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
451                        I40E_LLDP_TLV_SUBTYPE_SHIFT);
452         /* Return if not CEE DCBX */
453         if (subtype != I40E_CEE_DCBX_TYPE)
454                 return;
455
456         typelength = I40E_NTOHS(tlv->typelength);
457         tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
458                         I40E_LLDP_TLV_LEN_SHIFT);
459         len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
460               sizeof(struct i40e_cee_ctrl_tlv);
461         /* Return if no CEE DCBX Feature TLVs */
462         if (tlvlen <= len)
463                 return;
464
465         sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
466         while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
467                 typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
468                 sublen = (u16)((typelength &
469                                 I40E_LLDP_TLV_LEN_MASK) >>
470                                 I40E_LLDP_TLV_LEN_SHIFT);
471                 subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
472                                 I40E_LLDP_TLV_TYPE_SHIFT);
473                 switch (subtype) {
474                 case I40E_CEE_SUBTYPE_PG_CFG:
475                         i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
476                         break;
477                 case I40E_CEE_SUBTYPE_PFC_CFG:
478                         i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
479                         break;
480                 case I40E_CEE_SUBTYPE_APP_PRI:
481                         i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
482                         break;
483                 default:
484                         return; /* Invalid Sub-type return */
485                 }
486                 feat_tlv_count++;
487                 /* Move to next sub TLV */
488                 sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
489                                                 sizeof(sub_tlv->hdr.typelen) +
490                                                 sublen);
491         }
492 }
493
494 /**
495  * i40e_parse_org_tlv
496  * @tlv: Organization specific TLV
497  * @dcbcfg: Local store to update ETS REC data
498  *
499  * Currently only IEEE 802.1Qaz TLV is supported, all others
500  * will be returned
501  **/
502 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
503                                struct i40e_dcbx_config *dcbcfg)
504 {
505         u32 ouisubtype;
506         u32 oui;
507
508         ouisubtype = I40E_NTOHL(tlv->ouisubtype);
509         oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
510                     I40E_LLDP_TLV_OUI_SHIFT);
511         switch (oui) {
512         case I40E_IEEE_8021QAZ_OUI:
513                 i40e_parse_ieee_tlv(tlv, dcbcfg);
514                 break;
515         case I40E_CEE_DCBX_OUI:
516                 i40e_parse_cee_tlv(tlv, dcbcfg);
517                 break;
518         default:
519                 break;
520         }
521 }
522
523 /**
524  * i40e_lldp_to_dcb_config
525  * @lldpmib: LLDPDU to be parsed
526  * @dcbcfg: store for LLDPDU data
527  *
528  * Parse DCB configuration from the LLDPDU
529  **/
530 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
531                                     struct i40e_dcbx_config *dcbcfg)
532 {
533         enum i40e_status_code ret = I40E_SUCCESS;
534         struct i40e_lldp_org_tlv *tlv;
535         u16 type;
536         u16 length;
537         u16 typelength;
538         u16 offset = 0;
539
540         if (!lldpmib || !dcbcfg)
541                 return I40E_ERR_PARAM;
542
543         /* set to the start of LLDPDU */
544         lldpmib += I40E_LLDP_MIB_HLEN;
545         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
546         while (1) {
547                 typelength = I40E_NTOHS(tlv->typelength);
548                 type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
549                              I40E_LLDP_TLV_TYPE_SHIFT);
550                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
551                                I40E_LLDP_TLV_LEN_SHIFT);
552                 offset += sizeof(typelength) + length;
553
554                 /* END TLV or beyond LLDPDU size */
555                 if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
556                         break;
557
558                 switch (type) {
559                 case I40E_TLV_TYPE_ORG:
560                         i40e_parse_org_tlv(tlv, dcbcfg);
561                         break;
562                 default:
563                         break;
564                 }
565
566                 /* Move to next TLV */
567                 tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
568                                                     sizeof(tlv->typelength) +
569                                                     length);
570         }
571
572         return ret;
573 }
574
575 /**
576  * i40e_aq_get_dcb_config
577  * @hw: pointer to the hw struct
578  * @mib_type: mib type for the query
579  * @bridgetype: bridge type for the query (remote)
580  * @dcbcfg: store for LLDPDU data
581  *
582  * Query DCB configuration from the Firmware
583  **/
584 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
585                                    u8 bridgetype,
586                                    struct i40e_dcbx_config *dcbcfg)
587 {
588         enum i40e_status_code ret = I40E_SUCCESS;
589         struct i40e_virt_mem mem;
590         u8 *lldpmib;
591
592         /* Allocate the LLDPDU */
593         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
594         if (ret)
595                 return ret;
596
597         lldpmib = (u8 *)mem.va;
598         ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
599                                    (void *)lldpmib, I40E_LLDPDU_SIZE,
600                                    NULL, NULL, NULL);
601         if (ret)
602                 goto free_mem;
603
604         /* Parse LLDP MIB to get dcb configuration */
605         ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
606
607 free_mem:
608         i40e_free_virt_mem(hw, &mem);
609         return ret;
610 }
611
612 /**
613  * i40e_cee_to_dcb_v1_config
614  * @cee_cfg: pointer to CEE v1 response configuration struct
615  * @dcbcfg: DCB configuration struct
616  *
617  * Convert CEE v1 configuration from firmware to DCB configuration
618  **/
619 static void i40e_cee_to_dcb_v1_config(
620                         struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
621                         struct i40e_dcbx_config *dcbcfg)
622 {
623         u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
624         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
625         u8 i, tc, err;
626
627         /* CEE PG data to ETS config */
628         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
629
630         /* Note that the FW creates the oper_prio_tc nibbles reversed
631          * from those in the CEE Priority Group sub-TLV.
632          */
633         for (i = 0; i < 4; i++) {
634                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
635                          I40E_CEE_PGID_PRIO_0_MASK) >>
636                          I40E_CEE_PGID_PRIO_0_SHIFT);
637                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
638                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
639                          I40E_CEE_PGID_PRIO_1_MASK) >>
640                          I40E_CEE_PGID_PRIO_1_SHIFT);
641                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
642         }
643
644         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
645                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
646
647         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
648                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
649                         /* Map it to next empty TC */
650                         dcbcfg->etscfg.prioritytable[i] =
651                                                 cee_cfg->oper_num_tc - 1;
652                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
653                 } else {
654                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
655                 }
656         }
657
658         /* CEE PFC data to ETS config */
659         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
660         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
661
662         status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
663                   I40E_AQC_CEE_APP_STATUS_SHIFT;
664         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
665         /* Add APPs if Error is False */
666         if (!err) {
667                 /* CEE operating configuration supports FCoE/iSCSI/FIP only */
668                 dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
669
670                 /* FCoE APP */
671                 dcbcfg->app[0].priority =
672                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
673                          I40E_AQC_CEE_APP_FCOE_SHIFT;
674                 dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
675                 dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
676
677                 /* iSCSI APP */
678                 dcbcfg->app[1].priority =
679                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
680                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
681                 dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
682                 dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
683
684                 /* FIP APP */
685                 dcbcfg->app[2].priority =
686                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
687                          I40E_AQC_CEE_APP_FIP_SHIFT;
688                 dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
689                 dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
690         }
691 }
692
693 /**
694  * i40e_cee_to_dcb_config
695  * @cee_cfg: pointer to CEE configuration struct
696  * @dcbcfg: DCB configuration struct
697  *
698  * Convert CEE configuration from firmware to DCB configuration
699  **/
700 static void i40e_cee_to_dcb_config(
701                                 struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
702                                 struct i40e_dcbx_config *dcbcfg)
703 {
704         u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
705         u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
706         u8 i, tc, err, sync, oper;
707
708         /* CEE PG data to ETS config */
709         dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
710
711         /* Note that the FW creates the oper_prio_tc nibbles reversed
712          * from those in the CEE Priority Group sub-TLV.
713          */
714         for (i = 0; i < 4; i++) {
715                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
716                          I40E_CEE_PGID_PRIO_0_MASK) >>
717                          I40E_CEE_PGID_PRIO_0_SHIFT);
718                 dcbcfg->etscfg.prioritytable[i*2] =  tc;
719                 tc = (u8)((cee_cfg->oper_prio_tc[i] &
720                          I40E_CEE_PGID_PRIO_1_MASK) >>
721                          I40E_CEE_PGID_PRIO_1_SHIFT);
722                 dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
723         }
724
725         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
726                 dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
727
728         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
729                 if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
730                         /* Map it to next empty TC */
731                         dcbcfg->etscfg.prioritytable[i] =
732                                                 cee_cfg->oper_num_tc - 1;
733                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
734                 } else {
735                         dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
736                 }
737         }
738
739         /* CEE PFC data to ETS config */
740         dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
741         dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
742
743         i = 0;
744         status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
745                   I40E_AQC_CEE_FCOE_STATUS_SHIFT;
746         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
747         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
748         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
749         /* Add FCoE APP if Error is False and Oper/Sync is True */
750         if (!err && sync && oper) {
751                 /* FCoE APP */
752                 dcbcfg->app[i].priority =
753                         (app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
754                          I40E_AQC_CEE_APP_FCOE_SHIFT;
755                 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
756                 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
757                 i++;
758         }
759
760         status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
761                   I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
762         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
763         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
764         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
765         /* Add iSCSI APP if Error is False and Oper/Sync is True */
766         if (!err && sync && oper) {
767                 /* iSCSI APP */
768                 dcbcfg->app[i].priority =
769                         (app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
770                          I40E_AQC_CEE_APP_ISCSI_SHIFT;
771                 dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
772                 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
773                 i++;
774         }
775
776         status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
777                   I40E_AQC_CEE_FIP_STATUS_SHIFT;
778         err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
779         sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
780         oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
781         /* Add FIP APP if Error is False and Oper/Sync is True */
782         if (!err && sync && oper) {
783                 /* FIP APP */
784                 dcbcfg->app[i].priority =
785                         (app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
786                          I40E_AQC_CEE_APP_FIP_SHIFT;
787                 dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
788                 dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
789                 i++;
790         }
791         dcbcfg->numapps = i;
792 }
793
794 /**
795  * i40e_get_ieee_dcb_config
796  * @hw: pointer to the hw struct
797  *
798  * Get IEEE mode DCB configuration from the Firmware
799  **/
800 static enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw)
801 {
802         enum i40e_status_code ret = I40E_SUCCESS;
803
804         /* IEEE mode */
805         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
806         /* Get Local DCB Config */
807         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
808                                      &hw->local_dcbx_config);
809         if (ret)
810                 goto out;
811
812         /* Get Remote DCB Config */
813         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
814                                      I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
815                                      &hw->remote_dcbx_config);
816         /* Don't treat ENOENT as an error for Remote MIBs */
817         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
818                 ret = I40E_SUCCESS;
819
820 out:
821         return ret;
822 }
823
824 /**
825  * i40e_get_dcb_config
826  * @hw: pointer to the hw struct
827  *
828  * Get DCB configuration from the Firmware
829  **/
830 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
831 {
832         enum i40e_status_code ret = I40E_SUCCESS;
833         struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
834         struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
835
836         /* If Firmware version < v4.33 on X710/XL710, IEEE only */
837         if ((hw->mac.type == I40E_MAC_XL710) &&
838             (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
839               (hw->aq.fw_maj_ver < 4)))
840                 return i40e_get_ieee_dcb_config(hw);
841
842         /* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
843         if ((hw->mac.type == I40E_MAC_XL710) &&
844             ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
845                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
846                                                  sizeof(cee_v1_cfg), NULL);
847                 if (ret == I40E_SUCCESS) {
848                         /* CEE mode */
849                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
850                         hw->local_dcbx_config.tlv_status =
851                                         LE16_TO_CPU(cee_v1_cfg.tlv_status);
852                         i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
853                                                   &hw->local_dcbx_config);
854                 }
855         } else {
856                 ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
857                                                  sizeof(cee_cfg), NULL);
858                 if (ret == I40E_SUCCESS) {
859                         /* CEE mode */
860                         hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
861                         hw->local_dcbx_config.tlv_status =
862                                         LE32_TO_CPU(cee_cfg.tlv_status);
863                         i40e_cee_to_dcb_config(&cee_cfg,
864                                                &hw->local_dcbx_config);
865                 }
866         }
867
868         /* CEE mode not enabled try querying IEEE data */
869         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
870                 return i40e_get_ieee_dcb_config(hw);
871
872         if (ret != I40E_SUCCESS)
873                 goto out;
874
875         /* Get CEE DCB Desired Config */
876         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
877                                      &hw->desired_dcbx_config);
878         if (ret)
879                 goto out;
880
881         /* Get Remote DCB Config */
882         ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
883                              I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
884                              &hw->remote_dcbx_config);
885         /* Don't treat ENOENT as an error for Remote MIBs */
886         if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
887                 ret = I40E_SUCCESS;
888
889 out:
890         return ret;
891 }
892
893 /**
894  * i40e_init_dcb
895  * @hw: pointer to the hw struct
896  * @enable_mib_change: enable mib change event
897  *
898  * Update DCB configuration from the Firmware
899  **/
900 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw, bool enable_mib_change)
901 {
902         enum i40e_status_code ret = I40E_SUCCESS;
903         struct i40e_lldp_variables lldp_cfg;
904         u8 adminstatus = 0;
905
906         if (!hw->func_caps.dcb)
907                 return I40E_NOT_SUPPORTED;
908
909         /* Read LLDP NVM area */
910         if (hw->flags & I40E_HW_FLAG_FW_LLDP_PERSISTENT) {
911                 u8 offset = 0;
912
913                 if (hw->mac.type == I40E_MAC_XL710)
914                         offset = I40E_LLDP_CURRENT_STATUS_XL710_OFFSET;
915                 else if (hw->mac.type == I40E_MAC_X722)
916                         offset = I40E_LLDP_CURRENT_STATUS_X722_OFFSET;
917                 else
918                         return I40E_NOT_SUPPORTED;
919
920                 ret = i40e_read_nvm_module_data(hw,
921                                                 I40E_SR_EMP_SR_SETTINGS_PTR,
922                                                 offset,
923                                                 I40E_LLDP_CURRENT_STATUS_OFFSET,
924                                                 I40E_LLDP_CURRENT_STATUS_SIZE,
925                                                 &lldp_cfg.adminstatus);
926         } else {
927                 ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
928         }
929         if (ret)
930                 return I40E_ERR_NOT_READY;
931
932         /* Get the LLDP AdminStatus for the current port */
933         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
934         adminstatus &= 0xF;
935
936         /* LLDP agent disabled */
937         if (!adminstatus) {
938                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
939                 return I40E_ERR_NOT_READY;
940         }
941
942         /* Get DCBX status */
943         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
944         if (ret)
945                 return ret;
946
947         /* Check the DCBX Status */
948         if (hw->dcbx_status == I40E_DCBX_STATUS_DONE ||
949             hw->dcbx_status == I40E_DCBX_STATUS_IN_PROGRESS) {
950                 /* Get current DCBX configuration */
951                 ret = i40e_get_dcb_config(hw);
952                 if (ret)
953                         return ret;
954         } else if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
955                 return I40E_ERR_NOT_READY;
956         }
957
958         /* Configure the LLDP MIB change event */
959         if (enable_mib_change)
960                 ret = i40e_aq_cfg_lldp_mib_change_event(hw, TRUE, NULL);
961
962         return ret;
963 }
964
965 /**
966  * i40e_get_fw_lldp_status
967  * @hw: pointer to the hw struct
968  * @lldp_status: pointer to the status enum
969  *
970  * Get status of FW Link Layer Discovery Protocol (LLDP) Agent.
971  * Status of agent is reported via @lldp_status parameter.
972  **/
973 enum i40e_status_code
974 i40e_get_fw_lldp_status(struct i40e_hw *hw,
975                         enum i40e_get_fw_lldp_status_resp *lldp_status)
976 {
977         enum i40e_status_code ret;
978         struct i40e_virt_mem mem;
979         u8 *lldpmib;
980
981         if (!lldp_status)
982                 return I40E_ERR_PARAM;
983
984         /* Allocate buffer for the LLDPDU */
985         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
986         if (ret)
987                 return ret;
988
989         lldpmib = (u8 *)mem.va;
990         ret = i40e_aq_get_lldp_mib(hw, 0, 0, (void *)lldpmib,
991                                    I40E_LLDPDU_SIZE, NULL, NULL, NULL);
992
993         if (ret == I40E_SUCCESS) {
994                 *lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED;
995         } else if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) {
996                 /* MIB is not available yet but the agent is running */
997                 *lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED;
998                 ret = I40E_SUCCESS;
999         } else if (hw->aq.asq_last_status == I40E_AQ_RC_EPERM) {
1000                 *lldp_status = I40E_GET_FW_LLDP_STATUS_DISABLED;
1001                 ret = I40E_SUCCESS;
1002         }
1003
1004         i40e_free_virt_mem(hw, &mem);
1005         return ret;
1006 }
1007
1008
1009 /**
1010  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
1011  * @tlv: Fill the ETS config data in IEEE format
1012  * @dcbcfg: Local store which holds the DCB Config
1013  *
1014  * Prepare IEEE 802.1Qaz ETS CFG TLV
1015  **/
1016 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
1017                                   struct i40e_dcbx_config *dcbcfg)
1018 {
1019         u8 priority0, priority1, maxtcwilling = 0;
1020         struct i40e_dcb_ets_config *etscfg;
1021         u16 offset = 0, typelength, i;
1022         u8 *buf = tlv->tlvinfo;
1023         u32 ouisubtype;
1024
1025         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1026                         I40E_IEEE_ETS_TLV_LENGTH);
1027         tlv->typelength = I40E_HTONS(typelength);
1028
1029         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1030                         I40E_IEEE_SUBTYPE_ETS_CFG);
1031         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1032
1033         /* First Octet post subtype
1034          * --------------------------
1035          * |will-|CBS  | Re-  | Max |
1036          * |ing  |     |served| TCs |
1037          * --------------------------
1038          * |1bit | 1bit|3 bits|3bits|
1039          */
1040         etscfg = &dcbcfg->etscfg;
1041         if (etscfg->willing)
1042                 maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
1043         maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
1044         buf[offset] = maxtcwilling;
1045
1046         /* Move offset to Priority Assignment Table */
1047         offset++;
1048
1049         /* Priority Assignment Table (4 octets)
1050          * Octets:|    1    |    2    |    3    |    4    |
1051          *        -----------------------------------------
1052          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1053          *        -----------------------------------------
1054          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1055          *        -----------------------------------------
1056          */
1057         for (i = 0; i < 4; i++) {
1058                 priority0 = etscfg->prioritytable[i * 2] & 0xF;
1059                 priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
1060                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1061                                 priority1;
1062                 offset++;
1063         }
1064
1065         /* TC Bandwidth Table (8 octets)
1066          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1067          *        ---------------------------------
1068          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1069          *        ---------------------------------
1070          */
1071         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1072                 buf[offset++] = etscfg->tcbwtable[i];
1073
1074         /* TSA Assignment Table (8 octets)
1075          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1076          *        ---------------------------------
1077          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1078          *        ---------------------------------
1079          */
1080         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1081                 buf[offset++] = etscfg->tsatable[i];
1082 }
1083
1084 /**
1085  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1086  * @tlv: Fill ETS Recommended TLV in IEEE format
1087  * @dcbcfg: Local store which holds the DCB Config
1088  *
1089  * Prepare IEEE 802.1Qaz ETS REC TLV
1090  **/
1091 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
1092                                      struct i40e_dcbx_config *dcbcfg)
1093 {
1094         struct i40e_dcb_ets_config *etsrec;
1095         u16 offset = 0, typelength, i;
1096         u8 priority0, priority1;
1097         u8 *buf = tlv->tlvinfo;
1098         u32 ouisubtype;
1099
1100         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1101                         I40E_IEEE_ETS_TLV_LENGTH);
1102         tlv->typelength = I40E_HTONS(typelength);
1103
1104         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1105                         I40E_IEEE_SUBTYPE_ETS_REC);
1106         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1107
1108         etsrec = &dcbcfg->etsrec;
1109         /* First Octet is reserved */
1110         /* Move offset to Priority Assignment Table */
1111         offset++;
1112
1113         /* Priority Assignment Table (4 octets)
1114          * Octets:|    1    |    2    |    3    |    4    |
1115          *        -----------------------------------------
1116          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1117          *        -----------------------------------------
1118          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1119          *        -----------------------------------------
1120          */
1121         for (i = 0; i < 4; i++) {
1122                 priority0 = etsrec->prioritytable[i * 2] & 0xF;
1123                 priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
1124                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1125                                 priority1;
1126                 offset++;
1127         }
1128
1129         /* TC Bandwidth Table (8 octets)
1130          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1131          *        ---------------------------------
1132          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1133          *        ---------------------------------
1134          */
1135         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1136                 buf[offset++] = etsrec->tcbwtable[i];
1137
1138         /* TSA Assignment Table (8 octets)
1139          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1140          *        ---------------------------------
1141          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1142          *        ---------------------------------
1143          */
1144         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1145                 buf[offset++] = etsrec->tsatable[i];
1146 }
1147
1148  /**
1149  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1150  * @tlv: Fill PFC TLV in IEEE format
1151  * @dcbcfg: Local store to get PFC CFG data
1152  *
1153  * Prepare IEEE 802.1Qaz PFC CFG TLV
1154  **/
1155 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
1156                                   struct i40e_dcbx_config *dcbcfg)
1157 {
1158         u8 *buf = tlv->tlvinfo;
1159         u32 ouisubtype;
1160         u16 typelength;
1161
1162         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1163                         I40E_IEEE_PFC_TLV_LENGTH);
1164         tlv->typelength = I40E_HTONS(typelength);
1165
1166         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1167                         I40E_IEEE_SUBTYPE_PFC_CFG);
1168         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1169
1170         /* ----------------------------------------
1171          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1172          * |ing  |     |served| cap |              |
1173          * -----------------------------------------
1174          * |1bit | 1bit|2 bits|4bits| 1 octet      |
1175          */
1176         if (dcbcfg->pfc.willing)
1177                 buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
1178
1179         if (dcbcfg->pfc.mbc)
1180                 buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
1181
1182         buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1183         buf[1] = dcbcfg->pfc.pfcenable;
1184 }
1185
1186 /**
1187  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1188  * @tlv: Fill APP TLV in IEEE format
1189  * @dcbcfg: Local store to get APP CFG data
1190  *
1191  * Prepare IEEE 802.1Qaz APP CFG TLV
1192  **/
1193 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
1194                                       struct i40e_dcbx_config *dcbcfg)
1195 {
1196         u16 typelength, length, offset = 0;
1197         u8 priority, selector, i = 0;
1198         u8 *buf = tlv->tlvinfo;
1199         u32 ouisubtype;
1200
1201         /* No APP TLVs then just return */
1202         if (dcbcfg->numapps == 0)
1203                 return;
1204         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1205                         I40E_IEEE_SUBTYPE_APP_PRI);
1206         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1207
1208         /* Move offset to App Priority Table */
1209         offset++;
1210         /* Application Priority Table (3 octets)
1211          * Octets:|         1          |    2    |    3    |
1212          *        -----------------------------------------
1213          *        |Priority|Rsrvd| Sel |    Protocol ID    |
1214          *        -----------------------------------------
1215          *   Bits:|23    21|20 19|18 16|15                0|
1216          *        -----------------------------------------
1217          */
1218         while (i < dcbcfg->numapps) {
1219                 priority = dcbcfg->app[i].priority & 0x7;
1220                 selector = dcbcfg->app[i].selector & 0x7;
1221                 buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
1222                 buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
1223                 buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
1224                 /* Move to next app */
1225                 offset += 3;
1226                 i++;
1227                 if (i >= I40E_DCBX_MAX_APPS)
1228                         break;
1229         }
1230         /* length includes size of ouisubtype + 1 reserved + 3*numapps */
1231         length = sizeof(tlv->ouisubtype) + 1 + (i*3);
1232         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1233                 (length & 0x1FF));
1234         tlv->typelength = I40E_HTONS(typelength);
1235 }
1236
1237  /**
1238  * i40e_add_dcb_tlv - Add all IEEE TLVs
1239  * @tlv: pointer to org tlv
1240  *
1241  * add tlv information
1242  **/
1243 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
1244                              struct i40e_dcbx_config *dcbcfg,
1245                              u16 tlvid)
1246 {
1247         switch (tlvid) {
1248         case I40E_IEEE_TLV_ID_ETS_CFG:
1249                 i40e_add_ieee_ets_tlv(tlv, dcbcfg);
1250                 break;
1251         case I40E_IEEE_TLV_ID_ETS_REC:
1252                 i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
1253                 break;
1254         case I40E_IEEE_TLV_ID_PFC_CFG:
1255                 i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
1256                 break;
1257         case I40E_IEEE_TLV_ID_APP_PRI:
1258                 i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
1259                 break;
1260         default:
1261                 break;
1262         }
1263 }
1264
1265  /**
1266  * i40e_set_dcb_config - Set the local LLDP MIB to FW
1267  * @hw: pointer to the hw struct
1268  *
1269  * Set DCB configuration to the Firmware
1270  **/
1271 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
1272 {
1273         enum i40e_status_code ret = I40E_SUCCESS;
1274         struct i40e_dcbx_config *dcbcfg;
1275         struct i40e_virt_mem mem;
1276         u8 mib_type, *lldpmib;
1277         u16 miblen;
1278
1279         /* update the hw local config */
1280         dcbcfg = &hw->local_dcbx_config;
1281         /* Allocate the LLDPDU */
1282         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
1283         if (ret)
1284                 return ret;
1285
1286         mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
1287         if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
1288                 mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
1289                             SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
1290         }
1291         lldpmib = (u8 *)mem.va;
1292         ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
1293         ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
1294
1295         i40e_free_virt_mem(hw, &mem);
1296         return ret;
1297 }
1298
1299 /**
1300  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1301  * @lldpmib: pointer to mib to be output
1302  * @miblen: pointer to u16 for length of lldpmib
1303  * @dcbcfg: store for LLDPDU data
1304  *
1305  * send DCB configuration to FW
1306  **/
1307 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
1308                                               struct i40e_dcbx_config *dcbcfg)
1309 {
1310         u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
1311         enum i40e_status_code ret = I40E_SUCCESS;
1312         struct i40e_lldp_org_tlv *tlv;
1313         u16 typelength;
1314
1315         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
1316         while (1) {
1317                 i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1318                 typelength = I40E_NTOHS(tlv->typelength);
1319                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
1320                                 I40E_LLDP_TLV_LEN_SHIFT);
1321                 if (length)
1322                         offset += length + 2;
1323                 /* END TLV or beyond LLDPDU size */
1324                 if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
1325                     (offset > I40E_LLDPDU_SIZE))
1326                         break;
1327                 /* Move to next TLV */
1328                 if (length)
1329                         tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
1330                               sizeof(tlv->typelength) + length);
1331         }
1332         *miblen = offset;
1333         return ret;
1334 }
1335
1336
1337 /**
1338  * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM
1339  * @hw: pointer to the HW structure
1340  * @lldp_cfg: pointer to hold lldp configuration variables
1341  * @module: address of the module pointer
1342  * @word_offset: offset of LLDP configuration
1343  *
1344  * Reads the LLDP configuration data from NVM using passed addresses
1345  **/
1346 static enum i40e_status_code _i40e_read_lldp_cfg(struct i40e_hw *hw,
1347                                           struct i40e_lldp_variables *lldp_cfg,
1348                                           u8 module, u32 word_offset)
1349 {
1350         u32 address, offset = (2 * word_offset);
1351         enum i40e_status_code ret;
1352         __le16 raw_mem;
1353         u16 mem;
1354
1355         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1356         if (ret != I40E_SUCCESS)
1357                 return ret;
1358
1359         ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem,
1360                                TRUE, NULL);
1361         i40e_release_nvm(hw);
1362         if (ret != I40E_SUCCESS)
1363                 return ret;
1364
1365         mem = LE16_TO_CPU(raw_mem);
1366         /* Check if this pointer needs to be read in word size or 4K sector
1367          * units.
1368          */
1369         if (mem & I40E_PTR_TYPE)
1370                 address = (0x7FFF & mem) * 4096;
1371         else
1372                 address = (0x7FFF & mem) * 2;
1373
1374         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1375         if (ret != I40E_SUCCESS)
1376                 goto err_lldp_cfg;
1377
1378         ret = i40e_aq_read_nvm(hw, module, offset, sizeof(raw_mem), &raw_mem,
1379                                TRUE, NULL);
1380         i40e_release_nvm(hw);
1381         if (ret != I40E_SUCCESS)
1382                 return ret;
1383
1384         mem = LE16_TO_CPU(raw_mem);
1385         offset = mem + word_offset;
1386         offset *= 2;
1387
1388         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1389         if (ret != I40E_SUCCESS)
1390                 goto err_lldp_cfg;
1391
1392         ret = i40e_aq_read_nvm(hw, 0, address + offset,
1393                                sizeof(struct i40e_lldp_variables), lldp_cfg,
1394                                TRUE, NULL);
1395         i40e_release_nvm(hw);
1396
1397 err_lldp_cfg:
1398         return ret;
1399 }
1400
1401 /**
1402  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
1403  * @hw: pointer to the HW structure
1404  * @lldp_cfg: pointer to hold lldp configuration variables
1405  *
1406  * Reads the LLDP configuration data from NVM
1407  **/
1408 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
1409                                          struct i40e_lldp_variables *lldp_cfg)
1410 {
1411         enum i40e_status_code ret = I40E_SUCCESS;
1412         u32 mem;
1413
1414         if (!lldp_cfg)
1415                 return I40E_ERR_PARAM;
1416
1417         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1418         if (ret != I40E_SUCCESS)
1419                 return ret;
1420
1421         ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem),
1422                                &mem, TRUE, NULL);
1423         i40e_release_nvm(hw);
1424         if (ret != I40E_SUCCESS)
1425                 return ret;
1426
1427         /* Read a bit that holds information whether we are running flat or
1428          * structured NVM image. Flat image has LLDP configuration in shadow
1429          * ram, so there is a need to pass different addresses for both cases.
1430          */
1431         if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) {
1432                 /* Flat NVM case */
1433                 ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR,
1434                                           I40E_SR_LLDP_CFG_PTR);
1435         } else {
1436                 /* Good old structured NVM image */
1437                 ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR,
1438                                           I40E_NVM_LLDP_CFG_PTR);
1439         }
1440
1441         return ret;
1442 }