xref: /f-stack/dpdk/drivers/net/i40e/base/i40e_dcb.c (revision 031be553)
1 /*******************************************************************************
2 
3 Copyright (c) 2013 - 2015, 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_etsrec_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 	/* Number of TCs supported (1 octet) */
351 	etscfg->maxtcs = buf[offset];
352 }
353 
354 /**
355  * i40e_parse_cee_pfccfg_tlv
356  * @tlv: CEE DCBX PFC CFG TLV
357  * @dcbcfg: Local store to update PFC CFG data
358  *
359  * Parses CEE DCBX PFC CFG TLV
360  **/
361 static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
362 				      struct i40e_dcbx_config *dcbcfg)
363 {
364 	u8 *buf = tlv->tlvinfo;
365 
366 	if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
367 		dcbcfg->pfc.willing = 1;
368 
369 	/* ------------------------
370 	 * | PFC Enable | PFC TCs |
371 	 * ------------------------
372 	 * | 1 octet    | 1 octet |
373 	 */
374 	dcbcfg->pfc.pfcenable = buf[0];
375 	dcbcfg->pfc.pfccap = buf[1];
376 }
377 
378 /**
379  * i40e_parse_cee_app_tlv
380  * @tlv: CEE DCBX APP TLV
381  * @dcbcfg: Local store to update APP PRIO data
382  *
383  * Parses CEE DCBX APP PRIO TLV
384  **/
385 static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
386 				   struct i40e_dcbx_config *dcbcfg)
387 {
388 	u16 length, typelength, offset = 0;
389 	struct i40e_cee_app_prio *app;
390 	u8 i;
391 
392 	typelength = I40E_NTOHS(tlv->hdr.typelen);
393 	length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
394 		       I40E_LLDP_TLV_LEN_SHIFT);
395 
396 	dcbcfg->numapps = length / sizeof(*app);
397 	if (!dcbcfg->numapps)
398 		return;
399 	if (dcbcfg->numapps > I40E_DCBX_MAX_APPS)
400 		dcbcfg->numapps = I40E_DCBX_MAX_APPS;
401 
402 	for (i = 0; i < dcbcfg->numapps; i++) {
403 		u8 up, selector;
404 
405 		app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
406 		for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
407 			if (app->prio_map & BIT(up))
408 				break;
409 		}
410 		dcbcfg->app[i].priority = up;
411 
412 		/* Get Selector from lower 2 bits, and convert to IEEE */
413 		selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
414 		switch (selector) {
415 		case I40E_CEE_APP_SEL_ETHTYPE:
416 			dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
417 			break;
418 		case I40E_CEE_APP_SEL_TCPIP:
419 			dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
420 			break;
421 		default:
422 			/* Keep selector as it is for unknown types */
423 			dcbcfg->app[i].selector = selector;
424 		}
425 
426 		dcbcfg->app[i].protocolid = I40E_NTOHS(app->protocol);
427 		/* Move to next app */
428 		offset += sizeof(*app);
429 	}
430 }
431 
432 /**
433  * i40e_parse_cee_tlv
434  * @tlv: CEE DCBX TLV
435  * @dcbcfg: Local store to update DCBX config data
436  *
437  * Get the TLV subtype and send it to parsing function
438  * based on the subtype value
439  **/
440 static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
441 			       struct i40e_dcbx_config *dcbcfg)
442 {
443 	u16 len, tlvlen, sublen, typelength;
444 	struct i40e_cee_feat_tlv *sub_tlv;
445 	u8 subtype, feat_tlv_count = 0;
446 	u32 ouisubtype;
447 
448 	ouisubtype = I40E_NTOHL(tlv->ouisubtype);
449 	subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
450 		       I40E_LLDP_TLV_SUBTYPE_SHIFT);
451 	/* Return if not CEE DCBX */
452 	if (subtype != I40E_CEE_DCBX_TYPE)
453 		return;
454 
455 	typelength = I40E_NTOHS(tlv->typelength);
456 	tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
457 			I40E_LLDP_TLV_LEN_SHIFT);
458 	len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
459 	      sizeof(struct i40e_cee_ctrl_tlv);
460 	/* Return if no CEE DCBX Feature TLVs */
461 	if (tlvlen <= len)
462 		return;
463 
464 	sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
465 	while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
466 		typelength = I40E_NTOHS(sub_tlv->hdr.typelen);
467 		sublen = (u16)((typelength &
468 				I40E_LLDP_TLV_LEN_MASK) >>
469 				I40E_LLDP_TLV_LEN_SHIFT);
470 		subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
471 				I40E_LLDP_TLV_TYPE_SHIFT);
472 		switch (subtype) {
473 		case I40E_CEE_SUBTYPE_PG_CFG:
474 			i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
475 			break;
476 		case I40E_CEE_SUBTYPE_PFC_CFG:
477 			i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
478 			break;
479 		case I40E_CEE_SUBTYPE_APP_PRI:
480 			i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
481 			break;
482 		default:
483 			return; /* Invalid Sub-type return */
484 		}
485 		feat_tlv_count++;
486 		/* Move to next sub TLV */
487 		sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
488 						sizeof(sub_tlv->hdr.typelen) +
489 						sublen);
490 	}
491 }
492 
493 /**
494  * i40e_parse_org_tlv
495  * @tlv: Organization specific TLV
496  * @dcbcfg: Local store to update ETS REC data
497  *
498  * Currently only IEEE 802.1Qaz TLV is supported, all others
499  * will be returned
500  **/
501 static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
502 			       struct i40e_dcbx_config *dcbcfg)
503 {
504 	u32 ouisubtype;
505 	u32 oui;
506 
507 	ouisubtype = I40E_NTOHL(tlv->ouisubtype);
508 	oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
509 		    I40E_LLDP_TLV_OUI_SHIFT);
510 	switch (oui) {
511 	case I40E_IEEE_8021QAZ_OUI:
512 		i40e_parse_ieee_tlv(tlv, dcbcfg);
513 		break;
514 	case I40E_CEE_DCBX_OUI:
515 		i40e_parse_cee_tlv(tlv, dcbcfg);
516 		break;
517 	default:
518 		break;
519 	}
520 }
521 
522 /**
523  * i40e_lldp_to_dcb_config
524  * @lldpmib: LLDPDU to be parsed
525  * @dcbcfg: store for LLDPDU data
526  *
527  * Parse DCB configuration from the LLDPDU
528  **/
529 enum i40e_status_code i40e_lldp_to_dcb_config(u8 *lldpmib,
530 				    struct i40e_dcbx_config *dcbcfg)
531 {
532 	enum i40e_status_code ret = I40E_SUCCESS;
533 	struct i40e_lldp_org_tlv *tlv;
534 	u16 type;
535 	u16 length;
536 	u16 typelength;
537 	u16 offset = 0;
538 
539 	if (!lldpmib || !dcbcfg)
540 		return I40E_ERR_PARAM;
541 
542 	/* set to the start of LLDPDU */
543 	lldpmib += I40E_LLDP_MIB_HLEN;
544 	tlv = (struct i40e_lldp_org_tlv *)lldpmib;
545 	while (1) {
546 		typelength = I40E_NTOHS(tlv->typelength);
547 		type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
548 			     I40E_LLDP_TLV_TYPE_SHIFT);
549 		length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
550 			       I40E_LLDP_TLV_LEN_SHIFT);
551 		offset += sizeof(typelength) + length;
552 
553 		/* END TLV or beyond LLDPDU size */
554 		if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
555 			break;
556 
557 		switch (type) {
558 		case I40E_TLV_TYPE_ORG:
559 			i40e_parse_org_tlv(tlv, dcbcfg);
560 			break;
561 		default:
562 			break;
563 		}
564 
565 		/* Move to next TLV */
566 		tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
567 						    sizeof(tlv->typelength) +
568 						    length);
569 	}
570 
571 	return ret;
572 }
573 
574 /**
575  * i40e_aq_get_dcb_config
576  * @hw: pointer to the hw struct
577  * @mib_type: mib type for the query
578  * @bridgetype: bridge type for the query (remote)
579  * @dcbcfg: store for LLDPDU data
580  *
581  * Query DCB configuration from the Firmware
582  **/
583 enum i40e_status_code i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
584 				   u8 bridgetype,
585 				   struct i40e_dcbx_config *dcbcfg)
586 {
587 	enum i40e_status_code ret = I40E_SUCCESS;
588 	struct i40e_virt_mem mem;
589 	u8 *lldpmib;
590 
591 	/* Allocate the LLDPDU */
592 	ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
593 	if (ret)
594 		return ret;
595 
596 	lldpmib = (u8 *)mem.va;
597 	ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
598 				   (void *)lldpmib, I40E_LLDPDU_SIZE,
599 				   NULL, NULL, NULL);
600 	if (ret)
601 		goto free_mem;
602 
603 	/* Parse LLDP MIB to get dcb configuration */
604 	ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
605 
606 free_mem:
607 	i40e_free_virt_mem(hw, &mem);
608 	return ret;
609 }
610 
611 /**
612  * i40e_cee_to_dcb_v1_config
613  * @cee_cfg: pointer to CEE v1 response configuration struct
614  * @dcbcfg: DCB configuration struct
615  *
616  * Convert CEE v1 configuration from firmware to DCB configuration
617  **/
618 static void i40e_cee_to_dcb_v1_config(
619 			struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
620 			struct i40e_dcbx_config *dcbcfg)
621 {
622 	u16 status, tlv_status = LE16_TO_CPU(cee_cfg->tlv_status);
623 	u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
624 	u8 i, tc, err;
625 
626 	/* CEE PG data to ETS config */
627 	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
628 
629 	/* Note that the FW creates the oper_prio_tc nibbles reversed
630 	 * from those in the CEE Priority Group sub-TLV.
631 	 */
632 	for (i = 0; i < 4; i++) {
633 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
634 			 I40E_CEE_PGID_PRIO_0_MASK) >>
635 			 I40E_CEE_PGID_PRIO_0_SHIFT);
636 		dcbcfg->etscfg.prioritytable[i*2] =  tc;
637 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
638 			 I40E_CEE_PGID_PRIO_1_MASK) >>
639 			 I40E_CEE_PGID_PRIO_1_SHIFT);
640 		dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
641 	}
642 
643 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
644 		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
645 
646 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
647 		if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
648 			/* Map it to next empty TC */
649 			dcbcfg->etscfg.prioritytable[i] =
650 						cee_cfg->oper_num_tc - 1;
651 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
652 		} else {
653 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
654 		}
655 	}
656 
657 	/* CEE PFC data to ETS config */
658 	dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
659 	dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
660 
661 	status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
662 		  I40E_AQC_CEE_APP_STATUS_SHIFT;
663 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
664 	/* Add APPs if Error is False */
665 	if (!err) {
666 		/* CEE operating configuration supports FCoE/iSCSI/FIP only */
667 		dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
668 
669 		/* FCoE APP */
670 		dcbcfg->app[0].priority =
671 			(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
672 			 I40E_AQC_CEE_APP_FCOE_SHIFT;
673 		dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
674 		dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
675 
676 		/* iSCSI APP */
677 		dcbcfg->app[1].priority =
678 			(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
679 			 I40E_AQC_CEE_APP_ISCSI_SHIFT;
680 		dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
681 		dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
682 
683 		/* FIP APP */
684 		dcbcfg->app[2].priority =
685 			(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
686 			 I40E_AQC_CEE_APP_FIP_SHIFT;
687 		dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
688 		dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
689 	}
690 }
691 
692 /**
693  * i40e_cee_to_dcb_config
694  * @cee_cfg: pointer to CEE configuration struct
695  * @dcbcfg: DCB configuration struct
696  *
697  * Convert CEE configuration from firmware to DCB configuration
698  **/
699 static void i40e_cee_to_dcb_config(
700 				struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
701 				struct i40e_dcbx_config *dcbcfg)
702 {
703 	u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
704 	u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
705 	u8 i, tc, err, sync, oper;
706 
707 	/* CEE PG data to ETS config */
708 	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
709 
710 	/* Note that the FW creates the oper_prio_tc nibbles reversed
711 	 * from those in the CEE Priority Group sub-TLV.
712 	 */
713 	for (i = 0; i < 4; i++) {
714 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
715 			 I40E_CEE_PGID_PRIO_0_MASK) >>
716 			 I40E_CEE_PGID_PRIO_0_SHIFT);
717 		dcbcfg->etscfg.prioritytable[i*2] =  tc;
718 		tc = (u8)((cee_cfg->oper_prio_tc[i] &
719 			 I40E_CEE_PGID_PRIO_1_MASK) >>
720 			 I40E_CEE_PGID_PRIO_1_SHIFT);
721 		dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
722 	}
723 
724 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
725 		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
726 
727 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
728 		if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
729 			/* Map it to next empty TC */
730 			dcbcfg->etscfg.prioritytable[i] =
731 						cee_cfg->oper_num_tc - 1;
732 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
733 		} else {
734 			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
735 		}
736 	}
737 
738 	/* CEE PFC data to ETS config */
739 	dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
740 	dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
741 
742 	i = 0;
743 	status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
744 		  I40E_AQC_CEE_FCOE_STATUS_SHIFT;
745 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
746 	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
747 	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
748 	/* Add FCoE APP if Error is False and Oper/Sync is True */
749 	if (!err && sync && oper) {
750 		/* FCoE APP */
751 		dcbcfg->app[i].priority =
752 			(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
753 			 I40E_AQC_CEE_APP_FCOE_SHIFT;
754 		dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
755 		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
756 		i++;
757 	}
758 
759 	status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
760 		  I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
761 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
762 	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
763 	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
764 	/* Add iSCSI APP if Error is False and Oper/Sync is True */
765 	if (!err && sync && oper) {
766 		/* iSCSI APP */
767 		dcbcfg->app[i].priority =
768 			(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
769 			 I40E_AQC_CEE_APP_ISCSI_SHIFT;
770 		dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
771 		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
772 		i++;
773 	}
774 
775 	status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
776 		  I40E_AQC_CEE_FIP_STATUS_SHIFT;
777 	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
778 	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
779 	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
780 	/* Add FIP APP if Error is False and Oper/Sync is True */
781 	if (!err && sync && oper) {
782 		/* FIP APP */
783 		dcbcfg->app[i].priority =
784 			(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
785 			 I40E_AQC_CEE_APP_FIP_SHIFT;
786 		dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
787 		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
788 		i++;
789 	}
790 	dcbcfg->numapps = i;
791 }
792 
793 /**
794  * i40e_get_ieee_dcb_config
795  * @hw: pointer to the hw struct
796  *
797  * Get IEEE mode DCB configuration from the Firmware
798  **/
799 STATIC enum i40e_status_code i40e_get_ieee_dcb_config(struct i40e_hw *hw)
800 {
801 	enum i40e_status_code ret = I40E_SUCCESS;
802 
803 	/* IEEE mode */
804 	hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
805 	/* Get Local DCB Config */
806 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
807 				     &hw->local_dcbx_config);
808 	if (ret)
809 		goto out;
810 
811 	/* Get Remote DCB Config */
812 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
813 				     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
814 				     &hw->remote_dcbx_config);
815 	/* Don't treat ENOENT as an error for Remote MIBs */
816 	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
817 		ret = I40E_SUCCESS;
818 
819 out:
820 	return ret;
821 }
822 
823 /**
824  * i40e_get_dcb_config
825  * @hw: pointer to the hw struct
826  *
827  * Get DCB configuration from the Firmware
828  **/
829 enum i40e_status_code i40e_get_dcb_config(struct i40e_hw *hw)
830 {
831 	enum i40e_status_code ret = I40E_SUCCESS;
832 	struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
833 	struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
834 
835 	/* If Firmware version < v4.33 on X710/XL710, IEEE only */
836 	if ((hw->mac.type == I40E_MAC_XL710) &&
837 	    (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
838 	      (hw->aq.fw_maj_ver < 4)))
839 		return i40e_get_ieee_dcb_config(hw);
840 
841 	/* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
842 	if ((hw->mac.type == I40E_MAC_XL710) &&
843 	    ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
844 		ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
845 						 sizeof(cee_v1_cfg), NULL);
846 		if (ret == I40E_SUCCESS) {
847 			/* CEE mode */
848 			hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
849 			hw->local_dcbx_config.tlv_status =
850 					LE16_TO_CPU(cee_v1_cfg.tlv_status);
851 			i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
852 						  &hw->local_dcbx_config);
853 		}
854 	} else {
855 		ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
856 						 sizeof(cee_cfg), NULL);
857 		if (ret == I40E_SUCCESS) {
858 			/* CEE mode */
859 			hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
860 			hw->local_dcbx_config.tlv_status =
861 					LE32_TO_CPU(cee_cfg.tlv_status);
862 			i40e_cee_to_dcb_config(&cee_cfg,
863 					       &hw->local_dcbx_config);
864 		}
865 	}
866 
867 	/* CEE mode not enabled try querying IEEE data */
868 	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
869 		return i40e_get_ieee_dcb_config(hw);
870 
871 	if (ret != I40E_SUCCESS)
872 		goto out;
873 
874 	/* Get CEE DCB Desired Config */
875 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
876 				     &hw->desired_dcbx_config);
877 	if (ret)
878 		goto out;
879 
880 	/* Get Remote DCB Config */
881 	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
882 			     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
883 			     &hw->remote_dcbx_config);
884 	/* Don't treat ENOENT as an error for Remote MIBs */
885 	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
886 		ret = I40E_SUCCESS;
887 
888 out:
889 	return ret;
890 }
891 
892 /**
893  * i40e_init_dcb
894  * @hw: pointer to the hw struct
895  *
896  * Update DCB configuration from the Firmware
897  **/
898 enum i40e_status_code i40e_init_dcb(struct i40e_hw *hw)
899 {
900 	enum i40e_status_code ret = I40E_SUCCESS;
901 	struct i40e_lldp_variables lldp_cfg;
902 	u8 adminstatus = 0;
903 
904 	if (!hw->func_caps.dcb)
905 		return ret;
906 
907 	/* Read LLDP NVM area */
908 	ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
909 	if (ret)
910 		return ret;
911 
912 	/* Get the LLDP AdminStatus for the current port */
913 	adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
914 	adminstatus &= 0xF;
915 
916 	/* LLDP agent disabled */
917 	if (!adminstatus) {
918 		hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
919 		return ret;
920 	}
921 
922 	/* Get DCBX status */
923 	ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
924 	if (ret)
925 		return ret;
926 
927 	/* Check the DCBX Status */
928 	switch (hw->dcbx_status) {
929 	case I40E_DCBX_STATUS_DONE:
930 	case I40E_DCBX_STATUS_IN_PROGRESS:
931 		/* Get current DCBX configuration */
932 		ret = i40e_get_dcb_config(hw);
933 		if (ret)
934 			return ret;
935 		break;
936 	case I40E_DCBX_STATUS_DISABLED:
937 		return ret;
938 	case I40E_DCBX_STATUS_NOT_STARTED:
939 	case I40E_DCBX_STATUS_MULTIPLE_PEERS:
940 	default:
941 		break;
942 	}
943 
944 	/* Configure the LLDP MIB change event */
945 	ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
946 	if (ret)
947 		return ret;
948 
949 	return ret;
950 }
951 
952 /**
953  * i40e_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
954  * @tlv: Fill the ETS config data in IEEE format
955  * @dcbcfg: Local store which holds the DCB Config
956  *
957  * Prepare IEEE 802.1Qaz ETS CFG TLV
958  **/
959 static void i40e_add_ieee_ets_tlv(struct i40e_lldp_org_tlv *tlv,
960 				  struct i40e_dcbx_config *dcbcfg)
961 {
962 	u8 priority0, priority1, maxtcwilling = 0;
963 	struct i40e_dcb_ets_config *etscfg;
964 	u16 offset = 0, typelength, i;
965 	u8 *buf = tlv->tlvinfo;
966 	u32 ouisubtype;
967 
968 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
969 			I40E_IEEE_ETS_TLV_LENGTH);
970 	tlv->typelength = I40E_HTONS(typelength);
971 
972 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
973 			I40E_IEEE_SUBTYPE_ETS_CFG);
974 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
975 
976 	/* First Octet post subtype
977 	 * --------------------------
978 	 * |will-|CBS  | Re-  | Max |
979 	 * |ing  |     |served| TCs |
980 	 * --------------------------
981 	 * |1bit | 1bit|3 bits|3bits|
982 	 */
983 	etscfg = &dcbcfg->etscfg;
984 	if (etscfg->willing)
985 		maxtcwilling = BIT(I40E_IEEE_ETS_WILLING_SHIFT);
986 	maxtcwilling |= etscfg->maxtcs & I40E_IEEE_ETS_MAXTC_MASK;
987 	buf[offset] = maxtcwilling;
988 
989 	/* Move offset to Priority Assignment Table */
990 	offset++;
991 
992 	/* Priority Assignment Table (4 octets)
993 	 * Octets:|    1    |    2    |    3    |    4    |
994 	 *        -----------------------------------------
995 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
996 	 *        -----------------------------------------
997 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
998 	 *        -----------------------------------------
999 	 */
1000 	for (i = 0; i < 4; i++) {
1001 		priority0 = etscfg->prioritytable[i * 2] & 0xF;
1002 		priority1 = etscfg->prioritytable[i * 2 + 1] & 0xF;
1003 		buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1004 				priority1;
1005 		offset++;
1006 	}
1007 
1008 	/* TC Bandwidth Table (8 octets)
1009 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1010 	 *        ---------------------------------
1011 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1012 	 *        ---------------------------------
1013 	 */
1014 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1015 		buf[offset++] = etscfg->tcbwtable[i];
1016 
1017 	/* TSA Assignment Table (8 octets)
1018 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1019 	 *        ---------------------------------
1020 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1021 	 *        ---------------------------------
1022 	 */
1023 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1024 		buf[offset++] = etscfg->tsatable[i];
1025 }
1026 
1027 /**
1028  * i40e_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1029  * @tlv: Fill ETS Recommended TLV in IEEE format
1030  * @dcbcfg: Local store which holds the DCB Config
1031  *
1032  * Prepare IEEE 802.1Qaz ETS REC TLV
1033  **/
1034 static void i40e_add_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
1035 				     struct i40e_dcbx_config *dcbcfg)
1036 {
1037 	struct i40e_dcb_ets_config *etsrec;
1038 	u16 offset = 0, typelength, i;
1039 	u8 priority0, priority1;
1040 	u8 *buf = tlv->tlvinfo;
1041 	u32 ouisubtype;
1042 
1043 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1044 			I40E_IEEE_ETS_TLV_LENGTH);
1045 	tlv->typelength = I40E_HTONS(typelength);
1046 
1047 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1048 			I40E_IEEE_SUBTYPE_ETS_REC);
1049 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
1050 
1051 	etsrec = &dcbcfg->etsrec;
1052 	/* First Octet is reserved */
1053 	/* Move offset to Priority Assignment Table */
1054 	offset++;
1055 
1056 	/* Priority Assignment Table (4 octets)
1057 	 * Octets:|    1    |    2    |    3    |    4    |
1058 	 *        -----------------------------------------
1059 	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1060 	 *        -----------------------------------------
1061 	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1062 	 *        -----------------------------------------
1063 	 */
1064 	for (i = 0; i < 4; i++) {
1065 		priority0 = etsrec->prioritytable[i * 2] & 0xF;
1066 		priority1 = etsrec->prioritytable[i * 2 + 1] & 0xF;
1067 		buf[offset] = (priority0 << I40E_IEEE_ETS_PRIO_1_SHIFT) |
1068 				priority1;
1069 		offset++;
1070 	}
1071 
1072 	/* TC Bandwidth Table (8 octets)
1073 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1074 	 *        ---------------------------------
1075 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1076 	 *        ---------------------------------
1077 	 */
1078 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1079 		buf[offset++] = etsrec->tcbwtable[i];
1080 
1081 	/* TSA Assignment Table (8 octets)
1082 	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1083 	 *        ---------------------------------
1084 	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1085 	 *        ---------------------------------
1086 	 */
1087 	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
1088 		buf[offset++] = etsrec->tsatable[i];
1089 }
1090 
1091  /**
1092  * i40e_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1093  * @tlv: Fill PFC TLV in IEEE format
1094  * @dcbcfg: Local store to get PFC CFG data
1095  *
1096  * Prepare IEEE 802.1Qaz PFC CFG TLV
1097  **/
1098 static void i40e_add_ieee_pfc_tlv(struct i40e_lldp_org_tlv *tlv,
1099 				  struct i40e_dcbx_config *dcbcfg)
1100 {
1101 	u8 *buf = tlv->tlvinfo;
1102 	u32 ouisubtype;
1103 	u16 typelength;
1104 
1105 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1106 			I40E_IEEE_PFC_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_PFC_CFG);
1111 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
1112 
1113 	/* ----------------------------------------
1114 	 * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1115 	 * |ing  |     |served| cap |              |
1116 	 * -----------------------------------------
1117 	 * |1bit | 1bit|2 bits|4bits| 1 octet      |
1118 	 */
1119 	if (dcbcfg->pfc.willing)
1120 		buf[0] = BIT(I40E_IEEE_PFC_WILLING_SHIFT);
1121 
1122 	if (dcbcfg->pfc.mbc)
1123 		buf[0] |= BIT(I40E_IEEE_PFC_MBC_SHIFT);
1124 
1125 	buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1126 	buf[1] = dcbcfg->pfc.pfcenable;
1127 }
1128 
1129 /**
1130  * i40e_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1131  * @tlv: Fill APP TLV in IEEE format
1132  * @dcbcfg: Local store to get APP CFG data
1133  *
1134  * Prepare IEEE 802.1Qaz APP CFG TLV
1135  **/
1136 static void i40e_add_ieee_app_pri_tlv(struct i40e_lldp_org_tlv *tlv,
1137 				      struct i40e_dcbx_config *dcbcfg)
1138 {
1139 	u16 typelength, length, offset = 0;
1140 	u8 priority, selector, i = 0;
1141 	u8 *buf = tlv->tlvinfo;
1142 	u32 ouisubtype;
1143 
1144 	/* No APP TLVs then just return */
1145 	if (dcbcfg->numapps == 0)
1146 		return;
1147 	ouisubtype = (u32)((I40E_IEEE_8021QAZ_OUI << I40E_LLDP_TLV_OUI_SHIFT) |
1148 			I40E_IEEE_SUBTYPE_APP_PRI);
1149 	tlv->ouisubtype = I40E_HTONL(ouisubtype);
1150 
1151 	/* Move offset to App Priority Table */
1152 	offset++;
1153 	/* Application Priority Table (3 octets)
1154 	 * Octets:|         1          |    2    |    3    |
1155 	 *        -----------------------------------------
1156 	 *        |Priority|Rsrvd| Sel |    Protocol ID    |
1157 	 *        -----------------------------------------
1158 	 *   Bits:|23    21|20 19|18 16|15                0|
1159 	 *        -----------------------------------------
1160 	 */
1161 	while (i < dcbcfg->numapps) {
1162 		priority = dcbcfg->app[i].priority & 0x7;
1163 		selector = dcbcfg->app[i].selector & 0x7;
1164 		buf[offset] = (priority << I40E_IEEE_APP_PRIO_SHIFT) | selector;
1165 		buf[offset + 1] = (dcbcfg->app[i].protocolid >> 0x8) & 0xFF;
1166 		buf[offset + 2] =  dcbcfg->app[i].protocolid & 0xFF;
1167 		/* Move to next app */
1168 		offset += 3;
1169 		i++;
1170 		if (i >= I40E_DCBX_MAX_APPS)
1171 			break;
1172 	}
1173 	/* length includes size of ouisubtype + 1 reserved + 3*numapps */
1174 	length = sizeof(tlv->ouisubtype) + 1 + (i*3);
1175 	typelength = (u16)((I40E_TLV_TYPE_ORG << I40E_LLDP_TLV_TYPE_SHIFT) |
1176 		(length & 0x1FF));
1177 	tlv->typelength = I40E_HTONS(typelength);
1178 }
1179 
1180  /**
1181  * i40e_add_dcb_tlv - Add all IEEE TLVs
1182  * @tlv: pointer to org tlv
1183  *
1184  * add tlv information
1185  **/
1186 static void i40e_add_dcb_tlv(struct i40e_lldp_org_tlv *tlv,
1187 			     struct i40e_dcbx_config *dcbcfg,
1188 			     u16 tlvid)
1189 {
1190 	switch (tlvid) {
1191 	case I40E_IEEE_TLV_ID_ETS_CFG:
1192 		i40e_add_ieee_ets_tlv(tlv, dcbcfg);
1193 		break;
1194 	case I40E_IEEE_TLV_ID_ETS_REC:
1195 		i40e_add_ieee_etsrec_tlv(tlv, dcbcfg);
1196 		break;
1197 	case I40E_IEEE_TLV_ID_PFC_CFG:
1198 		i40e_add_ieee_pfc_tlv(tlv, dcbcfg);
1199 		break;
1200 	case I40E_IEEE_TLV_ID_APP_PRI:
1201 		i40e_add_ieee_app_pri_tlv(tlv, dcbcfg);
1202 		break;
1203 	default:
1204 		break;
1205 	}
1206 }
1207 
1208  /**
1209  * i40e_set_dcb_config - Set the local LLDP MIB to FW
1210  * @hw: pointer to the hw struct
1211  *
1212  * Set DCB configuration to the Firmware
1213  **/
1214 enum i40e_status_code i40e_set_dcb_config(struct i40e_hw *hw)
1215 {
1216 	enum i40e_status_code ret = I40E_SUCCESS;
1217 	struct i40e_dcbx_config *dcbcfg;
1218 	struct i40e_virt_mem mem;
1219 	u8 mib_type, *lldpmib;
1220 	u16 miblen;
1221 
1222 	/* update the hw local config */
1223 	dcbcfg = &hw->local_dcbx_config;
1224 	/* Allocate the LLDPDU */
1225 	ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
1226 	if (ret)
1227 		return ret;
1228 
1229 	mib_type = SET_LOCAL_MIB_AC_TYPE_LOCAL_MIB;
1230 	if (dcbcfg->app_mode == I40E_DCBX_APPS_NON_WILLING) {
1231 		mib_type |= SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS <<
1232 			    SET_LOCAL_MIB_AC_TYPE_NON_WILLING_APPS_SHIFT;
1233 	}
1234 	lldpmib = (u8 *)mem.va;
1235 	ret = i40e_dcb_config_to_lldp(lldpmib, &miblen, dcbcfg);
1236 	ret = i40e_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen, NULL);
1237 
1238 	i40e_free_virt_mem(hw, &mem);
1239 	return ret;
1240 }
1241 
1242 /**
1243  * i40e_dcb_config_to_lldp - Convert Dcbconfig to MIB format
1244  * @hw: pointer to the hw struct
1245  * @dcbcfg: store for LLDPDU data
1246  *
1247  * send DCB configuration to FW
1248  **/
1249 enum i40e_status_code i40e_dcb_config_to_lldp(u8 *lldpmib, u16 *miblen,
1250 					      struct i40e_dcbx_config *dcbcfg)
1251 {
1252 	u16 length, offset = 0, tlvid = I40E_TLV_ID_START;
1253 	enum i40e_status_code ret = I40E_SUCCESS;
1254 	struct i40e_lldp_org_tlv *tlv;
1255 	u16 typelength;
1256 
1257 	tlv = (struct i40e_lldp_org_tlv *)lldpmib;
1258 	while (1) {
1259 		i40e_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1260 		typelength = I40E_NTOHS(tlv->typelength);
1261 		length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
1262 				I40E_LLDP_TLV_LEN_SHIFT);
1263 		if (length)
1264 			offset += length + 2;
1265 		/* END TLV or beyond LLDPDU size */
1266 		if ((tlvid >= I40E_TLV_ID_END_OF_LLDPPDU) ||
1267 		    (offset > I40E_LLDPDU_SIZE))
1268 			break;
1269 		/* Move to next TLV */
1270 		if (length)
1271 			tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
1272 			      sizeof(tlv->typelength) + length);
1273 	}
1274 	*miblen = offset;
1275 	return ret;
1276 }
1277 
1278 
1279 /**
1280  * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
1281  * @hw: pointer to the HW structure
1282  * @lldp_cfg: pointer to hold lldp configuration variables
1283  *
1284  * Reads the LLDP configuration data from NVM
1285  **/
1286 enum i40e_status_code i40e_read_lldp_cfg(struct i40e_hw *hw,
1287 					 struct i40e_lldp_variables *lldp_cfg)
1288 {
1289 	enum i40e_status_code ret = I40E_SUCCESS;
1290 	u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
1291 
1292 	if (!lldp_cfg)
1293 		return I40E_ERR_PARAM;
1294 
1295 	ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
1296 	if (ret != I40E_SUCCESS)
1297 		goto err_lldp_cfg;
1298 
1299 	ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
1300 			       sizeof(struct i40e_lldp_variables),
1301 			       (u8 *)lldp_cfg,
1302 			       true, NULL);
1303 	i40e_release_nvm(hw);
1304 
1305 err_lldp_cfg:
1306 	return ret;
1307 }
1308