Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*******************************************************************************
  2 *
  3 * Intel Ethernet Controller XL710 Family Linux Driver
  4 * Copyright(c) 2013 - 2014 Intel Corporation.
  5 *
  6 * This program is free software; you can redistribute it and/or modify it
  7 * under the terms and conditions of the GNU General Public License,
  8 * version 2, as published by the Free Software Foundation.
  9 *
 10 * This program is distributed in the hope it will be useful, but WITHOUT
 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 13 * more details.
 14 *
 15 * You should have received a copy of the GNU General Public License along
 16 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 17 *
 18 * The full GNU General Public License is included in this distribution in
 19 * the file called "COPYING".
 20 *
 21 * Contact Information:
 22 * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
 23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 24 *
 25 ******************************************************************************/
 26
 27#include "i40e_adminq.h"
 28#include "i40e_prototype.h"
 29#include "i40e_dcb.h"
 30
 31/**
 32 * i40e_get_dcbx_status
 33 * @hw: pointer to the hw struct
 34 * @status: Embedded DCBX Engine Status
 35 *
 36 * Get the DCBX status from the Firmware
 37 **/
 38i40e_status i40e_get_dcbx_status(struct i40e_hw *hw, u16 *status)
 39{
 40	u32 reg;
 41
 42	if (!status)
 43		return I40E_ERR_PARAM;
 44
 45	reg = rd32(hw, I40E_PRTDCB_GENS);
 46	*status = (u16)((reg & I40E_PRTDCB_GENS_DCBX_STATUS_MASK) >>
 47			I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT);
 48
 49	return 0;
 50}
 51
 52/**
 53 * i40e_parse_ieee_etscfg_tlv
 54 * @tlv: IEEE 802.1Qaz ETS CFG TLV
 55 * @dcbcfg: Local store to update ETS CFG data
 56 *
 57 * Parses IEEE 802.1Qaz ETS CFG TLV
 58 **/
 59static void i40e_parse_ieee_etscfg_tlv(struct i40e_lldp_org_tlv *tlv,
 60				       struct i40e_dcbx_config *dcbcfg)
 61{
 62	struct i40e_dcb_ets_config *etscfg;
 63	u8 *buf = tlv->tlvinfo;
 64	u16 offset = 0;
 65	u8 priority;
 66	int i;
 67
 68	/* First Octet post subtype
 69	 * --------------------------
 70	 * |will-|CBS  | Re-  | Max |
 71	 * |ing  |     |served| TCs |
 72	 * --------------------------
 73	 * |1bit | 1bit|3 bits|3bits|
 74	 */
 75	etscfg = &dcbcfg->etscfg;
 76	etscfg->willing = (u8)((buf[offset] & I40E_IEEE_ETS_WILLING_MASK) >>
 77			       I40E_IEEE_ETS_WILLING_SHIFT);
 78	etscfg->cbs = (u8)((buf[offset] & I40E_IEEE_ETS_CBS_MASK) >>
 79			   I40E_IEEE_ETS_CBS_SHIFT);
 80	etscfg->maxtcs = (u8)((buf[offset] & I40E_IEEE_ETS_MAXTC_MASK) >>
 81			      I40E_IEEE_ETS_MAXTC_SHIFT);
 82
 83	/* Move offset to Priority Assignment Table */
 84	offset++;
 85
 86	/* Priority Assignment Table (4 octets)
 87	 * Octets:|    1    |    2    |    3    |    4    |
 88	 *        -----------------------------------------
 89	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
 90	 *        -----------------------------------------
 91	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
 92	 *        -----------------------------------------
 93	 */
 94	for (i = 0; i < 4; i++) {
 95		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
 96				I40E_IEEE_ETS_PRIO_1_SHIFT);
 97		etscfg->prioritytable[i * 2] =  priority;
 98		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
 99				I40E_IEEE_ETS_PRIO_0_SHIFT);
