1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2020, the University of Queensland 14 */ 15 16 /* 17 * Mellanox Connect-X 4/5/6 driver. 18 */ 19 20 #include <sys/modctl.h> 21 #include <sys/conf.h> 22 #include <sys/devops.h> 23 #include <sys/sysmacros.h> 24 #include <sys/vlan.h> 25 26 #include <sys/pattr.h> 27 #include <sys/dlpi.h> 28 29 #include <sys/mac_provider.h> 30 31 /* Need these for mac_vlan_header_info() */ 32 #include <sys/mac_client.h> 33 #include <sys/mac_client_priv.h> 34 35 #include <mlxcx.h> 36 37 static char *mlxcx_priv_props[] = { 38 NULL 39 }; 40 41 #define MBITS 1000000ULL 42 #define GBITS (1000ULL * MBITS) 43 44 static uint64_t 45 mlxcx_speed_to_bits(mlxcx_eth_proto_t v) 46 { 47 switch (v) { 48 case MLXCX_PROTO_SGMII_100BASE: 49 return (100ULL * MBITS); 50 case MLXCX_PROTO_SGMII: 51 case MLXCX_PROTO_1000BASE_KX: 52 return (1000ULL * MBITS); 53 case MLXCX_PROTO_10GBASE_CX4: 54 case MLXCX_PROTO_10GBASE_KX4: 55 case MLXCX_PROTO_10GBASE_KR: 56 case MLXCX_PROTO_10GBASE_CR: 57 case MLXCX_PROTO_10GBASE_SR: 58 case MLXCX_PROTO_10GBASE_ER_LR: 59 return (10ULL * GBITS); 60 case MLXCX_PROTO_40GBASE_CR4: 61 case MLXCX_PROTO_40GBASE_KR4: 62 case MLXCX_PROTO_40GBASE_SR4: 63 case MLXCX_PROTO_40GBASE_LR4_ER4: 64 return (40ULL * GBITS); 65 case MLXCX_PROTO_25GBASE_CR: 66 case MLXCX_PROTO_25GBASE_KR: 67 case MLXCX_PROTO_25GBASE_SR: 68 return (25ULL * GBITS); 69 case MLXCX_PROTO_50GBASE_SR2: 70 case MLXCX_PROTO_50GBASE_CR2: 71 case MLXCX_PROTO_50GBASE_KR2: 72 return (50ULL * GBITS); 73 case MLXCX_PROTO_100GBASE_CR4: 74 case MLXCX_PROTO_100GBASE_SR4: 75 case MLXCX_PROTO_100GBASE_KR4: 76 return (100ULL * GBITS); 77 default: 78 return (0); 79 } 80 } 81 82 static int 83 mlxcx_mac_stat_rfc_2863(mlxcx_t *mlxp, mlxcx_port_t *port, uint_t stat, 84 uint64_t *val) 85 { 86 int ret = 0; 87 boolean_t ok; 88 mlxcx_register_data_t data; 89 mlxcx_ppcnt_rfc_2863_t *st; 90 91 ASSERT(mutex_owned(&port->mlp_mtx)); 92 93 bzero(&data, sizeof (data)); 94 data.mlrd_ppcnt.mlrd_ppcnt_local_port = port->mlp_num + 1; 95 data.mlrd_ppcnt.mlrd_ppcnt_grp = MLXCX_PPCNT_GRP_RFC_2863; 96 data.mlrd_ppcnt.mlrd_ppcnt_clear = MLXCX_PPCNT_NO_CLEAR; 97 98 ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ, 99 MLXCX_REG_PPCNT, &data); 100 if (!ok) 101 return (EIO); 102 st = &data.mlrd_ppcnt.mlrd_ppcnt_rfc_2863; 103 104 switch (stat) { 105 case MAC_STAT_RBYTES: 106 *val = from_be64(st->mlppc_rfc_2863_in_octets); 107 break; 108 case MAC_STAT_MULTIRCV: 109 *val = from_be64(st->mlppc_rfc_2863_in_mcast_pkts); 110 break; 111 case MAC_STAT_BRDCSTRCV: 112 *val = from_be64(st->mlppc_rfc_2863_in_bcast_pkts); 113 break; 114 case MAC_STAT_MULTIXMT: 115 *val = from_be64(st->mlppc_rfc_2863_out_mcast_pkts); 116 break; 117 case MAC_STAT_BRDCSTXMT: 118 *val = from_be64(st->mlppc_rfc_2863_out_bcast_pkts); 119 break; 120 case MAC_STAT_IERRORS: 121 *val = from_be64(st->mlppc_rfc_2863_in_errors); 122 break; 123 case MAC_STAT_UNKNOWNS: 124 *val = from_be64(st->mlppc_rfc_2863_in_unknown_protos); 125 break; 126 case MAC_STAT_OERRORS: 127 *val = from_be64(st->mlppc_rfc_2863_out_errors); 128 break; 129 case MAC_STAT_OBYTES: 130 *val = from_be64(st->mlppc_rfc_2863_out_octets); 131 break; 132 default: 133 ret = ENOTSUP; 134 } 135 136 return (ret); 137 } 138 139 static int 140 mlxcx_mac_stat_ieee_802_3(mlxcx_t *mlxp, mlxcx_port_t *port, uint_t stat, 141 uint64_t *val) 142 { 143 int ret = 0; 144 boolean_t ok; 145 mlxcx_register_data_t data; 146 mlxcx_ppcnt_ieee_802_3_t *st; 147 148 ASSERT(mutex_owned(&port->mlp_mtx)); 149 150 bzero(&data, sizeof (data)); 151 data.mlrd_ppcnt.mlrd_ppcnt_local_port = port->mlp_num + 1; 152 data.mlrd_ppcnt.mlrd_ppcnt_grp = MLXCX_PPCNT_GRP_IEEE_802_3; 153 data.mlrd_ppcnt.mlrd_ppcnt_clear = MLXCX_PPCNT_NO_CLEAR; 154 155 ok = mlxcx_cmd_access_register(mlxp, MLXCX_CMD_ACCESS_REGISTER_READ, 156 MLXCX_REG_PPCNT, &data); 157 if (!ok) 158 return (EIO); 159 st = &data.mlrd_ppcnt.mlrd_ppcnt_ieee_802_3; 160 161 switch (stat) { 162 case MAC_STAT_IPACKETS: 163 *val = from_be64(st->mlppc_ieee_802_3_frames_rx); 164 break; 165 case MAC_STAT_OPACKETS: 166 *val = from_be64(st->mlppc_ieee_802_3_frames_tx); 167 break; 168 case ETHER_STAT_ALIGN_ERRORS: 169 *val = from_be64(st->mlppc_ieee_802_3_align_err); 170 break; 171 case ETHER_STAT_FCS_ERRORS: 172 *val = from_be64(st->mlppc_ieee_802_3_fcs_err); 173 break; 174 case ETHER_STAT_TOOLONG_ERRORS: 175 *val = from_be64(st->mlppc_ieee_802_3_frame_too_long_err); 176 break; 177 default: 178 ret = ENOTSUP; 179 } 180 181 return (ret); 182 } 183 184 static int 185 mlxcx_mac_stat(void *arg, uint_t stat, uint64_t *val) 186 { 187 mlxcx_t *mlxp = (mlxcx_t *)arg; 188 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 189 int ret = 0; 190 191 mutex_enter(&port->mlp_mtx); 192 193 switch (stat) { 194 case MAC_STAT_IFSPEED: 195 *val = mlxcx_speed_to_bits(port->mlp_oper_proto); 196 break; 197 case ETHER_STAT_LINK_DUPLEX: 198 *val = LINK_DUPLEX_FULL; 199 break; 200 case MAC_STAT_RBYTES: 201 case MAC_STAT_MULTIRCV: 202 case MAC_STAT_BRDCSTRCV: 203 case MAC_STAT_MULTIXMT: 204 case MAC_STAT_BRDCSTXMT: 205 case MAC_STAT_IERRORS: 206 case MAC_STAT_UNKNOWNS: 207 case MAC_STAT_OERRORS: 208 case MAC_STAT_OBYTES: 209 ret = mlxcx_mac_stat_rfc_2863(mlxp, port, stat, val); 210 break; 211 case MAC_STAT_IPACKETS: 212 case MAC_STAT_OPACKETS: 213 case ETHER_STAT_ALIGN_ERRORS: 214 case ETHER_STAT_FCS_ERRORS: 215 case ETHER_STAT_TOOLONG_ERRORS: 216 ret = mlxcx_mac_stat_ieee_802_3(mlxp, port, stat, val); 217 break; 218 case MAC_STAT_NORCVBUF: 219 *val = port->mlp_stats.mlps_rx_drops; 220 break; 221 default: 222 ret = ENOTSUP; 223 } 224 225 mutex_exit(&port->mlp_mtx); 226 227 return (ret); 228 } 229 230 static int 231 mlxcx_mac_led_set(void *arg, mac_led_mode_t mode, uint_t flags) 232 { 233 mlxcx_t *mlxp = arg; 234 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 235 int ret = 0; 236 237 if (flags != 0) { 238 return (EINVAL); 239 } 240 241 mutex_enter(&port->mlp_mtx); 242 243 switch (mode) { 244 case MAC_LED_DEFAULT: 245 case MAC_LED_OFF: 246 if (!mlxcx_cmd_set_port_led(mlxp, port, 0)) { 247 ret = EIO; 248 break; 249 } 250 break; 251 case MAC_LED_IDENT: 252 if (!mlxcx_cmd_set_port_led(mlxp, port, UINT16_MAX)) { 253 ret = EIO; 254 break; 255 } 256 break; 257 default: 258 ret = ENOTSUP; 259 } 260 261 mutex_exit(&port->mlp_mtx); 262 263 return (ret); 264 } 265 266 static int 267 mlxcx_mac_txr_info(void *arg, uint_t id, mac_transceiver_info_t *infop) 268 { 269 mlxcx_t *mlxp = arg; 270 mlxcx_module_status_t st; 271 272 if (!mlxcx_cmd_query_module_status(mlxp, id, &st, NULL)) 273 return (EIO); 274 275 if (st != MLXCX_MODULE_UNPLUGGED) 276 mac_transceiver_info_set_present(infop, B_TRUE); 277 278 if (st == MLXCX_MODULE_PLUGGED) 279 mac_transceiver_info_set_usable(infop, B_TRUE); 280 281 return (0); 282 } 283 284 static int 285 mlxcx_mac_txr_read(void *arg, uint_t id, uint_t page, void *vbuf, 286 size_t nbytes, off_t offset, size_t *nread) 287 { 288 mlxcx_t *mlxp = arg; 289 mlxcx_register_data_t data; 290 uint8_t *buf = vbuf; 291 boolean_t ok; 292 size_t take, done = 0; 293 uint8_t i2c_addr; 294 295 if (id != 0 || vbuf == NULL || nbytes == 0 || nread == NULL) 296 return (EINVAL); 297 298 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) 299 return (EINVAL); 300 301 /* 302 * The PRM is really not very clear about any of this, but it seems 303 * that the i2c_device_addr field in MCIA is the SFP+ spec "page" 304 * number shifted right by 1 bit. They're written in the SFF spec 305 * like "1010000X" so Mellanox just dropped the X. 306 * 307 * This means that if we want page 0xA0, we put 0x50 in the 308 * i2c_device_addr field. 309 * 310 * The "page_number" field in MCIA means something else. Don't ask me 311 * what. FreeBSD leaves it as zero, so we will too! 312 */ 313 i2c_addr = page >> 1; 314 315 while (done < nbytes) { 316 take = nbytes - done; 317 if (take > sizeof (data.mlrd_mcia.mlrd_mcia_data)) 318 take = sizeof (data.mlrd_mcia.mlrd_mcia_data); 319 320 bzero(&data, sizeof (data)); 321 ASSERT3U(id, <=, 0xff); 322 data.mlrd_mcia.mlrd_mcia_module = (uint8_t)id; 323 data.mlrd_mcia.mlrd_mcia_i2c_device_addr = i2c_addr; 324 data.mlrd_mcia.mlrd_mcia_device_addr = to_be16(offset); 325 data.mlrd_mcia.mlrd_mcia_size = to_be16(take); 326 327 ok = mlxcx_cmd_access_register(mlxp, 328 MLXCX_CMD_ACCESS_REGISTER_READ, MLXCX_REG_MCIA, &data); 329 if (!ok) { 330 *nread = 0; 331 return (EIO); 332 } 333 334 if (data.mlrd_mcia.mlrd_mcia_status != MLXCX_MCIA_STATUS_OK) { 335 *nread = 0; 336 return (EIO); 337 } 338 339 bcopy(data.mlrd_mcia.mlrd_mcia_data, &buf[done], take); 340 341 done += take; 342 offset += take; 343 } 344 *nread = done; 345 return (0); 346 } 347 348 static int 349 mlxcx_mac_ring_stat(mac_ring_driver_t rh, uint_t stat, uint64_t *val) 350 { 351 mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)rh; 352 (void) wq; 353 354 /* 355 * We should add support for using hw flow counters and such to 356 * get per-ring statistics. Not done yet though! 357 */ 358 359 switch (stat) { 360 default: 361 *val = 0; 362 return (ENOTSUP); 363 } 364 365 return (0); 366 } 367 368 static int 369 mlxcx_mac_start(void *arg) 370 { 371 mlxcx_t *mlxp = (mlxcx_t *)arg; 372 (void) mlxp; 373 return (0); 374 } 375 376 static void 377 mlxcx_mac_stop(void *arg) 378 { 379 mlxcx_t *mlxp = (mlxcx_t *)arg; 380 (void) mlxp; 381 } 382 383 static mblk_t * 384 mlxcx_mac_ring_tx(void *arg, mblk_t *mp) 385 { 386 mlxcx_work_queue_t *sq = (mlxcx_work_queue_t *)arg; 387 mlxcx_t *mlxp = sq->mlwq_mlx; 388 mlxcx_completion_queue_t *cq; 389 mlxcx_buffer_t *b; 390 mac_header_info_t mhi; 391 mblk_t *kmp, *nmp; 392 uint8_t inline_hdrs[MLXCX_MAX_INLINE_HEADERLEN]; 393 size_t inline_hdrlen, rem, off; 394 uint32_t chkflags = 0; 395 boolean_t ok; 396 size_t take = 0; 397 398 VERIFY(mp->b_next == NULL); 399 400 mac_hcksum_get(mp, NULL, NULL, NULL, NULL, &chkflags); 401 402 if (mac_vlan_header_info(mlxp->mlx_mac_hdl, mp, &mhi) != 0) { 403 /* 404 * We got given a frame without a valid L2 header on it. We 405 * can't really transmit that (mlx parts don't like it), so 406 * we will just drop it on the floor. 407 */ 408 freemsg(mp); 409 return (NULL); 410 } 411 412 inline_hdrlen = rem = mhi.mhi_hdrsize; 413 414 kmp = mp; 415 off = 0; 416 while (rem > 0) { 417 const ptrdiff_t sz = MBLKL(kmp); 418 ASSERT3S(sz, >=, 0); 419 ASSERT3U(sz, <=, SIZE_MAX); 420 take = sz; 421 if (take > rem) 422 take = rem; 423 bcopy(kmp->b_rptr, inline_hdrs + off, take); 424 rem -= take; 425 off += take; 426 if (take == sz) { 427 take = 0; 428 kmp = kmp->b_cont; 429 } 430 } 431 432 if (!mlxcx_buf_bind_or_copy(mlxp, sq, kmp, take, &b)) { 433 /* 434 * Something went really wrong, and we probably will never be 435 * able to TX again (all our buffers are broken and DMA is 436 * failing). Drop the packet on the floor -- FMA should be 437 * reporting this error elsewhere. 438 */ 439 freemsg(mp); 440 return (NULL); 441 } 442 443 mutex_enter(&sq->mlwq_mtx); 444 VERIFY3U(sq->mlwq_inline_mode, <=, MLXCX_ETH_INLINE_L2); 445 cq = sq->mlwq_cq; 446 447 /* 448 * state is a single int, so read-only access without the CQ lock 449 * should be fine. 450 */ 451 if (cq->mlcq_state & MLXCX_CQ_TEARDOWN) { 452 mutex_exit(&sq->mlwq_mtx); 453 mlxcx_buf_return_chain(mlxp, b, B_FALSE); 454 return (NULL); 455 } 456 457 if (sq->mlwq_state & MLXCX_WQ_TEARDOWN) { 458 mutex_exit(&sq->mlwq_mtx); 459 mlxcx_buf_return_chain(mlxp, b, B_FALSE); 460 return (NULL); 461 } 462 463 /* 464 * Similar logic here: bufcnt is only manipulated atomically, and 465 * bufhwm is set at startup. 466 */ 467 if (cq->mlcq_bufcnt >= cq->mlcq_bufhwm) { 468 atomic_or_uint(&cq->mlcq_state, MLXCX_CQ_BLOCKED_MAC); 469 mutex_exit(&sq->mlwq_mtx); 470 mlxcx_buf_return_chain(mlxp, b, B_TRUE); 471 return (mp); 472 } 473 474 ok = mlxcx_sq_add_buffer(mlxp, sq, inline_hdrs, inline_hdrlen, 475 chkflags, b); 476 if (!ok) { 477 atomic_or_uint(&cq->mlcq_state, MLXCX_CQ_BLOCKED_MAC); 478 mutex_exit(&sq->mlwq_mtx); 479 mlxcx_buf_return_chain(mlxp, b, B_TRUE); 480 return (mp); 481 } 482 483 /* 484 * Now that we've successfully enqueued the rest of the packet, 485 * free any mblks that we cut off while inlining headers. 486 */ 487 for (; mp != kmp; mp = nmp) { 488 nmp = mp->b_cont; 489 freeb(mp); 490 } 491 492 mutex_exit(&sq->mlwq_mtx); 493 494 return (NULL); 495 } 496 497 static int 498 mlxcx_mac_setpromisc(void *arg, boolean_t on) 499 { 500 mlxcx_t *mlxp = (mlxcx_t *)arg; 501 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 502 mlxcx_flow_group_t *fg; 503 mlxcx_flow_entry_t *fe; 504 mlxcx_flow_table_t *ft; 505 mlxcx_ring_group_t *g; 506 int ret = 0; 507 uint_t idx; 508 509 mutex_enter(&port->mlp_mtx); 510 511 /* 512 * First, do the top-level flow entry on the root flow table for 513 * the port. This catches all traffic that doesn't match any MAC 514 * MAC filters. 515 */ 516 ft = port->mlp_rx_flow; 517 mutex_enter(&ft->mlft_mtx); 518 fg = port->mlp_promisc; 519 fe = list_head(&fg->mlfg_entries); 520 if (on && !(fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) { 521 if (!mlxcx_cmd_set_flow_table_entry(mlxp, fe)) { 522 ret = EIO; 523 } 524 } else if (!on && (fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) { 525 if (!mlxcx_cmd_delete_flow_table_entry(mlxp, fe)) { 526 ret = EIO; 527 } 528 } 529 mutex_exit(&ft->mlft_mtx); 530 531 /* 532 * If we failed to change the top-level entry, don't bother with 533 * trying the per-group ones. 534 */ 535 if (ret != 0) { 536 mutex_exit(&port->mlp_mtx); 537 return (ret); 538 } 539 540 /* 541 * Then, do the per-rx-group flow entries which catch traffic that 542 * matched a MAC filter but failed to match a VLAN filter. 543 */ 544 for (idx = 0; idx < mlxp->mlx_rx_ngroups; ++idx) { 545 g = &mlxp->mlx_rx_groups[idx]; 546 547 mutex_enter(&g->mlg_mtx); 548 549 ft = g->mlg_rx_vlan_ft; 550 mutex_enter(&ft->mlft_mtx); 551 552 fg = g->mlg_rx_vlan_promisc_fg; 553 fe = list_head(&fg->mlfg_entries); 554 if (on && !(fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) { 555 if (!mlxcx_cmd_set_flow_table_entry(mlxp, fe)) { 556 ret = EIO; 557 } 558 } else if (!on && (fe->mlfe_state & MLXCX_FLOW_ENTRY_CREATED)) { 559 if (!mlxcx_cmd_delete_flow_table_entry(mlxp, fe)) { 560 ret = EIO; 561 } 562 } 563 564 mutex_exit(&ft->mlft_mtx); 565 mutex_exit(&g->mlg_mtx); 566 } 567 568 mutex_exit(&port->mlp_mtx); 569 return (ret); 570 } 571 572 static int 573 mlxcx_mac_multicast(void *arg, boolean_t add, const uint8_t *addr) 574 { 575 mlxcx_t *mlxp = (mlxcx_t *)arg; 576 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 577 mlxcx_ring_group_t *g = &mlxp->mlx_rx_groups[0]; 578 int ret = 0; 579 580 mutex_enter(&port->mlp_mtx); 581 mutex_enter(&g->mlg_mtx); 582 if (add) { 583 if (!mlxcx_add_umcast_entry(mlxp, port, g, addr)) { 584 ret = EIO; 585 } 586 } else { 587 if (!mlxcx_remove_umcast_entry(mlxp, port, g, addr)) { 588 ret = EIO; 589 } 590 } 591 mutex_exit(&g->mlg_mtx); 592 mutex_exit(&port->mlp_mtx); 593 return (ret); 594 } 595 596 static int 597 mlxcx_group_add_mac(void *arg, const uint8_t *mac_addr) 598 { 599 mlxcx_ring_group_t *g = arg; 600 mlxcx_t *mlxp = g->mlg_mlx; 601 mlxcx_port_t *port = g->mlg_port; 602 int ret = 0; 603 604 mutex_enter(&port->mlp_mtx); 605 mutex_enter(&g->mlg_mtx); 606 if (!mlxcx_add_umcast_entry(mlxp, port, g, mac_addr)) { 607 ret = EIO; 608 } 609 mutex_exit(&g->mlg_mtx); 610 mutex_exit(&port->mlp_mtx); 611 612 return (ret); 613 } 614 615 /* 616 * Support for VLAN steering into groups is not yet available in upstream 617 * illumos. 618 */ 619 #if defined(MAC_VLAN_UNTAGGED) 620 621 static int 622 mlxcx_group_add_vlan(mac_group_driver_t gh, uint16_t vid) 623 { 624 mlxcx_ring_group_t *g = (mlxcx_ring_group_t *)gh; 625 mlxcx_t *mlxp = g->mlg_mlx; 626 int ret = 0; 627 boolean_t tagged = B_TRUE; 628 629 if (vid == MAC_VLAN_UNTAGGED) { 630 vid = 0; 631 tagged = B_FALSE; 632 } 633 634 mutex_enter(&g->mlg_mtx); 635 if (!mlxcx_add_vlan_entry(mlxp, g, tagged, vid)) { 636 ret = EIO; 637 } 638 mutex_exit(&g->mlg_mtx); 639 640 return (ret); 641 } 642 643 static int 644 mlxcx_group_remove_vlan(mac_group_driver_t gh, uint16_t vid) 645 { 646 mlxcx_ring_group_t *g = (mlxcx_ring_group_t *)gh; 647 mlxcx_t *mlxp = g->mlg_mlx; 648 int ret = 0; 649 boolean_t tagged = B_TRUE; 650 651 if (vid == MAC_VLAN_UNTAGGED) { 652 vid = 0; 653 tagged = B_FALSE; 654 } 655 656 mutex_enter(&g->mlg_mtx); 657 if (!mlxcx_remove_vlan_entry(mlxp, g, tagged, vid)) { 658 ret = EIO; 659 } 660 mutex_exit(&g->mlg_mtx); 661 662 return (ret); 663 } 664 665 #endif /* MAC_VLAN_UNTAGGED */ 666 667 static int 668 mlxcx_group_remove_mac(void *arg, const uint8_t *mac_addr) 669 { 670 mlxcx_ring_group_t *g = arg; 671 mlxcx_t *mlxp = g->mlg_mlx; 672 mlxcx_port_t *port = g->mlg_port; 673 int ret = 0; 674 675 mutex_enter(&port->mlp_mtx); 676 mutex_enter(&g->mlg_mtx); 677 if (!mlxcx_remove_umcast_entry(mlxp, port, g, mac_addr)) { 678 ret = EIO; 679 } 680 mutex_exit(&g->mlg_mtx); 681 mutex_exit(&port->mlp_mtx); 682 683 return (ret); 684 } 685 686 static int 687 mlxcx_mac_ring_start(mac_ring_driver_t rh, uint64_t gen_num) 688 { 689 mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)rh; 690 mlxcx_completion_queue_t *cq = wq->mlwq_cq; 691 mlxcx_ring_group_t *g = wq->mlwq_group; 692 mlxcx_t *mlxp = wq->mlwq_mlx; 693 694 ASSERT(cq != NULL); 695 ASSERT(g != NULL); 696 697 ASSERT(wq->mlwq_type == MLXCX_WQ_TYPE_SENDQ || 698 wq->mlwq_type == MLXCX_WQ_TYPE_RECVQ); 699 if (wq->mlwq_type == MLXCX_WQ_TYPE_SENDQ && 700 !mlxcx_tx_ring_start(mlxp, g, wq)) 701 return (EIO); 702 if (wq->mlwq_type == MLXCX_WQ_TYPE_RECVQ && 703 !mlxcx_rx_ring_start(mlxp, g, wq)) 704 return (EIO); 705 706 mutex_enter(&cq->mlcq_mtx); 707 cq->mlcq_mac_gen = gen_num; 708 mutex_exit(&cq->mlcq_mtx); 709 710 return (0); 711 } 712 713 static void 714 mlxcx_mac_ring_stop(mac_ring_driver_t rh) 715 { 716 mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)rh; 717 mlxcx_completion_queue_t *cq = wq->mlwq_cq; 718 mlxcx_t *mlxp = wq->mlwq_mlx; 719 mlxcx_buf_shard_t *s; 720 mlxcx_buffer_t *buf; 721 722 mutex_enter(&cq->mlcq_mtx); 723 mutex_enter(&wq->mlwq_mtx); 724 if (wq->mlwq_state & MLXCX_WQ_STARTED) { 725 if (wq->mlwq_type == MLXCX_WQ_TYPE_RECVQ && 726 !mlxcx_cmd_stop_rq(mlxp, wq)) { 727 mutex_exit(&wq->mlwq_mtx); 728 mutex_exit(&cq->mlcq_mtx); 729 return; 730 } 731 if (wq->mlwq_type == MLXCX_WQ_TYPE_SENDQ && 732 !mlxcx_cmd_stop_sq(mlxp, wq)) { 733 mutex_exit(&wq->mlwq_mtx); 734 mutex_exit(&cq->mlcq_mtx); 735 return; 736 } 737 } 738 ASSERT0(wq->mlwq_state & MLXCX_WQ_STARTED); 739 740 if (wq->mlwq_state & MLXCX_WQ_BUFFERS) { 741 /* Return any outstanding buffers to the free pool. */ 742 while ((buf = list_remove_head(&cq->mlcq_buffers)) != NULL) { 743 mlxcx_buf_return_chain(mlxp, buf, B_FALSE); 744 } 745 mutex_enter(&cq->mlcq_bufbmtx); 746 while ((buf = list_remove_head(&cq->mlcq_buffers_b)) != NULL) { 747 mlxcx_buf_return_chain(mlxp, buf, B_FALSE); 748 } 749 mutex_exit(&cq->mlcq_bufbmtx); 750 cq->mlcq_bufcnt = 0; 751 752 s = wq->mlwq_bufs; 753 mutex_enter(&s->mlbs_mtx); 754 while (!list_is_empty(&s->mlbs_busy)) 755 cv_wait(&s->mlbs_free_nonempty, &s->mlbs_mtx); 756 while ((buf = list_head(&s->mlbs_free)) != NULL) { 757 mlxcx_buf_destroy(mlxp, buf); 758 } 759 mutex_exit(&s->mlbs_mtx); 760 761 s = wq->mlwq_foreign_bufs; 762 if (s != NULL) { 763 mutex_enter(&s->mlbs_mtx); 764 while (!list_is_empty(&s->mlbs_busy)) 765 cv_wait(&s->mlbs_free_nonempty, &s->mlbs_mtx); 766 while ((buf = list_head(&s->mlbs_free)) != NULL) { 767 mlxcx_buf_destroy(mlxp, buf); 768 } 769 mutex_exit(&s->mlbs_mtx); 770 } 771 772 wq->mlwq_state &= ~MLXCX_WQ_BUFFERS; 773 } 774 ASSERT0(wq->mlwq_state & MLXCX_WQ_BUFFERS); 775 776 mutex_exit(&wq->mlwq_mtx); 777 mutex_exit(&cq->mlcq_mtx); 778 } 779 780 static int 781 mlxcx_mac_group_start(mac_group_driver_t gh) 782 { 783 mlxcx_ring_group_t *g = (mlxcx_ring_group_t *)gh; 784 mlxcx_t *mlxp = g->mlg_mlx; 785 786 VERIFY3S(g->mlg_type, ==, MLXCX_GROUP_RX); 787 ASSERT(mlxp != NULL); 788 789 if (g->mlg_state & MLXCX_GROUP_RUNNING) 790 return (0); 791 792 if (!mlxcx_rx_group_start(mlxp, g)) 793 return (EIO); 794 795 return (0); 796 } 797 798 static void 799 mlxcx_mac_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index, 800 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 801 { 802 mlxcx_t *mlxp = (mlxcx_t *)arg; 803 mlxcx_ring_group_t *g; 804 mlxcx_work_queue_t *wq; 805 mac_intr_t *mintr = &infop->mri_intr; 806 807 if (rtype != MAC_RING_TYPE_TX) 808 return; 809 ASSERT3S(group_index, ==, -1); 810 811 g = &mlxp->mlx_tx_groups[0]; 812 ASSERT(g->mlg_state & MLXCX_GROUP_INIT); 813 mutex_enter(&g->mlg_mtx); 814 815 ASSERT3S(ring_index, >=, 0); 816 ASSERT3S(ring_index, <, g->mlg_nwqs); 817 818 wq = &g->mlg_wqs[ring_index]; 819 820 wq->mlwq_cq->mlcq_mac_hdl = rh; 821 822 infop->mri_driver = (mac_ring_driver_t)wq; 823 infop->mri_start = mlxcx_mac_ring_start; 824 infop->mri_stop = mlxcx_mac_ring_stop; 825 infop->mri_tx = mlxcx_mac_ring_tx; 826 infop->mri_stat = mlxcx_mac_ring_stat; 827 828 mintr->mi_ddi_handle = mlxp->mlx_intr_handles[ 829 wq->mlwq_cq->mlcq_eq->mleq_intr_index]; 830 831 mutex_exit(&g->mlg_mtx); 832 } 833 834 static int 835 mlxcx_mac_ring_intr_enable(mac_intr_handle_t intrh) 836 { 837 mlxcx_completion_queue_t *cq = (mlxcx_completion_queue_t *)intrh; 838 mlxcx_event_queue_t *eq = cq->mlcq_eq; 839 mlxcx_t *mlxp = cq->mlcq_mlx; 840 841 /* 842 * We are going to call mlxcx_arm_cq() here, so we take the EQ lock 843 * as well as the CQ one to make sure we don't race against 844 * mlxcx_intr_n(). 845 */ 846 mutex_enter(&eq->mleq_mtx); 847 mutex_enter(&cq->mlcq_mtx); 848 if (cq->mlcq_state & MLXCX_CQ_POLLING) { 849 cq->mlcq_state &= ~MLXCX_CQ_POLLING; 850 if (!(cq->mlcq_state & MLXCX_CQ_ARMED)) 851 mlxcx_arm_cq(mlxp, cq); 852 } 853 mutex_exit(&cq->mlcq_mtx); 854 mutex_exit(&eq->mleq_mtx); 855 856 return (0); 857 } 858 859 static int 860 mlxcx_mac_ring_intr_disable(mac_intr_handle_t intrh) 861 { 862 mlxcx_completion_queue_t *cq = (mlxcx_completion_queue_t *)intrh; 863 864 atomic_or_uint(&cq->mlcq_state, MLXCX_CQ_POLLING); 865 mutex_enter(&cq->mlcq_mtx); 866 VERIFY(cq->mlcq_state & MLXCX_CQ_POLLING); 867 mutex_exit(&cq->mlcq_mtx); 868 869 return (0); 870 } 871 872 static mblk_t * 873 mlxcx_mac_ring_rx_poll(void *arg, int poll_bytes) 874 { 875 mlxcx_work_queue_t *wq = (mlxcx_work_queue_t *)arg; 876 mlxcx_completion_queue_t *cq = wq->mlwq_cq; 877 mlxcx_t *mlxp = wq->mlwq_mlx; 878 mblk_t *mp; 879 880 ASSERT(cq != NULL); 881 ASSERT3S(poll_bytes, >, 0); 882 if (poll_bytes == 0) 883 return (NULL); 884 885 mutex_enter(&cq->mlcq_mtx); 886 mp = mlxcx_rx_poll(mlxp, cq, poll_bytes); 887 mutex_exit(&cq->mlcq_mtx); 888 889 return (mp); 890 } 891 892 static void 893 mlxcx_mac_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index, 894 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 895 { 896 mlxcx_t *mlxp = (mlxcx_t *)arg; 897 mlxcx_ring_group_t *g; 898 mlxcx_work_queue_t *wq; 899 mac_intr_t *mintr = &infop->mri_intr; 900 901 if (rtype != MAC_RING_TYPE_RX) 902 return; 903 ASSERT3S(group_index, >=, 0); 904 ASSERT3S(group_index, <, mlxp->mlx_rx_ngroups); 905 906 g = &mlxp->mlx_rx_groups[group_index]; 907 ASSERT(g->mlg_state & MLXCX_GROUP_INIT); 908 mutex_enter(&g->mlg_mtx); 909 910 ASSERT3S(ring_index, >=, 0); 911 ASSERT3S(ring_index, <, g->mlg_nwqs); 912 913 ASSERT(g->mlg_state & MLXCX_GROUP_WQS); 914 wq = &g->mlg_wqs[ring_index]; 915 916 wq->mlwq_cq->mlcq_mac_hdl = rh; 917 918 infop->mri_driver = (mac_ring_driver_t)wq; 919 infop->mri_start = mlxcx_mac_ring_start; 920 infop->mri_stop = mlxcx_mac_ring_stop; 921 infop->mri_poll = mlxcx_mac_ring_rx_poll; 922 infop->mri_stat = mlxcx_mac_ring_stat; 923 924 mintr->mi_handle = (mac_intr_handle_t)wq->mlwq_cq; 925 mintr->mi_enable = mlxcx_mac_ring_intr_enable; 926 mintr->mi_disable = mlxcx_mac_ring_intr_disable; 927 928 mintr->mi_ddi_handle = mlxp->mlx_intr_handles[ 929 wq->mlwq_cq->mlcq_eq->mleq_intr_index]; 930 931 mutex_exit(&g->mlg_mtx); 932 } 933 934 static void 935 mlxcx_mac_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index, 936 mac_group_info_t *infop, mac_group_handle_t gh) 937 { 938 mlxcx_t *mlxp = (mlxcx_t *)arg; 939 mlxcx_ring_group_t *g; 940 941 if (rtype != MAC_RING_TYPE_RX) 942 return; 943 944 ASSERT3S(index, >=, 0); 945 ASSERT3S(index, <, mlxp->mlx_rx_ngroups); 946 g = &mlxp->mlx_rx_groups[index]; 947 ASSERT(g->mlg_state & MLXCX_GROUP_INIT); 948 949 g->mlg_mac_hdl = gh; 950 951 infop->mgi_driver = (mac_group_driver_t)g; 952 infop->mgi_start = mlxcx_mac_group_start; 953 infop->mgi_stop = NULL; 954 infop->mgi_addmac = mlxcx_group_add_mac; 955 infop->mgi_remmac = mlxcx_group_remove_mac; 956 #if defined(MAC_VLAN_UNTAGGED) 957 infop->mgi_addvlan = mlxcx_group_add_vlan; 958 infop->mgi_remvlan = mlxcx_group_remove_vlan; 959 #endif /* MAC_VLAN_UNTAGGED */ 960 961 infop->mgi_count = g->mlg_nwqs; 962 } 963 964 static boolean_t 965 mlxcx_mac_getcapab(void *arg, mac_capab_t cap, void *cap_data) 966 { 967 mlxcx_t *mlxp = (mlxcx_t *)arg; 968 mac_capab_rings_t *cap_rings; 969 mac_capab_led_t *cap_leds; 970 mac_capab_transceiver_t *cap_txr; 971 uint_t i, n = 0; 972 973 switch (cap) { 974 975 case MAC_CAPAB_RINGS: 976 cap_rings = cap_data; 977 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 978 switch (cap_rings->mr_type) { 979 case MAC_RING_TYPE_TX: 980 cap_rings->mr_gnum = 0; 981 cap_rings->mr_rnum = mlxp->mlx_tx_groups[0].mlg_nwqs; 982 cap_rings->mr_rget = mlxcx_mac_fill_tx_ring; 983 cap_rings->mr_gget = NULL; 984 cap_rings->mr_gaddring = NULL; 985 cap_rings->mr_gremring = NULL; 986 break; 987 case MAC_RING_TYPE_RX: 988 cap_rings->mr_gnum = mlxp->mlx_rx_ngroups; 989 for (i = 0; i < mlxp->mlx_rx_ngroups; ++i) 990 n += mlxp->mlx_rx_groups[i].mlg_nwqs; 991 cap_rings->mr_rnum = n; 992 cap_rings->mr_rget = mlxcx_mac_fill_rx_ring; 993 cap_rings->mr_gget = mlxcx_mac_fill_rx_group; 994 cap_rings->mr_gaddring = NULL; 995 cap_rings->mr_gremring = NULL; 996 break; 997 default: 998 return (B_FALSE); 999 } 1000 break; 1001 1002 case MAC_CAPAB_HCKSUM: 1003 if (mlxp->mlx_caps->mlc_checksum) { 1004 *(uint32_t *)cap_data = HCKSUM_INET_FULL_V4 | 1005 HCKSUM_INET_FULL_V6 | HCKSUM_IPHDRCKSUM; 1006 } 1007 break; 1008 1009 case MAC_CAPAB_LED: 1010 cap_leds = cap_data; 1011 1012 cap_leds->mcl_flags = 0; 1013 cap_leds->mcl_modes = MAC_LED_DEFAULT | MAC_LED_OFF | 1014 MAC_LED_IDENT; 1015 cap_leds->mcl_set = mlxcx_mac_led_set; 1016 break; 1017 1018 case MAC_CAPAB_TRANSCEIVER: 1019 cap_txr = cap_data; 1020 1021 cap_txr->mct_flags = 0; 1022 cap_txr->mct_ntransceivers = 1; 1023 cap_txr->mct_info = mlxcx_mac_txr_info; 1024 cap_txr->mct_read = mlxcx_mac_txr_read; 1025 break; 1026 1027 default: 1028 return (B_FALSE); 1029 } 1030 1031 return (B_TRUE); 1032 } 1033 1034 static void 1035 mlxcx_mac_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1036 mac_prop_info_handle_t prh) 1037 { 1038 mlxcx_t *mlxp = (mlxcx_t *)arg; 1039 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 1040 1041 mutex_enter(&port->mlp_mtx); 1042 1043 switch (pr_num) { 1044 case MAC_PROP_DUPLEX: 1045 case MAC_PROP_SPEED: 1046 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1047 break; 1048 case MAC_PROP_MTU: 1049 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 1050 mac_prop_info_set_range_uint32(prh, MLXCX_MTU_OFFSET, 1051 port->mlp_max_mtu); 1052 mac_prop_info_set_default_uint32(prh, 1053 port->mlp_mtu - MLXCX_MTU_OFFSET); 1054 break; 1055 case MAC_PROP_AUTONEG: 1056 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1057 mac_prop_info_set_default_uint8(prh, 1); 1058 break; 1059 default: 1060 break; 1061 } 1062 1063 mutex_exit(&port->mlp_mtx); 1064 } 1065 1066 static int 1067 mlxcx_mac_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1068 uint_t pr_valsize, const void *pr_val) 1069 { 1070 mlxcx_t *mlxp = (mlxcx_t *)arg; 1071 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 1072 int ret = 0; 1073 uint32_t new_mtu, new_hw_mtu, old_mtu; 1074 mlxcx_buf_shard_t *sh; 1075 boolean_t allocd = B_FALSE; 1076 1077 mutex_enter(&port->mlp_mtx); 1078 1079 switch (pr_num) { 1080 case MAC_PROP_MTU: 1081 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 1082 new_hw_mtu = new_mtu + MLXCX_MTU_OFFSET; 1083 if (new_hw_mtu == port->mlp_mtu) 1084 break; 1085 if (new_hw_mtu > port->mlp_max_mtu) { 1086 ret = EINVAL; 1087 break; 1088 } 1089 sh = list_head(&mlxp->mlx_buf_shards); 1090 for (; sh != NULL; sh = list_next(&mlxp->mlx_buf_shards, sh)) { 1091 mutex_enter(&sh->mlbs_mtx); 1092 if (!list_is_empty(&sh->mlbs_free) || 1093 !list_is_empty(&sh->mlbs_busy)) { 1094 allocd = B_TRUE; 1095 mutex_exit(&sh->mlbs_mtx); 1096 break; 1097 } 1098 mutex_exit(&sh->mlbs_mtx); 1099 } 1100 if (allocd) { 1101 ret = EBUSY; 1102 break; 1103 } 1104 old_mtu = port->mlp_mtu; 1105 ret = mac_maxsdu_update(mlxp->mlx_mac_hdl, new_mtu); 1106 if (ret != 0) 1107 break; 1108 port->mlp_mtu = new_hw_mtu; 1109 if (!mlxcx_cmd_modify_nic_vport_ctx(mlxp, port, 1110 MLXCX_MODIFY_NIC_VPORT_CTX_MTU)) { 1111 port->mlp_mtu = old_mtu; 1112 (void) mac_maxsdu_update(mlxp->mlx_mac_hdl, old_mtu); 1113 ret = EIO; 1114 break; 1115 } 1116 if (!mlxcx_cmd_set_port_mtu(mlxp, port)) { 1117 port->mlp_mtu = old_mtu; 1118 (void) mac_maxsdu_update(mlxp->mlx_mac_hdl, old_mtu); 1119 ret = EIO; 1120 break; 1121 } 1122 break; 1123 default: 1124 ret = ENOTSUP; 1125 break; 1126 } 1127 1128 mutex_exit(&port->mlp_mtx); 1129 1130 return (ret); 1131 } 1132 1133 static int 1134 mlxcx_mac_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1135 uint_t pr_valsize, void *pr_val) 1136 { 1137 mlxcx_t *mlxp = (mlxcx_t *)arg; 1138 mlxcx_port_t *port = &mlxp->mlx_ports[0]; 1139 uint64_t speed; 1140 int ret = 0; 1141 1142 mutex_enter(&port->mlp_mtx); 1143 1144 switch (pr_num) { 1145 case MAC_PROP_DUPLEX: 1146 if (pr_valsize < sizeof (link_duplex_t)) { 1147 ret = EOVERFLOW; 1148 break; 1149 } 1150 /* connectx parts only support full duplex */ 1151 *(link_duplex_t *)pr_val = LINK_DUPLEX_FULL; 1152 break; 1153 case MAC_PROP_SPEED: 1154 if (pr_valsize < sizeof (uint64_t)) { 1155 ret = EOVERFLOW; 1156 break; 1157 } 1158 speed = mlxcx_speed_to_bits(port->mlp_oper_proto); 1159 bcopy(&speed, pr_val, sizeof (speed)); 1160 break; 1161 case MAC_PROP_STATUS: 1162 if (pr_valsize < sizeof (link_state_t)) { 1163 ret = EOVERFLOW; 1164 break; 1165 } 1166 switch (port->mlp_oper_status) { 1167 case MLXCX_PORT_STATUS_UP: 1168 case MLXCX_PORT_STATUS_UP_ONCE: 1169 *(link_state_t *)pr_val = LINK_STATE_UP; 1170 break; 1171 case MLXCX_PORT_STATUS_DOWN: 1172 *(link_state_t *)pr_val = LINK_STATE_DOWN; 1173 break; 1174 default: 1175 *(link_state_t *)pr_val = LINK_STATE_UNKNOWN; 1176 } 1177 break; 1178 case MAC_PROP_AUTONEG: 1179 if (pr_valsize < sizeof (uint8_t)) { 1180 ret = EOVERFLOW; 1181 break; 1182 } 1183 *(uint8_t *)pr_val = port->mlp_autoneg; 1184 break; 1185 case MAC_PROP_MTU: 1186 if (pr_valsize < sizeof (uint32_t)) { 1187 ret = EOVERFLOW; 1188 break; 1189 } 1190 *(uint32_t *)pr_val = port->mlp_mtu - MLXCX_MTU_OFFSET; 1191 break; 1192 default: 1193 ret = ENOTSUP; 1194 break; 1195 } 1196 1197 mutex_exit(&port->mlp_mtx); 1198 1199 return (ret); 1200 } 1201 1202 #define MLXCX_MAC_CALLBACK_FLAGS \ 1203 (MC_GETCAPAB | MC_GETPROP | MC_PROPINFO | MC_SETPROP) 1204 1205 static mac_callbacks_t mlxcx_mac_callbacks = { 1206 .mc_callbacks = MLXCX_MAC_CALLBACK_FLAGS, 1207 .mc_getstat = mlxcx_mac_stat, 1208 .mc_start = mlxcx_mac_start, 1209 .mc_stop = mlxcx_mac_stop, 1210 .mc_setpromisc = mlxcx_mac_setpromisc, 1211 .mc_multicst = mlxcx_mac_multicast, 1212 .mc_ioctl = NULL, 1213 .mc_getcapab = mlxcx_mac_getcapab, 1214 .mc_setprop = mlxcx_mac_setprop, 1215 .mc_getprop = mlxcx_mac_getprop, 1216 .mc_propinfo = mlxcx_mac_propinfo, 1217 .mc_tx = NULL, 1218 .mc_unicst = NULL, 1219 }; 1220 1221 boolean_t 1222 mlxcx_register_mac(mlxcx_t *mlxp) 1223 { 1224 mac_register_t *mac = mac_alloc(MAC_VERSION); 1225 mlxcx_port_t *port; 1226 int ret; 1227 1228 if (mac == NULL) 1229 return (B_FALSE); 1230 1231 VERIFY3U(mlxp->mlx_nports, ==, 1); 1232 port = &mlxp->mlx_ports[0]; 1233 1234 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1235 mac->m_driver = mlxp; 1236 mac->m_dip = mlxp->mlx_dip; 1237 mac->m_src_addr = port->mlp_mac_address; 1238 mac->m_callbacks = &mlxcx_mac_callbacks; 1239 mac->m_min_sdu = MLXCX_MTU_OFFSET; 1240 mac->m_max_sdu = port->mlp_mtu - MLXCX_MTU_OFFSET; 1241 mac->m_margin = VLAN_TAGSZ; 1242 mac->m_priv_props = mlxcx_priv_props; 1243 mac->m_v12n = MAC_VIRT_LEVEL1; 1244 1245 ret = mac_register(mac, &mlxp->mlx_mac_hdl); 1246 if (ret != 0) { 1247 mlxcx_warn(mlxp, "mac_register() returned %d", ret); 1248 } 1249 mac_free(mac); 1250 1251 mlxcx_update_link_state(mlxp, port); 1252 1253 return (ret == 0); 1254 } 1255