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