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