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
38static int
39bnxt_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
54static int
55bnxt_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
84static int
85bnxt_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
112static int
113bnxt_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
158static int
159bnxt_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
197static int
198bnxt_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
243static int
244bnxt_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
294static int
295bnxt_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
315static int
316bnxt_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
360set_app_exit:
361	iflib_dma_free(&dma_data);
362	return rc;
363}
364
365static int
366bnxt_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
446set_app_exit:
447	iflib_dma_free(&dma_data);
448	return rc;
449}
450
451static int
452bnxt_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
474static int
475bnxt_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
513end:
514	iflib_dma_free(&dma_data);
515	return rc;
516}
517
518static int
519bnxt_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
553static int
554bnxt_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
600int
601bnxt_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;
625error:
626	return rc;
627}
628
629int
630bnxt_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;
666error:
667	return rc;
668}
669
670int
671bnxt_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
692int
693bnxt_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
713static int
714bnxt_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
725int
726bnxt_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
751int
752bnxt_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
776int
777bnxt_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
785uint8_t
786bnxt_dcb_getdcbx(struct bnxt_softc *softc)
787{
788	return softc->dcbx_cap;
789}
790
791uint8_t
792bnxt_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
823void
824bnxt_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
854void
855bnxt_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