1 /* Broadcom NetXtreme-C/E network driver. 2 * 3 * Copyright (c) 2014-2016 Broadcom Corporation 4 * Copyright (c) 2016-2017 Broadcom Limited 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation. 9 */ 10 11 #include <linux/netdevice.h> 12 #include <linux/types.h> 13 #include <linux/errno.h> 14 #include <linux/rtnetlink.h> 15 #include <linux/interrupt.h> 16 #include <linux/pci.h> 17 #include <linux/etherdevice.h> 18 #include <rdma/ib_verbs.h> 19 #include "bnxt_hsi.h" 20 #include "bnxt.h" 21 #include "bnxt_dcb.h" 22 23 #ifdef CONFIG_BNXT_DCB 24 static int bnxt_hwrm_queue_pri2cos_cfg(struct bnxt *bp, struct ieee_ets *ets) 25 { 26 struct hwrm_queue_pri2cos_cfg_input req = {0}; 27 int rc = 0, i; 28 u8 *pri2cos; 29 30 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_CFG, -1, -1); 31 req.flags = cpu_to_le32(QUEUE_PRI2COS_CFG_REQ_FLAGS_PATH_BIDIR | 32 QUEUE_PRI2COS_CFG_REQ_FLAGS_IVLAN); 33 34 pri2cos = &req.pri0_cos_queue_id; 35 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 36 req.enables |= cpu_to_le32( 37 QUEUE_PRI2COS_CFG_REQ_ENABLES_PRI0_COS_QUEUE_ID << i); 38 39 pri2cos[i] = bp->q_info[ets->prio_tc[i]].queue_id; 40 } 41 rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 42 return rc; 43 } 44 45 static int bnxt_hwrm_queue_pri2cos_qcfg(struct bnxt *bp, struct ieee_ets *ets) 46 { 47 struct hwrm_queue_pri2cos_qcfg_output *resp = bp->hwrm_cmd_resp_addr; 48 struct hwrm_queue_pri2cos_qcfg_input req = {0}; 49 int rc = 0; 50 51 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PRI2COS_QCFG, -1, -1); 52 req.flags = cpu_to_le32(QUEUE_PRI2COS_QCFG_REQ_FLAGS_IVLAN); 53 54 mutex_lock(&bp->hwrm_cmd_lock); 55 rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 56 if (!rc) { 57 u8 *pri2cos = &resp->pri0_cos_queue_id; 58 int i, j; 59 60 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 61 u8 queue_id = pri2cos[i]; 62 63 for (j = 0; j < bp->max_tc; j++) { 64 if (bp->q_info[j].queue_id == queue_id) { 65 ets->prio_tc[i] = j; 66 break; 67 } 68 } 69 } 70 } 71 mutex_unlock(&bp->hwrm_cmd_lock); 72 return rc; 73 } 74 75 static int bnxt_hwrm_queue_cos2bw_cfg(struct bnxt *bp, struct ieee_ets *ets, 76 u8 max_tc) 77 { 78 struct hwrm_queue_cos2bw_cfg_input req = {0}; 79 struct bnxt_cos2bw_cfg cos2bw; 80 int rc = 0, i; 81 void *data; 82 83 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_CFG, -1, -1); 84 data = &req.unused_0; 85 for (i = 0; i < max_tc; i++, data += sizeof(cos2bw) - 4) { 86 req.enables |= cpu_to_le32( 87 QUEUE_COS2BW_CFG_REQ_ENABLES_COS_QUEUE_ID0_VALID << i); 88 89 memset(&cos2bw, 0, sizeof(cos2bw)); 90 cos2bw.queue_id = bp->q_info[i].queue_id; 91 if (ets->tc_tsa[i] == IEEE_8021QAZ_TSA_STRICT) { 92 cos2bw.tsa = 93 QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP; 94 cos2bw.pri_lvl = i; 95 } else { 96 cos2bw.tsa = 97 QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_ETS; 98 cos2bw.bw_weight = ets->tc_tx_bw[i]; 99 /* older firmware requires min_bw to be set to the 100 * same weight value in percent. 101 */ 102 cos2bw.min_bw = 103 cpu_to_le32((ets->tc_tx_bw[i] * 100) | 104 BW_VALUE_UNIT_PERCENT1_100); 105 } 106 memcpy(data, &cos2bw.queue_id, sizeof(cos2bw) - 4); 107 if (i == 0) { 108 req.queue_id0 = cos2bw.queue_id; 109 req.unused_0 = 0; 110 } 111 } 112 rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 113 return rc; 114 } 115 116 static int bnxt_hwrm_queue_cos2bw_qcfg(struct bnxt *bp, struct ieee_ets *ets) 117 { 118 struct hwrm_queue_cos2bw_qcfg_output *resp = bp->hwrm_cmd_resp_addr; 119 struct hwrm_queue_cos2bw_qcfg_input req = {0}; 120 struct bnxt_cos2bw_cfg cos2bw; 121 void *data; 122 int rc, i; 123 124 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_COS2BW_QCFG, -1, -1); 125 126 mutex_lock(&bp->hwrm_cmd_lock); 127 rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 128 if (rc) { 129 mutex_unlock(&bp->hwrm_cmd_lock); 130 return rc; 131 } 132 133 data = &resp->queue_id0 + offsetof(struct bnxt_cos2bw_cfg, queue_id); 134 for (i = 0; i < bp->max_tc; i++, data += sizeof(cos2bw) - 4) { 135 int j; 136 137 memcpy(&cos2bw.queue_id, data, sizeof(cos2bw) - 4); 138 if (i == 0) 139 cos2bw.queue_id = resp->queue_id0; 140 141 for (j = 0; j < bp->max_tc; j++) { 142 if (bp->q_info[j].queue_id != cos2bw.queue_id) 143 continue; 144 if (cos2bw.tsa == 145 QUEUE_COS2BW_QCFG_RESP_QUEUE_ID0_TSA_ASSIGN_SP) { 146 ets->tc_tsa[j] = IEEE_8021QAZ_TSA_STRICT; 147 } else { 148 ets->tc_tsa[j] = IEEE_8021QAZ_TSA_ETS; 149 ets->tc_tx_bw[j] = cos2bw.bw_weight; 150 } 151 } 152 } 153 mutex_unlock(&bp->hwrm_cmd_lock); 154 return 0; 155 } 156 157 static int bnxt_hwrm_queue_cfg(struct bnxt *bp, unsigned int lltc_mask) 158 { 159 struct hwrm_queue_cfg_input req = {0}; 160 int i; 161 162 if (netif_running(bp->dev)) 163 bnxt_tx_disable(bp); 164 165 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_CFG, -1, -1); 166 req.flags = cpu_to_le32(QUEUE_CFG_REQ_FLAGS_PATH_BIDIR); 167 req.enables = cpu_to_le32(QUEUE_CFG_REQ_ENABLES_SERVICE_PROFILE); 168 169 /* Configure lossless queues to lossy first */ 170 req.service_profile = QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSY; 171 for (i = 0; i < bp->max_tc; i++) { 172 if (BNXT_LLQ(bp->q_info[i].queue_profile)) { 173 req.queue_id = cpu_to_le32(bp->q_info[i].queue_id); 174 hwrm_send_message(bp, &req, sizeof(req), 175 HWRM_CMD_TIMEOUT); 176 bp->q_info[i].queue_profile = 177 QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSY; 178 } 179 } 180 181 /* Now configure desired queues to lossless */ 182 req.service_profile = QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSLESS; 183 for (i = 0; i < bp->max_tc; i++) { 184 if (lltc_mask & (1 << i)) { 185 req.queue_id = cpu_to_le32(bp->q_info[i].queue_id); 186 hwrm_send_message(bp, &req, sizeof(req), 187 HWRM_CMD_TIMEOUT); 188 bp->q_info[i].queue_profile = 189 QUEUE_CFG_REQ_SERVICE_PROFILE_LOSSLESS; 190 } 191 } 192 if (netif_running(bp->dev)) 193 bnxt_tx_enable(bp); 194 195 return 0; 196 } 197 198 static int bnxt_hwrm_queue_pfc_cfg(struct bnxt *bp, struct ieee_pfc *pfc) 199 { 200 struct hwrm_queue_pfcenable_cfg_input req = {0}; 201 struct ieee_ets *my_ets = bp->ieee_ets; 202 unsigned int tc_mask = 0, pri_mask = 0; 203 u8 i, pri, lltc_count = 0; 204 bool need_q_recfg = false; 205 int rc; 206 207 if (!my_ets) 208 return -EINVAL; 209 210 for (i = 0; i < bp->max_tc; i++) { 211 for (pri = 0; pri < IEEE_8021QAZ_MAX_TCS; pri++) { 212 if ((pfc->pfc_en & (1 << pri)) && 213 (my_ets->prio_tc[pri] == i)) { 214 pri_mask |= 1 << pri; 215 tc_mask |= 1 << i; 216 } 217 } 218 if (tc_mask & (1 << i)) 219 lltc_count++; 220 } 221 if (lltc_count > bp->max_lltc) 222 return -EINVAL; 223 224 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_CFG, -1, -1); 225 req.flags = cpu_to_le32(pri_mask); 226 rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 227 if (rc) 228 return rc; 229 230 for (i = 0; i < bp->max_tc; i++) { 231 if (tc_mask & (1 << i)) { 232 if (!BNXT_LLQ(bp->q_info[i].queue_profile)) 233 need_q_recfg = true; 234 } 235 } 236 237 if (need_q_recfg) 238 rc = bnxt_hwrm_queue_cfg(bp, tc_mask); 239 240 return rc; 241 } 242 243 static int bnxt_hwrm_queue_pfc_qcfg(struct bnxt *bp, struct ieee_pfc *pfc) 244 { 245 struct hwrm_queue_pfcenable_qcfg_output *resp = bp->hwrm_cmd_resp_addr; 246 struct hwrm_queue_pfcenable_qcfg_input req = {0}; 247 u8 pri_mask; 248 int rc; 249 250 bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_QUEUE_PFCENABLE_QCFG, -1, -1); 251 252 mutex_lock(&bp->hwrm_cmd_lock); 253 rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); 254 if (rc) { 255 mutex_unlock(&bp->hwrm_cmd_lock); 256 return rc; 257 } 258 259 pri_mask = le32_to_cpu(resp->flags); 260 pfc->pfc_en = pri_mask; 261 mutex_unlock(&bp->hwrm_cmd_lock); 262 return 0; 263 } 264 265 static int bnxt_hwrm_set_dcbx_app(struct bnxt *bp, struct dcb_app *app, 266 bool add) 267 { 268 struct hwrm_fw_set_structured_data_input set = {0}; 269 struct hwrm_fw_get_structured_data_input get = {0}; 270 struct hwrm_struct_data_dcbx_app *fw_app; 271 struct hwrm_struct_hdr *data; 272 dma_addr_t mapping; 273 size_t data_len; 274 int rc, n, i; 275 276 if (bp->hwrm_spec_code < 0x10601) 277 return 0; 278 279 n = IEEE_8021QAZ_MAX_TCS; 280 data_len = sizeof(*data) + sizeof(*fw_app) * n; 281 data = dma_alloc_coherent(&bp->pdev->dev, data_len, &mapping, 282 GFP_KERNEL); 283 if (!data) 284 return -ENOMEM; 285 286 memset(data, 0, data_len); 287 bnxt_hwrm_cmd_hdr_init(bp, &get, HWRM_FW_GET_STRUCTURED_DATA, -1, -1); 288 get.dest_data_addr = cpu_to_le64(mapping); 289 get.structure_id = cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP); 290 get.subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); 291 get.count = 0; 292 rc = hwrm_send_message(bp, &get, sizeof(get), HWRM_CMD_TIMEOUT); 293 if (rc) 294 goto set_app_exit; 295 296 fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1); 297 298 if (data->struct_id != cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP)) { 299 rc = -ENODEV; 300 goto set_app_exit; 301 } 302 303 n = data->count; 304 for (i = 0; i < n; i++, fw_app++) { 305 if (fw_app->protocol_id == cpu_to_be16(app->protocol) && 306 fw_app->protocol_selector == app->selector && 307 fw_app->priority == app->priority) { 308 if (add) 309 goto set_app_exit; 310 else 311 break; 312 } 313 } 314 if (add) { 315 /* append */ 316 n++; 317 fw_app->protocol_id = cpu_to_be16(app->protocol); 318 fw_app->protocol_selector = app->selector; 319 fw_app->priority = app->priority; 320 fw_app->valid = 1; 321 } else { 322 size_t len = 0; 323 324 /* not found, nothing to delete */ 325 if (n == i) 326 goto set_app_exit; 327 328 len = (n - 1 - i) * sizeof(*fw_app); 329 if (len) 330 memmove(fw_app, fw_app + 1, len); 331 n--; 332 memset(fw_app + n, 0, sizeof(*fw_app)); 333 } 334 data->count = n; 335 data->len = cpu_to_le16(sizeof(*fw_app) * n); 336 data->subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); 337 338 bnxt_hwrm_cmd_hdr_init(bp, &set, HWRM_FW_SET_STRUCTURED_DATA, -1, -1); 339 set.src_data_addr = cpu_to_le64(mapping); 340 set.data_len = cpu_to_le16(sizeof(*data) + sizeof(*fw_app) * n); 341 set.hdr_cnt = 1; 342 rc = hwrm_send_message(bp, &set, sizeof(set), HWRM_CMD_TIMEOUT); 343 if (rc) 344 rc = -EIO; 345 346 set_app_exit: 347 dma_free_coherent(&bp->pdev->dev, data_len, data, mapping); 348 return rc; 349 } 350 351 static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc) 352 { 353 int total_ets_bw = 0; 354 u8 max_tc = 0; 355 int i; 356 357 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 358 if (ets->prio_tc[i] > bp->max_tc) { 359 netdev_err(bp->dev, "priority to TC mapping exceeds TC count %d\n", 360 ets->prio_tc[i]); 361 return -EINVAL; 362 } 363 if (ets->prio_tc[i] > max_tc) 364 max_tc = ets->prio_tc[i]; 365 366 if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > bp->max_tc) 367 return -EINVAL; 368 369 switch (ets->tc_tsa[i]) { 370 case IEEE_8021QAZ_TSA_STRICT: 371 break; 372 case IEEE_8021QAZ_TSA_ETS: 373 total_ets_bw += ets->tc_tx_bw[i]; 374 break; 375 default: 376 return -ENOTSUPP; 377 } 378 } 379 if (total_ets_bw > 100) 380 return -EINVAL; 381 382 *tc = max_tc + 1; 383 return 0; 384 } 385 386 static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) 387 { 388 struct bnxt *bp = netdev_priv(dev); 389 struct ieee_ets *my_ets = bp->ieee_ets; 390 391 ets->ets_cap = bp->max_tc; 392 393 if (!my_ets) { 394 int rc; 395 396 if (bp->dcbx_cap & DCB_CAP_DCBX_HOST) 397 return 0; 398 399 my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL); 400 if (!my_ets) 401 return 0; 402 rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets); 403 if (rc) 404 return 0; 405 rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets); 406 if (rc) 407 return 0; 408 } 409 410 ets->cbs = my_ets->cbs; 411 memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); 412 memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); 413 memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); 414 memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); 415 return 0; 416 } 417 418 static int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets) 419 { 420 struct bnxt *bp = netdev_priv(dev); 421 struct ieee_ets *my_ets = bp->ieee_ets; 422 u8 max_tc = 0; 423 int rc, i; 424 425 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 426 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 427 return -EINVAL; 428 429 rc = bnxt_ets_validate(bp, ets, &max_tc); 430 if (!rc) { 431 if (!my_ets) { 432 my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL); 433 if (!my_ets) 434 return -ENOMEM; 435 /* initialize PRI2TC mappings to invalid value */ 436 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 437 my_ets->prio_tc[i] = IEEE_8021QAZ_MAX_TCS; 438 bp->ieee_ets = my_ets; 439 } 440 rc = bnxt_setup_mq_tc(dev, max_tc); 441 if (rc) 442 return rc; 443 rc = bnxt_hwrm_queue_cos2bw_cfg(bp, ets, max_tc); 444 if (rc) 445 return rc; 446 rc = bnxt_hwrm_queue_pri2cos_cfg(bp, ets); 447 if (rc) 448 return rc; 449 memcpy(my_ets, ets, sizeof(*my_ets)); 450 } 451 return rc; 452 } 453 454 static int bnxt_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *pfc) 455 { 456 struct bnxt *bp = netdev_priv(dev); 457 __le64 *stats = (__le64 *)bp->hw_rx_port_stats; 458 struct ieee_pfc *my_pfc = bp->ieee_pfc; 459 long rx_off, tx_off; 460 int i, rc; 461 462 pfc->pfc_cap = bp->max_lltc; 463 464 if (!my_pfc) { 465 if (bp->dcbx_cap & DCB_CAP_DCBX_HOST) 466 return 0; 467 468 my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL); 469 if (!my_pfc) 470 return 0; 471 bp->ieee_pfc = my_pfc; 472 rc = bnxt_hwrm_queue_pfc_qcfg(bp, my_pfc); 473 if (rc) 474 return 0; 475 } 476 477 pfc->pfc_en = my_pfc->pfc_en; 478 pfc->mbc = my_pfc->mbc; 479 pfc->delay = my_pfc->delay; 480 481 if (!stats) 482 return 0; 483 484 rx_off = BNXT_RX_STATS_OFFSET(rx_pfc_ena_frames_pri0); 485 tx_off = BNXT_TX_STATS_OFFSET(tx_pfc_ena_frames_pri0); 486 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++, rx_off++, tx_off++) { 487 pfc->requests[i] = le64_to_cpu(*(stats + tx_off)); 488 pfc->indications[i] = le64_to_cpu(*(stats + rx_off)); 489 } 490 491 return 0; 492 } 493 494 static int bnxt_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc) 495 { 496 struct bnxt *bp = netdev_priv(dev); 497 struct ieee_pfc *my_pfc = bp->ieee_pfc; 498 int rc; 499 500 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 501 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 502 return -EINVAL; 503 504 if (!my_pfc) { 505 my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL); 506 if (!my_pfc) 507 return -ENOMEM; 508 bp->ieee_pfc = my_pfc; 509 } 510 rc = bnxt_hwrm_queue_pfc_cfg(bp, pfc); 511 if (!rc) 512 memcpy(my_pfc, pfc, sizeof(*my_pfc)); 513 514 return rc; 515 } 516 517 static int bnxt_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app) 518 { 519 struct bnxt *bp = netdev_priv(dev); 520 int rc = -EINVAL; 521 522 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 523 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 524 return -EINVAL; 525 526 rc = dcb_ieee_setapp(dev, app); 527 if (rc) 528 return rc; 529 530 if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 531 app->protocol == ETH_P_IBOE) || 532 (app->selector == IEEE_8021QAZ_APP_SEL_DGRAM && 533 app->protocol == ROCE_V2_UDP_DPORT)) 534 rc = bnxt_hwrm_set_dcbx_app(bp, app, true); 535 536 return rc; 537 } 538 539 static int bnxt_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app) 540 { 541 struct bnxt *bp = netdev_priv(dev); 542 int rc; 543 544 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 545 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 546 return -EINVAL; 547 548 rc = dcb_ieee_delapp(dev, app); 549 if (rc) 550 return rc; 551 if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 552 app->protocol == ETH_P_IBOE) || 553 (app->selector == IEEE_8021QAZ_APP_SEL_DGRAM && 554 app->protocol == ROCE_V2_UDP_DPORT)) 555 rc = bnxt_hwrm_set_dcbx_app(bp, app, false); 556 557 return rc; 558 } 559 560 static u8 bnxt_dcbnl_getdcbx(struct net_device *dev) 561 { 562 struct bnxt *bp = netdev_priv(dev); 563 564 return bp->dcbx_cap; 565 } 566 567 static u8 bnxt_dcbnl_setdcbx(struct net_device *dev, u8 mode) 568 { 569 struct bnxt *bp = netdev_priv(dev); 570 571 /* All firmware DCBX settings are set in NVRAM */ 572 if (bp->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) 573 return 1; 574 575 if (mode & DCB_CAP_DCBX_HOST) { 576 if (BNXT_VF(bp) || (bp->flags & BNXT_FLAG_FW_LLDP_AGENT)) 577 return 1; 578 579 /* only support IEEE */ 580 if ((mode & DCB_CAP_DCBX_VER_CEE) || 581 !(mode & DCB_CAP_DCBX_VER_IEEE)) 582 return 1; 583 } 584 585 if (mode == bp->dcbx_cap) 586 return 0; 587 588 bp->dcbx_cap = mode; 589 return 0; 590 } 591 592 static const struct dcbnl_rtnl_ops dcbnl_ops = { 593 .ieee_getets = bnxt_dcbnl_ieee_getets, 594 .ieee_setets = bnxt_dcbnl_ieee_setets, 595 .ieee_getpfc = bnxt_dcbnl_ieee_getpfc, 596 .ieee_setpfc = bnxt_dcbnl_ieee_setpfc, 597 .ieee_setapp = bnxt_dcbnl_ieee_setapp, 598 .ieee_delapp = bnxt_dcbnl_ieee_delapp, 599 .getdcbx = bnxt_dcbnl_getdcbx, 600 .setdcbx = bnxt_dcbnl_setdcbx, 601 }; 602 603 void bnxt_dcb_init(struct bnxt *bp) 604 { 605 if (bp->hwrm_spec_code < 0x10501) 606 return; 607 608 bp->dcbx_cap = DCB_CAP_DCBX_VER_IEEE; 609 if (BNXT_PF(bp) && !(bp->flags & BNXT_FLAG_FW_LLDP_AGENT)) 610 bp->dcbx_cap |= DCB_CAP_DCBX_HOST; 611 else if (bp->flags & BNXT_FLAG_FW_DCBX_AGENT) 612 bp->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED; 613 bp->dev->dcbnl_ops = &dcbnl_ops; 614 } 615 616 void bnxt_dcb_free(struct bnxt *bp) 617 { 618 kfree(bp->ieee_pfc); 619 kfree(bp->ieee_ets); 620 bp->ieee_pfc = NULL; 621 bp->ieee_ets = NULL; 622 } 623 624 #else 625 626 void bnxt_dcb_init(struct bnxt *bp) 627 { 628 } 629 630 void bnxt_dcb_free(struct bnxt *bp) 631 { 632 } 633 634 #endif 635