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