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 **/
45enum 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 **/
66static 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 **/
137static 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 **/
192static 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 **/
219static 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 **/
274static 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 **/
308static 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 **/
367static 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 **/
391static 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 **/
446static 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 **/
507static 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 **/
535enum 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 **/
589enum 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
612free_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 **/
624static 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 **/
705static 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 **/
805static 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
825out:
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 **/
835enum 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
894out:
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 **/
905enum 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 **/
978enum i40e_status_code
979i40e_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 **/
1021static 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 **/
1096static 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 **/
1160static 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 **/
1198static 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 **/
1248static 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 **/
1276enum 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 **/
1312enum 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 **/
1351static 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
1402err_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 **/
1413enum 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