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_zalloc_coherent(&bp->pdev->dev, data_len, &mapping, 282 GFP_KERNEL); 283 if (!data) 284 return -ENOMEM; 285 286 bnxt_hwrm_cmd_hdr_init(bp, &get, HWRM_FW_GET_STRUCTURED_DATA, -1, -1); 287 get.dest_data_addr = cpu_to_le64(mapping); 288 get.structure_id = cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP); 289 get.subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); 290 get.count = 0; 291 rc = hwrm_send_message(bp, &get, sizeof(get), HWRM_CMD_TIMEOUT); 292 if (rc) 293 goto set_app_exit; 294 295 fw_app = (struct hwrm_struct_data_dcbx_app *)(data + 1); 296 297 if (data->struct_id != cpu_to_le16(STRUCT_HDR_STRUCT_ID_DCBX_APP)) { 298 rc = -ENODEV; 299 goto set_app_exit; 300 } 301 302 n = data->count; 303 for (i = 0; i < n; i++, fw_app++) { 304 if (fw_app->protocol_id == cpu_to_be16(app->protocol) && 305 fw_app->protocol_selector == app->selector && 306 fw_app->priority == app->priority) { 307 if (add) 308 goto set_app_exit; 309 else 310 break; 311 } 312 } 313 if (add) { 314 /* append */ 315 n++; 316 fw_app->protocol_id = cpu_to_be16(app->protocol); 317 fw_app->protocol_selector = app->selector; 318 fw_app->priority = app->priority; 319 fw_app->valid = 1; 320 } else { 321 size_t len = 0; 322 323 /* not found, nothing to delete */ 324 if (n == i) 325 goto set_app_exit; 326 327 len = (n - 1 - i) * sizeof(*fw_app); 328 if (len) 329 memmove(fw_app, fw_app + 1, len); 330 n--; 331 memset(fw_app + n, 0, sizeof(*fw_app)); 332 } 333 data->count = n; 334 data->len = cpu_to_le16(sizeof(*fw_app) * n); 335 data->subtype = cpu_to_le16(HWRM_STRUCT_DATA_SUBTYPE_HOST_OPERATIONAL); 336 337 bnxt_hwrm_cmd_hdr_init(bp, &set, HWRM_FW_SET_STRUCTURED_DATA, -1, -1); 338 set.src_data_addr = cpu_to_le64(mapping); 339 set.data_len = cpu_to_le16(sizeof(*data) + sizeof(*fw_app) * n); 340 set.hdr_cnt = 1; 341 rc = hwrm_send_message(bp, &set, sizeof(set), HWRM_CMD_TIMEOUT); 342 if (rc) 343 rc = -EIO; 344 345 set_app_exit: 346 dma_free_coherent(&bp->pdev->dev, data_len, data, mapping); 347 return rc; 348 } 349 350 static int bnxt_ets_validate(struct bnxt *bp, struct ieee_ets *ets, u8 *tc) 351 { 352 int total_ets_bw = 0; 353 u8 max_tc = 0; 354 int i; 355 356 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { 357 if (ets->prio_tc[i] > bp->max_tc) { 358 netdev_err(bp->dev, "priority to TC mapping exceeds TC count %d\n", 359 ets->prio_tc[i]); 360 return -EINVAL; 361 } 362 if (ets->prio_tc[i] > max_tc) 363 max_tc = ets->prio_tc[i]; 364 365 if ((ets->tc_tx_bw[i] || ets->tc_tsa[i]) && i > bp->max_tc) 366 return -EINVAL; 367 368 switch (ets->tc_tsa[i]) { 369 case IEEE_8021QAZ_TSA_STRICT: 370 break; 371 case IEEE_8021QAZ_TSA_ETS: 372 total_ets_bw += ets->tc_tx_bw[i]; 373 break; 374 default: 375 return -ENOTSUPP; 376 } 377 } 378 if (total_ets_bw > 100) 379 return -EINVAL; 380 381 *tc = max_tc + 1; 382 return 0; 383 } 384 385 static int bnxt_dcbnl_ieee_getets(struct net_device *dev, struct ieee_ets *ets) 386 { 387 struct bnxt *bp = netdev_priv(dev); 388 struct ieee_ets *my_ets = bp->ieee_ets; 389 390 ets->ets_cap = bp->max_tc; 391 392 if (!my_ets) { 393 int rc; 394 395 if (bp->dcbx_cap & DCB_CAP_DCBX_HOST) 396 return 0; 397 398 my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL); 399 if (!my_ets) 400 return 0; 401 rc = bnxt_hwrm_queue_cos2bw_qcfg(bp, my_ets); 402 if (rc) 403 return 0; 404 rc = bnxt_hwrm_queue_pri2cos_qcfg(bp, my_ets); 405 if (rc) 406 return 0; 407 } 408 409 ets->cbs = my_ets->cbs; 410 memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); 411 memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); 412 memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); 413 memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); 414 return 0; 415 } 416 417 static int bnxt_dcbnl_ieee_setets(struct net_device *dev, struct ieee_ets *ets) 418 { 419 struct bnxt *bp = netdev_priv(dev); 420 struct ieee_ets *my_ets = bp->ieee_ets; 421 u8 max_tc = 0; 422 int rc, i; 423 424 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 425 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 426 return -EINVAL; 427 428 rc = bnxt_ets_validate(bp, ets, &max_tc); 429 if (!rc) { 430 if (!my_ets) { 431 my_ets = kzalloc(sizeof(*my_ets), GFP_KERNEL); 432 if (!my_ets) 433 return -ENOMEM; 434 /* initialize PRI2TC mappings to invalid value */ 435 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) 436 my_ets->prio_tc[i] = IEEE_8021QAZ_MAX_TCS; 437 bp->ieee_ets = my_ets; 438 } 439 rc = bnxt_setup_mq_tc(dev, max_tc); 440 if (rc) 441 return rc; 442 rc = bnxt_hwrm_queue_cos2bw_cfg(bp, ets, max_tc); 443 if (rc) 444 return rc; 445 rc = bnxt_hwrm_queue_pri2cos_cfg(bp, ets); 446 if (rc) 447 return rc; 448 memcpy(my_ets, ets, sizeof(*my_ets)); 449 } 450 return rc; 451 } 452 453 static int bnxt_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *pfc) 454 { 455 struct bnxt *bp = netdev_priv(dev); 456 __le64 *stats = (__le64 *)bp->hw_rx_port_stats; 457 struct ieee_pfc *my_pfc = bp->ieee_pfc; 458 long rx_off, tx_off; 459 int i, rc; 460 461 pfc->pfc_cap = bp->max_lltc; 462 463 if (!my_pfc) { 464 if (bp->dcbx_cap & DCB_CAP_DCBX_HOST) 465 return 0; 466 467 my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL); 468 if (!my_pfc) 469 return 0; 470 bp->ieee_pfc = my_pfc; 471 rc = bnxt_hwrm_queue_pfc_qcfg(bp, my_pfc); 472 if (rc) 473 return 0; 474 } 475 476 pfc->pfc_en = my_pfc->pfc_en; 477 pfc->mbc = my_pfc->mbc; 478 pfc->delay = my_pfc->delay; 479 480 if (!stats) 481 return 0; 482 483 rx_off = BNXT_RX_STATS_OFFSET(rx_pfc_ena_frames_pri0); 484 tx_off = BNXT_TX_STATS_OFFSET(tx_pfc_ena_frames_pri0); 485 for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++, rx_off++, tx_off++) { 486 pfc->requests[i] = le64_to_cpu(*(stats + tx_off)); 487 pfc->indications[i] = le64_to_cpu(*(stats + rx_off)); 488 } 489 490 return 0; 491 } 492 493 static int bnxt_dcbnl_ieee_setpfc(struct net_device *dev, struct ieee_pfc *pfc) 494 { 495 struct bnxt *bp = netdev_priv(dev); 496 struct ieee_pfc *my_pfc = bp->ieee_pfc; 497 int rc; 498 499 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 500 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 501 return -EINVAL; 502 503 if (!my_pfc) { 504 my_pfc = kzalloc(sizeof(*my_pfc), GFP_KERNEL); 505 if (!my_pfc) 506 return -ENOMEM; 507 bp->ieee_pfc = my_pfc; 508 } 509 rc = bnxt_hwrm_queue_pfc_cfg(bp, pfc); 510 if (!rc) 511 memcpy(my_pfc, pfc, sizeof(*my_pfc)); 512 513 return rc; 514 } 515 516 static int bnxt_dcbnl_ieee_setapp(struct net_device *dev, struct dcb_app *app) 517 { 518 struct bnxt *bp = netdev_priv(dev); 519 int rc = -EINVAL; 520 521 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 522 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 523 return -EINVAL; 524 525 rc = dcb_ieee_setapp(dev, app); 526 if (rc) 527 return rc; 528 529 if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 530 app->protocol == ETH_P_IBOE) || 531 (app->selector == IEEE_8021QAZ_APP_SEL_DGRAM && 532 app->protocol == ROCE_V2_UDP_DPORT)) 533 rc = bnxt_hwrm_set_dcbx_app(bp, app, true); 534 535 return rc; 536 } 537 538 static int bnxt_dcbnl_ieee_delapp(struct net_device *dev, struct dcb_app *app) 539 { 540 struct bnxt *bp = netdev_priv(dev); 541 int rc; 542 543 if (!(bp->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) || 544 !(bp->dcbx_cap & DCB_CAP_DCBX_HOST)) 545 return -EINVAL; 546 547 rc = dcb_ieee_delapp(dev, app); 548 if (rc) 549 return rc; 550 if ((app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && 551 app->protocol == ETH_P_IBOE) || 552 (app->selector == IEEE_8021QAZ_APP_SEL_DGRAM && 553 app->protocol == ROCE_V2_UDP_DPORT)) 554 rc = bnxt_hwrm_set_dcbx_app(bp, app, false); 555 556 return rc; 557 } 558 559 static u8 bnxt_dcbnl_getdcbx(struct net_device *dev) 560 { 561 struct bnxt *bp = netdev_priv(dev); 562 563 return bp->dcbx_cap; 564 } 565 566 static u8 bnxt_dcbnl_setdcbx(struct net_device *dev, u8 mode) 567 { 568 struct bnxt *bp = netdev_priv(dev); 569 570 /* All firmware DCBX settings are set in NVRAM */ 571 if (bp->dcbx_cap & DCB_CAP_DCBX_LLD_MANAGED) 572 return 1; 573 574 if (mode & DCB_CAP_DCBX_HOST) { 575 if (BNXT_VF(bp) || (bp->flags & BNXT_FLAG_FW_LLDP_AGENT)) 576 return 1; 577 578 /* only support IEEE */ 579 if ((mode & DCB_CAP_DCBX_VER_CEE) || 580 !(mode & DCB_CAP_DCBX_VER_IEEE)) 581 return 1; 582 } 583 584 if (mode == bp->dcbx_cap) 585 return 0; 586 587 bp->dcbx_cap = mode; 588 return 0; 589 } 590 591 static const struct dcbnl_rtnl_ops dcbnl_ops = { 592 .ieee_getets = bnxt_dcbnl_ieee_getets, 593 .ieee_setets = bnxt_dcbnl_ieee_setets, 594 .ieee_getpfc = bnxt_dcbnl_ieee_getpfc, 595 .ieee_setpfc = bnxt_dcbnl_ieee_setpfc, 596 .ieee_setapp = bnxt_dcbnl_ieee_setapp, 597 .ieee_delapp = bnxt_dcbnl_ieee_delapp, 598 .getdcbx = bnxt_dcbnl_getdcbx, 599 .setdcbx = bnxt_dcbnl_setdcbx, 600 }; 601 602 void bnxt_dcb_init(struct bnxt *bp) 603 { 604 if (bp->hwrm_spec_code < 0x10501) 605 return; 606 607 bp->dcbx_cap = DCB_CAP_DCBX_VER_IEEE; 608 if (BNXT_PF(bp) && !(bp->flags & BNXT_FLAG_FW_LLDP_AGENT)) 609 bp->dcbx_cap |= DCB_CAP_DCBX_HOST; 610 else if (bp->flags & BNXT_FLAG_FW_DCBX_AGENT) 611 bp->dcbx_cap |= DCB_CAP_DCBX_LLD_MANAGED; 612 bp->dev->dcbnl_ops = &dcbnl_ops; 613 } 614 615 void bnxt_dcb_free(struct bnxt *bp) 616 { 617 kfree(bp->ieee_pfc); 618 kfree(bp->ieee_ets); 619 bp->ieee_pfc = NULL; 620 bp->ieee_ets = NULL; 621 } 622 623 #else 624 625 void bnxt_dcb_init(struct bnxt *bp) 626 { 627 } 628 629 void bnxt_dcb_free(struct bnxt *bp) 630 { 631 } 632 633 #endif 634