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
bnxt_tx_queue_to_tc(struct bnxt_softc * softc,uint8_t queue_id)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
bnxt_hwrm_queue_pri2cos_cfg(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets,uint32_t path_dir)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
bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets)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
bnxt_hwrm_queue_cos2bw_cfg(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets,uint8_t max_tc)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
bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets)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
bnxt_queue_remap(struct bnxt_softc * softc,unsigned int lltc_mask)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
bnxt_hwrm_queue_pfc_cfg(struct bnxt_softc * softc,struct bnxt_ieee_pfc * pfc)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
bnxt_hwrm_queue_pfc_qcfg(struct bnxt_softc * softc,struct bnxt_ieee_pfc * pfc)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
bnxt_hwrm_get_dcbx_app(struct bnxt_softc * softc,struct bnxt_dcb_app * app,size_t nitems,int * num_inputs)316 bnxt_hwrm_get_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
317 size_t nitems, int *num_inputs)
318 {
319 struct hwrm_fw_get_structured_data_input get = {0};
320 struct hwrm_struct_data_dcbx_app *fw_app;
321 struct hwrm_struct_hdr *data;
322 struct iflib_dma_info dma_data;
323 size_t data_len;
324 int rc, n, i;
325
326 if (softc->hwrm_spec_code < 0x10601)
327 return 0;
328
329 if (BNXT_VF(softc))
330 return 0;
331
332 bnxt_hwrm_cmd_hdr_init(softc, &get, HWRM_FW_GET_STRUCTURED_DATA);
333
334 n = BNXT_IEEE_8021QAZ_MAX_TCS;
335 data_len = sizeof(*data) + sizeof(*fw_app) * n;
336 rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data,
337 BUS_DMA_NOWAIT);
338 if (rc)
339 return ENOMEM;
340 get.dest_data_addr = htole64(dma_data.idi_paddr);
341 get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP);
342 get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
343 get.count = 0;
344 rc = _hwrm_send_message(softc, &get, sizeof(get));
345 if (rc)
346 goto set_app_exit;
347
348 data = (void *)dma_data.idi_vaddr;
349 fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1);
350
351 if (data->struct_id != htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP)) {
352 rc = -ENODEV;
353 goto set_app_exit;
354 }
355
356 n = data->count;
357 for (i = 0; i < n && *num_inputs < nitems; i++, fw_app++) {
358 app[*num_inputs].priority = fw_app->priority;
359 app[*num_inputs].protocol = htobe16(fw_app->protocol_id);
360 app[*num_inputs].selector = fw_app->protocol_selector;
361 (*num_inputs)++;
362 }
363
364 set_app_exit:
365 iflib_dma_free(&dma_data);
366 return rc;
367 }
368
369 static int
bnxt_hwrm_set_dcbx_app(struct bnxt_softc * softc,struct bnxt_dcb_app * app,bool add)370 bnxt_hwrm_set_dcbx_app(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
371 bool add)
372 {
373 struct hwrm_fw_set_structured_data_input set = {0};
374 struct hwrm_fw_get_structured_data_input get = {0};
375 struct hwrm_struct_data_dcbx_app *fw_app;
376 struct hwrm_struct_hdr *data;
377 struct iflib_dma_info dma_data;
378 size_t data_len;
379 int rc, n, i;
380
381 if (softc->hwrm_spec_code < 0x10601)
382 return 0;
383
384 bnxt_hwrm_cmd_hdr_init(softc, &get, HWRM_FW_GET_STRUCTURED_DATA);
385
386 n = BNXT_IEEE_8021QAZ_MAX_TCS;
387 data_len = sizeof(*data) + sizeof(*fw_app) * n;
388 rc = iflib_dma_alloc(softc->ctx, data_len, &dma_data,
389 BUS_DMA_NOWAIT);
390 if (rc)
391 return ENOMEM;
392 get.dest_data_addr = htole64(dma_data.idi_paddr);
393 get.structure_id = htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP);
394 get.subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
395 get.count = 0;
396 rc = _hwrm_send_message(softc, &get, sizeof(get));
397 if (rc)
398 goto set_app_exit;
399
400 data = (void *)dma_data.idi_vaddr;
401 fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1);
402
403 if (data->struct_id != htole16(HWRM_STRUCT_HDR_STRUCT_ID_DCBX_APP)) {
404 rc = -ENODEV;
405 goto set_app_exit;
406 }
407
408 n = data->count;
409 for (i = 0; i < n; i++, fw_app++) {
410 if (fw_app->protocol_id == htobe16(app->protocol) &&
411 fw_app->protocol_selector == app->selector &&
412 fw_app->priority == app->priority) {
413 if (add)
414 goto set_app_exit;
415 else
416 break;
417 }
418 }
419 if (add) {
420 /* append */
421 n++;
422 fw_app->protocol_id = htobe16(app->protocol);
423 fw_app->protocol_selector = app->selector;
424 fw_app->priority = app->priority;
425 fw_app->valid = 1;
426 } else {
427 size_t len = 0;
428
429 /* not found, nothing to delete */
430 if (n == i)
431 goto set_app_exit;
432
433 len = (n - 1 - i) * sizeof(*fw_app);
434 if (len)
435 memmove(fw_app, fw_app + 1, len);
436 n--;
437 memset(fw_app + n, 0, sizeof(*fw_app));
438 }
439 data->count = n;
440 data->len = htole16(sizeof(*fw_app) * n);
441 data->subtype = htole16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL);
442
443 bnxt_hwrm_cmd_hdr_init(softc, &set, HWRM_FW_SET_STRUCTURED_DATA);
444
445 set.src_data_addr = htole64(dma_data.idi_paddr);
446 set.data_len = htole16(sizeof(*data) + sizeof(*fw_app) * n);
447 set.hdr_cnt = 1;
448 rc = _hwrm_send_message(softc, &set, sizeof(set));
449
450 set_app_exit:
451 iflib_dma_free(&dma_data);
452 return rc;
453 }
454
455 static int
bnxt_hwrm_queue_dscp_qcaps(struct bnxt_softc * softc)456 bnxt_hwrm_queue_dscp_qcaps(struct bnxt_softc *softc)
457 {
458 struct hwrm_queue_dscp_qcaps_output *resp =
459 (void *)softc->hwrm_cmd_resp.idi_vaddr;
460 struct hwrm_queue_dscp_qcaps_input req = {0};
461 int rc;
462
463 softc->max_dscp_value = 0;
464 if (softc->hwrm_spec_code < 0x10800 || BNXT_VF(softc))
465 return 0;
466
467 bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP_QCAPS);
468
469 rc = _hwrm_send_message(softc, &req, sizeof(req));
470 if (!rc) {
471 softc->max_dscp_value = (1 << resp->num_dscp_bits) - 1;
472 if (softc->max_dscp_value < 0x3f)
473 softc->max_dscp_value = 0;
474 }
475 return rc;
476 }
477
478 static int
bnxt_hwrm_queue_dscp2pri_qcfg(struct bnxt_softc * softc,struct bnxt_dcb_app * app,size_t nitems,int * num_inputs)479 bnxt_hwrm_queue_dscp2pri_qcfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
480 size_t nitems, int *num_inputs)
481 {
482 struct hwrm_queue_dscp2pri_qcfg_input req = {0};
483 struct hwrm_queue_dscp2pri_qcfg_output *resp =
484 (void *)softc->hwrm_cmd_resp.idi_vaddr;
485 struct bnxt_dscp2pri_entry *dscp2pri;
486 struct iflib_dma_info dma_data;
487 int rc, entry_cnt;
488 int i;
489
490 if (softc->hwrm_spec_code < 0x10800)
491 return 0;
492
493 rc = iflib_dma_alloc(softc->ctx, sizeof(*dscp2pri) * 128, &dma_data,
494 BUS_DMA_NOWAIT);
495 if (rc)
496 return ENOMEM;
497
498 dscp2pri = (void *)dma_data.idi_vaddr;
499
500 bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP2PRI_QCFG);
501
502 req.dest_data_addr = htole64(dma_data.idi_paddr);
503 req.dest_data_buffer_size = htole16(sizeof(*dscp2pri) * 64);
504 req.port_id = htole16(softc->pf.port_id);
505 rc = _hwrm_send_message(softc, &req, sizeof(req));
506
507 if (rc)
508 goto end;
509
510 entry_cnt = le16toh(resp->entry_cnt);
511 for (i = 0; i < entry_cnt && *num_inputs < nitems; i++) {
512 app[*num_inputs].priority = dscp2pri[i].pri;
513 app[*num_inputs].protocol = dscp2pri[i].dscp;
514 app[*num_inputs].selector = BNXT_IEEE_8021QAZ_APP_SEL_DSCP;
515 (*num_inputs)++;
516 }
517
518 end:
519 iflib_dma_free(&dma_data);
520 return rc;
521 }
522
523 static int
bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt_softc * softc,struct bnxt_dcb_app * app,bool add)524 bnxt_hwrm_queue_dscp2pri_cfg(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
525 bool add)
526 {
527 struct hwrm_queue_dscp2pri_cfg_input req = {0};
528 struct bnxt_dscp2pri_entry *dscp2pri;
529 struct iflib_dma_info dma_data;
530 int rc;
531
532 if (softc->hwrm_spec_code < 0x10800)
533 return 0;
534
535 rc = iflib_dma_alloc(softc->ctx, sizeof(*dscp2pri), &dma_data,
536 BUS_DMA_NOWAIT);
537 if (rc)
538 return ENOMEM;
539
540 bnxt_hwrm_cmd_hdr_init(softc, &req, HWRM_QUEUE_DSCP2PRI_CFG);
541
542 req.src_data_addr = htole64(dma_data.idi_paddr);
543 dscp2pri = (void *)dma_data.idi_vaddr;
544 dscp2pri->dscp = app->protocol;
545 if (add)
546 dscp2pri->mask = 0x3f;
547 else
548 dscp2pri->mask = 0;
549 dscp2pri->pri = app->priority;
550 req.entry_cnt = htole16(1);
551 req.port_id = htole16(softc->pf.port_id);
552 rc = _hwrm_send_message(softc, &req, sizeof(req));
553
554 iflib_dma_free(&dma_data);
555 return rc;
556 }
557
558 static int
bnxt_ets_validate(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets,uint8_t * tc)559 bnxt_ets_validate(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets, uint8_t *tc)
560 {
561 int total_ets_bw = 0;
562 bool zero = false;
563 uint8_t max_tc = 0;
564 int i;
565
566 for (i = 0; i < BNXT_IEEE_8021QAZ_MAX_TCS; i++) {
567 if (ets->prio_tc[i] > softc->max_tc) {
568 device_printf(softc->dev, "priority to TC mapping exceeds TC count %d\n",
569 ets->prio_tc[i]);
570 return -EINVAL;
571 }
572 if (ets->prio_tc[i] > max_tc)
573 max_tc = ets->prio_tc[i];
574
575 if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > softc->max_tc)
576 return -EINVAL;
577
578 switch (ets->tc_tsa[i]) {
579 case BNXT_IEEE_8021QAZ_TSA_STRICT:
580 break;
581 case BNXT_IEEE_8021QAZ_TSA_ETS:
582 total_ets_bw += ets->tc_tx_bw[i];
583 zero = zero || !ets->tc_tx_bw[i];
584 break;
585 default:
586 return -ENOTSUPP;
587 }
588 }
589 if (total_ets_bw > 100) {
590 device_printf(softc->dev, "rejecting ETS config exceeding available bandwidth\n");
591 return -EINVAL;
592 }
593 if (zero && total_ets_bw == 100) {
594 device_printf(softc->dev, "rejecting ETS config starving a TC\n");
595 return -EINVAL;
596 }
597
598 if (max_tc >= softc->max_tc)
599 *tc = softc->max_tc;
600 else
601 *tc = max_tc + 1;
602 return 0;
603 }
604
605 int
bnxt_dcb_ieee_getets(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets)606 bnxt_dcb_ieee_getets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
607 {
608 struct bnxt_ieee_ets *my_ets = softc->ieee_ets;
609 int rc;
610
611 if (!my_ets)
612 return 0;
613
614 rc = bnxt_hwrm_queue_cos2bw_qcfg(softc, my_ets);
615 if (rc)
616 goto error;
617 rc = bnxt_hwrm_queue_pri2cos_qcfg(softc, my_ets);
618 if (rc)
619 goto error;
620
621 if (ets) {
622 ets->cbs = my_ets->cbs;
623 ets->ets_cap = softc->max_tc;
624 memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw));
625 memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw));
626 memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa));
627 memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc));
628 }
629 return 0;
630 error:
631 return rc;
632 }
633
634 int
bnxt_dcb_ieee_setets(struct bnxt_softc * softc,struct bnxt_ieee_ets * ets)635 bnxt_dcb_ieee_setets(struct bnxt_softc *softc, struct bnxt_ieee_ets *ets)
636 {
637 uint8_t max_tc = 0;
638 int rc;
639
640 if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
641 !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST))
642 return -EINVAL;
643
644 rc = bnxt_ets_validate(softc, ets, &max_tc);
645 if (rc)
646 return rc;
647
648 rc = bnxt_hwrm_queue_cos2bw_cfg(softc, ets, max_tc);
649 if (rc)
650 goto error;
651
652 if (!softc->is_asym_q) {
653 rc = bnxt_hwrm_queue_pri2cos_cfg(softc, ets,
654 HWRM_QUEUE_PRI2COS_CFG_INPUT_FLAGS_PATH_BIDIR);
655 if (rc)
656 goto error;
657 } else {
658 rc = bnxt_hwrm_queue_pri2cos_cfg(softc, ets,
659 HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_PATH_TX);
660 if (rc)
661 goto error;
662
663 rc = bnxt_hwrm_queue_pri2cos_cfg(softc, ets,
664 HWRM_QUEUE_PRI2COS_QCFG_INPUT_FLAGS_PATH_RX);
665 if (rc)
666 goto error;
667 }
668
669 memcpy(softc->ieee_ets, ets, sizeof(*ets));
670 return 0;
671 error:
672 return rc;
673 }
674
675 int
bnxt_dcb_ieee_getpfc(struct bnxt_softc * softc,struct bnxt_ieee_pfc * pfc)676 bnxt_dcb_ieee_getpfc(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
677 {
678 struct bnxt_ieee_pfc *my_pfc = softc->ieee_pfc;
679 int rc;
680
681 if (!my_pfc)
682 return -1;
683
684 pfc->pfc_cap = softc->max_lltc;
685
686 rc = bnxt_hwrm_queue_pfc_qcfg(softc, my_pfc);
687 if (rc)
688 return 0;
689
690 pfc->pfc_en = my_pfc->pfc_en;
691 pfc->mbc = my_pfc->mbc;
692 pfc->delay = my_pfc->delay;
693
694 return 0;
695 }
696
697 int
bnxt_dcb_ieee_setpfc(struct bnxt_softc * softc,struct bnxt_ieee_pfc * pfc)698 bnxt_dcb_ieee_setpfc(struct bnxt_softc *softc, struct bnxt_ieee_pfc *pfc)
699 {
700 struct bnxt_ieee_pfc *my_pfc = softc->ieee_pfc;
701 int rc;
702
703 if (!my_pfc)
704 return -1;
705
706 if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
707 !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST) ||
708 (softc->phy_flags & BNXT_PHY_FL_NO_PAUSE))
709 return -EINVAL;
710
711 rc = bnxt_hwrm_queue_pfc_cfg(softc, pfc);
712 if (!rc)
713 memcpy(my_pfc, pfc, sizeof(*my_pfc));
714
715 return rc;
716 }
717
718 static int
bnxt_dcb_ieee_dscp_app_prep(struct bnxt_softc * softc,struct bnxt_dcb_app * app)719 bnxt_dcb_ieee_dscp_app_prep(struct bnxt_softc *softc, struct bnxt_dcb_app *app)
720 {
721 if (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DSCP) {
722 if (!softc->max_dscp_value)
723 return -ENOTSUPP;
724 if (app->protocol > softc->max_dscp_value)
725 return -EINVAL;
726 }
727 return 0;
728 }
729
730 int
bnxt_dcb_ieee_setapp(struct bnxt_softc * softc,struct bnxt_dcb_app * app)731 bnxt_dcb_ieee_setapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app)
732 {
733 int rc;
734
735
736 if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
737 !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST))
738 return -EINVAL;
739
740 rc = bnxt_dcb_ieee_dscp_app_prep(softc, app);
741 if (rc)
742 return rc;
743
744 if ((app->selector == BNXT_IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
745 app->protocol == ETH_P_ROCE) ||
746 (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DGRAM &&
747 app->protocol == ROCE_V2_UDP_DPORT))
748 rc = bnxt_hwrm_set_dcbx_app(softc, app, true);
749
750 if (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DSCP)
751 rc = bnxt_hwrm_queue_dscp2pri_cfg(softc, app, true);
752
753 return rc;
754 }
755
756 int
bnxt_dcb_ieee_delapp(struct bnxt_softc * softc,struct bnxt_dcb_app * app)757 bnxt_dcb_ieee_delapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app)
758 {
759 int rc;
760
761 if (!(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_VER_IEEE) ||
762 !(softc->dcbx_cap & BNXT_DCB_CAP_DCBX_HOST))
763 return -EINVAL;
764
765 rc = bnxt_dcb_ieee_dscp_app_prep(softc, app);
766 if (rc)
767 return rc;
768
769 if ((app->selector == BNXT_IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
770 app->protocol == ETH_P_ROCE) ||
771 (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DGRAM &&
772 app->protocol == ROCE_V2_UDP_DPORT))
773 rc = bnxt_hwrm_set_dcbx_app(softc, app, false);
774
775 if (app->selector == BNXT_IEEE_8021QAZ_APP_SEL_DSCP)
776 rc = bnxt_hwrm_queue_dscp2pri_cfg(softc, app, false);
777
778 return rc;
779 }
780
781 int
bnxt_dcb_ieee_listapp(struct bnxt_softc * softc,struct bnxt_dcb_app * app,size_t nitems,int * num_inputs)782 bnxt_dcb_ieee_listapp(struct bnxt_softc *softc, struct bnxt_dcb_app *app,
783 size_t nitems, int *num_inputs)
784 {
785 bnxt_hwrm_get_dcbx_app(softc, app, nitems, num_inputs);
786 bnxt_hwrm_queue_dscp2pri_qcfg(softc, app, nitems, num_inputs);
787
788 return 0;
789 }
790
791 uint8_t
bnxt_dcb_getdcbx(struct bnxt_softc * softc)792 bnxt_dcb_getdcbx(struct bnxt_softc *softc)
793 {
794 return softc->dcbx_cap;
795 }
796
797 uint8_t
bnxt_dcb_setdcbx(struct bnxt_softc * softc,uint8_t mode)798 bnxt_dcb_setdcbx(struct bnxt_softc *softc, uint8_t mode)
799 {
800 /* All firmware DCBX settings are set in NVRAM */
801 if (softc->dcbx_cap & BNXT_DCB_CAP_DCBX_LLD_MANAGED)
802 return 1;
803
804 /*
805 * Do't allow editing CAP_DCBX_LLD_MANAGED since it is driven
806 * based on FUNC_QCFG_OUTPUT_FLAGS_FW_DCBX_AGENT_ENABLED
807 */
808 if ((softc->dcbx_cap & BNXT_DCB_CAP_DCBX_LLD_MANAGED) !=
809 (mode & BNXT_DCB_CAP_DCBX_LLD_MANAGED))
810 return 1;
811
812 if (mode & BNXT_DCB_CAP_DCBX_HOST) {
813 if (BNXT_VF(softc) || (softc->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
814 return 1;
815
816 /* only support BNXT_IEEE */
817 if ((mode & BNXT_DCB_CAP_DCBX_VER_CEE) ||
818 !(mode & BNXT_DCB_CAP_DCBX_VER_IEEE))
819 return 1;
820 }
821
822 if (mode == softc->dcbx_cap)
823 return 0;
824
825 softc->dcbx_cap = mode;
826 return 0;
827 }
828
829 void
bnxt_dcb_init(struct bnxt_softc * softc)830 bnxt_dcb_init(struct bnxt_softc *softc)
831 {
832 struct bnxt_ieee_ets ets = {0};
833 struct bnxt_ieee_pfc pfc = {0};
834
835 softc->dcbx_cap = 0;
836
837 if (softc->hwrm_spec_code < 0x10501)
838 return;
839
840 softc->ieee_ets = malloc(sizeof(struct bnxt_ieee_ets), M_DEVBUF, M_NOWAIT | M_ZERO);
841 if (!softc->ieee_ets)
842 return;
843
844 softc->ieee_pfc = malloc(sizeof(struct bnxt_ieee_pfc), M_DEVBUF, M_NOWAIT | M_ZERO);
845 if (!softc->ieee_pfc)
846 return;
847
848 bnxt_hwrm_queue_dscp_qcaps(softc);
849 softc->dcbx_cap = BNXT_DCB_CAP_DCBX_VER_IEEE;
850 if (BNXT_PF(softc) && !(softc->fw_cap & BNXT_FW_CAP_LLDP_AGENT))
851 softc->dcbx_cap |= BNXT_DCB_CAP_DCBX_HOST;
852 else if (softc->fw_cap & BNXT_FW_CAP_DCBX_AGENT)
853 softc->dcbx_cap |= BNXT_DCB_CAP_DCBX_LLD_MANAGED;
854
855 bnxt_dcb_ieee_setets(softc, &ets);
856 bnxt_dcb_ieee_setpfc(softc, &pfc);
857
858 }
859
860 void
bnxt_dcb_free(struct bnxt_softc * softc)861 bnxt_dcb_free(struct bnxt_softc *softc)
862 {
863 free(softc->ieee_ets, M_DEVBUF);
864 softc->ieee_ets = NULL;
865 free(softc->ieee_pfc, M_DEVBUF);
866 softc->ieee_pfc = NULL;
867 }
868