xref: /freebsd/sys/dev/bnxt/bnxt_en/bnxt_dcb.c (revision e9ac41698b2f322d55ccf9da50a3596edb2c1800)
1 /*-
2  * Broadcom NetXtreme-C/E network driver.
3  *
4  * Copyright (c) 2024 Broadcom, All Rights Reserved.
5  * The term Broadcom refers to Broadcom Limited and/or its subsidiaries
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS'
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/endian.h>
30 #include <linux/errno.h>
31 #include <linux/bitops.h>
32 
33 #include "bnxt.h"
34 #include "bnxt_hwrm.h"
35 #include "bnxt_dcb.h"
36 #include "hsi_struct_def.h"
37 
38 static int
39 bnxt_tx_queue_to_tc(struct bnxt_softc *softc, uint8_t queue_id)
40 {
41 	int i, j;
42 
43 	for (i = 0; i < softc->max_tc; i++) {
44 		if (softc->tx_q_info[i].queue_id == queue_id) {
45 			for (j = 0; j < softc->max_tc; j++) {
46 				if (softc->tc_to_qidx[j] == i)
47 					return j;
48 			}
49 		}
50 	}
51 	return -EINVAL;
52 }
53 
54 static int
55 bnxt_hwrm_queue_pri2cos_cfg(struct bnxt_softc *softc,
56 				       struct bnxt_ieee_ets *ets,
57 				       uint32_t path_dir)
58 {
59 	struct hwrm_queue_pri2cos_cfg_input req = {0};
60 	struct bnxt_queue_info *q_info;
61 	uint8_t *pri2cos;
62 	int i;
63 
64 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PRI2COS_CFG);
65 
66 	req.flags = htole32(path_dir | HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_IVLAN);
67 	if (path_dir == HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_BIDIR ||
68 	    path_dir == HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_TX)
69 		q_info = softc->tx_q_info;
70 	else
71 		q_info = softc->rx_q_info;
72 	pri2cos = &req.pri0_cos_queue_id;
73 	for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) {
74 		uint8_t qidx;
75 
76 		req.enables |= htole32(HWRM_QUEUE_PRI2COS_CFG_INPUT_ENABLES_PRI0_COS_QUEUE_ID << i);
77 
78 		qidx = softc->tc_to_qidx[ets->prio_tc[i]];
79 		pri2cos[i] = q_info[qidx].queue_id;
80 	}
81 	return _hwrm_send_message(softc, &req, sizeof(req));
82 }
83 
84 static int
85 bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
86 {
87 	struct hwrm_queue_pri2cos_qcfg_output *resp =
88 		(void *)softc->hwrm_cmd_resp.idi_vaddr;
89 	struct hwrm_queue_pri2cos_qcfg_input req = {0};
90 	int rc;
91 
92 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PRI2COS_QCFG);
93 
94 	req.flags = htole32(HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_IVLAN);
95 	rc = _hwrm_send_message(softc, &req, sizeof(req));
96 	if (!rc) {
97 		uint8_t *pri2cos = &resp->pri0_cos_queue_id;
98 		int i;
99 
100 		for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) {
101 			uint8_t queue_id = pri2cos[i];
102 			int tc;
103 
104 			tc = bnxt_tx_queue_to_tc(softc, queue_id);
105 			if (tc >= 0)
106 				ets->prio_tc[i] = tc;
107 		}
108 	}
109 	return rc;
110 }
111 
112 static int
113 bnxt_hwrm_queue_cos2bw_cfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets,
114 				      uint8_t max_tc)
115 {
116 	struct hwrm_queue_cos2bw_cfg_input req = {0};
117 	struct bnxt_cos2bw_cfg cos2bw;
118 	void *data;
119 	int i;
120 
121 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_COS2BW_CFG);
122 
123 	for (i = 0; i < max_tc; i++) {
124 		uint8_t qidx = softc->tc_to_qidx[i];
125 
126 		req.enables |=
127 			htole32(HWRM_QUEUE_COS2BW_CFG_INPUT_ENABLES_COS_QUEUE_ID0_VALID << qidx);
128 
129 		memset(&cos2bw, 0, sizeof(cos2bw));
130 		cos2bw.queue_id = softc->tx_q_info[qidx].queue_id;
131 		if (ets->tc_tsa[i] == BNXT_IEEE_8021QAZ_TSA_STRICT) {
132 			cos2bw.tsa =
133 				HWRM_QUEUE_COS2BW_QCFG_OUTPUT_QUEUE_ID0_TSA_ASSIGN_SP;
134 			cos2bw.pri_lvl = i;
135 		} else {
136 			cos2bw.tsa =
137 				HWRM_QUEUE_COS2BW_QCFG_OUTPUT_QUEUE_ID0_TSA_ASSIGN_ETS;
138 			cos2bw.bw_weight = ets->tc_tx_bw[i];
139 			/* older firmware requires min_bw to be set to the
140 			 * same weight value in percent.
141 			 */
142 			if (BNXT_FW_MAJ(softc) < 218) {
143 				cos2bw.min_bw =
144 					htole32((ets->tc_tx_bw[i] * 100) |
145 						    BW_VALUE_UNIT_PERCENT1_100);
146 			}
147 		}
148 		data = &req.unused_0 + qidx * (sizeof(cos2bw) - 4);
149 		memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4);
150 		if (qidx == 0) {
151 			req.queue_id0 = cos2bw.queue_id;
152 			req.unused_0 = 0;
153 		}
154 	}
155 	return _hwrm_send_message(softc, &req, sizeof(req));
156 }
157 
158 static int
159 bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
160 {
161 	struct hwrm_queue_cos2bw_qcfg_output *resp =
162 		(void *)softc->hwrm_cmd_resp.idi_vaddr;
163 	struct hwrm_queue_cos2bw_qcfg_input req = {0};
164 	struct bnxt_cos2bw_cfg cos2bw;
165 	uint8_t *data;
166 	int rc, i;
167 
168 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_COS2BW_QCFG);
169 
170 	rc = _hwrm_send_message(softc, &req, sizeof(req));
171 	if (rc) {
172 		return rc;
173 	}
174 
175 	data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id);
176 	for (i = 0; i < softc->max_tc; i++, data += sizeof(cos2bw.cfg)) {
177 		int tc;
178 
179 		memcpy(&cos2bw.cfg, data, sizeof(cos2bw.cfg));
180 		if (i == 0)
181 			cos2bw.queue_id = resp->queue_id0;
182 
183 		tc = bnxt_tx_queue_to_tc(softc, cos2bw.queue_id);
184 		if (tc < 0)
185 			continue;
186 
187 		if (cos2bw.tsa == HWRM_QUEUE_COS2BW_QCFG_OUTPUT_QUEUE_ID0_TSA_ASSIGN_SP) {
188 			ets->tc_tsa[tc] = BNXT_IEEE_8021QAZ_TSA_STRICT;
189 		} else {
190 			ets->tc_tsa[tc] = BNXT_IEEE_8021QAZ_TSA_ETS;
191 			ets->tc_tx_bw[tc] = cos2bw.bw_weight;
192 		}
193 	}
194 	return 0;
195 }
196 
197 static int
198 bnxt_queue_remap(struct bnxt_softc *softc, unsigned int lltc_mask)
199 {
200 	unsigned long qmap = 0;
201 	int max = softc->max_tc;
202 	int i, j, rc;
203 
204 	/* Assign lossless TCs first */
205 	for (i = 0, j = 0; i < max; ) {
206 		if (lltc_mask & (1 << i)) {
207 			if (BNXT_LLQ(softc->rx_q_info[j].queue_profile)) {
208 				softc->tc_to_qidx[i] = j;
209 				__set_bit(j, &qmap);
210 				i++;
211 			}
212 			j++;
213 			continue;
214 		}
215 		i++;
216 	}
217 
218 	for (i = 0, j = 0; i < max; i++) {
219 		if (lltc_mask & (1 << i))
220 			continue;
221 		j = find_next_zero_bit(&qmap, max, j);
222 		softc->tc_to_qidx[i] = j;
223 		__set_bit(j, &qmap);
224 		j++;
225 	}
226 
227 	if (softc->ieee_ets) {
228 		rc = bnxt_hwrm_queue_cos2bw_cfg(softc, softc->ieee_ets, softc->max_tc);
229 		if (rc) {
230 			device_printf(softc->dev, "failed to config BW, rc = %d\n", rc);
231 			return rc;
232 		}
233 		rc = bnxt_hwrm_queue_pri2cos_cfg(softc, softc->ieee_ets,
234 						 HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_BIDIR);
235 		if (rc) {
236 			device_printf(softc->dev, "failed to config prio, rc = %d\n", rc);
237 			return rc;
238 		}
239 	}
240 	return 0;
241 }
242 
243 static int
244 bnxt_hwrm_queue_pfc_cfg(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
245 {
246 	struct hwrm_queue_pfcenable_cfg_input req = {0};
247 	struct bnxt_ieee_ets *my_ets = softc->ieee_ets;
248 	unsigned int tc_mask = 0, pri_mask = 0;
249 	uint8_t i, pri, lltc_count = 0;
250 	bool need_q_remap = false;
251 
252 	if (!my_ets)
253 		return -EINVAL;
254 
255 	for (i = 0; i < softc->max_tc; i++) {
256 		for (pri = 0; pri < BNXT_IEEE_8021QAZ_MAX_TCS; pri++) {
257 			if ((pfc->pfc_en & (1 << pri)) &&
258 			    (my_ets->prio_tc[pri] == i)) {
259 				pri_mask |= 1 << pri;
260 				tc_mask |= 1 << i;
261 			}
262 		}
263 		if (tc_mask & (1 << i))
264 			lltc_count++;
265 	}
266 
267 	if (lltc_count > softc->max_lltc) {
268 		device_printf(softc->dev,
269 			       "Hardware doesn't support %d lossless queues "
270 			       "to configure PFC (cap %d)\n", lltc_count, softc->max_lltc);
271 		return -EINVAL;
272 	}
273 
274 	for (i = 0; i < softc->max_tc; i++) {
275 		if (tc_mask & (1 << i)) {
276 			uint8_t qidx = softc->tc_to_qidx[i];
277 
278 			if (!BNXT_LLQ(softc->rx_q_info[qidx].queue_profile)) {
279 				need_q_remap = true;
280 				break;
281 			}
282 		}
283 	}
284 
285 	if (need_q_remap)
286 		bnxt_queue_remap(softc, tc_mask);
287 
288 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PFCENABLE_CFG);
289 
290 	req.flags = htole32(pri_mask);
291 	return _hwrm_send_message(softc, &req, sizeof(req));
292 }
293 
294 static int
295 bnxt_hwrm_queue_pfc_qcfg(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
296 {
297 	struct hwrm_queue_pfcenable_qcfg_output *resp =
298 		(void *)softc->hwrm_cmd_resp.idi_vaddr;
299 	struct hwrm_queue_pfcenable_qcfg_input req = {0};
300 	uint8_t pri_mask;
301 	int rc;
302 
303 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_PFCENABLE_QCFG);
304 
305 	rc = _hwrm_send_message(softc, &req, sizeof(req));
306 	if (rc) {
307 		return rc;
308 	}
309 
310 	pri_mask = le32toh(resp->flags);
311 	pfc->pfc_en = pri_mask;
312 	return 0;
313 }
314 
315 static int
316 bnxt_hwrm_get_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app, int *num_inputs)
317 {
318 	struct hwrm_fw_get_structured_data_input get = {0};
319 	struct hwrm_struct_data_dcbx_app *fw_app;
320 	struct hwrm_struct_hdr *data;
321 	struct iflib_dma_info dma_data;
322 	size_t data_len;
323 	int rc, n, i;
324 
325 	if (softc->hwrm_spec_code < 0x10601)
326 		return 0;
327 
328 	bnxt_hwrm_cmd_hdr_init(softc, &get, HWRM_FW_GET_STRUCTURED_DATA);
329 
330 	n = BNXT_IEEE_8021QAZ_MAX_TCS;
331 	data_len = sizeof(*data) + sizeof(*fw_app) * n;
332 	rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data,
333 			     BUS_DMA_NOWAIT);
334 	if (rc)
335 		return ENOMEM;
336 	get.dest_data_addr = htole64(dma_data.idi_paddr);
337 	get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP);
338 	get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
339 	get.count = 0;
340 	rc = _hwrm_send_message(softc, &get, sizeof(get));
341 	if (rc)
342 		goto set_app_exit;
343 
344 	data = (void *)dma_data.idi_vaddr;
345 	fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1);
346 
347 	if (data->struct_id != htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP)) {
348 		rc = -ENODEV;
349 		goto set_app_exit;
350 	}
351 
352 	n = data->count;
353 	for (i = 0; i < n; i++, fw_app++) {
354 		app[*num_inputs].priority = fw_app->priority;
355 		app[*num_inputs].protocol = htobe16(fw_app->protocol_id);
356 		app[*num_inputs].selector = fw_app->protocol_selector;
357 		(*num_inputs)++;
358 	}
359 
360 set_app_exit:
361 	iflib_dma_free(&dma_data);
362 	return rc;
363 }
364 
365 static int
366 bnxt_hwrm_set_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
367 				  bool add)
368 {
369 	struct hwrm_fw_set_structured_data_input set = {0};
370 	struct hwrm_fw_get_structured_data_input get = {0};
371 	struct hwrm_struct_data_dcbx_app *fw_app;
372 	struct hwrm_struct_hdr *data;
373 	struct iflib_dma_info dma_data;
374 	size_t data_len;
375 	int rc, n, i;
376 
377 	if (softc->hwrm_spec_code < 0x10601)
378 		return 0;
379 
380 	bnxt_hwrm_cmd_hdr_init(softc, &get, HWRM_FW_GET_STRUCTURED_DATA);
381 
382 	n = BNXT_IEEE_8021QAZ_MAX_TCS;
383 	data_len = sizeof(*data) + sizeof(*fw_app) * n;
384 	rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data,
385 			     BUS_DMA_NOWAIT);
386 	if (rc)
387 		return ENOMEM;
388 	get.dest_data_addr = htole64(dma_data.idi_paddr);
389 	get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP);
390 	get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
391 	get.count = 0;
392 	rc = _hwrm_send_message(softc, &get, sizeof(get));
393 	if (rc)
394 		goto set_app_exit;
395 
396 	data = (void *)dma_data.idi_vaddr;
397 	fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1);
398 
399 	if (data->struct_id != htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP)) {
400 		rc = -ENODEV;
401 		goto set_app_exit;
402 	}
403 
404 	n = data->count;
405 	for (i = 0; i < n; i++, fw_app++) {
406 		if (fw_app->protocol_id == htobe16(app->protocol) &&
407 		    fw_app->protocol_selector == app->selector &&
408 		    fw_app->priority == app->priority) {
409 			if (add)
410 				goto set_app_exit;
411 			else
412 				break;
413 		}
414 	}
415 	if (add) {
416 		/* append */
417 		n++;
418 		fw_app->protocol_id = htobe16(app->protocol);
419 		fw_app->protocol_selector = app->selector;
420 		fw_app->priority = app->priority;
421 		fw_app->valid = 1;
422 	} else {
423 		size_t len = 0;
424 
425 		/* not found, nothing to delete */
426 		if (n == i)
427 			goto set_app_exit;
428 
429 		len = (n - 1 - i) * sizeof(*fw_app);
430 		if (len)
431 			memmove(fw_app, fw_app + 1, len);
432 		n--;
433 		memset(fw_app + n, 0, sizeof(*fw_app));
434 	}
435 	data->count = n;
436 	data->len = htole16(sizeof(*fw_app) * n);
437 	data->subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
438 
439 	bnxt_hwrm_cmd_hdr_init(softc, &set, HWRM_FW_SET_STRUCTURED_DATA);
440 
441 	set.src_data_addr = htole64(dma_data.idi_paddr);
442 	set.data_len = htole16(sizeof(*data) + sizeof(*fw_app) * n);
443 	set.hdr_cnt = 1;
444 	rc = _hwrm_send_message(softc, &set, sizeof(set));
445 
446 set_app_exit:
447 	iflib_dma_free(&dma_data);
448 	return rc;
449 }
450 
451 static int
452 bnxt_hwrm_queue_dscp_qcaps(struct bnxt_softc *softc)
453 {
454 	struct hwrm_queue_dscp_qcaps_output *resp =
455 		(void *)softc->hwrm_cmd_resp.idi_vaddr;
456 	struct hwrm_queue_dscp_qcaps_input req = {0};
457 	int rc;
458 
459 	softc->max_dscp_value = 0;
460 	if (softc->hwrm_spec_code < 0x10800 || BNXT_VF(softc))
461 		return 0;
462 
463 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP_QCAPS);
464 
465 	rc = _hwrm_send_message(softc, &req, sizeof(req));
466 	if (!rc) {
467 		softc->max_dscp_value = (1 << resp->num_dscp_bits) - 1;
468 		if (softc->max_dscp_value < 0x3f)
469 			softc->max_dscp_value = 0;
470 	}
471 	return rc;
472 }
473 
474 static int
475 bnxt_hwrm_queue_dscp2pri_qcfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app, int *num_inputs)
476 {
477 	struct hwrm_queue_dscp2pri_qcfg_input req = {0};
478 	struct hwrm_queue_dscp2pri_qcfg_output *resp =
479 		(void *)softc->hwrm_cmd_resp.idi_vaddr;
480 	struct bnxt_dscp2pri_entry *dscp2pri;
481 	struct iflib_dma_info dma_data;
482 	int rc, entry_cnt;
483 	int i;
484 
485 	if (softc->hwrm_spec_code < 0x10800)
486 		return 0;
487 
488 	rc = iflib_dma_alloc(softc->ctx, sizeof(*dscp2pri) * 128, &dma_data,
489 			     BUS_DMA_NOWAIT);
490 	if (rc)
491 		return ENOMEM;
492 
493 	dscp2pri = (void *)dma_data.idi_vaddr;
494 
495 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP2PRI_QCFG);
496 
497 	req.dest_data_addr = htole64(dma_data.idi_paddr);
498 	req.dest_data_buffer_size = htole16(sizeof(*dscp2pri) * 64);
499 	req.port_id = htole16(softc->pf.port_id);
500 	rc = _hwrm_send_message(softc, &req, sizeof(req));
501 
502 	if (rc)
503 		goto end;
504 
505 	entry_cnt =  le16toh(resp->entry_cnt);
506 	for (i = 0; i < entry_cnt; i++) {
507 		app[*num_inputs].priority = dscp2pri[i].pri;
508 		app[*num_inputs].protocol = dscp2pri[i].dscp;
509 		app[*num_inputs].selector = BNXT_IEEE_8021QAZ_APP_SEL_DSCP;
510 		(*num_inputs)++;
511 	}
512 
513 end:
514 	iflib_dma_free(&dma_data);
515 	return rc;
516 }
517 
518 static int
519 bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
520 			     bool add)
521 {
522 	struct hwrm_queue_dscp2pri_cfg_input req = {0};
523 	struct bnxt_dscp2pri_entry *dscp2pri;
524 	struct iflib_dma_info dma_data;
525 	int rc;
526 
527 	if (softc->hwrm_spec_code < 0x10800)
528 		return 0;
529 
530 	rc = iflib_dma_alloc(softc->ctx, sizeof(*dscp2pri), &dma_data,
531 			     BUS_DMA_NOWAIT);
532 	if (rc)
533 		return ENOMEM;
534 
535 	bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP2PRI_CFG);
536 
537 	req.src_data_addr = htole64(dma_data.idi_paddr);
538 	dscp2pri = (void *)dma_data.idi_vaddr;
539 	dscp2pri->dscp = app->protocol;
540 	if (add)
541 		dscp2pri->mask = 0x3f;
542 	else
543 		dscp2pri->mask = 0;
544 	dscp2pri->pri = app->priority;
545 	req.entry_cnt = htole16(1);
546 	req.port_id = htole16(softc->pf.port_id);
547 	rc = _hwrm_send_message(softc, &req, sizeof(req));
548 
549 	iflib_dma_free(&dma_data);
550 	return rc;
551 }
552 
553 static int
554 bnxt_ets_validate(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets, uint8_t *tc)
555 {
556 	int total_ets_bw = 0;
557 	bool zero = false;
558 	uint8_t max_tc = 0;
559 	int i;
560 
561 	for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) {
562 		if (ets->prio_tc[i] > softc->max_tc) {
563 			device_printf(softc->dev, "priority to TC mapping exceeds TC count %d\n",
564 				   ets->prio_tc[i]);
565 			return -EINVAL;
566 		}
567 		if (ets->prio_tc[i] > max_tc)
568 			max_tc = ets->prio_tc[i];
569 
570 		if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > softc->max_tc)
571 			return -EINVAL;
572 
573 		switch (ets->tc_tsa[i]) {
574 		case BNXT_IEEE_8021QAZ_TSA_STRICT:
575 			break;
576 		case BNXT_IEEE_8021QAZ_TSA_ETS:
577 			total_ets_bw += ets->tc_tx_bw[i];
578 			zero = zero || !ets->tc_tx_bw[i];
579 			break;
580 		default:
581 			return -ENOTSUPP;
582 		}
583 	}
584 	if (total_ets_bw > 100) {
585 		device_printf(softc->dev, "rejecting ETS config exceeding available bandwidth\n");
586 		return -EINVAL;
587 	}
588 	if (zero && total_ets_bw == 100) {
589 		device_printf(softc->dev, "rejecting ETS config starving a TC\n");
590 		return -EINVAL;
591 	}
592 
593 	if (max_tc >= softc->max_tc)
594 		*tc = softc->max_tc;
595 	else
596 		*tc = max_tc + 1;
597 	return 0;
598 }
599 
600 int
601 bnxt_dcb_ieee_getets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
602 {
603 	struct bnxt_ieee_ets *my_ets = softc->ieee_ets;
604 	int rc;
605 
606 	if (!my_ets)
607 		return 0;
608 
609 	rc = bnxt_hwrm_queue_cos2bw_qcfg(softc, my_ets);
610 	if (rc)
611 		goto error;
612 	rc = bnxt_hwrm_queue_pri2cos_qcfg(softc, my_ets);
613 	if (rc)
614 		goto error;
615 
616 	if (ets) {
617 		ets->cbs = my_ets->cbs;
618 		ets->ets_cap = softc->max_tc;
619 		memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
620 		memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
621 		memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
622 		memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
623 	}
624 	return 0;
625 error:
626 	return rc;
627 }
628 
629 int
630 bnxt_dcb_ieee_setets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
631 {
632 	uint8_t max_tc = 0;
633 	int rc;
634 
635 	if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
636 	    !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST))
637 		return -EINVAL;
638 
639 	rc = bnxt_ets_validate(softc, ets, &max_tc);
640 	if (rc)
641 		return rc;
642 
643 	rc = bnxt_hwrm_queue_cos2bw_cfg(softc, ets, max_tc);
644 	if (rc)
645 		goto error;
646 
647 	if (!softc->is_asym_q) {
648 		rc = bnxt_hwrm_queue_pri2cos_cfg(softc, ets,
649 						 HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_BIDIR);
650 		if (rc)
651 			goto error;
652 	} else {
653 		rc = bnxt_hwrm_queue_pri2cos_cfg(softc, ets,
654 						 HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_PATH_TX);
655 		if (rc)
656 			goto error;
657 
658 		rc = bnxt_hwrm_queue_pri2cos_cfg(softc, ets,
659 						 HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_PATH_RX);
660 		if (rc)
661 			goto error;
662 	}
663 
664 	memcpy(softc->ieee_ets, ets, sizeof(*ets));
665 	return 0;
666 error:
667 	return rc;
668 }
669 
670 int
671 bnxt_dcb_ieee_getpfc(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
672 {
673 	struct bnxt_ieee_pfc *my_pfc = softc->ieee_pfc;
674 	int rc;
675 
676 	if (!my_pfc)
677 		return -1;
678 
679 	pfc->pfc_cap = softc->max_lltc;
680 
681 	rc = bnxt_hwrm_queue_pfc_qcfg(softc, my_pfc);
682 	if (rc)
683 		return 0;
684 
685 	pfc->pfc_en = my_pfc->pfc_en;
686 	pfc->mbc = my_pfc->mbc;
687 	pfc->delay = my_pfc->delay;
688 
689 	return 0;
690 }
691 
692 int
693 bnxt_dcb_ieee_setpfc(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
694 {
695 	struct bnxt_ieee_pfc *my_pfc = softc->ieee_pfc;
696 	int rc;
697 
698 	if (!my_pfc)
699 		return -1;
700 
701 	if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
702 	    !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST) ||
703 	    (softc->phy_flags & BNXT_PHY_FL_NO_PAUSE))
704 		return -EINVAL;
705 
706 	rc = bnxt_hwrm_queue_pfc_cfg(softc, pfc);
707 	if (!rc)
708 		memcpy(my_pfc, pfc, sizeof(*my_pfc));
709 
710 	return rc;
711 }
712 
713 static int
714 bnxt_dcb_ieee_dscp_app_prep(struct bnxt_softc *softc, struct bnxt_dcb_app *app)
715 {
716 	if (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DSCP) {
717 		if (!softc->max_dscp_value)
718 			return -ENOTSUPP;
719 		if (app->protocol > softc->max_dscp_value)
720 			return -EINVAL;
721 	}
722 	return 0;
723 }
724 
725 int
726 bnxt_dcb_ieee_setapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app)
727 {
728 	int rc;
729 
730 
731 	if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
732 	    !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST))
733 		return -EINVAL;
734 
735 	rc = bnxt_dcb_ieee_dscp_app_prep(softc, app);
736 	if (rc)
737 		return rc;
738 
739 	if ((app->selector == BNXT_IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
740 	     app->protocol == ETH_P_ROCE) ||
741 	    (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DGRAM &&
742 	     app->protocol == ROCE_V2_UDP_DPORT))
743 		rc = bnxt_hwrm_set_dcbx_app(softc, app, true);
744 
745 	if (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DSCP)
746 		rc = bnxt_hwrm_queue_dscp2pri_cfg(softc, app, true);
747 
748 	return rc;
749 }
750 
751 int
752 bnxt_dcb_ieee_delapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app)
753 {
754 	int rc;
755 
756 	if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
757 	    !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST))
758 		return -EINVAL;
759 
760 	rc = bnxt_dcb_ieee_dscp_app_prep(softc, app);
761 	if (rc)
762 		return rc;
763 
764 	if ((app->selector == BNXT_IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
765 	     app->protocol == ETH_P_ROCE) ||
766 	    (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DGRAM &&
767 	     app->protocol == ROCE_V2_UDP_DPORT))
768 		rc = bnxt_hwrm_set_dcbx_app(softc, app, false);
769 
770 	if (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DSCP)
771 		rc = bnxt_hwrm_queue_dscp2pri_cfg(softc, app, false);
772 
773 	return rc;
774 }
775 
776 int
777 bnxt_dcb_ieee_listapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app, int *num_inputs)
778 {
779 	bnxt_hwrm_get_dcbx_app(softc, app, num_inputs);
780 	bnxt_hwrm_queue_dscp2pri_qcfg(softc, app, num_inputs);
781 
782 	return 0;
783 }
784 
785 uint8_t
786 bnxt_dcb_getdcbx(struct bnxt_softc *softc)
787 {
788 	return softc->dcbx_cap;
789 }
790 
791 uint8_t
792 bnxt_dcb_setdcbx(struct bnxt_softc *softc, uint8_t mode)
793 {
794 	/* All firmware DCBX settings are set in NVRAM */
795 	if (softc->dcbx_cap & BNXT_DCB_CAP_DCBX_LLD_MANAGED)
796 		return 1;
797 
798 	/*
799 	 * Do't allow editing CAP_DCBX_LLD_MANAGED since it is driven
800 	 * based on FUNC_QCFG_OUTPUT_FLAGS_FW_DCBX_AGENT_ENABLED
801 	 */
802 	if ((softc->dcbx_cap & BNXT_DCB_CAP_DCBX_LLD_MANAGED) !=
803 	    (mode & BNXT_DCB_CAP_DCBX_LLD_MANAGED))
804 		return 1;
805 
806 	if (mode & BNXT_DCB_CAP_DCBX_HOST) {
807 		if (BNXT_VF(softc) || (softc->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
808 			return 1;
809 
810 		/* only support BNXT_IEEE */
811 		if ((mode & BNXT_DCB_CAP_DCBX_VER_CEE) ||
812 		    !(mode & BNXT_DCB_CAP_DCBX_VER_IEEE))
813 			return 1;
814 	}
815 
816 	if (mode == softc->dcbx_cap)
817 		return 0;
818 
819 	softc->dcbx_cap = mode;
820 	return 0;
821 }
822 
823 void
824 bnxt_dcb_init(struct bnxt_softc *softc)
825 {
826 	struct bnxt_ieee_ets ets = {0};
827 	struct bnxt_ieee_pfc pfc = {0};
828 
829 	softc->dcbx_cap = 0;
830 
831 	if (softc->hwrm_spec_code < 0x10501)
832 		return;
833 
834 	softc->ieee_ets = malloc(sizeof(struct bnxt_ieee_ets), M_DEVBUF, M_NOWAIT | M_ZERO);
835 	if (!softc->ieee_ets)
836 		return;
837 
838 	softc->ieee_pfc = malloc(sizeof(struct bnxt_ieee_pfc), M_DEVBUF, M_NOWAIT | M_ZERO);
839 	if (!softc->ieee_pfc)
840 		return;
841 
842 	bnxt_hwrm_queue_dscp_qcaps(softc);
843 	softc->dcbx_cap = BNXT_DCB_CAP_DCBX_VER_IEEE;
844 	if (BNXT_PF(softc) && !(softc->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
845 		softc->dcbx_cap |= BNXT_DCB_CAP_DCBX_HOST;
846 	else if (softc->fw_cap & BNXT_FW_CAP_DCBX_AGENT)
847 		softc->dcbx_cap |= BNXT_DCB_CAP_DCBX_LLD_MANAGED;
848 
849 	bnxt_dcb_ieee_setets(softc, &ets);
850 	bnxt_dcb_ieee_setpfc(softc, &pfc);
851 
852 }
853 
854 void
855 bnxt_dcb_free(struct bnxt_softc *softc)
856 {
857 	free(softc->ieee_ets, M_DEVBUF);
858 	softc->ieee_ets = NULL;
859 	free(softc->ieee_pfc, M_DEVBUF);
860 	softc->ieee_pfc = NULL;
861 }
862