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