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