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