1/* SPDX-License-Identifier: BSD-3-Clause */
2/*  Copyright (c) 2024, Intel Corporation
3 *  All rights reserved.
4 *
5 *  Redistribution and use in source and binary forms, with or without
6 *  modification, are permitted provided that the following conditions are met:
7 *
8 *   1. Redistributions of source code must retain the above copyright notice,
9 *      this list of conditions and the following disclaimer.
10 *
11 *   2. Redistributions in binary form must reproduce the above copyright
12 *      notice, this list of conditions and the following disclaimer in the
13 *      documentation and/or other materials provided with the distribution.
14 *
15 *   3. Neither the name of the Intel Corporation nor the names of its
16 *      contributors may be used to endorse or promote products derived from
17 *      this software without specific prior written permission.
18 *
19 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 *  POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "ice_common.h"
33#include "ice_sched.h"
34#include "ice_dcb.h"
35
36/**
37 * ice_aq_get_lldp_mib
38 * @hw: pointer to the HW struct
39 * @bridge_type: type of bridge requested
40 * @mib_type: Local, Remote or both Local and Remote MIBs
41 * @buf: pointer to the caller-supplied buffer to store the MIB block
42 * @buf_size: size of the buffer (in bytes)
43 * @local_len: length of the returned Local LLDP MIB
44 * @remote_len: length of the returned Remote LLDP MIB
45 * @cd: pointer to command details structure or NULL
46 *
47 * Requests the complete LLDP MIB (entire packet). (0x0A00)
48 */
49enum ice_status
50ice_aq_get_lldp_mib(struct ice_hw *hw, u8 bridge_type, u8 mib_type, void *buf,
51		    u16 buf_size, u16 *local_len, u16 *remote_len,
52		    struct ice_sq_cd *cd)
53{
54	struct ice_aqc_lldp_get_mib *cmd;
55	struct ice_aq_desc desc;
56	enum ice_status status;
57
58	cmd = &desc.params.lldp_get_mib;
59
60	if (buf_size == 0 || !buf)
61		return ICE_ERR_PARAM;
62
63	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_get_mib);
64
65	cmd->type = mib_type & ICE_AQ_LLDP_MIB_TYPE_M;
66	cmd->type |= (bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
67		ICE_AQ_LLDP_BRID_TYPE_M;
68
69	desc.datalen = CPU_TO_LE16(buf_size);
70
71	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
72	if (!status) {
73		if (local_len)
74			*local_len = LE16_TO_CPU(cmd->local_len);
75		if (remote_len)
76			*remote_len = LE16_TO_CPU(cmd->remote_len);
77	}
78
79	return status;
80}
81
82/**
83 * ice_aq_cfg_lldp_mib_change
84 * @hw: pointer to the HW struct
85 * @ena_update: Enable or Disable event posting
86 * @cd: pointer to command details structure or NULL
87 *
88 * Enable or Disable posting of an event on ARQ when LLDP MIB
89 * associated with the interface changes (0x0A01)
90 */
91enum ice_status
92ice_aq_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_update,
93			   struct ice_sq_cd *cd)
94{
95	struct ice_aqc_lldp_set_mib_change *cmd;
96	struct ice_aq_desc desc;
97
98	cmd = &desc.params.lldp_set_event;
99
100	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_set_mib_change);
101
102	if (!ena_update)
103		cmd->command |= ICE_AQ_LLDP_MIB_UPDATE_DIS;
104	else
105		cmd->command |= ICE_AQ_LLDP_MIB_PENDING_ENABLE <<
106				ICE_AQ_LLDP_MIB_PENDING_S;
107
108	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
109}
110
111/**
112 * ice_aq_add_delete_lldp_tlv
113 * @hw: pointer to the HW struct
114 * @bridge_type: type of bridge
115 * @add_lldp_tlv: add (true) or delete (false) TLV
116 * @buf: buffer with TLV to add or delete
117 * @buf_size: length of the buffer
118 * @tlv_len: length of the TLV to be added/deleted
119 * @mib_len: length of the LLDP MIB returned in response
120 * @cd: pointer to command details structure or NULL
121 *
122 * (Add tlv)
123 * Add the specified TLV to LLDP Local MIB for the given bridge type,
124 * it is responsibility of the caller to make sure that the TLV is not
125 * already present in the LLDPDU.
126 * In return firmware will write the complete LLDP MIB with the newly
127 * added TLV in the response buffer. (0x0A02)
128 *
129 * (Delete tlv)
130 * Delete the specified TLV from LLDP Local MIB for the given bridge type.
131 * The firmware places the entire LLDP MIB in the response buffer. (0x0A04)
132 */
133enum ice_status
134ice_aq_add_delete_lldp_tlv(struct ice_hw *hw, u8 bridge_type, bool add_lldp_tlv,
135			   void *buf, u16 buf_size, u16 tlv_len, u16 *mib_len,
136			   struct ice_sq_cd *cd)
137{
138	struct ice_aqc_lldp_add_delete_tlv *cmd;
139	struct ice_aq_desc desc;
140	enum ice_status status;
141
142	if (tlv_len == 0)
143		return ICE_ERR_PARAM;
144
145	cmd = &desc.params.lldp_add_delete_tlv;
146
147	if (add_lldp_tlv)
148		ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_add_tlv);
149	else
150		ice_fill_dflt_direct_cmd_desc(&desc,
151					      ice_aqc_opc_lldp_delete_tlv);
152
153	desc.flags |= CPU_TO_LE16((u16)(ICE_AQ_FLAG_RD));
154
155	cmd->type = ((bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
156		     ICE_AQ_LLDP_BRID_TYPE_M);
157	cmd->len = CPU_TO_LE16(tlv_len);
158
159	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
160	if (!status && mib_len)
161		*mib_len = LE16_TO_CPU(desc.datalen);
162
163	return status;
164}
165
166/**
167 * ice_aq_update_lldp_tlv
168 * @hw: pointer to the HW struct
169 * @bridge_type: type of bridge
170 * @buf: buffer with TLV to update
171 * @buf_size: size of the buffer holding original and updated TLVs
172 * @old_len: Length of the Original TLV
173 * @new_len: Length of the Updated TLV
174 * @offset: offset of the updated TLV in the buff
175 * @mib_len: length of the returned LLDP MIB
176 * @cd: pointer to command details structure or NULL
177 *
178 * Update the specified TLV to the LLDP Local MIB for the given bridge type.
179 * Firmware will place the complete LLDP MIB in response buffer with the
180 * updated TLV. (0x0A03)
181 */
182enum ice_status
183ice_aq_update_lldp_tlv(struct ice_hw *hw, u8 bridge_type, void *buf,
184		       u16 buf_size, u16 old_len, u16 new_len, u16 offset,
185		       u16 *mib_len, struct ice_sq_cd *cd)
186{
187	struct ice_aqc_lldp_update_tlv *cmd;
188	struct ice_aq_desc desc;
189	enum ice_status status;
190
191	cmd = &desc.params.lldp_update_tlv;
192
193	if (offset == 0 || old_len == 0 || new_len == 0)
194		return ICE_ERR_PARAM;
195
196	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_update_tlv);
197
198	desc.flags |= CPU_TO_LE16((u16)(ICE_AQ_FLAG_RD));
199
200	cmd->type = ((bridge_type << ICE_AQ_LLDP_BRID_TYPE_S) &
201		     ICE_AQ_LLDP_BRID_TYPE_M);
202	cmd->old_len = CPU_TO_LE16(old_len);
203	cmd->new_offset = CPU_TO_LE16(offset);
204	cmd->new_len = CPU_TO_LE16(new_len);
205
206	status = ice_aq_send_cmd(hw, &desc, buf, buf_size, cd);
207	if (!status && mib_len)
208		*mib_len = LE16_TO_CPU(desc.datalen);
209
210	return status;
211}
212
213/**
214 * ice_aq_stop_lldp
215 * @hw: pointer to the HW struct
216 * @shutdown_lldp_agent: True if LLDP Agent needs to be Shutdown
217 *			 False if LLDP Agent needs to be Stopped
218 * @persist: True if Stop/Shutdown of LLDP Agent needs to be persistent across
219 *	     reboots
220 * @cd: pointer to command details structure or NULL
221 *
222 * Stop or Shutdown the embedded LLDP Agent (0x0A05)
223 */
224enum ice_status
225ice_aq_stop_lldp(struct ice_hw *hw, bool shutdown_lldp_agent, bool persist,
226		 struct ice_sq_cd *cd)
227{
228	struct ice_aqc_lldp_stop *cmd;
229	struct ice_aq_desc desc;
230
231	cmd = &desc.params.lldp_stop;
232
233	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_stop);
234
235	if (shutdown_lldp_agent)
236		cmd->command |= ICE_AQ_LLDP_AGENT_SHUTDOWN;
237
238	if (persist)
239		cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_DIS;
240
241	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
242}
243
244/**
245 * ice_aq_start_lldp
246 * @hw: pointer to the HW struct
247 * @persist: True if Start of LLDP Agent needs to be persistent across reboots
248 * @cd: pointer to command details structure or NULL
249 *
250 * Start the embedded LLDP Agent on all ports. (0x0A06)
251 */
252enum ice_status
253ice_aq_start_lldp(struct ice_hw *hw, bool persist, struct ice_sq_cd *cd)
254{
255	struct ice_aqc_lldp_start *cmd;
256	struct ice_aq_desc desc;
257
258	cmd = &desc.params.lldp_start;
259
260	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_lldp_start);
261
262	cmd->command = ICE_AQ_LLDP_AGENT_START;
263
264	if (persist)
265		cmd->command |= ICE_AQ_LLDP_AGENT_PERSIST_ENA;
266
267	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
268}
269
270/**
271 * ice_get_dcbx_status
272 * @hw: pointer to the HW struct
273 *
274 * Get the DCBX status from the Firmware
275 */
276u8 ice_get_dcbx_status(struct ice_hw *hw)
277{
278	u32 reg;
279
280	reg = rd32(hw, PRTDCB_GENS);
281	return (u8)((reg & PRTDCB_GENS_DCBX_STATUS_M) >>
282		    PRTDCB_GENS_DCBX_STATUS_S);
283}
284
285/**
286 * ice_parse_ieee_ets_common_tlv
287 * @buf: Data buffer to be parsed for ETS CFG/REC data
288 * @ets_cfg: Container to store parsed data
289 *
290 * Parses the common data of IEEE 802.1Qaz ETS CFG/REC TLV
291 */
292static void
293ice_parse_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
294{
295	u8 offset = 0;
296	int i;
297
298	/* Priority Assignment Table (4 octets)
299	 * Octets:|    1    |    2    |    3    |    4    |
300	 *        -----------------------------------------
301	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
302	 *        -----------------------------------------
303	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
304	 *        -----------------------------------------
305	 */
306	for (i = 0; i < 4; i++) {
307		ets_cfg->prio_table[i * 2] =
308			((buf[offset] & ICE_IEEE_ETS_PRIO_1_M) >>
309			 ICE_IEEE_ETS_PRIO_1_S);
310		ets_cfg->prio_table[i * 2 + 1] =
311			((buf[offset] & ICE_IEEE_ETS_PRIO_0_M) >>
312			 ICE_IEEE_ETS_PRIO_0_S);
313		offset++;
314	}
315
316	/* TC Bandwidth Table (8 octets)
317	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
318	 *        ---------------------------------
319	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
320	 *        ---------------------------------
321	 *
322	 * TSA Assignment Table (8 octets)
323	 * Octets:| 9 | 10| 11| 12| 13| 14| 15| 16|
324	 *        ---------------------------------
325	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
326	 *        ---------------------------------
327	 */
328	ice_for_each_traffic_class(i) {
329		ets_cfg->tcbwtable[i] = buf[offset];
330		ets_cfg->tsatable[i] = buf[ICE_MAX_TRAFFIC_CLASS + offset++];
331	}
332}
333
334/**
335 * ice_parse_ieee_etscfg_tlv
336 * @tlv: IEEE 802.1Qaz ETS CFG TLV
337 * @dcbcfg: Local store to update ETS CFG data
338 *
339 * Parses IEEE 802.1Qaz ETS CFG TLV
340 */
341static void
342ice_parse_ieee_etscfg_tlv(struct ice_lldp_org_tlv *tlv,
343			  struct ice_dcbx_cfg *dcbcfg)
344{
345	struct ice_dcb_ets_cfg *etscfg;
346	u8 *buf = tlv->tlvinfo;
347
348	/* First Octet post subtype
349	 * --------------------------
350	 * |will-|CBS  | Re-  | Max |
351	 * |ing  |     |served| TCs |
352	 * --------------------------
353	 * |1bit | 1bit|3 bits|3bits|
354	 */
355	etscfg = &dcbcfg->etscfg;
356	etscfg->willing = ((buf[0] & ICE_IEEE_ETS_WILLING_M) >>
357			   ICE_IEEE_ETS_WILLING_S);
358	etscfg->cbs = ((buf[0] & ICE_IEEE_ETS_CBS_M) >> ICE_IEEE_ETS_CBS_S);
359	etscfg->maxtcs = ((buf[0] & ICE_IEEE_ETS_MAXTC_M) >>
360			  ICE_IEEE_ETS_MAXTC_S);
361
362	/* Begin parsing at Priority Assignment Table (offset 1 in buf) */
363	ice_parse_ieee_ets_common_tlv(&buf[1], etscfg);
364}
365
366/**
367 * ice_parse_ieee_etsrec_tlv
368 * @tlv: IEEE 802.1Qaz ETS REC TLV
369 * @dcbcfg: Local store to update ETS REC data
370 *
371 * Parses IEEE 802.1Qaz ETS REC TLV
372 */
373static void
374ice_parse_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
375			  struct ice_dcbx_cfg *dcbcfg)
376{
377	u8 *buf = tlv->tlvinfo;
378
379	/* Begin parsing at Priority Assignment Table (offset 1 in buf) */
380	ice_parse_ieee_ets_common_tlv(&buf[1], &dcbcfg->etsrec);
381}
382
383/**
384 * ice_parse_ieee_pfccfg_tlv
385 * @tlv: IEEE 802.1Qaz PFC CFG TLV
386 * @dcbcfg: Local store to update PFC CFG data
387 *
388 * Parses IEEE 802.1Qaz PFC CFG TLV
389 */
390static void
391ice_parse_ieee_pfccfg_tlv(struct ice_lldp_org_tlv *tlv,
392			  struct ice_dcbx_cfg *dcbcfg)
393{
394	u8 *buf = tlv->tlvinfo;
395
396	/* ----------------------------------------
397	 * |will-|MBC  | Re-  | PFC |  PFC Enable  |
398	 * |ing  |     |served| cap |              |
399	 * -----------------------------------------
400	 * |1bit | 1bit|2 bits|4bits| 1 octet      |
401	 */
402	dcbcfg->pfc.willing = ((buf[0] & ICE_IEEE_PFC_WILLING_M) >>
403			       ICE_IEEE_PFC_WILLING_S);
404	dcbcfg->pfc.mbc = ((buf[0] & ICE_IEEE_PFC_MBC_M) >> ICE_IEEE_PFC_MBC_S);
405	dcbcfg->pfc.pfccap = ((buf[0] & ICE_IEEE_PFC_CAP_M) >>
406			      ICE_IEEE_PFC_CAP_S);
407	dcbcfg->pfc.pfcena = buf[1];
408}
409
410/**
411 * ice_parse_ieee_app_tlv
412 * @tlv: IEEE 802.1Qaz APP TLV
413 * @dcbcfg: Local store to update APP PRIO data
414 *
415 * Parses IEEE 802.1Qaz APP PRIO TLV
416 */
417static void
418ice_parse_ieee_app_tlv(struct ice_lldp_org_tlv *tlv,
419		       struct ice_dcbx_cfg *dcbcfg)
420{
421	u16 offset = 0;
422	u16 typelen;
423	int i = 0;
424	u16 len;
425	u8 *buf;
426
427	typelen = NTOHS(tlv->typelen);
428	len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
429	buf = tlv->tlvinfo;
430
431	/* Removing sizeof(ouisubtype) and reserved byte from len.
432	 * Remaining len div 3 is number of APP TLVs.
433	 */
434	len -= (sizeof(tlv->ouisubtype) + 1);
435
436	/* Move offset to App Priority Table */
437	offset++;
438
439	/* Application Priority Table (3 octets)
440	 * Octets:|         1          |    2    |    3    |
441	 *        -----------------------------------------
442	 *        |Priority|Rsrvd| Sel |    Protocol ID    |
443	 *        -----------------------------------------
444	 *   Bits:|23    21|20 19|18 16|15                0|
445	 *        -----------------------------------------
446	 */
447	while (offset < len) {
448		dcbcfg->app[i].priority = ((buf[offset] &
449					    ICE_IEEE_APP_PRIO_M) >>
450					   ICE_IEEE_APP_PRIO_S);
451		dcbcfg->app[i].selector = ((buf[offset] &
452					    ICE_IEEE_APP_SEL_M) >>
453					   ICE_IEEE_APP_SEL_S);
454		dcbcfg->app[i].prot_id = (buf[offset + 1] << 0x8) |
455			buf[offset + 2];
456		/* Move to next app */
457		offset += 3;
458		i++;
459		if (i >= ICE_DCBX_MAX_APPS)
460			break;
461	}
462
463	dcbcfg->numapps = i;
464}
465
466/**
467 * ice_parse_ieee_tlv
468 * @tlv: IEEE 802.1Qaz TLV
469 * @dcbcfg: Local store to update ETS REC data
470 *
471 * Get the TLV subtype and send it to parsing function
472 * based on the subtype value
473 */
474static void
475ice_parse_ieee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
476{
477	u32 ouisubtype;
478	u8 subtype;
479
480	ouisubtype = NTOHL(tlv->ouisubtype);
481	subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
482		       ICE_LLDP_TLV_SUBTYPE_S);
483	switch (subtype) {
484	case ICE_IEEE_SUBTYPE_ETS_CFG:
485		ice_parse_ieee_etscfg_tlv(tlv, dcbcfg);
486		break;
487	case ICE_IEEE_SUBTYPE_ETS_REC:
488		ice_parse_ieee_etsrec_tlv(tlv, dcbcfg);
489		break;
490	case ICE_IEEE_SUBTYPE_PFC_CFG:
491		ice_parse_ieee_pfccfg_tlv(tlv, dcbcfg);
492		break;
493	case ICE_IEEE_SUBTYPE_APP_PRI:
494		ice_parse_ieee_app_tlv(tlv, dcbcfg);
495		break;
496	default:
497		break;
498	}
499}
500
501/**
502 * ice_parse_cee_pgcfg_tlv
503 * @tlv: CEE DCBX PG CFG TLV
504 * @dcbcfg: Local store to update ETS CFG data
505 *
506 * Parses CEE DCBX PG CFG TLV
507 */
508static void
509ice_parse_cee_pgcfg_tlv(struct ice_cee_feat_tlv *tlv,
510			struct ice_dcbx_cfg *dcbcfg)
511{
512	struct ice_dcb_ets_cfg *etscfg;
513	u8 *buf = tlv->tlvinfo;
514	u16 offset = 0;
515	int i;
516
517	etscfg = &dcbcfg->etscfg;
518
519	if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
520		etscfg->willing = 1;
521
522	etscfg->cbs = 0;
523	/* Priority Group Table (4 octets)
524	 * Octets:|    1    |    2    |    3    |    4    |
525	 *        -----------------------------------------
526	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
527	 *        -----------------------------------------
528	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
529	 *        -----------------------------------------
530	 */
531	for (i = 0; i < 4; i++) {
532		etscfg->prio_table[i * 2] =
533			((buf[offset] & ICE_CEE_PGID_PRIO_1_M) >>
534			 ICE_CEE_PGID_PRIO_1_S);
535		etscfg->prio_table[i * 2 + 1] =
536			((buf[offset] & ICE_CEE_PGID_PRIO_0_M) >>
537			 ICE_CEE_PGID_PRIO_0_S);
538		offset++;
539	}
540
541	/* PG Percentage Table (8 octets)
542	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
543	 *        ---------------------------------
544	 *        |pg0|pg1|pg2|pg3|pg4|pg5|pg6|pg7|
545	 *        ---------------------------------
546	 */
547	ice_for_each_traffic_class(i) {
548		etscfg->tcbwtable[i] = buf[offset++];
549
550		if (etscfg->prio_table[i] == ICE_CEE_PGID_STRICT)
551			dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
552		else
553			dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
554	}
555
556	/* Number of TCs supported (1 octet) */
557	etscfg->maxtcs = buf[offset];
558}
559
560/**
561 * ice_parse_cee_pfccfg_tlv
562 * @tlv: CEE DCBX PFC CFG TLV
563 * @dcbcfg: Local store to update PFC CFG data
564 *
565 * Parses CEE DCBX PFC CFG TLV
566 */
567static void
568ice_parse_cee_pfccfg_tlv(struct ice_cee_feat_tlv *tlv,
569			 struct ice_dcbx_cfg *dcbcfg)
570{
571	u8 *buf = tlv->tlvinfo;
572
573	if (tlv->en_will_err & ICE_CEE_FEAT_TLV_WILLING_M)
574		dcbcfg->pfc.willing = 1;
575
576	/* ------------------------
577	 * | PFC Enable | PFC TCs |
578	 * ------------------------
579	 * | 1 octet    | 1 octet |
580	 */
581	dcbcfg->pfc.pfcena = buf[0];
582	dcbcfg->pfc.pfccap = buf[1];
583}
584
585/**
586 * ice_parse_cee_app_tlv
587 * @tlv: CEE DCBX APP TLV
588 * @dcbcfg: Local store to update APP PRIO data
589 *
590 * Parses CEE DCBX APP PRIO TLV
591 */
592static void
593ice_parse_cee_app_tlv(struct ice_cee_feat_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
594{
595	u16 len, typelen, offset = 0;
596	struct ice_cee_app_prio *app;
597	u8 i;
598
599	typelen = NTOHS(tlv->hdr.typelen);
600	len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
601
602	dcbcfg->numapps = len / sizeof(*app);
603	if (!dcbcfg->numapps)
604		return;
605	if (dcbcfg->numapps > ICE_DCBX_MAX_APPS)
606		dcbcfg->numapps = ICE_DCBX_MAX_APPS;
607
608	for (i = 0; i < dcbcfg->numapps; i++) {
609		u8 up, selector;
610
611		app = (struct ice_cee_app_prio *)(tlv->tlvinfo + offset);
612		for (up = 0; up < ICE_MAX_USER_PRIORITY; up++)
613			if (app->prio_map & BIT(up))
614				break;
615
616		dcbcfg->app[i].priority = up;
617
618		/* Get Selector from lower 2 bits, and convert to IEEE */
619		selector = (app->upper_oui_sel & ICE_CEE_APP_SELECTOR_M);
620		switch (selector) {
621		case ICE_CEE_APP_SEL_ETHTYPE:
622			dcbcfg->app[i].selector = ICE_APP_SEL_ETHTYPE;
623			break;
624		case ICE_CEE_APP_SEL_TCPIP:
625			dcbcfg->app[i].selector = ICE_APP_SEL_TCPIP;
626			break;
627		default:
628			/* Keep selector as it is for unknown types */
629			dcbcfg->app[i].selector = selector;
630		}
631
632		dcbcfg->app[i].prot_id = NTOHS(app->protocol);
633		/* Move to next app */
634		offset += sizeof(*app);
635	}
636}
637
638/**
639 * ice_parse_cee_tlv
640 * @tlv: CEE DCBX TLV
641 * @dcbcfg: Local store to update DCBX config data
642 *
643 * Get the TLV subtype and send it to parsing function
644 * based on the subtype value
645 */
646static void
647ice_parse_cee_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
648{
649	struct ice_cee_feat_tlv *sub_tlv;
650	u8 subtype, feat_tlv_count = 0;
651	u16 len, tlvlen, typelen;
652	u32 ouisubtype;
653
654	ouisubtype = NTOHL(tlv->ouisubtype);
655	subtype = (u8)((ouisubtype & ICE_LLDP_TLV_SUBTYPE_M) >>
656		       ICE_LLDP_TLV_SUBTYPE_S);
657	/* Return if not CEE DCBX */
658	if (subtype != ICE_CEE_DCBX_TYPE)
659		return;
660
661	typelen = NTOHS(tlv->typelen);
662	tlvlen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
663	len = sizeof(tlv->typelen) + sizeof(ouisubtype) +
664		sizeof(struct ice_cee_ctrl_tlv);
665	/* Return if no CEE DCBX Feature TLVs */
666	if (tlvlen <= len)
667		return;
668
669	sub_tlv = (struct ice_cee_feat_tlv *)((char *)tlv + len);
670	while (feat_tlv_count < ICE_CEE_MAX_FEAT_TYPE) {
671		u16 sublen;
672
673		typelen = NTOHS(sub_tlv->hdr.typelen);
674		sublen = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
675		subtype = (u8)((typelen & ICE_LLDP_TLV_TYPE_M) >>
676			       ICE_LLDP_TLV_TYPE_S);
677		switch (subtype) {
678		case ICE_CEE_SUBTYPE_PG_CFG:
679			ice_parse_cee_pgcfg_tlv(sub_tlv, dcbcfg);
680			break;
681		case ICE_CEE_SUBTYPE_PFC_CFG:
682			ice_parse_cee_pfccfg_tlv(sub_tlv, dcbcfg);
683			break;
684		case ICE_CEE_SUBTYPE_APP_PRI:
685			ice_parse_cee_app_tlv(sub_tlv, dcbcfg);
686			break;
687		default:
688			return;	/* Invalid Sub-type return */
689		}
690		feat_tlv_count++;
691		/* Move to next sub TLV */
692		sub_tlv = (struct ice_cee_feat_tlv *)
693			  ((char *)sub_tlv + sizeof(sub_tlv->hdr.typelen) +
694			   sublen);
695	}
696}
697
698/**
699 * ice_parse_org_tlv
700 * @tlv: Organization specific TLV
701 * @dcbcfg: Local store to update ETS REC data
702 *
703 * Currently only IEEE 802.1Qaz TLV is supported, all others
704 * will be returned
705 */
706static void
707ice_parse_org_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
708{
709	u32 ouisubtype;
710	u32 oui;
711
712	ouisubtype = NTOHL(tlv->ouisubtype);
713	oui = ((ouisubtype & ICE_LLDP_TLV_OUI_M) >> ICE_LLDP_TLV_OUI_S);
714	switch (oui) {
715	case ICE_IEEE_8021QAZ_OUI:
716		ice_parse_ieee_tlv(tlv, dcbcfg);
717		break;
718	case ICE_CEE_DCBX_OUI:
719		ice_parse_cee_tlv(tlv, dcbcfg);
720		break;
721	default:
722		break;
723	}
724}
725
726/**
727 * ice_lldp_to_dcb_cfg
728 * @lldpmib: LLDPDU to be parsed
729 * @dcbcfg: store for LLDPDU data
730 *
731 * Parse DCB configuration from the LLDPDU
732 */
733enum ice_status ice_lldp_to_dcb_cfg(u8 *lldpmib, struct ice_dcbx_cfg *dcbcfg)
734{
735	struct ice_lldp_org_tlv *tlv;
736	enum ice_status ret = ICE_SUCCESS;
737	u16 offset = 0;
738	u16 typelen;
739	u16 type;
740	u16 len;
741
742	if (!lldpmib || !dcbcfg)
743		return ICE_ERR_PARAM;
744
745	/* set to the start of LLDPDU */
746	lldpmib += ETH_HEADER_LEN;
747	tlv = (struct ice_lldp_org_tlv *)lldpmib;
748	while (1) {
749		typelen = NTOHS(tlv->typelen);
750		type = ((typelen & ICE_LLDP_TLV_TYPE_M) >> ICE_LLDP_TLV_TYPE_S);
751		len = ((typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S);
752		offset += sizeof(typelen) + len;
753
754		/* END TLV or beyond LLDPDU size */
755		if (type == ICE_TLV_TYPE_END || offset > ICE_LLDPDU_SIZE)
756			break;
757
758		switch (type) {
759		case ICE_TLV_TYPE_ORG:
760			ice_parse_org_tlv(tlv, dcbcfg);
761			break;
762		default:
763			break;
764		}
765
766		/* Move to next TLV */
767		tlv = (struct ice_lldp_org_tlv *)
768		      ((char *)tlv + sizeof(tlv->typelen) + len);
769	}
770
771	return ret;
772}
773
774/**
775 * ice_aq_get_dcb_cfg
776 * @hw: pointer to the HW struct
777 * @mib_type: MIB type for the query
778 * @bridgetype: bridge type for the query (remote)
779 * @dcbcfg: store for LLDPDU data
780 *
781 * Query DCB configuration from the firmware
782 */
783enum ice_status
784ice_aq_get_dcb_cfg(struct ice_hw *hw, u8 mib_type, u8 bridgetype,
785		   struct ice_dcbx_cfg *dcbcfg)
786{
787	enum ice_status ret;
788	u8 *lldpmib;
789
790	/* Allocate the LLDPDU */
791	lldpmib = (u8 *)ice_malloc(hw, ICE_LLDPDU_SIZE);
792	if (!lldpmib)
793		return ICE_ERR_NO_MEMORY;
794
795	ret = ice_aq_get_lldp_mib(hw, bridgetype, mib_type, (void *)lldpmib,
796				  ICE_LLDPDU_SIZE, NULL, NULL, NULL);
797
798	if (ret == ICE_SUCCESS)
799		/* Parse LLDP MIB to get DCB configuration */
800		ret = ice_lldp_to_dcb_cfg(lldpmib, dcbcfg);
801
802	ice_free(hw, lldpmib);
803
804	return ret;
805}
806
807/**
808 * ice_aq_dcb_ignore_pfc - Ignore PFC for given TCs
809 * @hw: pointer to the HW struct
810 * @tcmap: TC map for request/release any ignore PFC condition
811 * @request: request (true) or release (false) ignore PFC condition
812 * @tcmap_ret: return TCs for which PFC is currently ignored
813 * @cd: pointer to command details structure or NULL
814 *
815 * This sends out request/release to ignore PFC condition for a TC.
816 * It will return the TCs for which PFC is currently ignored. (0x0301)
817 */
818enum ice_status
819ice_aq_dcb_ignore_pfc(struct ice_hw *hw, u8 tcmap, bool request, u8 *tcmap_ret,
820		      struct ice_sq_cd *cd)
821{
822	struct ice_aqc_pfc_ignore *cmd;
823	struct ice_aq_desc desc;
824	enum ice_status status;
825
826	cmd = &desc.params.pfc_ignore;
827
828	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_pfc_ignore);
829
830	if (request)
831		cmd->cmd_flags = ICE_AQC_PFC_IGNORE_SET;
832
833	cmd->tc_bitmap = tcmap;
834
835	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
836
837	if (!status && tcmap_ret)
838		*tcmap_ret = cmd->tc_bitmap;
839
840	return status;
841}
842
843/**
844 * ice_aq_start_stop_dcbx - Start/Stop DCBX service in FW
845 * @hw: pointer to the HW struct
846 * @start_dcbx_agent: True if DCBX Agent needs to be started
847 *		      False if DCBX Agent needs to be stopped
848 * @dcbx_agent_status: FW indicates back the DCBX agent status
849 *		       True if DCBX Agent is active
850 *		       False if DCBX Agent is stopped
851 * @cd: pointer to command details structure or NULL
852 *
853 * Start/Stop the embedded dcbx Agent. In case that this wrapper function
854 * returns ICE_SUCCESS, caller will need to check if FW returns back the same
855 * value as stated in dcbx_agent_status, and react accordingly. (0x0A09)
856 */
857enum ice_status
858ice_aq_start_stop_dcbx(struct ice_hw *hw, bool start_dcbx_agent,
859		       bool *dcbx_agent_status, struct ice_sq_cd *cd)
860{
861	struct ice_aqc_lldp_stop_start_specific_agent *cmd;
862	enum ice_adminq_opc opcode;
863	struct ice_aq_desc desc;
864	enum ice_status status;
865
866	cmd = &desc.params.lldp_agent_ctrl;
867
868	opcode = ice_aqc_opc_lldp_stop_start_specific_agent;
869
870	ice_fill_dflt_direct_cmd_desc(&desc, opcode);
871
872	if (start_dcbx_agent)
873		cmd->command = ICE_AQC_START_STOP_AGENT_START_DCBX;
874
875	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
876
877	*dcbx_agent_status = false;
878
879	if (status == ICE_SUCCESS &&
880	    cmd->command == ICE_AQC_START_STOP_AGENT_START_DCBX)
881		*dcbx_agent_status = true;
882
883	return status;
884}
885
886/**
887 * ice_aq_get_cee_dcb_cfg
888 * @hw: pointer to the HW struct
889 * @buff: response buffer that stores CEE operational configuration
890 * @cd: pointer to command details structure or NULL
891 *
892 * Get CEE DCBX mode operational configuration from firmware (0x0A07)
893 */
894enum ice_status
895ice_aq_get_cee_dcb_cfg(struct ice_hw *hw,
896		       struct ice_aqc_get_cee_dcb_cfg_resp *buff,
897		       struct ice_sq_cd *cd)
898{
899	struct ice_aq_desc desc;
900
901	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_get_cee_dcb_cfg);
902
903	return ice_aq_send_cmd(hw, &desc, (void *)buff, sizeof(*buff), cd);
904}
905
906/**
907 * ice_aq_query_pfc_mode - Query PFC mode
908 * @hw: pointer to the HW struct
909 * @pfcmode_ret: Return PFC mode
910 * @cd: pointer to command details structure or NULL
911 *
912 * This will return an indication if DSCP-based PFC or VLAN-based PFC
913 * is enabled. (0x0302)
914 */
915enum ice_status
916ice_aq_query_pfc_mode(struct ice_hw *hw, u8 *pfcmode_ret, struct ice_sq_cd *cd)
917{
918	struct ice_aqc_set_query_pfc_mode *cmd;
919	struct ice_aq_desc desc;
920	enum ice_status status;
921
922	cmd = &desc.params.set_query_pfc_mode;
923
924	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_pfc_mode);
925
926	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
927
928	if (!status)
929		*pfcmode_ret = cmd->pfc_mode;
930
931	return status;
932}
933
934/**
935 * ice_aq_set_pfc_mode - Set PFC mode
936 * @hw: pointer to the HW struct
937 * @pfc_mode: value of PFC mode to set
938 * @cd: pointer to command details structure or NULL
939 *
940 * This AQ call configures the PFC mdoe to DSCP-based PFC mode or VLAN
941 * -based PFC (0x0303)
942 */
943enum ice_status
944ice_aq_set_pfc_mode(struct ice_hw *hw, u8 pfc_mode, struct ice_sq_cd *cd)
945{
946	struct ice_aqc_set_query_pfc_mode *cmd;
947	struct ice_aq_desc desc;
948	enum ice_status status;
949
950	if (pfc_mode > ICE_AQC_PFC_DSCP_BASED_PFC)
951		return ICE_ERR_PARAM;
952
953	cmd = &desc.params.set_query_pfc_mode;
954
955	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_pfc_mode);
956
957	cmd->pfc_mode = pfc_mode;
958
959	status = ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
960	if (status)
961		return status;
962
963	/* FW will write the PFC mode set back into cmd->pfc_mode, but if DCB is
964	 * disabled, FW will write back 0 to cmd->pfc_mode. After the AQ has
965	 * been executed, check if cmd->pfc_mode is what was requested. If not,
966	 * return an error.
967	 */
968	if (cmd->pfc_mode != pfc_mode)
969		return ICE_ERR_NOT_SUPPORTED;
970
971	return ICE_SUCCESS;
972}
973
974/**
975 * ice_aq_set_dcb_parameters - Set DCB parameters
976 * @hw: pointer to the HW struct
977 * @dcb_enable: True if DCB configuration needs to be applied
978 * @cd: pointer to command details structure or NULL
979 *
980 * This AQ command will tell FW if it will apply or not apply the default DCB
981 * configuration when link up (0x0306).
982 */
983enum ice_status
984ice_aq_set_dcb_parameters(struct ice_hw *hw, bool dcb_enable,
985			  struct ice_sq_cd *cd)
986{
987	struct ice_aqc_set_dcb_params *cmd;
988	struct ice_aq_desc desc;
989
990	cmd = &desc.params.set_dcb_params;
991
992	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_set_dcb_params);
993
994	cmd->valid_flags = ICE_AQC_LINK_UP_DCB_CFG_VALID;
995	if (dcb_enable)
996		cmd->cmd_flags = ICE_AQC_LINK_UP_DCB_CFG;
997
998	return ice_aq_send_cmd(hw, &desc, NULL, 0, cd);
999}
1000
1001/**
1002 * ice_cee_to_dcb_cfg
1003 * @cee_cfg: pointer to CEE configuration struct
1004 * @pi: port information structure
1005 *
1006 * Convert CEE configuration from firmware to DCB configuration
1007 */
1008static void
1009ice_cee_to_dcb_cfg(struct ice_aqc_get_cee_dcb_cfg_resp *cee_cfg,
1010		   struct ice_port_info *pi)
1011{
1012	u32 status, tlv_status = LE32_TO_CPU(cee_cfg->tlv_status);
1013	u32 ice_aqc_cee_status_mask, ice_aqc_cee_status_shift;
1014	u8 i, j, err, sync, oper, app_index, ice_app_sel_type;
1015	u16 app_prio = LE16_TO_CPU(cee_cfg->oper_app_prio);
1016	u16 ice_aqc_cee_app_mask, ice_aqc_cee_app_shift;
1017	struct ice_dcbx_cfg *cmp_dcbcfg, *dcbcfg;
1018	u16 ice_app_prot_id_type;
1019
1020	dcbcfg = &pi->qos_cfg.local_dcbx_cfg;
1021	dcbcfg->dcbx_mode = ICE_DCBX_MODE_CEE;
1022	dcbcfg->tlv_status = tlv_status;
1023
1024	/* CEE PG data */
1025	dcbcfg->etscfg.maxtcs = cee_cfg->oper_num_tc;
1026
1027	/* Note that the FW creates the oper_prio_tc nibbles reversed
1028	 * from those in the CEE Priority Group sub-TLV.
1029	 */
1030	for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
1031		dcbcfg->etscfg.prio_table[i * 2] =
1032			((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_0_M) >>
1033			 ICE_CEE_PGID_PRIO_0_S);
1034		dcbcfg->etscfg.prio_table[i * 2 + 1] =
1035			((cee_cfg->oper_prio_tc[i] & ICE_CEE_PGID_PRIO_1_M) >>
1036			 ICE_CEE_PGID_PRIO_1_S);
1037	}
1038
1039	ice_for_each_traffic_class(i) {
1040		dcbcfg->etscfg.tcbwtable[i] = cee_cfg->oper_tc_bw[i];
1041
1042		if (dcbcfg->etscfg.prio_table[i] == ICE_CEE_PGID_STRICT) {
1043			/* Map it to next empty TC */
1044			dcbcfg->etscfg.prio_table[i] = cee_cfg->oper_num_tc - 1;
1045			dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_STRICT;
1046		} else {
1047			dcbcfg->etscfg.tsatable[i] = ICE_IEEE_TSA_ETS;
1048		}
1049	}
1050
1051	/* CEE PFC data */
1052	dcbcfg->pfc.pfcena = cee_cfg->oper_pfc_en;
1053	dcbcfg->pfc.pfccap = ICE_MAX_TRAFFIC_CLASS;
1054
1055	/* CEE APP TLV data */
1056	if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
1057		cmp_dcbcfg = &pi->qos_cfg.desired_dcbx_cfg;
1058	else
1059		cmp_dcbcfg = &pi->qos_cfg.remote_dcbx_cfg;
1060
1061	app_index = 0;
1062	for (i = 0; i < 3; i++) {
1063		if (i == 0) {
1064			/* FCoE APP */
1065			ice_aqc_cee_status_mask = ICE_AQC_CEE_FCOE_STATUS_M;
1066			ice_aqc_cee_status_shift = ICE_AQC_CEE_FCOE_STATUS_S;
1067			ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FCOE_M;
1068			ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FCOE_S;
1069			ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
1070			ice_app_prot_id_type = ICE_APP_PROT_ID_FCOE;
1071		} else if (i == 1) {
1072			/* iSCSI APP */
1073			ice_aqc_cee_status_mask = ICE_AQC_CEE_ISCSI_STATUS_M;
1074			ice_aqc_cee_status_shift = ICE_AQC_CEE_ISCSI_STATUS_S;
1075			ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_ISCSI_M;
1076			ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_ISCSI_S;
1077			ice_app_sel_type = ICE_APP_SEL_TCPIP;
1078			ice_app_prot_id_type = ICE_APP_PROT_ID_ISCSI;
1079
1080			for (j = 0; j < cmp_dcbcfg->numapps; j++) {
1081				u16 prot_id = cmp_dcbcfg->app[j].prot_id;
1082				u8 sel = cmp_dcbcfg->app[j].selector;
1083
1084				if  (sel == ICE_APP_SEL_TCPIP &&
1085				     (prot_id == ICE_APP_PROT_ID_ISCSI ||
1086				      prot_id == ICE_APP_PROT_ID_ISCSI_860)) {
1087					ice_app_prot_id_type = prot_id;
1088					break;
1089				}
1090			}
1091		} else {
1092			/* FIP APP */
1093			ice_aqc_cee_status_mask = ICE_AQC_CEE_FIP_STATUS_M;
1094			ice_aqc_cee_status_shift = ICE_AQC_CEE_FIP_STATUS_S;
1095			ice_aqc_cee_app_mask = ICE_AQC_CEE_APP_FIP_M;
1096			ice_aqc_cee_app_shift = ICE_AQC_CEE_APP_FIP_S;
1097			ice_app_sel_type = ICE_APP_SEL_ETHTYPE;
1098			ice_app_prot_id_type = ICE_APP_PROT_ID_FIP;
1099		}
1100
1101		status = (tlv_status & ice_aqc_cee_status_mask) >>
1102			 ice_aqc_cee_status_shift;
1103		err = (status & ICE_TLV_STATUS_ERR) ? 1 : 0;
1104		sync = (status & ICE_TLV_STATUS_SYNC) ? 1 : 0;
1105		oper = (status & ICE_TLV_STATUS_OPER) ? 1 : 0;
1106		/* Add FCoE/iSCSI/FIP APP if Error is False and
1107		 * Oper/Sync is True
1108		 */
1109		if (!err && sync && oper) {
1110			dcbcfg->app[app_index].priority =
1111				(u8)((app_prio & ice_aqc_cee_app_mask) >>
1112				     ice_aqc_cee_app_shift);
1113			dcbcfg->app[app_index].selector = ice_app_sel_type;
1114			dcbcfg->app[app_index].prot_id = ice_app_prot_id_type;
1115			app_index++;
1116		}
1117	}
1118
1119	dcbcfg->numapps = app_index;
1120}
1121
1122/**
1123 * ice_get_ieee_or_cee_dcb_cfg
1124 * @pi: port information structure
1125 * @dcbx_mode: mode of DCBX (IEEE or CEE)
1126 *
1127 * Get IEEE or CEE mode DCB configuration from the Firmware
1128 */
1129STATIC enum ice_status
1130ice_get_ieee_or_cee_dcb_cfg(struct ice_port_info *pi, u8 dcbx_mode)
1131{
1132	struct ice_dcbx_cfg *dcbx_cfg = NULL;
1133	enum ice_status ret;
1134
1135	if (!pi)
1136		return ICE_ERR_PARAM;
1137
1138	if (dcbx_mode == ICE_DCBX_MODE_IEEE)
1139		dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
1140	else if (dcbx_mode == ICE_DCBX_MODE_CEE)
1141		dcbx_cfg = &pi->qos_cfg.desired_dcbx_cfg;
1142
1143	/* Get Local DCB Config in case of ICE_DCBX_MODE_IEEE
1144	 * or get CEE DCB Desired Config in case of ICE_DCBX_MODE_CEE
1145	 */
1146	ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_LOCAL,
1147				 ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
1148	if (ret)
1149		goto out;
1150
1151	/* Get Remote DCB Config */
1152	dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;
1153	ret = ice_aq_get_dcb_cfg(pi->hw, ICE_AQ_LLDP_MIB_REMOTE,
1154				 ICE_AQ_LLDP_BRID_TYPE_NEAREST_BRID, dcbx_cfg);
1155	/* Don't treat ENOENT as an error for Remote MIBs */
1156	if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT)
1157		ret = ICE_SUCCESS;
1158
1159out:
1160	return ret;
1161}
1162
1163/**
1164 * ice_get_dcb_cfg
1165 * @pi: port information structure
1166 *
1167 * Get DCB configuration from the Firmware
1168 */
1169enum ice_status ice_get_dcb_cfg(struct ice_port_info *pi)
1170{
1171	struct ice_aqc_get_cee_dcb_cfg_resp cee_cfg;
1172	struct ice_dcbx_cfg *dcbx_cfg;
1173	enum ice_status ret;
1174
1175	if (!pi)
1176		return ICE_ERR_PARAM;
1177
1178	ret = ice_aq_get_cee_dcb_cfg(pi->hw, &cee_cfg, NULL);
1179	if (ret == ICE_SUCCESS) {
1180		/* CEE mode */
1181		ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_CEE);
1182		ice_cee_to_dcb_cfg(&cee_cfg, pi);
1183	} else if (pi->hw->adminq.sq_last_status == ICE_AQ_RC_ENOENT) {
1184		/* CEE mode not enabled try querying IEEE data */
1185		dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
1186		dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;
1187		ret = ice_get_ieee_or_cee_dcb_cfg(pi, ICE_DCBX_MODE_IEEE);
1188	}
1189
1190	return ret;
1191}
1192
1193/**
1194 * ice_get_dcb_cfg_from_mib_change
1195 * @pi: port information structure
1196 * @event: pointer to the admin queue receive event
1197 *
1198 * Set DCB configuration from received MIB Change event
1199 */
1200void ice_get_dcb_cfg_from_mib_change(struct ice_port_info *pi,
1201				     struct ice_rq_event_info *event)
1202{
1203	struct ice_dcbx_cfg *dcbx_cfg = &pi->qos_cfg.local_dcbx_cfg;
1204	struct ice_aqc_lldp_get_mib *mib;
1205	u8 change_type, dcbx_mode;
1206
1207	mib = (struct ice_aqc_lldp_get_mib *)&event->desc.params.raw;
1208
1209	change_type = mib->type & ICE_AQ_LLDP_MIB_TYPE_M;
1210	if (change_type == ICE_AQ_LLDP_MIB_REMOTE)
1211		dcbx_cfg = &pi->qos_cfg.remote_dcbx_cfg;
1212
1213	dcbx_mode = ((mib->type & ICE_AQ_LLDP_DCBX_M) >>
1214		     ICE_AQ_LLDP_DCBX_S);
1215
1216	switch (dcbx_mode) {
1217	case ICE_AQ_LLDP_DCBX_IEEE:
1218		dcbx_cfg->dcbx_mode = ICE_DCBX_MODE_IEEE;
1219		ice_lldp_to_dcb_cfg(event->msg_buf, dcbx_cfg);
1220		break;
1221
1222	case ICE_AQ_LLDP_DCBX_CEE:
1223		pi->qos_cfg.desired_dcbx_cfg = pi->qos_cfg.local_dcbx_cfg;
1224		ice_cee_to_dcb_cfg((struct ice_aqc_get_cee_dcb_cfg_resp *)
1225				   event->msg_buf, pi);
1226		break;
1227	}
1228}
1229
1230/**
1231 * ice_init_dcb
1232 * @hw: pointer to the HW struct
1233 * @enable_mib_change: enable MIB change event
1234 *
1235 * Update DCB configuration from the Firmware
1236 */
1237enum ice_status ice_init_dcb(struct ice_hw *hw, bool enable_mib_change)
1238{
1239	struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;
1240	enum ice_status ret = ICE_SUCCESS;
1241
1242	if (!hw->func_caps.common_cap.dcb)
1243		return ICE_ERR_NOT_SUPPORTED;
1244
1245	qos_cfg->is_sw_lldp = true;
1246
1247	/* Get DCBX status */
1248	qos_cfg->dcbx_status = ice_get_dcbx_status(hw);
1249
1250	if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DONE ||
1251	    qos_cfg->dcbx_status == ICE_DCBX_STATUS_IN_PROGRESS ||
1252	    qos_cfg->dcbx_status == ICE_DCBX_STATUS_NOT_STARTED) {
1253		/* Get current DCBX configuration */
1254		ret = ice_get_dcb_cfg(hw->port_info);
1255		if (ret)
1256			return ret;
1257		qos_cfg->is_sw_lldp = false;
1258	} else if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS) {
1259		return ICE_ERR_NOT_READY;
1260	}
1261
1262	/* Configure the LLDP MIB change event */
1263	if (enable_mib_change) {
1264		ret = ice_aq_cfg_lldp_mib_change(hw, true, NULL);
1265		if (ret)
1266			qos_cfg->is_sw_lldp = true;
1267	}
1268
1269	return ret;
1270}
1271
1272/**
1273 * ice_cfg_lldp_mib_change
1274 * @hw: pointer to the HW struct
1275 * @ena_mib: enable/disable MIB change event
1276 *
1277 * Configure (disable/enable) MIB
1278 */
1279enum ice_status ice_cfg_lldp_mib_change(struct ice_hw *hw, bool ena_mib)
1280{
1281	struct ice_qos_cfg *qos_cfg = &hw->port_info->qos_cfg;
1282	enum ice_status ret;
1283
1284	if (!hw->func_caps.common_cap.dcb)
1285		return ICE_ERR_NOT_SUPPORTED;
1286
1287	/* Get DCBX status */
1288	qos_cfg->dcbx_status = ice_get_dcbx_status(hw);
1289
1290	if (qos_cfg->dcbx_status == ICE_DCBX_STATUS_DIS)
1291		return ICE_ERR_NOT_READY;
1292
1293	ret = ice_aq_cfg_lldp_mib_change(hw, ena_mib, NULL);
1294	if (!ret)
1295		qos_cfg->is_sw_lldp = !ena_mib;
1296
1297	return ret;
1298}
1299
1300/**
1301 * ice_add_ieee_ets_common_tlv
1302 * @buf: Data buffer to be populated with ice_dcb_ets_cfg data
1303 * @ets_cfg: Container for ice_dcb_ets_cfg data
1304 *
1305 * Populate the TLV buffer with ice_dcb_ets_cfg data
1306 */
1307static void
1308ice_add_ieee_ets_common_tlv(u8 *buf, struct ice_dcb_ets_cfg *ets_cfg)
1309{
1310	u8 priority0, priority1;
1311	u8 offset = 0;
1312	int i;
1313
1314	/* Priority Assignment Table (4 octets)
1315	 * Octets:|    1    |    2    |    3    |    4    |
1316	 *        -----------------------------------------
1317	 *        |pri0|pri1|pri2|pri3|pri4|pri5|pri6|pri7|
1318	 *        -----------------------------------------
1319	 *   Bits:|7  4|3  0|7  4|3  0|7  4|3  0|7  4|3  0|
1320	 *        -----------------------------------------
1321	 */
1322	for (i = 0; i < ICE_MAX_TRAFFIC_CLASS / 2; i++) {
1323		priority0 = ets_cfg->prio_table[i * 2] & 0xF;
1324		priority1 = ets_cfg->prio_table[i * 2 + 1] & 0xF;
1325		buf[offset] = (priority0 << ICE_IEEE_ETS_PRIO_1_S) | priority1;
1326		offset++;
1327	}
1328
1329	/* TC Bandwidth Table (8 octets)
1330	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1331	 *        ---------------------------------
1332	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1333	 *        ---------------------------------
1334	 *
1335	 * TSA Assignment Table (8 octets)
1336	 * Octets:| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
1337	 *        ---------------------------------
1338	 *        |tc0|tc1|tc2|tc3|tc4|tc5|tc6|tc7|
1339	 *        ---------------------------------
1340	 */
1341	ice_for_each_traffic_class(i) {
1342		buf[offset] = ets_cfg->tcbwtable[i];
1343		buf[ICE_MAX_TRAFFIC_CLASS + offset] = ets_cfg->tsatable[i];
1344		offset++;
1345	}
1346}
1347
1348/**
1349 * ice_add_ieee_ets_tlv - Prepare ETS TLV in IEEE format
1350 * @tlv: Fill the ETS config data in IEEE format
1351 * @dcbcfg: Local store which holds the DCB Config
1352 *
1353 * Prepare IEEE 802.1Qaz ETS CFG TLV
1354 */
1355static void
1356ice_add_ieee_ets_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1357{
1358	struct ice_dcb_ets_cfg *etscfg;
1359	u8 *buf = tlv->tlvinfo;
1360	u8 maxtcwilling = 0;
1361	u32 ouisubtype;
1362	u16 typelen;
1363
1364	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1365		   ICE_IEEE_ETS_TLV_LEN);
1366	tlv->typelen = HTONS(typelen);
1367
1368	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1369		      ICE_IEEE_SUBTYPE_ETS_CFG);
1370	tlv->ouisubtype = HTONL(ouisubtype);
1371
1372	/* First Octet post subtype
1373	 * --------------------------
1374	 * |will-|CBS  | Re-  | Max |
1375	 * |ing  |     |served| TCs |
1376	 * --------------------------
1377	 * |1bit | 1bit|3 bits|3bits|
1378	 */
1379	etscfg = &dcbcfg->etscfg;
1380	if (etscfg->willing)
1381		maxtcwilling = BIT(ICE_IEEE_ETS_WILLING_S);
1382	maxtcwilling |= etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1383	buf[0] = maxtcwilling;
1384
1385	/* Begin adding at Priority Assignment Table (offset 1 in buf) */
1386	ice_add_ieee_ets_common_tlv(&buf[1], etscfg);
1387}
1388
1389/**
1390 * ice_add_ieee_etsrec_tlv - Prepare ETS Recommended TLV in IEEE format
1391 * @tlv: Fill ETS Recommended TLV in IEEE format
1392 * @dcbcfg: Local store which holds the DCB Config
1393 *
1394 * Prepare IEEE 802.1Qaz ETS REC TLV
1395 */
1396static void
1397ice_add_ieee_etsrec_tlv(struct ice_lldp_org_tlv *tlv,
1398			struct ice_dcbx_cfg *dcbcfg)
1399{
1400	struct ice_dcb_ets_cfg *etsrec;
1401	u8 *buf = tlv->tlvinfo;
1402	u32 ouisubtype;
1403	u16 typelen;
1404
1405	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1406		   ICE_IEEE_ETS_TLV_LEN);
1407	tlv->typelen = HTONS(typelen);
1408
1409	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1410		      ICE_IEEE_SUBTYPE_ETS_REC);
1411	tlv->ouisubtype = HTONL(ouisubtype);
1412
1413	etsrec = &dcbcfg->etsrec;
1414
1415	/* First Octet is reserved */
1416	/* Begin adding at Priority Assignment Table (offset 1 in buf) */
1417	ice_add_ieee_ets_common_tlv(&buf[1], etsrec);
1418}
1419
1420/**
1421 * ice_add_ieee_pfc_tlv - Prepare PFC TLV in IEEE format
1422 * @tlv: Fill PFC TLV in IEEE format
1423 * @dcbcfg: Local store which holds the PFC CFG data
1424 *
1425 * Prepare IEEE 802.1Qaz PFC CFG TLV
1426 */
1427static void
1428ice_add_ieee_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1429{
1430	u8 *buf = tlv->tlvinfo;
1431	u32 ouisubtype;
1432	u16 typelen;
1433
1434	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1435		   ICE_IEEE_PFC_TLV_LEN);
1436	tlv->typelen = HTONS(typelen);
1437
1438	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1439		      ICE_IEEE_SUBTYPE_PFC_CFG);
1440	tlv->ouisubtype = HTONL(ouisubtype);
1441
1442	/* ----------------------------------------
1443	 * |will-|MBC  | Re-  | PFC |  PFC Enable  |
1444	 * |ing  |     |served| cap |              |
1445	 * -----------------------------------------
1446	 * |1bit | 1bit|2 bits|4bits| 1 octet      |
1447	 */
1448	if (dcbcfg->pfc.willing)
1449		buf[0] = BIT(ICE_IEEE_PFC_WILLING_S);
1450
1451	if (dcbcfg->pfc.mbc)
1452		buf[0] |= BIT(ICE_IEEE_PFC_MBC_S);
1453
1454	buf[0] |= dcbcfg->pfc.pfccap & 0xF;
1455	buf[1] = dcbcfg->pfc.pfcena;
1456}
1457
1458/**
1459 * ice_add_ieee_app_pri_tlv -  Prepare APP TLV in IEEE format
1460 * @tlv: Fill APP TLV in IEEE format
1461 * @dcbcfg: Local store which holds the APP CFG data
1462 *
1463 * Prepare IEEE 802.1Qaz APP CFG TLV
1464 */
1465static void
1466ice_add_ieee_app_pri_tlv(struct ice_lldp_org_tlv *tlv,
1467			 struct ice_dcbx_cfg *dcbcfg)
1468{
1469	u16 typelen, len, offset = 0;
1470	u8 priority, selector, i = 0;
1471	u8 *buf = tlv->tlvinfo;
1472	u32 ouisubtype;
1473
1474	/* No APP TLVs then just return */
1475	if (dcbcfg->numapps == 0)
1476		return;
1477	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
1478		      ICE_IEEE_SUBTYPE_APP_PRI);
1479	tlv->ouisubtype = HTONL(ouisubtype);
1480
1481	/* Move offset to App Priority Table */
1482	offset++;
1483	/* Application Priority Table (3 octets)
1484	 * Octets:|         1          |    2    |    3    |
1485	 *        -----------------------------------------
1486	 *        |Priority|Rsrvd| Sel |    Protocol ID    |
1487	 *        -----------------------------------------
1488	 *   Bits:|23    21|20 19|18 16|15                0|
1489	 *        -----------------------------------------
1490	 */
1491	while (i < dcbcfg->numapps) {
1492		priority = dcbcfg->app[i].priority & 0x7;
1493		selector = dcbcfg->app[i].selector & 0x7;
1494		buf[offset] = (priority << ICE_IEEE_APP_PRIO_S) | selector;
1495		buf[offset + 1] = (dcbcfg->app[i].prot_id >> 0x8) & 0xFF;
1496		buf[offset + 2] = dcbcfg->app[i].prot_id & 0xFF;
1497		/* Move to next app */
1498		offset += 3;
1499		i++;
1500		if (i >= ICE_DCBX_MAX_APPS)
1501			break;
1502	}
1503	/* len includes size of ouisubtype + 1 reserved + 3*numapps */
1504	len = sizeof(tlv->ouisubtype) + 1 + (i * 3);
1505	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | (len & 0x1FF));
1506	tlv->typelen = HTONS(typelen);
1507}
1508
1509/**
1510 * ice_add_dscp_up_tlv - Prepare DSCP to UP TLV
1511 * @tlv: location to build the TLV data
1512 * @dcbcfg: location of data to convert to TLV
1513 */
1514static void
1515ice_add_dscp_up_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1516{
1517	u8 *buf = tlv->tlvinfo;
1518	u32 ouisubtype;
1519	u16 typelen;
1520	int i;
1521
1522	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1523		   ICE_DSCP_UP_TLV_LEN);
1524	tlv->typelen = HTONS(typelen);
1525
1526	ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1527			   ICE_DSCP_SUBTYPE_DSCP2UP);
1528	tlv->ouisubtype = HTONL(ouisubtype);
1529
1530	/* bytes 0 - 63 - IPv4 DSCP2UP LUT */
1531	for (i = 0; i < ICE_DSCP_NUM_VAL; i++) {
1532		/* IPv4 mapping */
1533		buf[i] = dcbcfg->dscp_map[i];
1534		/* IPv6 mapping */
1535		buf[i + ICE_DSCP_IPV6_OFFSET] = dcbcfg->dscp_map[i];
1536	}
1537
1538	/* byte 64 - IPv4 untagged traffic */
1539	buf[i] = 0;
1540
1541	/* byte 144 - IPv6 untagged traffic */
1542	buf[i + ICE_DSCP_IPV6_OFFSET] = 0;
1543}
1544
1545#define ICE_BYTES_PER_TC	8
1546/**
1547 * ice_add_dscp_enf_tlv - Prepare DSCP Enforcement TLV
1548 * @tlv: location to build the TLV data
1549 */
1550static void
1551ice_add_dscp_enf_tlv(struct ice_lldp_org_tlv *tlv)
1552{
1553	u8 *buf = tlv->tlvinfo;
1554	u32 ouisubtype;
1555	u16 typelen;
1556
1557	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1558		   ICE_DSCP_ENF_TLV_LEN);
1559	tlv->typelen = HTONS(typelen);
1560
1561	ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1562			   ICE_DSCP_SUBTYPE_ENFORCE);
1563	tlv->ouisubtype = HTONL(ouisubtype);
1564
1565	/* Allow all DSCP values to be valid for all TC's (IPv4 and IPv6) */
1566	memset(buf, 0, 2 * (ICE_MAX_TRAFFIC_CLASS * ICE_BYTES_PER_TC));
1567}
1568
1569/**
1570 * ice_add_dscp_tc_bw_tlv - Prepare DSCP BW for TC TLV
1571 * @tlv: location to build the TLV data
1572 * @dcbcfg: location of the data to convert to TLV
1573 */
1574static void
1575ice_add_dscp_tc_bw_tlv(struct ice_lldp_org_tlv *tlv,
1576		       struct ice_dcbx_cfg *dcbcfg)
1577{
1578	struct ice_dcb_ets_cfg *etscfg;
1579	u8 *buf = tlv->tlvinfo;
1580	u32 ouisubtype;
1581	u8 offset = 0;
1582	u16 typelen;
1583	int i;
1584
1585	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1586		   ICE_DSCP_TC_BW_TLV_LEN);
1587	tlv->typelen = HTONS(typelen);
1588
1589	ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1590			   ICE_DSCP_SUBTYPE_TCBW);
1591	tlv->ouisubtype = HTONL(ouisubtype);
1592
1593	/* First Octect after subtype
1594	 * ----------------------------
1595	 * | RSV | CBS | RSV | Max TCs |
1596	 * | 1b  | 1b  | 3b  | 3b      |
1597	 * ----------------------------
1598	 */
1599	etscfg = &dcbcfg->etscfg;
1600	buf[0] = etscfg->maxtcs & ICE_IEEE_ETS_MAXTC_M;
1601
1602	/* bytes 1 - 4 reserved */
1603	offset = 5;
1604
1605	/* TC BW table
1606	 * bytes 0 - 7 for TC 0 - 7
1607	 *
1608	 * TSA Assignment table
1609	 * bytes 8 - 15 for TC 0 - 7
1610	 */
1611	for (i = 0; i < ICE_MAX_TRAFFIC_CLASS; i++) {
1612		buf[offset] = etscfg->tcbwtable[i];
1613		buf[offset + ICE_MAX_TRAFFIC_CLASS] = etscfg->tsatable[i];
1614		offset++;
1615	}
1616}
1617
1618/**
1619 * ice_add_dscp_pfc_tlv - Prepare DSCP PFC TLV
1620 * @tlv: Fill PFC TLV in IEEE format
1621 * @dcbcfg: Local store which holds the PFC CFG data
1622 */
1623static void
1624ice_add_dscp_pfc_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg)
1625{
1626	u8 *buf = tlv->tlvinfo;
1627	u32 ouisubtype;
1628	u16 typelen;
1629
1630	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
1631		   ICE_DSCP_PFC_TLV_LEN);
1632	tlv->typelen = HTONS(typelen);
1633
1634	ouisubtype = (u32)((ICE_DSCP_OUI << ICE_LLDP_TLV_OUI_S) |
1635			   ICE_DSCP_SUBTYPE_PFC);
1636	tlv->ouisubtype = HTONL(ouisubtype);
1637
1638	buf[0] = dcbcfg->pfc.pfccap & 0xF;
1639	buf[1] = dcbcfg->pfc.pfcena;
1640}
1641
1642/**
1643 * ice_add_dcb_tlv - Add all IEEE or DSCP TLVs
1644 * @tlv: Fill TLV data in IEEE format
1645 * @dcbcfg: Local store which holds the DCB Config
1646 * @tlvid: Type of IEEE TLV
1647 *
1648 * Add tlv information
1649 */
1650static void
1651ice_add_dcb_tlv(struct ice_lldp_org_tlv *tlv, struct ice_dcbx_cfg *dcbcfg,
1652		u16 tlvid)
1653{
1654	if (dcbcfg->pfc_mode == ICE_QOS_MODE_VLAN) {
1655		switch (tlvid) {
1656		case ICE_IEEE_TLV_ID_ETS_CFG:
1657			ice_add_ieee_ets_tlv(tlv, dcbcfg);
1658			break;
1659		case ICE_IEEE_TLV_ID_ETS_REC:
1660			ice_add_ieee_etsrec_tlv(tlv, dcbcfg);
1661			break;
1662		case ICE_IEEE_TLV_ID_PFC_CFG:
1663			ice_add_ieee_pfc_tlv(tlv, dcbcfg);
1664			break;
1665		case ICE_IEEE_TLV_ID_APP_PRI:
1666			ice_add_ieee_app_pri_tlv(tlv, dcbcfg);
1667			break;
1668		default:
1669			break;
1670		}
1671	} else {
1672		/* pfc_mode == ICE_QOS_MODE_DSCP */
1673		switch (tlvid) {
1674		case ICE_TLV_ID_DSCP_UP:
1675			ice_add_dscp_up_tlv(tlv, dcbcfg);
1676			break;
1677		case ICE_TLV_ID_DSCP_ENF:
1678			ice_add_dscp_enf_tlv(tlv);
1679			break;
1680		case ICE_TLV_ID_DSCP_TC_BW:
1681			ice_add_dscp_tc_bw_tlv(tlv, dcbcfg);
1682			break;
1683		case ICE_TLV_ID_DSCP_TO_PFC:
1684			ice_add_dscp_pfc_tlv(tlv, dcbcfg);
1685			break;
1686		default:
1687			break;
1688		}
1689	}
1690}
1691
1692/**
1693 * ice_dcb_cfg_to_lldp - Convert DCB configuration to MIB format
1694 * @lldpmib: pointer to the HW struct
1695 * @miblen: length of LLDP MIB
1696 * @dcbcfg: Local store which holds the DCB Config
1697 *
1698 * Convert the DCB configuration to MIB format
1699 */
1700void ice_dcb_cfg_to_lldp(u8 *lldpmib, u16 *miblen, struct ice_dcbx_cfg *dcbcfg)
1701{
1702	u16 len, offset = 0, tlvid = ICE_TLV_ID_START;
1703	struct ice_lldp_org_tlv *tlv;
1704	u16 typelen;
1705
1706	tlv = (struct ice_lldp_org_tlv *)lldpmib;
1707	while (1) {
1708		ice_add_dcb_tlv(tlv, dcbcfg, tlvid++);
1709		typelen = NTOHS(tlv->typelen);
1710		len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
1711		if (len)
1712			offset += len + 2;
1713		/* END TLV or beyond LLDPDU size */
1714		if (tlvid >= ICE_TLV_ID_END_OF_LLDPPDU ||
1715		    offset > ICE_LLDPDU_SIZE)
1716			break;
1717		/* Move to next TLV */
1718		if (len)
1719			tlv = (struct ice_lldp_org_tlv *)
1720				((char *)tlv + sizeof(tlv->typelen) + len);
1721	}
1722	*miblen = offset;
1723}
1724
1725/**
1726 * ice_set_dcb_cfg - Set the local LLDP MIB to FW
1727 * @pi: port information structure
1728 *
1729 * Set DCB configuration to the Firmware
1730 */
1731enum ice_status ice_set_dcb_cfg(struct ice_port_info *pi)
1732{
1733	u8 mib_type, *lldpmib = NULL;
1734	struct ice_dcbx_cfg *dcbcfg;
1735	enum ice_status ret;
1736	struct ice_hw *hw;
1737	u16 miblen;
1738
1739	if (!pi)
1740		return ICE_ERR_PARAM;
1741
1742	hw = pi->hw;
1743
1744	/* update the HW local config */
1745	dcbcfg = &pi->qos_cfg.local_dcbx_cfg;
1746	/* Allocate the LLDPDU */
1747	lldpmib = (u8 *)ice_malloc(hw, ICE_LLDPDU_SIZE);
1748	if (!lldpmib)
1749		return ICE_ERR_NO_MEMORY;
1750
1751	mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;
1752	if (dcbcfg->app_mode == ICE_DCBX_APPS_NON_WILLING)
1753		mib_type |= SET_LOCAL_MIB_TYPE_CEE_NON_WILLING;
1754
1755	ice_dcb_cfg_to_lldp(lldpmib, &miblen, dcbcfg);
1756	ret = ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, miblen,
1757				  NULL);
1758
1759	ice_free(hw, lldpmib);
1760
1761	return ret;
1762}
1763
1764/**
1765 * ice_aq_query_port_ets - query port ETS configuration
1766 * @pi: port information structure
1767 * @buf: pointer to buffer
1768 * @buf_size: buffer size in bytes
1769 * @cd: pointer to command details structure or NULL
1770 *
1771 * query current port ETS configuration
1772 */
1773enum ice_status
1774ice_aq_query_port_ets(struct ice_port_info *pi,
1775		      struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1776		      struct ice_sq_cd *cd)
1777{
1778	struct ice_aqc_query_port_ets *cmd;
1779	struct ice_aq_desc desc;
1780	enum ice_status status;
1781
1782	if (!pi || !pi->root)
1783		return ICE_ERR_PARAM;
1784	cmd = &desc.params.port_ets;
1785	ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_query_port_ets);
1786	cmd->port_teid = pi->root->info.node_teid;
1787
1788	status = ice_aq_send_cmd(pi->hw, &desc, buf, buf_size, cd);
1789	return status;
1790}
1791
1792/**
1793 * ice_update_port_tc_tree_cfg - update TC tree configuration
1794 * @pi: port information structure
1795 * @buf: pointer to buffer
1796 *
1797 * update the SW DB with the new TC changes
1798 */
1799enum ice_status
1800ice_update_port_tc_tree_cfg(struct ice_port_info *pi,
1801			    struct ice_aqc_port_ets_elem *buf)
1802{
1803	struct ice_sched_node *node, *tc_node;
1804	struct ice_aqc_txsched_elem_data elem;
1805	enum ice_status status = ICE_SUCCESS;
1806	u32 teid1, teid2;
1807	u8 i, j;
1808
1809	if (!pi)
1810		return ICE_ERR_PARAM;
1811	/* suspend the missing TC nodes */
1812	for (i = 0; i < pi->root->num_children; i++) {
1813		teid1 = LE32_TO_CPU(pi->root->children[i]->info.node_teid);
1814		ice_for_each_traffic_class(j) {
1815			teid2 = LE32_TO_CPU(buf->tc_node_teid[j]);
1816			if (teid1 == teid2)
1817				break;
1818		}
1819		if (j < ICE_MAX_TRAFFIC_CLASS)
1820			continue;
1821		/* TC is missing */
1822		pi->root->children[i]->in_use = false;
1823	}
1824	/* add the new TC nodes */
1825	ice_for_each_traffic_class(j) {
1826		teid2 = LE32_TO_CPU(buf->tc_node_teid[j]);
1827		if (teid2 == ICE_INVAL_TEID)
1828			continue;
1829		/* Is it already present in the tree ? */
1830		for (i = 0; i < pi->root->num_children; i++) {
1831			tc_node = pi->root->children[i];
1832			if (!tc_node)
1833				continue;
1834			teid1 = LE32_TO_CPU(tc_node->info.node_teid);
1835			if (teid1 == teid2) {
1836				tc_node->tc_num = j;
1837				tc_node->in_use = true;
1838				break;
1839			}
1840		}
1841		if (i < pi->root->num_children)
1842			continue;
1843		/* new TC */
1844		status = ice_sched_query_elem(pi->hw, teid2, &elem);
1845		if (!status)
1846			status = ice_sched_add_node(pi, 1, &elem, NULL);
1847		if (status)
1848			break;
1849		/* update the TC number */
1850		node = ice_sched_find_node_by_teid(pi->root, teid2);
1851		if (node)
1852			node->tc_num = j;
1853	}
1854	return status;
1855}
1856
1857/**
1858 * ice_query_port_ets - query port ETS configuration
1859 * @pi: port information structure
1860 * @buf: pointer to buffer
1861 * @buf_size: buffer size in bytes
1862 * @cd: pointer to command details structure or NULL
1863 *
1864 * query current port ETS configuration and update the
1865 * SW DB with the TC changes
1866 */
1867enum ice_status
1868ice_query_port_ets(struct ice_port_info *pi,
1869		   struct ice_aqc_port_ets_elem *buf, u16 buf_size,
1870		   struct ice_sq_cd *cd)
1871{
1872	enum ice_status status;
1873
1874	ice_acquire_lock(&pi->sched_lock);
1875	status = ice_aq_query_port_ets(pi, buf, buf_size, cd);
1876	if (!status)
1877		status = ice_update_port_tc_tree_cfg(pi, buf);
1878	ice_release_lock(&pi->sched_lock);
1879	return status;
1880}
1881