xref: /freebsd/sys/dev/ixl/i40e_dcb.c (revision 02e9120893770924227138ba49df1edb3896112a)
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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  **/
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