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