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