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 **/
i40e_get_dcbx_status(struct i40e_hw * hw,u16 * status)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 **/
i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_cee_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_parse_org_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_lldp_to_dcb_config(u8 * lldpmib,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_aq_get_dcb_config(struct i40e_hw * hw,u8 mib_type,u8 bridgetype,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_cee_to_dcb_v1_config(struct i40e_aqc_get_cee_dcb_cfg_v1_resp * cee_cfg,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_cee_to_dcb_config(struct i40e_aqc_get_cee_dcb_cfg_resp * cee_cfg,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_get_ieee_dcb_config(struct i40e_hw * hw)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 **/
i40e_get_dcb_config(struct i40e_hw * hw)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 **/
i40e_init_dcb(struct i40e_hw * hw)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 **/
i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg)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 **/
i40e_add_dcb_tlv(struct i40e_lldp_org_tlv * tlv,struct i40e_dcbx_config * dcbcfg,u16 tlvid)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 **/
i40e_set_dcb_config(struct i40e_hw * hw)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 **/
i40e_dcb_config_to_lldp(u8 * lldpmib,u16 * miblen,struct i40e_dcbx_config * dcbcfg)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 **/
_i40e_read_lldp_cfg(struct i40e_hw * hw,struct i40e_lldp_variables * lldp_cfg,u8 module,u32 word_offset)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 **/
i40e_read_lldp_cfg(struct i40e_hw * hw,struct i40e_lldp_variables * lldp_cfg)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 }
1386