100		etscfg->prioritytable[i * 2 + 1] = priority;
101		offset++;
102	}
103
104	/* TC Bandwidth Table (8 octets)
105	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
106	 *        ---------------------------------
107	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
108	 *        ---------------------------------
109	 */
110	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
111		etscfg->tcbwtable[i] = buf[offset++];
112
113	/* TSA Assignment Table (8 octets)
114	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
115	 *        ---------------------------------
116	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
117	 *        ---------------------------------
118	 */
119	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
120		etscfg->tsatable[i] = buf[offset++];
121}
122
123/**
124 * i40e_parse_ieee_etsrec_tlv
125 * @tlv: IEEE 802.1Qaz ETS REC TLV
126 * @dcbcfg: Local store to update ETS REC data
127 *
128 * Parses IEEE 802.1Qaz ETS REC TLV
129 **/
130static void i40e_parse_ieee_etsrec_tlv(struct i40e_lldp_org_tlv *tlv,
131				       struct i40e_dcbx_config *dcbcfg)
132{
133	u8 *buf = tlv->tlvinfo;
134	u16 offset = 0;
135	u8 priority;
136	int i;
137
138	/* Move offset to priority table */
139	offset++;
140
141	/* Priority Assignment Table (4 octets)
142	 * Octets:|    1    |    2    |    3    |    4    |
143	 *        -----------------------------------------
144	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
145	 *        -----------------------------------------
146	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
147	 *        -----------------------------------------
148	 */
149	for (i = 0; i < 4; i++) {
150		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_1_MASK) >>
151				I40E_IEEE_ETS_PRIO_1_SHIFT);
152		dcbcfg->etsrec.prioritytable[i*2] =  priority;
153		priority = (u8)((buf[offset] & I40E_IEEE_ETS_PRIO_0_MASK) >>
154				I40E_IEEE_ETS_PRIO_0_SHIFT);
155		dcbcfg->etsrec.prioritytable[i*2 + 1] = priority;
156		offset++;
157	}
158
159	/* TC Bandwidth Table (8 octets)
160	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
161	 *        ---------------------------------
162	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
163	 *        ---------------------------------
164	 */
165	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
166		dcbcfg->etsrec.tcbwtable[i] = buf[offset++];
167
168	/* TSA Assignment Table (8 octets)
169	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
170	 *        ---------------------------------
171	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
172	 *        ---------------------------------
173	 */
174	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
175		dcbcfg->etsrec.tsatable[i] = buf[offset++];
176}
177
178/**
179 * i40e_parse_ieee_pfccfg_tlv
180 * @tlv: IEEE 802.1Qaz PFC CFG TLV
181 * @dcbcfg: Local store to update PFC CFG data
182 *
183 * Parses IEEE 802.1Qaz PFC CFG TLV
184 **/
185static void i40e_parse_ieee_pfccfg_tlv(struct i40e_lldp_org_tlv *tlv,
186				       struct i40e_dcbx_config *dcbcfg)
187{
188	u8 *buf = tlv->tlvinfo;
189
190	/* ----------------------------------------
191	 * |will-|MBC  | Re-  | PFC |  PFC Enable  |
192	 * |ing  |     |served| cap |              |
193	 * -----------------------------------------
194	 * |1bit | 1bit|2 bits|4bits| 1 octet      |
195	 */
196	dcbcfg->pfc.willing = (u8)((buf[0] & I40E_IEEE_PFC_WILLING_MASK) >>
197				   I40E_IEEE_PFC_WILLING_SHIFT);
198	dcbcfg->pfc.mbc = (u8)((buf[0] & I40E_IEEE_PFC_MBC_MASK) >>
199			       I40E_IEEE_PFC_MBC_SHIFT);
200	dcbcfg->pfc.pfccap = (u8)((buf[0] & I40E_IEEE_PFC_CAP_MASK) >>
201				  I40E_IEEE_PFC_CAP_SHIFT);
202	dcbcfg->pfc.pfcenable = buf[1];
203}
204
205/**
206 * i40e_parse_ieee_app_tlv
207 * @tlv: IEEE 802.1Qaz APP TLV
208 * @dcbcfg: Local store to update APP PRIO data
209 *
210 * Parses IEEE 802.1Qaz APP PRIO TLV
211 **/
212static void i40e_parse_ieee_app_tlv(struct i40e_lldp_org_tlv *tlv,
213				    struct i40e_dcbx_config *dcbcfg)
214{
215	u16 typelength;
216	u16 offset = 0;
217	u16 length;
218	int i = 0;
219	u8 *buf;
220
221	typelength = ntohs(tlv->typelength);
222	length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
223		       I40E_LLDP_TLV_LEN_SHIFT);
224	buf = tlv->tlvinfo;
225
226	/* The App priority table starts 5 octets after TLV header */
227	length -= (sizeof(tlv->ouisubtype) + 1);
228
229	/* Move offset to App Priority Table */
230	offset++;
231
232	/* Application Priority Table (3 octets)
233	 * Octets:|         1          |    2    |    3    |
234	 *        -----------------------------------------
235	 *        |Priority|Rsrvd| Sel |    Protocol ID    |
236	 *        -----------------------------------------
237	 *   Bits:|23    21|20 19|18 16|15                0|
238	 *        -----------------------------------------
239	 */
240	while (offset < length) {
241		dcbcfg->app[i].priority = (u8)((buf[offset] &
242						I40E_IEEE_APP_PRIO_MASK) >>
243					       I40E_IEEE_APP_PRIO_SHIFT);
244		dcbcfg->app[i].selector = (u8)((buf[offset] &
245						I40E_IEEE_APP_SEL_MASK) >>
246					       I40E_IEEE_APP_SEL_SHIFT);
247		dcbcfg->app[i].protocolid = (buf[offset + 1] << 0x8) |
248					     buf[offset + 2];
249		/* Move to next app */
250		offset += 3;
251		i++;
252		if (i >= I40E_DCBX_MAX_APPS)
253			break;
254	}
255
256	dcbcfg->numapps = i;
257}
258
259/**
260 * i40e_parse_ieee_etsrec_tlv
261 * @tlv: IEEE 802.1Qaz TLV
262 * @dcbcfg: Local store to update ETS REC data
263 *
264 * Get the TLV subtype and send it to parsing function
265 * based on the subtype value
266 **/
267static void i40e_parse_ieee_tlv(struct i40e_lldp_org_tlv *tlv,
268				struct i40e_dcbx_config *dcbcfg)
269{
270	u32 ouisubtype;
271	u8 subtype;
272
273	ouisubtype = ntohl(tlv->ouisubtype);
274	subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
275		       I40E_LLDP_TLV_SUBTYPE_SHIFT);
276	switch (subtype) {
277	case I40E_IEEE_SUBTYPE_ETS_CFG:
278		i40e_parse_ieee_etscfg_tlv(tlv, dcbcfg);
279		break;
280	case I40E_IEEE_SUBTYPE_ETS_REC:
281		i40e_parse_ieee_etsrec_tlv(tlv, dcbcfg);
282		break;
283	case I40E_IEEE_SUBTYPE_PFC_CFG:
284		i40e_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
285		break;
286	case I40E_IEEE_SUBTYPE_APP_PRI:
287		i40e_parse_ieee_app_tlv(tlv, dcbcfg);
288		break;
289	default:
290		break;
291	}
292}
293
294/**
295 * i40e_parse_cee_pgcfg_tlv
296 * @tlv: CEE DCBX PG CFG TLV
297 * @dcbcfg: Local store to update ETS CFG data
298 *
299 * Parses CEE DCBX PG CFG TLV
300 **/
301static void i40e_parse_cee_pgcfg_tlv(struct i40e_cee_feat_tlv *tlv,
302				     struct i40e_dcbx_config *dcbcfg)
303{
304	struct i40e_dcb_ets_config *etscfg;
305	u8 *buf = tlv->tlvinfo;
306	u16 offset = 0;
307	u8 priority;
308	int i;
309
310	etscfg = &dcbcfg->etscfg;
311
312	if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
313		etscfg->willing = 1;
314
315	etscfg->cbs = 0;
316	/* Priority Group Table (4 octets)
317	 * Octets:|    1    |    2    |    3    |    4    |
318	 *        -----------------------------------------
319	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
320	 *        -----------------------------------------
321	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
322	 *        -----------------------------------------
323	 */
324	for (i = 0; i < 4; i++) {
325		priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_1_MASK) >>
326				 I40E_CEE_PGID_PRIO_1_SHIFT);
327		etscfg->prioritytable[i * 2] =  priority;
328		priority = (u8)((buf[offset] & I40E_CEE_PGID_PRIO_0_MASK) >>
329				 I40E_CEE_PGID_PRIO_0_SHIFT);
330		etscfg->prioritytable[i * 2 + 1] = priority;
331		offset++;
332	}
333
334	/* PG Percentage Table (8 octets)
335	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
336	 *        ---------------------------------
337	 *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
338	 *        ---------------------------------
339	 */
340	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
341		etscfg->tcbwtable[i] = buf[offset++];
342
343	/* Number of TCs supported (1 octet) */
344	etscfg->maxtcs = buf[offset];
345}
346
347/**
348 * i40e_parse_cee_pfccfg_tlv
349 * @tlv: CEE DCBX PFC CFG TLV
350 * @dcbcfg: Local store to update PFC CFG data
351 *
352 * Parses CEE DCBX PFC CFG TLV
353 **/
354static void i40e_parse_cee_pfccfg_tlv(struct i40e_cee_feat_tlv *tlv,
355				      struct i40e_dcbx_config *dcbcfg)
356{
357	u8 *buf = tlv->tlvinfo;
358
359	if (tlv->en_will_err & I40E_CEE_FEAT_TLV_WILLING_MASK)
360		dcbcfg->pfc.willing = 1;
361
362	/* ------------------------
363	 * | PFC Enable | PFC TCs |
364	 * ------------------------
365	 * | 1 octet    | 1 octet |
366	 */
367	dcbcfg->pfc.pfcenable = buf[0];
368	dcbcfg->pfc.pfccap = buf[1];
369}
370
371/**
372 * i40e_parse_cee_app_tlv
373 * @tlv: CEE DCBX APP TLV
374 * @dcbcfg: Local store to update APP PRIO data
375 *
376 * Parses CEE DCBX APP PRIO TLV
377 **/
378static void i40e_parse_cee_app_tlv(struct i40e_cee_feat_tlv *tlv,
379				   struct i40e_dcbx_config *dcbcfg)
380{
381	u16 length, typelength, offset = 0;
382	struct i40e_cee_app_prio *app;
383	u8 i;
384
385	typelength = ntohs(tlv->hdr.typelen);
386	length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
387		       I40E_LLDP_TLV_LEN_SHIFT);
388
389	dcbcfg->numapps = length / sizeof(*app);
390
391	if (!dcbcfg->numapps)
392		return;
393
394	for (i = 0; i < dcbcfg->numapps; i++) {
395		u8 up, selector;
396
397		app = (struct i40e_cee_app_prio *)(tlv->tlvinfo + offset);
398		for (up = 0; up < I40E_MAX_USER_PRIORITY; up++) {
399			if (app->prio_map & BIT(up))
400				break;
401		}
402		dcbcfg->app[i].priority = up;
403
404		/* Get Selector from lower 2 bits, and convert to IEEE */
405		selector = (app->upper_oui_sel & I40E_CEE_APP_SELECTOR_MASK);
406		switch (selector) {
407		case I40E_CEE_APP_SEL_ETHTYPE:
408			dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
409			break;
410		case I40E_CEE_APP_SEL_TCPIP:
411			dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
412			break;
413		default:
414			/* Keep selector as it is for unknown types */
415			dcbcfg->app[i].selector = selector;
416		}
417
418		dcbcfg->app[i].protocolid = ntohs(app->protocol);
419		/* Move to next app */
420		offset += sizeof(*app);
421	}
422}
423
424/**
425 * i40e_parse_cee_tlv
426 * @tlv: CEE DCBX TLV
427 * @dcbcfg: Local store to update DCBX config data
428 *
429 * Get the TLV subtype and send it to parsing function
430 * based on the subtype value
431 **/
432static void i40e_parse_cee_tlv(struct i40e_lldp_org_tlv *tlv,
433			       struct i40e_dcbx_config *dcbcfg)
434{
435	u16 len, tlvlen, sublen, typelength;
436	struct i40e_cee_feat_tlv *sub_tlv;
437	u8 subtype, feat_tlv_count = 0;
438	u32 ouisubtype;
439
440	ouisubtype = ntohl(tlv->ouisubtype);
441	subtype = (u8)((ouisubtype & I40E_LLDP_TLV_SUBTYPE_MASK) >>
442		       I40E_LLDP_TLV_SUBTYPE_SHIFT);
443	/* Return if not CEE DCBX */
444	if (subtype != I40E_CEE_DCBX_TYPE)
445		return;
446
447	typelength = ntohs(tlv->typelength);
448	tlvlen = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
449			I40E_LLDP_TLV_LEN_SHIFT);
450	len = sizeof(tlv->typelength) + sizeof(ouisubtype) +
451	      sizeof(struct i40e_cee_ctrl_tlv);
452	/* Return if no CEE DCBX Feature TLVs */
453	if (tlvlen <= len)
454		return;
455
456	sub_tlv = (struct i40e_cee_feat_tlv *)((char *)tlv + len);
457	while (feat_tlv_count < I40E_CEE_MAX_FEAT_TYPE) {
458		typelength = ntohs(sub_tlv->hdr.typelen);
459		sublen = (u16)((typelength &
460				I40E_LLDP_TLV_LEN_MASK) >>
461				I40E_LLDP_TLV_LEN_SHIFT);
462		subtype = (u8)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
463				I40E_LLDP_TLV_TYPE_SHIFT);
464		switch (subtype) {
465		case I40E_CEE_SUBTYPE_PG_CFG:
466			i40e_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
467			break;
468		case I40E_CEE_SUBTYPE_PFC_CFG:
469			i40e_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
470			break;
471		case I40E_CEE_SUBTYPE_APP_PRI:
472			i40e_parse_cee_app_tlv(sub_tlv, dcbcfg);
473			break;
474		default:
475			return; /* Invalid Sub-type return */
476		}
477		feat_tlv_count++;
478		/* Move to next sub TLV */
479		sub_tlv = (struct i40e_cee_feat_tlv *)((char *)sub_tlv +
480						sizeof(sub_tlv->hdr.typelen) +
481						sublen);
482	}
483}
484
485/**
486 * i40e_parse_org_tlv
487 * @tlv: Organization specific TLV
488 * @dcbcfg: Local store to update ETS REC data
489 *
490 * Currently only IEEE 802.1Qaz TLV is supported, all others
491 * will be returned
492 **/
493static void i40e_parse_org_tlv(struct i40e_lldp_org_tlv *tlv,
494			       struct i40e_dcbx_config *dcbcfg)
495{
496	u32 ouisubtype;
497	u32 oui;
498
499	ouisubtype = ntohl(tlv->ouisubtype);
500	oui = (u32)((ouisubtype & I40E_LLDP_TLV_OUI_MASK) >>
501		    I40E_LLDP_TLV_OUI_SHIFT);
502	switch (oui) {
503	case I40E_IEEE_8021QAZ_OUI:
504		i40e_parse_ieee_tlv(tlv, dcbcfg);
505		break;
506	case I40E_CEE_DCBX_OUI:
507		i40e_parse_cee_tlv(tlv, dcbcfg);
508		break;
509	default:
510		break;
511	}
512}
513
514/**
515 * i40e_lldp_to_dcb_config
516 * @lldpmib: LLDPDU to be parsed
517 * @dcbcfg: store for LLDPDU data
518 *
519 * Parse DCB configuration from the LLDPDU
520 **/
521i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib,
522				    struct i40e_dcbx_config *dcbcfg)
523{
524	i40e_status ret = 0;
525	struct i40e_lldp_org_tlv *tlv;
526	u16 type;
527	u16 length;
528	u16 typelength;
529	u16 offset = 0;
530
531	if (!lldpmib || !dcbcfg)
532		return I40E_ERR_PARAM;
533
534	/* set to the start of LLDPDU */
535	lldpmib += ETH_HLEN;
536	tlv = (struct i40e_lldp_org_tlv *)lldpmib;
537	while (1) {
538		typelength = ntohs(tlv->typelength);
539		type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >>
540			     I40E_LLDP_TLV_TYPE_SHIFT);
541		length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >>
542			       I40E_LLDP_TLV_LEN_SHIFT);
543		offset += sizeof(typelength) + length;
544
545		/* END TLV or beyond LLDPDU size */
546		if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE))
547			break;
548
549		switch (type) {
550		case I40E_TLV_TYPE_ORG:
551			i40e_parse_org_tlv(tlv, dcbcfg);
552			break;
553		default:
554			break;
555		}
556
557		/* Move to next TLV */
558		tlv = (struct i40e_lldp_org_tlv *)((char *)tlv +
559						    sizeof(tlv->typelength) +
560						    length);
561	}
562
563	return ret;
564}
565
566/**
567 * i40e_aq_get_dcb_config
568 * @hw: pointer to the hw struct
569 * @mib_type: mib type for the query
570 * @bridgetype: bridge type for the query (remote)
571 * @dcbcfg: store for LLDPDU data
572 *
573 * Query DCB configuration from the Firmware
574 **/
575i40e_status i40e_aq_get_dcb_config(struct i40e_hw *hw, u8 mib_type,
576				   u8 bridgetype,
577				   struct i40e_dcbx_config *dcbcfg)
578{
579	i40e_status ret = 0;
580	struct i40e_virt_mem mem;
581	u8 *lldpmib;
582
583	/* Allocate the LLDPDU */
584	ret = i40e_allocate_virt_mem(hw, &mem, I40E_LLDPDU_SIZE);
585	if (ret)
586		return ret;
587
588	lldpmib = (u8 *)mem.va;
589	ret = i40e_aq_get_lldp_mib(hw, bridgetype, mib_type,
590				   (void *)lldpmib, I40E_LLDPDU_SIZE,
591				   NULL, NULL, NULL);
592	if (ret)
593		goto free_mem;
594
595	/* Parse LLDP MIB to get dcb configuration */
596	ret = i40e_lldp_to_dcb_config(lldpmib, dcbcfg);
597
598free_mem:
599	i40e_free_virt_mem(hw, &mem);
600	return ret;
601}
602
603/**
604 * i40e_cee_to_dcb_v1_config
605 * @cee_cfg: pointer to CEE v1 response configuration struct
606 * @dcbcfg: DCB configuration struct
607 *
608 * Convert CEE v1 configuration from firmware to DCB configuration
609 **/
610static void i40e_cee_to_dcb_v1_config(
611			struct i40e_aqc_get_cee_dcb_cfg_v1_resp *cee_cfg,
612			struct i40e_dcbx_config *dcbcfg)
613{
614	u16 status, tlv_status = le16_to_cpu(cee_cfg->tlv_status);
615	u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
616	u8 i, tc, err;
617
618	/* CEE PG data to ETS config */
619	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
620
621	for (i = 0; i < 4; i++) {
622		tc = (u8)((cee_cfg->oper_prio_tc[i] &
623			 I40E_CEE_PGID_PRIO_1_MASK) >>
624			 I40E_CEE_PGID_PRIO_1_SHIFT);
625		dcbcfg->etscfg.prioritytable[i*2] =  tc;
626		tc = (u8)((cee_cfg->oper_prio_tc[i] &
627			 I40E_CEE_PGID_PRIO_0_MASK) >>
628			 I40E_CEE_PGID_PRIO_0_SHIFT);
629		dcbcfg->etscfg.prioritytable[i*2 + 1] = tc;
630	}
631
632	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
633		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
634
635	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
636		if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
637			/* Map it to next empty TC */
638			dcbcfg->etscfg.prioritytable[i] =
639						cee_cfg->oper_num_tc - 1;
640			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
641		} else {
642			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
643		}
644	}
645
646	/* CEE PFC data to ETS config */
647	dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
648	dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
649
650	status = (tlv_status & I40E_AQC_CEE_APP_STATUS_MASK) >>
651		  I40E_AQC_CEE_APP_STATUS_SHIFT;
652	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
653	/* Add APPs if Error is False */
654	if (!err) {
655		/* CEE operating configuration supports FCoE/iSCSI/FIP only */
656		dcbcfg->numapps = I40E_CEE_OPER_MAX_APPS;
657
658		/* FCoE APP */
659		dcbcfg->app[0].priority =
660			(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
661			 I40E_AQC_CEE_APP_FCOE_SHIFT;
662		dcbcfg->app[0].selector = I40E_APP_SEL_ETHTYPE;
663		dcbcfg->app[0].protocolid = I40E_APP_PROTOID_FCOE;
664
665		/* iSCSI APP */
666		dcbcfg->app[1].priority =
667			(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
668			 I40E_AQC_CEE_APP_ISCSI_SHIFT;
669		dcbcfg->app[1].selector = I40E_APP_SEL_TCPIP;
670		dcbcfg->app[1].protocolid = I40E_APP_PROTOID_ISCSI;
671
672		/* FIP APP */
673		dcbcfg->app[2].priority =
674			(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
675			 I40E_AQC_CEE_APP_FIP_SHIFT;
676		dcbcfg->app[2].selector = I40E_APP_SEL_ETHTYPE;
677		dcbcfg->app[2].protocolid = I40E_APP_PROTOID_FIP;
678	}
679}
680
681/**
682 * i40e_cee_to_dcb_config
683 * @cee_cfg: pointer to CEE configuration struct
684 * @dcbcfg: DCB configuration struct
685 *
686 * Convert CEE configuration from firmware to DCB configuration
687 **/
688static void i40e_cee_to_dcb_config(
689				struct i40e_aqc_get_cee_dcb_cfg_resp *cee_cfg,
690				struct i40e_dcbx_config *dcbcfg)
691{
692	u32 status, tlv_status = le32_to_cpu(cee_cfg->tlv_status);
693	u16 app_prio = le16_to_cpu(cee_cfg->oper_app_prio);
694	u8 i, tc, err, sync, oper;
695
696	/* CEE PG data to ETS config */
697	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
698
699	/* Note that the FW creates the oper_prio_tc nibbles reversed
700	 * from those in the CEE Priority Group sub-TLV.
701	 */
702	for (i = 0; i < 4; i++) {
703		tc = (u8)((cee_cfg->oper_prio_tc[i] &
704			 I40E_CEE_PGID_PRIO_0_MASK) >>
705			 I40E_CEE_PGID_PRIO_0_SHIFT);
706		dcbcfg->etscfg.prioritytable[i * 2] =  tc;
707		tc = (u8)((cee_cfg->oper_prio_tc[i] &
708			 I40E_CEE_PGID_PRIO_1_MASK) >>
709			 I40E_CEE_PGID_PRIO_1_SHIFT);
710		dcbcfg->etscfg.prioritytable[i * 2 + 1] = tc;
711	}
712
713	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
714		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
715
716	for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
717		if (dcbcfg->etscfg.prioritytable[i] == I40E_CEE_PGID_STRICT) {
718			/* Map it to next empty TC */
719			dcbcfg->etscfg.prioritytable[i] =
720						cee_cfg->oper_num_tc - 1;
721			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_STRICT;
722		} else {
723			dcbcfg->etscfg.tsatable[i] = I40E_IEEE_TSA_ETS;
724		}
725	}
726
727	/* CEE PFC data to ETS config */
728	dcbcfg->pfc.pfcenable = cee_cfg->oper_pfc_en;
729	dcbcfg->pfc.pfccap = I40E_MAX_TRAFFIC_CLASS;
730
731	i = 0;
732	status = (tlv_status & I40E_AQC_CEE_FCOE_STATUS_MASK) >>
733		  I40E_AQC_CEE_FCOE_STATUS_SHIFT;
734	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
735	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
736	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
737	/* Add FCoE APP if Error is False and Oper/Sync is True */
738	if (!err && sync && oper) {
739		/* FCoE APP */
740		dcbcfg->app[i].priority =
741			(app_prio & I40E_AQC_CEE_APP_FCOE_MASK) >>
742			 I40E_AQC_CEE_APP_FCOE_SHIFT;
743		dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
744		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FCOE;
745		i++;
746	}
747
748	status = (tlv_status & I40E_AQC_CEE_ISCSI_STATUS_MASK) >>
749		  I40E_AQC_CEE_ISCSI_STATUS_SHIFT;
750	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
751	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
752	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
753	/* Add iSCSI APP if Error is False and Oper/Sync is True */
754	if (!err && sync && oper) {
755		/* iSCSI APP */
756		dcbcfg->app[i].priority =
757			(app_prio & I40E_AQC_CEE_APP_ISCSI_MASK) >>
758			 I40E_AQC_CEE_APP_ISCSI_SHIFT;
759		dcbcfg->app[i].selector = I40E_APP_SEL_TCPIP;
760		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_ISCSI;
761		i++;
762	}
763
764	status = (tlv_status & I40E_AQC_CEE_FIP_STATUS_MASK) >>
765		  I40E_AQC_CEE_FIP_STATUS_SHIFT;
766	err = (status & I40E_TLV_STATUS_ERR) ? 1 : 0;
767	sync = (status & I40E_TLV_STATUS_SYNC) ? 1 : 0;
768	oper = (status & I40E_TLV_STATUS_OPER) ? 1 : 0;
769	/* Add FIP APP if Error is False and Oper/Sync is True */
770	if (!err && sync && oper) {
771		/* FIP APP */
772		dcbcfg->app[i].priority =
773			(app_prio & I40E_AQC_CEE_APP_FIP_MASK) >>
774			 I40E_AQC_CEE_APP_FIP_SHIFT;
775		dcbcfg->app[i].selector = I40E_APP_SEL_ETHTYPE;
776		dcbcfg->app[i].protocolid = I40E_APP_PROTOID_FIP;
777		i++;
778	}
779	dcbcfg->numapps = i;
780}
781
782/**
783 * i40e_get_ieee_dcb_config
784 * @hw: pointer to the hw struct
785 *
786 * Get IEEE mode DCB configuration from the Firmware
787 **/
788static i40e_status i40e_get_ieee_dcb_config(struct i40e_hw *hw)
789{
790	i40e_status ret = 0;
791
792	/* IEEE mode */
793	hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_IEEE;
794	/* Get Local DCB Config */
795	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
796				     &hw->local_dcbx_config);
797	if (ret)
798		goto out;
799
800	/* Get Remote DCB Config */
801	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
802				     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
803				     &hw->remote_dcbx_config);
804	/* Don't treat ENOENT as an error for Remote MIBs */
805	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
806		ret = 0;
807
808out:
809	return ret;
810}
811
812/**
813 * i40e_get_dcb_config
814 * @hw: pointer to the hw struct
815 *
816 * Get DCB configuration from the Firmware
817 **/
818i40e_status i40e_get_dcb_config(struct i40e_hw *hw)
819{
820	i40e_status ret = 0;
821	struct i40e_aqc_get_cee_dcb_cfg_resp cee_cfg;
822	struct i40e_aqc_get_cee_dcb_cfg_v1_resp cee_v1_cfg;
823
824	/* If Firmware version < v4.33 on X710/XL710, IEEE only */
825	if ((hw->mac.type == I40E_MAC_XL710) &&
826	    (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
827	      (hw->aq.fw_maj_ver < 4)))
828		return i40e_get_ieee_dcb_config(hw);
829
830	/* If Firmware version == v4.33 on X710/XL710, use old CEE struct */
831	if ((hw->mac.type == I40E_MAC_XL710) &&
832	    ((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver == 33))) {
833		ret = i40e_aq_get_cee_dcb_config(hw, &cee_v1_cfg,
834						 sizeof(cee_v1_cfg), NULL);
835		if (!ret) {
836			/* CEE mode */
837			hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
838			hw->local_dcbx_config.tlv_status =
839					le16_to_cpu(cee_v1_cfg.tlv_status);
840			i40e_cee_to_dcb_v1_config(&cee_v1_cfg,
841						  &hw->local_dcbx_config);
842		}
843	} else {
844		ret = i40e_aq_get_cee_dcb_config(hw, &cee_cfg,
845						 sizeof(cee_cfg), NULL);
846		if (!ret) {
847			/* CEE mode */
848			hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE;
849			hw->local_dcbx_config.tlv_status =
850					le32_to_cpu(cee_cfg.tlv_status);
851			i40e_cee_to_dcb_config(&cee_cfg,
852					       &hw->local_dcbx_config);
853		}
854	}
855
856	/* CEE mode not enabled try querying IEEE data */
857	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
858		return i40e_get_ieee_dcb_config(hw);
859
860	if (ret)
861		goto out;
862
863	/* Get CEE DCB Desired Config */
864	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_LOCAL, 0,
865				     &hw->desired_dcbx_config);
866	if (ret)
867		goto out;
868
869	/* Get Remote DCB Config */
870	ret = i40e_aq_get_dcb_config(hw, I40E_AQ_LLDP_MIB_REMOTE,
871				     I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
872				     &hw->remote_dcbx_config);
873	/* Don't treat ENOENT as an error for Remote MIBs */
874	if (hw->aq.asq_last_status == I40E_AQ_RC_ENOENT)
875		ret = 0;
876
877out:
878	return ret;
879}
880
881/**
882 * i40e_init_dcb
883 * @hw: pointer to the hw struct
884 *
885 * Update DCB configuration from the Firmware
886 **/
887i40e_status i40e_init_dcb(struct i40e_hw *hw)
888{
889	i40e_status ret = 0;
890	struct i40e_lldp_variables lldp_cfg;
891	u8 adminstatus = 0;
892
893	if (!hw->func_caps.dcb)
894		return ret;
895
896	/* Read LLDP NVM area */
897	ret = i40e_read_lldp_cfg(hw, &lldp_cfg);
898	if (ret)
899		return ret;
900
901	/* Get the LLDP AdminStatus for the current port */
902	adminstatus = lldp_cfg.adminstatus >> (hw->port * 4);
903	adminstatus &= 0xF;
904
905	/* LLDP agent disabled */
906	if (!adminstatus) {
907		hw->dcbx_status = I40E_DCBX_STATUS_DISABLED;
908		return ret;
909	}
910
911	/* Get DCBX status */
912	ret = i40e_get_dcbx_status(hw, &hw->dcbx_status);
913	if (ret)
914		return ret;
915
916	/* Check the DCBX Status */
917	switch (hw->dcbx_status) {
918	case I40E_DCBX_STATUS_DONE:
919	case I40E_DCBX_STATUS_IN_PROGRESS:
920		/* Get current DCBX configuration */
921		ret = i40e_get_dcb_config(hw);
922		if (ret)
923			return ret;
924		break;
925	case I40E_DCBX_STATUS_DISABLED:
926		return ret;
927	case I40E_DCBX_STATUS_NOT_STARTED:
928	case I40E_DCBX_STATUS_MULTIPLE_PEERS:
929	default:
930		break;
931	}
932
933	/* Configure the LLDP MIB change event */
934	ret = i40e_aq_cfg_lldp_mib_change_event(hw, true, NULL);
935	if (ret)
936		return ret;
937
938	return ret;
939}
940
941/**
942 * i40e_read_lldp_cfg - read LLDP Configuration data from NVM
943 * @hw: pointer to the HW structure
944 * @lldp_cfg: pointer to hold lldp configuration variables
945 *
946 * Reads the LLDP configuration data from NVM
947 **/
948i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
949			       struct i40e_lldp_variables *lldp_cfg)
950{
951	i40e_status ret = 0;
952	u32 offset = (2 * I40E_NVM_LLDP_CFG_PTR);
953
954	if (!lldp_cfg)
955		return I40E_ERR_PARAM;
956
957	ret = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
958	if (ret)
959		goto err_lldp_cfg;
960
961	ret = i40e_aq_read_nvm(hw, I40E_SR_EMP_MODULE_PTR, offset,
962			       sizeof(struct i40e_lldp_variables),
963			       (u8 *)lldp_cfg,
964			       true, NULL);
965	i40e_release_nvm(hw);
966
967err_lldp_cfg:
968	return ret;
969}