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