]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ixl/i40e_dcb.c
MFS r349163: ixl(4)/ixlv(4): Update Intel XL710 PF and VF drivers to ixl-1.11.9 and...
[FreeBSD/FreeBSD.git] / sys / dev / ixl / i40e_dcb.c
1 /******************************************************************************
2
3   Copyright (c) 2013-2019, 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         ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
911         if (ret)
912                 return I40E_ERR_NOT_READY;
913
914         /* Get the LLDP AdminStatus for the current port */
915         adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
916         adminstatus &= 0xF;
917
918         /* LLDP agent disabled */
919         if (!adminstatus) {
920                 hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
921                 return I40E_ERR_NOT_READY;
922         }
923
924         /* Get DCBX status */
925         ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
926         if (ret)
927                 return ret;
928
929         /* Check the DCBX Status */
930         if (hw->dcbx_status == I40E_DCBX_STATUS_DONE ||
931             hw->dcbx_status == I40E_DCBX_STATUS_IN_PROGRESS) {
932                 /* Get current DCBX configuration */
933                 ret = i40e_get_dcb_config(hw);
934                 if (ret)
935                         return ret;
936         } else if (hw->dcbx_status == I40E_DCBX_STATUS_DISABLED) {
937                 return I40E_ERR_NOT_READY;
938         }
939
940         /* Configure the LLDP MIB change event */
941         if (enable_mib_change)
942                 ret = i40e_aq_cfg_lldp_mib_change_event(hw, TRUE, NULL);
943
944         return ret;
945 }
946
947 /**
948  * i40e_get_fw_lldp_status
949  * @hw: pointer to the hw struct
950  * @lldp_status: pointer to the status enum
951  *
952  * Get status of FW Link Layer Discovery Protocol (LLDP) Agent.
953  * Status of agent is reported via @lldp_status parameter.
954  **/
955 enum i40e_status_code
956 i40e_get_fw_lldp_status(struct i40e_hw *hw,
957                         enum i40e_get_fw_lldp_status_resp *lldp_status)
958 {
959         enum i40e_status_code ret;
960         struct i40e_virt_mem mem;
961         u8 *lldpmib;
962
963         if (!lldp_status)
964                 return I40E_ERR_PARAM;
965
966         /* Allocate buffer for the LLDPDU */
967         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
968         if (ret)
969                 return ret;
970
971         lldpmib = (u8 *)mem.va;
972         ret = i40e_aq_get_lldp_mib(hw, 0, 0, (void *)lldpmib,
973                                    I40E_LLDPDU_SIZE, NULL, NULL, NULL);
974
975         if (ret == I40E_SUCCESS) {
976                 *lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED;
977         } else if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT) {
978                 /* MIB is not available yet but the agent is running */
979                 *lldp_status = I40E_GET_FW_LLDP_STATUS_ENABLED;
980                 ret = I40E_SUCCESS;
981         } else if (hw->aq.asq_last_status == I40E_AQ_RC_EPERM) {
982                 *lldp_status = I40E_GET_FW_LLDP_STATUS_DISABLED;
983                 ret = I40E_SUCCESS;
984         }
985
986         i40e_free_virt_mem(hw, &mem);
987         return ret;
988 }
989
990
991 /**
992  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
993  * @tlv: Fill the ETS config data in IEEE format
994  * @dcbcfg: Local store which holds the DCB Config
995  *
996  * Prepare IEEE 802.1Qaz ETS CFG TLV
997  **/
998 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
999                                   struct i40e_dcbx_config *dcbcfg)
1000 {
1001         u8 priority0, priority1, maxtcwilling = 0;
1002         struct i40e_dcb_ets_config *etscfg;
1003         u16 offset = 0, typelength, i;
1004         u8 *buf = tlv->tlvinfo;
1005         u32 ouisubtype;
1006
1007         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1008                         I40E_IEEE_ETS_TLV_LENGTH);
1009         tlv->typelength = I40E_HTONS(typelength);
1010
1011         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1012                         I40E_IEEE_SUBTYPE_ETS_CFG);
1013         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1014
1015         /* First Octet post subtype
1016          * --------------------------
1017          * |will-|CBS  | Re-  | Max |
1018          * |ing  |     |served| TCs |
1019          * --------------------------
1020          * |1bit | 1bit|3 bits|3bits|
1021          */
1022         etscfg = &dcbcfg->etscfg;
1023         if (etscfg->willing)
1024                 maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
1025         maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
1026         buf[offset] = maxtcwilling;
1027
1028         /* Move offset to Priority Assignment Table */
1029         offset++;
1030
1031         /* Priority Assignment Table (4 octets)
1032          * Octets:|    1    |    2    |    3    |    4    |
1033          *        -----------------------------------------
1034          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1035          *        -----------------------------------------
1036          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1037          *        -----------------------------------------
1038          */
1039         for (i = 0; i < 4; i++) {
1040                 priority0 = etscfg->prioritytable[i * 2] & 0xF;
1041                 priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
1042                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1043                                 priority1;
1044                 offset++;
1045         }
1046
1047         /* TC Bandwidth Table (8 octets)
1048          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1049          *        ---------------------------------
1050          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1051          *        ---------------------------------
1052          */
1053         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1054                 buf[offset++] = etscfg->tcbwtable[i];
1055
1056         /* TSA Assignment Table (8 octets)
1057          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1058          *        ---------------------------------
1059          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1060          *        ---------------------------------
1061          */
1062         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1063                 buf[offset++] = etscfg->tsatable[i];
1064 }
1065
1066 /**
1067  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1068  * @tlv: Fill ETS Recommended TLV in IEEE format
1069  * @dcbcfg: Local store which holds the DCB Config
1070  *
1071  * Prepare IEEE 802.1Qaz ETS REC TLV
1072  **/
1073 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
1074                                      struct i40e_dcbx_config *dcbcfg)
1075 {
1076         struct i40e_dcb_ets_config *etsrec;
1077         u16 offset = 0, typelength, i;
1078         u8 priority0, priority1;
1079         u8 *buf = tlv->tlvinfo;
1080         u32 ouisubtype;
1081
1082         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1083                         I40E_IEEE_ETS_TLV_LENGTH);
1084         tlv->typelength = I40E_HTONS(typelength);
1085
1086         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1087                         I40E_IEEE_SUBTYPE_ETS_REC);
1088         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1089
1090         etsrec = &dcbcfg->etsrec;
1091         /* First Octet is reserved */
1092         /* Move offset to Priority Assignment Table */
1093         offset++;
1094
1095         /* Priority Assignment Table (4 octets)
1096          * Octets:|    1    |    2    |    3    |    4    |
1097          *        -----------------------------------------
1098          *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1099          *        -----------------------------------------
1100          *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1101          *        -----------------------------------------
1102          */
1103         for (i = 0; i < 4; i++) {
1104                 priority0 = etsrec->prioritytable[i * 2] & 0xF;
1105                 priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
1106                 buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1107                                 priority1;
1108                 offset++;
1109         }
1110
1111         /* TC Bandwidth Table (8 octets)
1112          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1113          *        ---------------------------------
1114          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1115          *        ---------------------------------
1116          */
1117         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1118                 buf[offset++] = etsrec->tcbwtable[i];
1119
1120         /* TSA Assignment Table (8 octets)
1121          * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1122          *        ---------------------------------
1123          *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1124          *        ---------------------------------
1125          */
1126         for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1127                 buf[offset++] = etsrec->tsatable[i];
1128 }
1129
1130  /**
1131  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1132  * @tlv: Fill PFC TLV in IEEE format
1133  * @dcbcfg: Local store to get PFC CFG data
1134  *
1135  * Prepare IEEE 802.1Qaz PFC CFG TLV
1136  **/
1137 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
1138                                   struct i40e_dcbx_config *dcbcfg)
1139 {
1140         u8 *buf = tlv->tlvinfo;
1141         u32 ouisubtype;
1142         u16 typelength;
1143
1144         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1145                         I40E_IEEE_PFC_TLV_LENGTH);
1146         tlv->typelength = I40E_HTONS(typelength);
1147
1148         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1149                         I40E_IEEE_SUBTYPE_PFC_CFG);
1150         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1151
1152         /* ----------------------------------------
1153          * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1154          * |ing  |     |served| cap |              |
1155          * -----------------------------------------
1156          * |1bit | 1bit|2 bits|4bits| 1 octet      |
1157          */
1158         if (dcbcfg->pfc.willing)
1159                 buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
1160
1161         if (dcbcfg->pfc.mbc)
1162                 buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
1163
1164         buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1165         buf[1] = dcbcfg->pfc.pfcenable;
1166 }
1167
1168 /**
1169  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1170  * @tlv: Fill APP TLV in IEEE format
1171  * @dcbcfg: Local store to get APP CFG data
1172  *
1173  * Prepare IEEE 802.1Qaz APP CFG TLV
1174  **/
1175 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
1176                                       struct i40e_dcbx_config *dcbcfg)
1177 {
1178         u16 typelength, length, offset = 0;
1179         u8 priority, selector, i = 0;
1180         u8 *buf = tlv->tlvinfo;
1181         u32 ouisubtype;
1182
1183         /* No APP TLVs then just return */
1184         if (dcbcfg->numapps == 0)
1185                 return;
1186         ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1187                         I40E_IEEE_SUBTYPE_APP_PRI);
1188         tlv->ouisubtype = I40E_HTONL(ouisubtype);
1189
1190         /* Move offset to App Priority Table */
1191         offset++;
1192         /* Application Priority Table (3 octets)
1193          * Octets:|         1          |    2    |    3    |
1194          *        -----------------------------------------
1195          *        |Priority|Rsrvd| Sel |    Protocol ID    |
1196          *        -----------------------------------------
1197          *   Bits:|23    21|20 19|18 16|15                0|
1198          *        -----------------------------------------
1199          */
1200         while (i < dcbcfg->numapps) {
1201                 priority = dcbcfg->app[i].priority & 0x7;
1202                 selector = dcbcfg->app[i].selector & 0x7;
1203                 buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
1204                 buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
1205                 buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
1206                 /* Move to next app */
1207                 offset += 3;
1208                 i++;
1209                 if (i >= I40E_DCBX_MAX_APPS)
1210                         break;
1211         }
1212         /* length includes size of ouisubtype + 1 reserved + 3*numapps */
1213         length = sizeof(tlv->ouisubtype) + 1 + (i*3);
1214         typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1215                 (length & 0x1FF));
1216         tlv->typelength = I40E_HTONS(typelength);
1217 }
1218
1219  /**
1220  * i40e_add_dcb_tlv - Add all IEEE TLVs
1221  * @tlv: pointer to org tlv
1222  *
1223  * add tlv information
1224  **/
1225 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
1226                              struct i40e_dcbx_config *dcbcfg,
1227                              u16 tlvid)
1228 {
1229         switch (tlvid) {
1230         case I40E_IEEE_TLV_ID_ETS_CFG:
1231                 i40e_add_ieee_ets_tlv(tlv, dcbcfg);
1232                 break;
1233         case I40E_IEEE_TLV_ID_ETS_REC:
1234                 i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
1235                 break;
1236         case I40E_IEEE_TLV_ID_PFC_CFG:
1237                 i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
1238                 break;
1239         case I40E_IEEE_TLV_ID_APP_PRI:
1240                 i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
1241                 break;
1242         default:
1243                 break;
1244         }
1245 }
1246
1247  /**
1248  * i40e_set_dcb_config - Set the local LLDP MIB to FW
1249  * @hw: pointer to the hw struct
1250  *
1251  * Set DCB configuration to the Firmware
1252  **/
1253 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
1254 {
1255         enum i40e_status_code ret = I40E_SUCCESS;
1256         struct i40e_dcbx_config *dcbcfg;
1257         struct i40e_virt_mem mem;
1258         u8 mib_type, *lldpmib;
1259         u16 miblen;
1260
1261         /* update the hw local config */
1262         dcbcfg = &hw->local_dcbx_config;
1263         /* Allocate the LLDPDU */
1264         ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
1265         if (ret)
1266                 return ret;
1267
1268         mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
1269         if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
1270                 mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
1271                             SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
1272         }
1273         lldpmib = (u8 *)mem.va;
1274         ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
1275         ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
1276
1277         i40e_free_virt_mem(hw, &mem);
1278         return ret;
1279 }
1280
1281 /**
1282  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1283  * @hw: pointer to the hw struct
1284  * @dcbcfg: store for LLDPDU data
1285  *
1286  * send DCB configuration to FW
1287  **/
1288 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
1289                                               struct i40e_dcbx_config *dcbcfg)
1290 {
1291         u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
1292         enum i40e_status_code ret = I40E_SUCCESS;
1293         struct i40e_lldp_org_tlv *tlv;
1294         u16 typelength;
1295
1296         tlv = (struct i40e_lldp_org_tlv *)lldpmib;
1297         while (1) {
1298                 i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1299                 typelength = I40E_NTOHS(tlv->typelength);
1300                 length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
1301                                 I40E_LLDP_TLV_LEN_SHIFT);
1302                 if (length)
1303                         offset += length + 2;
1304                 /* END TLV or beyond LLDPDU size */
1305                 if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
1306                     (offset > I40E_LLDPDU_SIZE))
1307                         break;
1308                 /* Move to next TLV */
1309                 if (length)
1310                         tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
1311                               sizeof(tlv->typelength) + length);
1312         }
1313         *miblen = offset;
1314         return ret;
1315 }
1316
1317
1318 /**
1319  * _i40e_read_lldp_cfg - generic read of LLDP Configuration data from NVM
1320  * @hw: pointer to the HW structure
1321  * @lldp_cfg: pointer to hold lldp configuration variables
1322  * @module: address of the module pointer
1323  * @word_offset: offset of LLDP configuration
1324  *
1325  * Reads the LLDP configuration data from NVM using passed addresses
1326  **/
1327 static enum i40e_status_code _i40e_read_lldp_cfg(struct i40e_hw *hw,
1328                                           struct i40e_lldp_variables *lldp_cfg,
1329                                           u8 module, u32 word_offset)
1330 {
1331         u32 address, offset = (2 * word_offset);
1332         enum i40e_status_code ret;
1333         __le16 raw_mem;
1334         u16 mem;
1335
1336         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1337         if (ret != I40E_SUCCESS)
1338                 return ret;
1339
1340         ret = i40e_aq_read_nvm(hw, 0x0, module * 2, sizeof(raw_mem), &raw_mem,
1341                                TRUE, NULL);
1342         i40e_release_nvm(hw);
1343         if (ret != I40E_SUCCESS)
1344                 return ret;
1345
1346         mem = LE16_TO_CPU(raw_mem);
1347         /* Check if this pointer needs to be read in word size or 4K sector
1348          * units.
1349          */
1350         if (mem & I40E_PTR_TYPE)
1351                 address = (0x7FFF & mem) * 4096;
1352         else
1353                 address = (0x7FFF & mem) * 2;
1354
1355         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1356         if (ret != I40E_SUCCESS)
1357                 goto err_lldp_cfg;
1358
1359         ret = i40e_aq_read_nvm(hw, module, offset, 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         offset = mem + word_offset;
1367         offset *= 2;
1368
1369         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1370         if (ret != I40E_SUCCESS)
1371                 goto err_lldp_cfg;
1372
1373         ret = i40e_aq_read_nvm(hw, 0, address + offset,
1374                                sizeof(struct i40e_lldp_variables), lldp_cfg,
1375                                TRUE, NULL);
1376         i40e_release_nvm(hw);
1377
1378 err_lldp_cfg:
1379         return ret;
1380 }
1381
1382 /**
1383  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
1384  * @hw: pointer to the HW structure
1385  * @lldp_cfg: pointer to hold lldp configuration variables
1386  *
1387  * Reads the LLDP configuration data from NVM
1388  **/
1389 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
1390                                          struct i40e_lldp_variables *lldp_cfg)
1391 {
1392         enum i40e_status_code ret = I40E_SUCCESS;
1393         u32 mem;
1394
1395         if (!lldp_cfg)
1396                 return I40E_ERR_PARAM;
1397
1398         ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1399         if (ret != I40E_SUCCESS)
1400                 return ret;
1401
1402         ret = i40e_aq_read_nvm(hw, I40E_SR_NVM_CONTROL_WORD, 0, sizeof(mem),
1403                                &mem, TRUE, NULL);
1404         i40e_release_nvm(hw);
1405         if (ret != I40E_SUCCESS)
1406                 return ret;
1407
1408         /* Read a bit that holds information whether we are running flat or
1409          * structured NVM image. Flat image has LLDP configuration in shadow
1410          * ram, so there is a need to pass different addresses for both cases.
1411          */
1412         if (mem & I40E_SR_NVM_MAP_STRUCTURE_TYPE) {
1413                 /* Flat NVM case */
1414                 ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_SR_EMP_MODULE_PTR,
1415                                           I40E_SR_LLDP_CFG_PTR);
1416         } else {
1417                 /* Good old structured NVM image */
1418                 ret = _i40e_read_lldp_cfg(hw, lldp_cfg, I40E_EMP_MODULE_PTR,
1419                                           I40E_NVM_LLDP_CFG_PTR);
1420         }
1421
1422         return ret;
1423 }