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