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