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