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 2015 OmniTI Computer Consulting, Inc. All rights reserved. 14 * Copyright 2022 Joyent, Inc. 15 * Copyright 2017 Tegile Systems, Inc. All rights reserved. 16 * Copyright 2020 Ryan Zezeski 17 * Copyright 2020 RackTop Systems, Inc. 18 * Copyright 2023 Oxide Computer Company 19 */ 20 21 /* 22 * For more information, please see the big theory statement in i40e_main.c. 23 */ 24 25 #include "i40e_sw.h" 26 27 #define I40E_PROP_RX_DMA_THRESH "_rx_dma_threshold" 28 #define I40E_PROP_TX_DMA_THRESH "_tx_dma_threshold" 29 #define I40E_PROP_RX_ITR "_rx_intr_throttle" 30 #define I40E_PROP_TX_ITR "_tx_intr_throttle" 31 #define I40E_PROP_OTHER_ITR "_other_intr_throttle" 32 33 char *i40e_priv_props[] = { 34 I40E_PROP_RX_DMA_THRESH, 35 I40E_PROP_TX_DMA_THRESH, 36 I40E_PROP_RX_ITR, 37 I40E_PROP_TX_ITR, 38 I40E_PROP_OTHER_ITR, 39 NULL 40 }; 41 42 static int 43 i40e_group_remove_mac(void *arg, const uint8_t *mac_addr) 44 { 45 i40e_rx_group_t *rxg = arg; 46 i40e_t *i40e = rxg->irg_i40e; 47 struct i40e_aqc_remove_macvlan_element_data filt; 48 struct i40e_hw *hw = &i40e->i40e_hw_space; 49 int ret, i, last; 50 i40e_uaddr_t *iua; 51 52 if (I40E_IS_MULTICAST(mac_addr)) 53 return (EINVAL); 54 55 mutex_enter(&i40e->i40e_general_lock); 56 57 if (i40e->i40e_state & I40E_SUSPENDED) { 58 ret = ECANCELED; 59 goto done; 60 } 61 62 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) { 63 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac, 64 ETHERADDRL) == 0) 65 break; 66 } 67 68 if (i == i40e->i40e_resources.ifr_nmacfilt_used) { 69 ret = ENOENT; 70 goto done; 71 } 72 73 iua = &i40e->i40e_uaddrs[i]; 74 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0); 75 76 bzero(&filt, sizeof (filt)); 77 bcopy(mac_addr, filt.mac_addr, ETHERADDRL); 78 filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | 79 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; 80 81 if (i40e_aq_remove_macvlan(hw, iua->iua_vsi, &filt, 1, NULL) != 82 I40E_SUCCESS) { 83 i40e_error(i40e, "failed to remove mac address " 84 "%02x:%02x:%02x:%02x:%02x:%02x from unicast filter: %d", 85 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], 86 mac_addr[4], mac_addr[5], filt.error_code); 87 ret = EIO; 88 goto done; 89 } 90 91 last = i40e->i40e_resources.ifr_nmacfilt_used - 1; 92 if (i != last) { 93 i40e_uaddr_t *src = &i40e->i40e_uaddrs[last]; 94 bcopy(src, iua, sizeof (i40e_uaddr_t)); 95 } 96 97 /* 98 * Set the multicast bit in the last one to indicate to ourselves that 99 * it's invalid. 100 */ 101 bzero(&i40e->i40e_uaddrs[last], sizeof (i40e_uaddr_t)); 102 i40e->i40e_uaddrs[last].iua_mac[0] = 0x01; 103 i40e->i40e_resources.ifr_nmacfilt_used--; 104 ret = 0; 105 done: 106 mutex_exit(&i40e->i40e_general_lock); 107 108 return (ret); 109 } 110 111 static int 112 i40e_group_add_mac(void *arg, const uint8_t *mac_addr) 113 { 114 i40e_rx_group_t *rxg = arg; 115 i40e_t *i40e = rxg->irg_i40e; 116 struct i40e_hw *hw = &i40e->i40e_hw_space; 117 int i, ret; 118 i40e_uaddr_t *iua; 119 struct i40e_aqc_add_macvlan_element_data filt; 120 121 if (I40E_IS_MULTICAST(mac_addr)) 122 return (EINVAL); 123 124 mutex_enter(&i40e->i40e_general_lock); 125 if (i40e->i40e_state & I40E_SUSPENDED) { 126 ret = ECANCELED; 127 goto done; 128 } 129 130 if (i40e->i40e_resources.ifr_nmacfilt == 131 i40e->i40e_resources.ifr_nmacfilt_used) { 132 ret = ENOSPC; 133 goto done; 134 } 135 136 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) { 137 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac, 138 ETHERADDRL) == 0) { 139 ret = EEXIST; 140 goto done; 141 } 142 } 143 144 bzero(&filt, sizeof (filt)); 145 bcopy(mac_addr, filt.mac_addr, ETHERADDRL); 146 filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH | 147 I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 148 149 if ((ret = i40e_aq_add_macvlan(hw, rxg->irg_vsi_seid, &filt, 1, 150 NULL)) != I40E_SUCCESS) { 151 i40e_error(i40e, "failed to add mac address " 152 "%02x:%02x:%02x:%02x:%02x:%02x to unicast filter: %d", 153 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], 154 mac_addr[4], mac_addr[5], ret); 155 ret = EIO; 156 goto done; 157 } 158 159 iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used]; 160 bcopy(mac_addr, iua->iua_mac, ETHERADDRL); 161 iua->iua_vsi = rxg->irg_vsi_seid; 162 i40e->i40e_resources.ifr_nmacfilt_used++; 163 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <= 164 i40e->i40e_resources.ifr_nmacfilt); 165 ret = 0; 166 done: 167 mutex_exit(&i40e->i40e_general_lock); 168 return (ret); 169 } 170 171 static int 172 i40e_m_start(void *arg) 173 { 174 i40e_t *i40e = arg; 175 int rc = 0; 176 177 mutex_enter(&i40e->i40e_general_lock); 178 if (i40e->i40e_state & I40E_SUSPENDED) { 179 rc = ECANCELED; 180 goto done; 181 } 182 183 if (!i40e_start(i40e)) { 184 rc = EIO; 185 goto done; 186 } 187 188 atomic_or_32(&i40e->i40e_state, I40E_STARTED); 189 done: 190 mutex_exit(&i40e->i40e_general_lock); 191 192 return (rc); 193 } 194 195 static void 196 i40e_m_stop(void *arg) 197 { 198 i40e_t *i40e = arg; 199 200 mutex_enter(&i40e->i40e_general_lock); 201 202 if (i40e->i40e_state & I40E_SUSPENDED) 203 goto done; 204 205 atomic_and_32(&i40e->i40e_state, ~I40E_STARTED); 206 i40e_stop(i40e); 207 done: 208 mutex_exit(&i40e->i40e_general_lock); 209 } 210 211 /* 212 * Enable and disable promiscuous mode as requested. We have to toggle both 213 * unicast and multicast. Note that multicast may already be enabled due to the 214 * i40e_m_multicast may toggle it itself. See i40e_main.c for more information 215 * on this. 216 */ 217 static int 218 i40e_m_promisc(void *arg, boolean_t on) 219 { 220 i40e_t *i40e = arg; 221 struct i40e_hw *hw = &i40e->i40e_hw_space; 222 int ret = 0, err = 0; 223 224 mutex_enter(&i40e->i40e_general_lock); 225 if (i40e->i40e_state & I40E_SUSPENDED) { 226 ret = ECANCELED; 227 goto done; 228 } 229 230 231 ret = i40e_aq_set_vsi_unicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e), 232 on, NULL, B_FALSE); 233 if (ret != I40E_SUCCESS) { 234 i40e_error(i40e, "failed to %s unicast promiscuity on " 235 "the default VSI: %d", on == B_TRUE ? "enable" : "disable", 236 ret); 237 err = EIO; 238 goto done; 239 } 240 241 /* 242 * If we have a non-zero mcast_promisc_count, then it has already been 243 * enabled or we need to leave it that way and not touch it. 244 */ 245 if (i40e->i40e_mcast_promisc_count > 0) { 246 i40e->i40e_promisc_on = on; 247 goto done; 248 } 249 250 ret = i40e_aq_set_vsi_multicast_promiscuous(hw, I40E_DEF_VSI_SEID(i40e), 251 on, NULL); 252 if (ret != I40E_SUCCESS) { 253 i40e_error(i40e, "failed to %s multicast promiscuity on " 254 "the default VSI: %d", on == B_TRUE ? "enable" : "disable", 255 ret); 256 257 /* 258 * Try our best to put us back into a state that MAC expects us 259 * to be in. 260 */ 261 ret = i40e_aq_set_vsi_unicast_promiscuous(hw, 262 I40E_DEF_VSI_SEID(i40e), !on, NULL, B_FALSE); 263 if (ret != I40E_SUCCESS) { 264 i40e_error(i40e, "failed to %s unicast promiscuity on " 265 "the default VSI after toggling multicast failed: " 266 "%d", on == B_TRUE ? "disable" : "enable", ret); 267 } 268 269 err = EIO; 270 goto done; 271 } else { 272 i40e->i40e_promisc_on = on; 273 } 274 275 done: 276 mutex_exit(&i40e->i40e_general_lock); 277 return (err); 278 } 279 280 /* 281 * See the big theory statement in i40e_main.c for multicast address management. 282 */ 283 static int 284 i40e_multicast_add(i40e_t *i40e, const uint8_t *multicast_address) 285 { 286 struct i40e_hw *hw = &i40e->i40e_hw_space; 287 struct i40e_aqc_add_macvlan_element_data filt; 288 i40e_maddr_t *mc; 289 int ret; 290 291 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 292 293 if (i40e->i40e_resources.ifr_nmcastfilt_used == 294 i40e->i40e_resources.ifr_nmcastfilt) { 295 if (i40e->i40e_mcast_promisc_count == 0 && 296 i40e->i40e_promisc_on == B_FALSE) { 297 ret = i40e_aq_set_vsi_multicast_promiscuous(hw, 298 I40E_DEF_VSI_SEID(i40e), B_TRUE, NULL); 299 if (ret != I40E_SUCCESS) { 300 i40e_error(i40e, "failed to enable multicast " 301 "promiscuous mode on VSI %d: %d", 302 I40E_DEF_VSI_SEID(i40e), ret); 303 return (EIO); 304 } 305 } 306 i40e->i40e_mcast_promisc_count++; 307 return (0); 308 } 309 310 mc = &i40e->i40e_maddrs[i40e->i40e_resources.ifr_nmcastfilt_used]; 311 bzero(&filt, sizeof (filt)); 312 bcopy(multicast_address, filt.mac_addr, ETHERADDRL); 313 filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH | 314 I40E_AQC_MACVLAN_ADD_IGNORE_VLAN; 315 316 if ((ret = i40e_aq_add_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 1, 317 NULL)) != I40E_SUCCESS) { 318 i40e_error(i40e, "failed to add mac address " 319 "%02x:%02x:%02x:%02x:%02x:%02x to multicast filter: %d", 320 multicast_address[0], multicast_address[1], 321 multicast_address[2], multicast_address[3], 322 multicast_address[4], multicast_address[5], 323 ret); 324 return (EIO); 325 } 326 327 bcopy(multicast_address, mc->ima_mac, ETHERADDRL); 328 i40e->i40e_resources.ifr_nmcastfilt_used++; 329 return (0); 330 } 331 332 /* 333 * See the big theory statement in i40e_main.c for multicast address management. 334 */ 335 static int 336 i40e_multicast_remove(i40e_t *i40e, const uint8_t *multicast_address) 337 { 338 int i, ret; 339 struct i40e_hw *hw = &i40e->i40e_hw_space; 340 341 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 342 343 for (i = 0; i < i40e->i40e_resources.ifr_nmcastfilt_used; i++) { 344 struct i40e_aqc_remove_macvlan_element_data filt; 345 int last; 346 347 if (bcmp(multicast_address, i40e->i40e_maddrs[i].ima_mac, 348 ETHERADDRL) != 0) { 349 continue; 350 } 351 352 bzero(&filt, sizeof (filt)); 353 bcopy(multicast_address, filt.mac_addr, ETHERADDRL); 354 filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH | 355 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; 356 357 if (i40e_aq_remove_macvlan(hw, I40E_DEF_VSI_SEID(i40e), &filt, 358 1, NULL) != I40E_SUCCESS) { 359 i40e_error(i40e, "failed to remove mac address " 360 "%02x:%02x:%02x:%02x:%02x:%02x from multicast " 361 "filter: %d", 362 multicast_address[0], multicast_address[1], 363 multicast_address[2], multicast_address[3], 364 multicast_address[4], multicast_address[5], 365 filt.error_code); 366 return (EIO); 367 } 368 369 last = i40e->i40e_resources.ifr_nmcastfilt_used - 1; 370 if (i != last) { 371 bcopy(&i40e->i40e_maddrs[last], &i40e->i40e_maddrs[i], 372 sizeof (i40e_maddr_t)); 373 bzero(&i40e->i40e_maddrs[last], sizeof (i40e_maddr_t)); 374 } 375 376 ASSERT(i40e->i40e_resources.ifr_nmcastfilt_used > 0); 377 i40e->i40e_resources.ifr_nmcastfilt_used--; 378 return (0); 379 } 380 381 if (i40e->i40e_mcast_promisc_count > 0) { 382 if (i40e->i40e_mcast_promisc_count == 1 && 383 i40e->i40e_promisc_on == B_FALSE) { 384 ret = i40e_aq_set_vsi_multicast_promiscuous(hw, 385 I40E_DEF_VSI_SEID(i40e), B_FALSE, NULL); 386 if (ret != I40E_SUCCESS) { 387 i40e_error(i40e, "failed to disable " 388 "multicast promiscuous mode on VSI %d: %d", 389 I40E_DEF_VSI_SEID(i40e), ret); 390 return (EIO); 391 } 392 } 393 i40e->i40e_mcast_promisc_count--; 394 395 return (0); 396 } 397 398 return (ENOENT); 399 } 400 401 static int 402 i40e_m_multicast(void *arg, boolean_t add, const uint8_t *multicast_address) 403 { 404 i40e_t *i40e = arg; 405 int rc; 406 407 mutex_enter(&i40e->i40e_general_lock); 408 409 if (i40e->i40e_state & I40E_SUSPENDED) { 410 mutex_exit(&i40e->i40e_general_lock); 411 return (ECANCELED); 412 } 413 414 if (add == B_TRUE) { 415 rc = i40e_multicast_add(i40e, multicast_address); 416 } else { 417 rc = i40e_multicast_remove(i40e, multicast_address); 418 } 419 420 mutex_exit(&i40e->i40e_general_lock); 421 return (rc); 422 } 423 424 /* ARGSUSED */ 425 static void 426 i40e_m_ioctl(void *arg, queue_t *q, mblk_t *mp) 427 { 428 /* 429 * At this time, we don't support toggling i40e into loopback mode. It's 430 * questionable how much value this has when there's no clear way to 431 * toggle this behavior from a supported way in userland. 432 */ 433 miocnak(q, mp, 0, EINVAL); 434 } 435 436 static int 437 i40e_ring_start(mac_ring_driver_t rh, uint64_t gen_num) 438 { 439 i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh; 440 int rv; 441 442 if ((rv = i40e_setup_ring(itrq)) != 0) 443 return (rv); 444 445 /* 446 * GLDv3 requires we keep track of a generation number, as it uses 447 * that number to keep track of whether or not a ring is active. 448 */ 449 mutex_enter(&itrq->itrq_rx_lock); 450 itrq->itrq_rxgen = gen_num; 451 mutex_exit(&itrq->itrq_rx_lock); 452 return (0); 453 } 454 455 static void 456 i40e_ring_stop(mac_ring_driver_t rh) 457 { 458 i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh; 459 460 if (!i40e_shutdown_ring(itrq)) { 461 i40e_t *i40e = itrq->itrq_i40e; 462 463 ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST); 464 i40e_error(i40e, "Failed to stop ring %u", itrq->itrq_index); 465 } 466 } 467 468 /* ARGSUSED */ 469 static int 470 i40e_rx_ring_intr_enable(mac_intr_handle_t intrh) 471 { 472 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh; 473 474 mutex_enter(&itrq->itrq_rx_lock); 475 ASSERT(itrq->itrq_intr_poll == B_TRUE); 476 i40e_intr_rx_queue_enable(itrq); 477 itrq->itrq_intr_poll = B_FALSE; 478 mutex_exit(&itrq->itrq_rx_lock); 479 480 return (0); 481 } 482 483 /* ARGSUSED */ 484 static int 485 i40e_rx_ring_intr_disable(mac_intr_handle_t intrh) 486 { 487 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh; 488 489 mutex_enter(&itrq->itrq_rx_lock); 490 i40e_intr_rx_queue_disable(itrq); 491 itrq->itrq_intr_poll = B_TRUE; 492 mutex_exit(&itrq->itrq_rx_lock); 493 494 return (0); 495 } 496 497 /* ARGSUSED */ 498 static void 499 i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index, 500 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 501 { 502 i40e_t *i40e = arg; 503 mac_intr_t *mintr = &infop->mri_intr; 504 i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]); 505 506 /* 507 * Note the group index here is expected to be -1 due to the fact that 508 * we're not actually grouping things tx-wise at this time. 509 */ 510 ASSERT(group_index == -1); 511 ASSERT(ring_index < i40e->i40e_num_trqpairs_per_vsi); 512 513 itrq->itrq_mactxring = rh; 514 infop->mri_driver = (mac_ring_driver_t)itrq; 515 infop->mri_start = NULL; 516 infop->mri_stop = NULL; 517 infop->mri_tx = i40e_ring_tx; 518 infop->mri_stat = i40e_tx_ring_stat; 519 520 /* 521 * We only provide the handle in cases where we have MSI-X interrupts, 522 * to indicate that we'd actually support retargetting. 523 */ 524 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) { 525 mintr->mi_ddi_handle = 526 i40e->i40e_intr_handles[itrq->itrq_tx_intrvec]; 527 } 528 } 529 530 /* ARGSUSED */ 531 static void 532 i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index, 533 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 534 { 535 i40e_t *i40e = arg; 536 mac_intr_t *mintr = &infop->mri_intr; 537 uint_t trqpair_index; 538 i40e_trqpair_t *itrq; 539 540 /* This assumes static groups. */ 541 ASSERT3S(group_index, >=, 0); 542 ASSERT3S(ring_index, >=, 0); 543 trqpair_index = (group_index * i40e->i40e_num_trqpairs_per_vsi) + 544 ring_index; 545 ASSERT3U(trqpair_index, <, i40e->i40e_num_trqpairs); 546 itrq = &i40e->i40e_trqpairs[trqpair_index]; 547 548 itrq->itrq_macrxring = rh; 549 infop->mri_driver = (mac_ring_driver_t)itrq; 550 infop->mri_start = i40e_ring_start; 551 infop->mri_stop = i40e_ring_stop; 552 infop->mri_poll = i40e_ring_rx_poll; 553 infop->mri_stat = i40e_rx_ring_stat; 554 mintr->mi_handle = (mac_intr_handle_t)itrq; 555 mintr->mi_enable = i40e_rx_ring_intr_enable; 556 mintr->mi_disable = i40e_rx_ring_intr_disable; 557 558 /* 559 * We only provide the handle in cases where we have MSI-X interrupts, 560 * to indicate that we'd actually support retargetting. 561 */ 562 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) { 563 mintr->mi_ddi_handle = 564 i40e->i40e_intr_handles[itrq->itrq_rx_intrvec]; 565 } 566 } 567 568 /* ARGSUSED */ 569 static void 570 i40e_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index, 571 mac_group_info_t *infop, mac_group_handle_t gh) 572 { 573 i40e_t *i40e = arg; 574 i40e_rx_group_t *rxg; 575 576 if (rtype != MAC_RING_TYPE_RX) 577 return; 578 579 rxg = &i40e->i40e_rx_groups[index]; 580 rxg->irg_grp_hdl = gh; 581 582 infop->mgi_driver = (mac_group_driver_t)rxg; 583 infop->mgi_start = NULL; 584 infop->mgi_stop = NULL; 585 infop->mgi_addmac = i40e_group_add_mac; 586 infop->mgi_remmac = i40e_group_remove_mac; 587 588 ASSERT3U(i40e->i40e_num_rx_groups, <=, I40E_MAX_NUM_RX_GROUPS); 589 infop->mgi_count = i40e->i40e_num_trqpairs_per_vsi; 590 } 591 592 static int 593 i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) 594 { 595 boolean_t present, usable; 596 i40e_t *i40e = arg; 597 598 if (id != 0 || infop == NULL) 599 return (EINVAL); 600 601 mutex_enter(&i40e->i40e_general_lock); 602 switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { 603 case I40E_MODULE_TYPE_SFP: 604 case I40E_MODULE_TYPE_QSFP: 605 break; 606 default: 607 mutex_exit(&i40e->i40e_general_lock); 608 return (ENOTSUP); 609 } 610 611 present = !!(i40e->i40e_hw_space.phy.link_info.link_info & 612 I40E_AQ_MEDIA_AVAILABLE); 613 if (present) { 614 usable = !!(i40e->i40e_hw_space.phy.link_info.an_info & 615 I40E_AQ_QUALIFIED_MODULE); 616 } else { 617 usable = B_FALSE; 618 } 619 mutex_exit(&i40e->i40e_general_lock); 620 621 mac_transceiver_info_set_usable(infop, usable); 622 mac_transceiver_info_set_present(infop, present); 623 624 return (0); 625 } 626 627 static int 628 i40e_transceiver_read(void *arg, uint_t id, uint_t page, void *buf, 629 size_t nbytes, off_t offset, size_t *nread) 630 { 631 i40e_t *i40e = arg; 632 struct i40e_hw *hw = &i40e->i40e_hw_space; 633 uint8_t *buf8 = buf; 634 size_t i; 635 636 if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL || 637 (page != 0xa0 && page != 0xa2) || offset < 0) 638 return (EINVAL); 639 640 /* 641 * Both supported pages have a length of 256 bytes, ensure nothing asks 642 * us to go beyond that. 643 */ 644 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) { 645 return (EINVAL); 646 } 647 648 mutex_enter(&i40e->i40e_general_lock); 649 switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { 650 case I40E_MODULE_TYPE_SFP: 651 case I40E_MODULE_TYPE_QSFP: 652 break; 653 default: 654 mutex_exit(&i40e->i40e_general_lock); 655 return (ENOTSUP); 656 } 657 658 /* 659 * Make sure we have a sufficiently new firmware version to run this 660 * command. This was introduced in firmware API 1.7. This is apparently 661 * only supported on the XL710 MAC, not the XL722. 662 */ 663 if (hw->mac.type != I40E_MAC_XL710 || hw->aq.api_maj_ver != 1 || 664 hw->aq.api_min_ver < 7) { 665 mutex_exit(&i40e->i40e_general_lock); 666 return (ENOTSUP); 667 } 668 669 for (i = 0; i < nbytes; i++, offset++) { 670 enum i40e_status_code status; 671 uint32_t val; 672 673 status = i40e_aq_get_phy_register(hw, 674 I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, page, TRUE, offset, 675 &val, NULL); 676 if (status != I40E_SUCCESS) { 677 mutex_exit(&i40e->i40e_general_lock); 678 return (EIO); 679 } 680 681 buf8[i] = (uint8_t)val; 682 } 683 684 mutex_exit(&i40e->i40e_general_lock); 685 *nread = nbytes; 686 687 return (0); 688 } 689 690 static int 691 i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags) 692 { 693 i40e_t *i40e = arg; 694 struct i40e_hw *hw = &i40e->i40e_hw_space; 695 696 if (flags != 0) 697 return (EINVAL); 698 699 if (mode != MAC_LED_DEFAULT && 700 mode != MAC_LED_IDENT && 701 mode != MAC_LED_OFF && 702 mode != MAC_LED_ON) 703 return (ENOTSUP); 704 705 if (mode != MAC_LED_DEFAULT && !i40e->i40e_led_saved) { 706 i40e->i40e_led_status = i40e_led_get(hw); 707 i40e->i40e_led_saved = B_TRUE; 708 } 709 710 switch (mode) { 711 case MAC_LED_DEFAULT: 712 if (i40e->i40e_led_saved) { 713 i40e_led_set(hw, i40e->i40e_led_status, B_FALSE); 714 i40e->i40e_led_status = 0; 715 i40e->i40e_led_saved = B_FALSE; 716 } 717 break; 718 case MAC_LED_IDENT: 719 i40e_led_set(hw, 0xf, B_TRUE); 720 break; 721 case MAC_LED_OFF: 722 i40e_led_set(hw, 0x0, B_FALSE); 723 break; 724 case MAC_LED_ON: 725 i40e_led_set(hw, 0xf, B_FALSE); 726 break; 727 default: 728 return (ENOTSUP); 729 } 730 731 return (0); 732 } 733 734 static boolean_t 735 i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 736 { 737 i40e_t *i40e = arg; 738 mac_capab_rings_t *cap_rings; 739 mac_capab_transceiver_t *mct; 740 mac_capab_led_t *mcl; 741 742 switch (cap) { 743 case MAC_CAPAB_HCKSUM: { 744 uint32_t *txflags = cap_data; 745 746 *txflags = 0; 747 if (i40e->i40e_tx_hcksum_enable == B_TRUE) 748 *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; 749 break; 750 } 751 752 case MAC_CAPAB_LSO: { 753 mac_capab_lso_t *cap_lso = cap_data; 754 755 if (i40e->i40e_tx_lso_enable == B_TRUE) { 756 cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4 | 757 LSO_TX_BASIC_TCP_IPV6; 758 cap_lso->lso_basic_tcp_ipv4.lso_max = I40E_LSO_MAXLEN; 759 cap_lso->lso_basic_tcp_ipv6.lso_max = I40E_LSO_MAXLEN; 760 } else { 761 return (B_FALSE); 762 } 763 break; 764 } 765 766 case MAC_CAPAB_RINGS: 767 cap_rings = cap_data; 768 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 769 switch (cap_rings->mr_type) { 770 case MAC_RING_TYPE_TX: 771 /* 772 * Note, saying we have no groups, but some 773 * number of rings indicates to MAC that it 774 * should create psuedo-groups with one for 775 * each TX ring. This may not be the long term 776 * behavior we want, but it'll work for now. 777 */ 778 cap_rings->mr_gnum = 0; 779 cap_rings->mr_rnum = i40e->i40e_num_trqpairs_per_vsi; 780 cap_rings->mr_rget = i40e_fill_tx_ring; 781 cap_rings->mr_gget = NULL; 782 cap_rings->mr_gaddring = NULL; 783 cap_rings->mr_gremring = NULL; 784 break; 785 case MAC_RING_TYPE_RX: 786 cap_rings->mr_rnum = i40e->i40e_num_trqpairs; 787 cap_rings->mr_rget = i40e_fill_rx_ring; 788 cap_rings->mr_gnum = i40e->i40e_num_rx_groups; 789 cap_rings->mr_gget = i40e_fill_rx_group; 790 cap_rings->mr_gaddring = NULL; 791 cap_rings->mr_gremring = NULL; 792 break; 793 default: 794 return (B_FALSE); 795 } 796 break; 797 case MAC_CAPAB_TRANSCEIVER: 798 mct = cap_data; 799 800 /* 801 * Firmware doesn't have a great way of telling us in advance 802 * whether we'd expect a SFF transceiver. As such, we always 803 * advertise the support for this capability. 804 */ 805 mct->mct_flags = 0; 806 mct->mct_ntransceivers = 1; 807 mct->mct_info = i40e_transceiver_info; 808 mct->mct_read = i40e_transceiver_read; 809 810 return (B_TRUE); 811 case MAC_CAPAB_LED: 812 mcl = cap_data; 813 814 mcl->mcl_flags = 0; 815 mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT | MAC_LED_OFF | 816 MAC_LED_ON; 817 mcl->mcl_set = i40e_gld_led_set; 818 break; 819 820 default: 821 return (B_FALSE); 822 } 823 824 return (B_TRUE); 825 } 826 827 /* ARGSUSED */ 828 static int 829 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize, 830 const void *pr_val) 831 { 832 int ret; 833 long val; 834 char *eptr; 835 836 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 837 838 if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 || 839 *eptr != '\0') { 840 return (ret); 841 } 842 843 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 844 if (val < I40E_MIN_RX_DMA_THRESH || 845 val > I40E_MAX_RX_DMA_THRESH) { 846 return (EINVAL); 847 } 848 i40e->i40e_rx_dma_min = (uint32_t)val; 849 return (0); 850 } 851 852 if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 853 if (val < I40E_MIN_TX_DMA_THRESH || 854 val > I40E_MAX_TX_DMA_THRESH) { 855 return (EINVAL); 856 } 857 i40e->i40e_tx_dma_min = (uint32_t)val; 858 return (0); 859 } 860 861 if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 862 if (val < I40E_MIN_ITR || 863 val > I40E_MAX_ITR) { 864 return (EINVAL); 865 } 866 i40e->i40e_rx_itr = (uint32_t)val; 867 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr); 868 return (0); 869 } 870 871 if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 872 if (val < I40E_MIN_ITR || 873 val > I40E_MAX_ITR) { 874 return (EINVAL); 875 } 876 i40e->i40e_tx_itr = (uint32_t)val; 877 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr); 878 return (0); 879 } 880 881 if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 882 if (val < I40E_MIN_ITR || 883 val > I40E_MAX_ITR) { 884 return (EINVAL); 885 } 886 i40e->i40e_tx_itr = (uint32_t)val; 887 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER, 888 i40e->i40e_other_itr); 889 return (0); 890 } 891 892 return (ENOTSUP); 893 } 894 895 static int 896 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize, 897 void *pr_val) 898 { 899 uint32_t val; 900 901 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 902 903 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 904 val = i40e->i40e_rx_dma_min; 905 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 906 val = i40e->i40e_tx_dma_min; 907 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 908 val = i40e->i40e_rx_itr; 909 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 910 val = i40e->i40e_tx_itr; 911 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 912 val = i40e->i40e_other_itr; 913 } else { 914 return (ENOTSUP); 915 } 916 917 if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize) 918 return (ERANGE); 919 return (0); 920 } 921 922 /* 923 * Annoyingly for private properties MAC seems to ignore default values that 924 * aren't strings. That means that we have to translate all of these into 925 * uint32_t's and instead we size the buffer to be large enough to hold a 926 * uint32_t. 927 */ 928 /* ARGSUSED */ 929 static void 930 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name, 931 mac_prop_info_handle_t prh) 932 { 933 char buf[64]; 934 uint32_t def; 935 936 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 937 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 938 def = I40E_DEF_RX_DMA_THRESH; 939 mac_prop_info_set_range_uint32(prh, 940 I40E_MIN_RX_DMA_THRESH, 941 I40E_MAX_RX_DMA_THRESH); 942 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 943 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 944 def = I40E_DEF_TX_DMA_THRESH; 945 mac_prop_info_set_range_uint32(prh, 946 I40E_MIN_TX_DMA_THRESH, 947 I40E_MAX_TX_DMA_THRESH); 948 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 949 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 950 def = I40E_DEF_RX_ITR; 951 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 952 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 953 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 954 def = I40E_DEF_TX_ITR; 955 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 956 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 957 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 958 def = I40E_DEF_OTHER_ITR; 959 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 960 } else { 961 return; 962 } 963 964 (void) snprintf(buf, sizeof (buf), "%d", def); 965 mac_prop_info_set_default_str(prh, buf); 966 } 967 968 static int 969 i40e_update_fec(i40e_t *i40e, link_fec_t fec) 970 { 971 struct i40e_hw *hw = &i40e->i40e_hw_space; 972 struct i40e_aq_get_phy_abilities_resp abilities; 973 struct i40e_aq_set_phy_config config; 974 link_fec_t fec_requested; 975 int req_fec; 976 977 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 978 979 if (fec == i40e->i40e_fec_requested) 980 return (0); 981 982 fec_requested = fec; 983 if ((fec & LINK_FEC_AUTO) != 0) { 984 req_fec = I40E_AQ_SET_FEC_AUTO; 985 fec &= ~LINK_FEC_AUTO; 986 } else if ((fec & LINK_FEC_NONE) != 0) { 987 req_fec = 0; 988 fec &= ~LINK_FEC_NONE; 989 } else { 990 req_fec = 0; 991 if ((fec & LINK_FEC_BASE_R) != 0) { 992 req_fec |= I40E_AQ_SET_FEC_ABILITY_KR | 993 I40E_AQ_SET_FEC_REQUEST_KR; 994 fec &= ~LINK_FEC_BASE_R; 995 } 996 if ((fec & LINK_FEC_RS) != 0) { 997 req_fec |= I40E_AQ_SET_FEC_ABILITY_RS | 998 I40E_AQ_SET_FEC_REQUEST_RS; 999 fec &= ~LINK_FEC_RS; 1000 } 1001 if (req_fec == 0) 1002 return (EINVAL); 1003 } 1004 1005 /* 1006 * if fec is not zero now, then there is an invalid fec or 1007 * combination of settings. 1008 */ 1009 if (fec != 0) 1010 return (EINVAL); 1011 1012 if (i40e_aq_get_phy_capabilities(hw, B_FALSE, B_FALSE, &abilities, 1013 NULL) != I40E_SUCCESS) 1014 return (EIO); 1015 1016 bzero(&config, sizeof (config)); 1017 config.abilities = abilities.abilities; 1018 /* Restart the link */ 1019 config.abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK; 1020 config.phy_type = abilities.phy_type; 1021 config.phy_type_ext = abilities.phy_type_ext; 1022 config.link_speed = abilities.link_speed; 1023 config.eee_capability = abilities.eee_capability; 1024 config.eeer = abilities.eeer_val; 1025 config.low_power_ctrl = abilities.d3_lpan; 1026 config.fec_config = req_fec & I40E_AQ_PHY_FEC_CONFIG_MASK; 1027 if (i40e_aq_set_phy_config(hw, &config, NULL) != I40E_SUCCESS) 1028 return (EIO); 1029 1030 if (i40e_update_link_info(hw) != I40E_SUCCESS) 1031 return (EIO); 1032 1033 i40e->i40e_fec_requested = fec_requested; 1034 1035 return (0); 1036 } 1037 static int 1038 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1039 uint_t pr_valsize, const void *pr_val) 1040 { 1041 uint32_t new_mtu; 1042 link_fec_t fec; 1043 i40e_t *i40e = arg; 1044 int ret = 0; 1045 1046 mutex_enter(&i40e->i40e_general_lock); 1047 if (i40e->i40e_state & I40E_SUSPENDED) { 1048 mutex_exit(&i40e->i40e_general_lock); 1049 return (ECANCELED); 1050 } 1051 1052 switch (pr_num) { 1053 /* 1054 * These properties are always read-only across every device. 1055 */ 1056 case MAC_PROP_DUPLEX: 1057 case MAC_PROP_SPEED: 1058 case MAC_PROP_STATUS: 1059 case MAC_PROP_MEDIA: 1060 case MAC_PROP_ADV_100FDX_CAP: 1061 case MAC_PROP_ADV_1000FDX_CAP: 1062 case MAC_PROP_ADV_2500FDX_CAP: 1063 case MAC_PROP_ADV_5000FDX_CAP: 1064 case MAC_PROP_ADV_10GFDX_CAP: 1065 case MAC_PROP_ADV_25GFDX_CAP: 1066 case MAC_PROP_ADV_40GFDX_CAP: 1067 ret = ENOTSUP; 1068 break; 1069 /* 1070 * These are read-only at this time as we don't support configuring 1071 * auto-negotiation. See the theory statement in i40e_main.c. 1072 */ 1073 case MAC_PROP_EN_100FDX_CAP: 1074 case MAC_PROP_EN_1000FDX_CAP: 1075 case MAC_PROP_EN_2500FDX_CAP: 1076 case MAC_PROP_EN_5000FDX_CAP: 1077 case MAC_PROP_EN_10GFDX_CAP: 1078 case MAC_PROP_EN_25GFDX_CAP: 1079 case MAC_PROP_EN_40GFDX_CAP: 1080 case MAC_PROP_AUTONEG: 1081 case MAC_PROP_FLOWCTRL: 1082 ret = ENOTSUP; 1083 break; 1084 1085 case MAC_PROP_MTU: 1086 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 1087 if (new_mtu == i40e->i40e_sdu) 1088 break; 1089 1090 if (new_mtu < I40E_MIN_MTU || 1091 new_mtu > I40E_MAX_MTU) { 1092 ret = EINVAL; 1093 break; 1094 } 1095 1096 if (i40e->i40e_state & I40E_STARTED) { 1097 ret = EBUSY; 1098 break; 1099 } 1100 1101 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu); 1102 if (ret == 0) { 1103 i40e->i40e_sdu = new_mtu; 1104 i40e_update_mtu(i40e); 1105 } 1106 break; 1107 1108 case MAC_PROP_EN_FEC_CAP: 1109 bcopy(pr_val, &fec, sizeof (fec)); 1110 1111 ret = i40e_update_fec(i40e, fec); 1112 break; 1113 1114 case MAC_PROP_PRIVATE: 1115 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val); 1116 break; 1117 default: 1118 ret = ENOTSUP; 1119 break; 1120 } 1121 1122 mutex_exit(&i40e->i40e_general_lock); 1123 return (ret); 1124 } 1125 1126 static link_fec_t 1127 i40e_fec_to_linkfec(struct i40e_hw *hw) 1128 { 1129 struct i40e_link_status *ls = &hw->phy.link_info; 1130 1131 if ((ls->fec_info & I40E_AQ_CONFIG_FEC_KR_ENA) != 0) 1132 return (LINK_FEC_BASE_R); 1133 1134 if ((ls->fec_info & I40E_AQ_CONFIG_FEC_RS_ENA) != 0) 1135 return (LINK_FEC_RS); 1136 1137 return (LINK_FEC_NONE); 1138 } 1139 1140 mac_ether_media_t 1141 i40e_link_to_media(i40e_t *i40e) 1142 { 1143 switch (i40e->i40e_link_state) { 1144 case LINK_STATE_UP: 1145 break; 1146 case LINK_STATE_DOWN: 1147 return (ETHER_MEDIA_NONE); 1148 default: 1149 return (ETHER_MEDIA_UNKNOWN); 1150 } 1151 1152 switch (i40e->i40e_hw_space.phy.link_info.phy_type) { 1153 case I40E_PHY_TYPE_SGMII: 1154 return (ETHER_MEDIA_1000_SGMII); 1155 case I40E_PHY_TYPE_1000BASE_KX: 1156 return (ETHER_MEDIA_1000BASE_KX); 1157 case I40E_PHY_TYPE_10GBASE_KX4: 1158 return (ETHER_MEDIA_10GBASE_KX4); 1159 case I40E_PHY_TYPE_10GBASE_KR: 1160 return (ETHER_MEDIA_10GBASE_KR); 1161 case I40E_PHY_TYPE_40GBASE_KR4: 1162 return (ETHER_MEDIA_40GBASE_KR4); 1163 case I40E_PHY_TYPE_XAUI: 1164 return (ETHER_MEDIA_10G_XAUI); 1165 case I40E_PHY_TYPE_XFI: 1166 return (ETHER_MEDIA_10G_XFI); 1167 case I40E_PHY_TYPE_SFI: 1168 return (ETHER_MEDIA_10G_SFI); 1169 case I40E_PHY_TYPE_XLAUI: 1170 return (ETHER_MEDIA_40G_XLAUI); 1171 case I40E_PHY_TYPE_XLPPI: 1172 return (ETHER_MEDIA_40G_XLPPI); 1173 case I40E_PHY_TYPE_40GBASE_CR4_CU: 1174 return (ETHER_MEDIA_40GBASE_CR4); 1175 case I40E_PHY_TYPE_10GBASE_CR1_CU: 1176 return (ETHER_MEDIA_10GBASE_CR); 1177 case I40E_PHY_TYPE_10GBASE_AOC: 1178 return (ETHER_MEDIA_10GBASE_AOC); 1179 case I40E_PHY_TYPE_40GBASE_AOC: 1180 return (ETHER_MEDIA_40GBASE_AOC4); 1181 case I40E_PHY_TYPE_100BASE_TX: 1182 return (ETHER_MEDIA_100BASE_TX); 1183 case I40E_PHY_TYPE_1000BASE_T: 1184 return (ETHER_MEDIA_1000BASE_T); 1185 case I40E_PHY_TYPE_10GBASE_T: 1186 return (ETHER_MEDIA_10GBASE_T); 1187 case I40E_PHY_TYPE_10GBASE_SR: 1188 return (ETHER_MEDIA_10GBASE_SR); 1189 case I40E_PHY_TYPE_10GBASE_LR: 1190 return (ETHER_MEDIA_10GBASE_LR); 1191 case I40E_PHY_TYPE_10GBASE_SFPP_CU: 1192 return (ETHER_MEDIA_10GBASE_CR); 1193 case I40E_PHY_TYPE_10GBASE_CR1: 1194 return (ETHER_MEDIA_10GBASE_CR); 1195 case I40E_PHY_TYPE_40GBASE_CR4: 1196 return (ETHER_MEDIA_40GBASE_CR4); 1197 case I40E_PHY_TYPE_40GBASE_SR4: 1198 return (ETHER_MEDIA_40GBASE_SR4); 1199 case I40E_PHY_TYPE_40GBASE_LR4: 1200 return (ETHER_MEDIA_40GBASE_LR4); 1201 case I40E_PHY_TYPE_1000BASE_SX: 1202 return (ETHER_MEDIA_1000BASE_SX); 1203 case I40E_PHY_TYPE_1000BASE_LX: 1204 return (ETHER_MEDIA_1000BASE_LX); 1205 case I40E_PHY_TYPE_1000BASE_T_OPTICAL: 1206 return (ETHER_MEDIA_1000BASE_T); 1207 case I40E_PHY_TYPE_25GBASE_KR: 1208 return (ETHER_MEDIA_25GBASE_KR); 1209 case I40E_PHY_TYPE_25GBASE_CR: 1210 return (ETHER_MEDIA_25GBASE_CR); 1211 case I40E_PHY_TYPE_25GBASE_SR: 1212 return (ETHER_MEDIA_25GBASE_SR); 1213 case I40E_PHY_TYPE_25GBASE_LR: 1214 return (ETHER_MEDIA_25GBASE_LR); 1215 case I40E_PHY_TYPE_25GBASE_AOC: 1216 return (ETHER_MEDIA_25GBASE_AOC); 1217 case I40E_PHY_TYPE_25GBASE_ACC: 1218 return (ETHER_MEDIA_25GBASE_ACC); 1219 case I40E_PHY_TYPE_2_5GBASE_T: 1220 return (ETHER_MEDIA_2500BASE_T); 1221 case I40E_PHY_TYPE_5GBASE_T: 1222 return (ETHER_MEDIA_5000BASE_T); 1223 case I40E_PHY_TYPE_EMPTY: 1224 return (ETHER_MEDIA_NONE); 1225 /* 1226 * We don't currently support 20GBASE-KR2 in any way in the GLD. If 1227 * someone actually can generate this, then we should do this. 1228 */ 1229 case I40E_PHY_TYPE_20GBASE_KR2: 1230 case I40E_PHY_TYPE_DEFAULT: 1231 case I40E_PHY_TYPE_UNRECOGNIZED: 1232 case I40E_PHY_TYPE_UNSUPPORTED: 1233 case I40E_PHY_TYPE_NOT_SUPPORTED_HIGH_TEMP: 1234 default: 1235 return (ETHER_MEDIA_UNKNOWN); 1236 } 1237 } 1238 1239 static int 1240 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1241 uint_t pr_valsize, void *pr_val) 1242 { 1243 i40e_t *i40e = arg; 1244 uint64_t speed; 1245 int ret = 0; 1246 uint8_t *u8; 1247 link_flowctrl_t fctl; 1248 1249 mutex_enter(&i40e->i40e_general_lock); 1250 1251 switch (pr_num) { 1252 case MAC_PROP_DUPLEX: 1253 if (pr_valsize < sizeof (link_duplex_t)) { 1254 ret = EOVERFLOW; 1255 break; 1256 } 1257 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t)); 1258 break; 1259 case MAC_PROP_SPEED: 1260 if (pr_valsize < sizeof (uint64_t)) { 1261 ret = EOVERFLOW; 1262 break; 1263 } 1264 speed = i40e->i40e_link_speed * 1000000ULL; 1265 bcopy(&speed, pr_val, sizeof (speed)); 1266 break; 1267 case MAC_PROP_STATUS: 1268 if (pr_valsize < sizeof (link_state_t)) { 1269 ret = EOVERFLOW; 1270 break; 1271 } 1272 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t)); 1273 break; 1274 case MAC_PROP_MEDIA: 1275 *(mac_ether_media_t *)pr_val = i40e_link_to_media(i40e); 1276 break; 1277 case MAC_PROP_AUTONEG: 1278 if (pr_valsize < sizeof (uint8_t)) { 1279 ret = EOVERFLOW; 1280 break; 1281 } 1282 u8 = pr_val; 1283 *u8 = 1; 1284 break; 1285 case MAC_PROP_FLOWCTRL: 1286 /* 1287 * Because we don't currently support hardware flow control, we 1288 * just hardcode this to be none. 1289 */ 1290 if (pr_valsize < sizeof (link_flowctrl_t)) { 1291 ret = EOVERFLOW; 1292 break; 1293 } 1294 fctl = LINK_FLOWCTRL_NONE; 1295 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t)); 1296 break; 1297 case MAC_PROP_MTU: 1298 if (pr_valsize < sizeof (uint32_t)) { 1299 ret = EOVERFLOW; 1300 break; 1301 } 1302 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t)); 1303 break; 1304 case MAC_PROP_ADV_FEC_CAP: 1305 if (pr_valsize < sizeof (link_fec_t)) { 1306 ret = EOVERFLOW; 1307 break; 1308 } 1309 *(link_fec_t *)pr_val = 1310 i40e_fec_to_linkfec(&i40e->i40e_hw_space); 1311 break; 1312 case MAC_PROP_EN_FEC_CAP: 1313 if (pr_valsize < sizeof (link_fec_t)) { 1314 ret = EOVERFLOW; 1315 break; 1316 } 1317 *(link_fec_t *)pr_val = i40e->i40e_fec_requested; 1318 break; 1319 1320 /* 1321 * Because we don't let users control the speeds we may auto-negotiate 1322 * to, the values of the ADV_ and EN_ will always be the same. 1323 */ 1324 case MAC_PROP_ADV_100FDX_CAP: 1325 case MAC_PROP_EN_100FDX_CAP: 1326 if (pr_valsize < sizeof (uint8_t)) { 1327 ret = EOVERFLOW; 1328 break; 1329 } 1330 u8 = pr_val; 1331 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0; 1332 break; 1333 case MAC_PROP_ADV_1000FDX_CAP: 1334 case MAC_PROP_EN_1000FDX_CAP: 1335 if (pr_valsize < sizeof (uint8_t)) { 1336 ret = EOVERFLOW; 1337 break; 1338 } 1339 u8 = pr_val; 1340 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0; 1341 break; 1342 case MAC_PROP_ADV_2500FDX_CAP: 1343 case MAC_PROP_EN_2500FDX_CAP: 1344 if (pr_valsize < sizeof (uint8_t)) { 1345 ret = EOVERFLOW; 1346 break; 1347 } 1348 u8 = pr_val; 1349 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_2_5GB) != 0; 1350 break; 1351 case MAC_PROP_ADV_5000FDX_CAP: 1352 case MAC_PROP_EN_5000FDX_CAP: 1353 if (pr_valsize < sizeof (uint8_t)) { 1354 ret = EOVERFLOW; 1355 break; 1356 } 1357 u8 = pr_val; 1358 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_5GB) != 0; 1359 break; 1360 case MAC_PROP_ADV_10GFDX_CAP: 1361 case MAC_PROP_EN_10GFDX_CAP: 1362 if (pr_valsize < sizeof (uint8_t)) { 1363 ret = EOVERFLOW; 1364 break; 1365 } 1366 u8 = pr_val; 1367 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0; 1368 break; 1369 case MAC_PROP_ADV_25GFDX_CAP: 1370 case MAC_PROP_EN_25GFDX_CAP: 1371 if (pr_valsize < sizeof (uint8_t)) { 1372 ret = EOVERFLOW; 1373 break; 1374 } 1375 u8 = pr_val; 1376 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0; 1377 break; 1378 case MAC_PROP_ADV_40GFDX_CAP: 1379 case MAC_PROP_EN_40GFDX_CAP: 1380 if (pr_valsize < sizeof (uint8_t)) { 1381 ret = EOVERFLOW; 1382 break; 1383 } 1384 u8 = pr_val; 1385 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0; 1386 break; 1387 case MAC_PROP_PRIVATE: 1388 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val); 1389 break; 1390 default: 1391 ret = ENOTSUP; 1392 break; 1393 } 1394 1395 mutex_exit(&i40e->i40e_general_lock); 1396 1397 return (ret); 1398 } 1399 1400 static void 1401 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1402 mac_prop_info_handle_t prh) 1403 { 1404 i40e_t *i40e = arg; 1405 1406 mutex_enter(&i40e->i40e_general_lock); 1407 1408 switch (pr_num) { 1409 case MAC_PROP_DUPLEX: 1410 case MAC_PROP_SPEED: 1411 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1412 break; 1413 case MAC_PROP_FLOWCTRL: 1414 /* 1415 * At the moment, the driver doesn't support flow control, hence 1416 * why this is set to read-only and none. 1417 */ 1418 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1419 mac_prop_info_set_default_link_flowctrl(prh, 1420 LINK_FLOWCTRL_NONE); 1421 break; 1422 case MAC_PROP_MTU: 1423 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU); 1424 break; 1425 case MAC_PROP_ADV_FEC_CAP: 1426 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1427 if (i40e_is_25G_device(i40e->i40e_hw_space.device_id)) 1428 mac_prop_info_set_default_fec(prh, LINK_FEC_AUTO); 1429 break; 1430 case MAC_PROP_EN_FEC_CAP: 1431 if (i40e_is_25G_device(i40e->i40e_hw_space.device_id)) { 1432 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 1433 mac_prop_info_set_default_fec(prh, LINK_FEC_AUTO); 1434 } else { 1435 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1436 } 1437 break; 1438 1439 /* 1440 * We set the defaults for these based upon the phy's ability to 1441 * support the speeds. Note, auto-negotiation is required for fiber, 1442 * hence it is read-only and always enabled. When we have access to 1443 * copper phys we can revisit this. 1444 */ 1445 case MAC_PROP_AUTONEG: 1446 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1447 mac_prop_info_set_default_uint8(prh, 1); 1448 break; 1449 case MAC_PROP_ADV_100FDX_CAP: 1450 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1451 mac_prop_info_set_default_uint8(prh, 1452 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1453 break; 1454 case MAC_PROP_EN_100FDX_CAP: 1455 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1456 mac_prop_info_set_default_uint8(prh, 1457 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1458 break; 1459 case MAC_PROP_ADV_1000FDX_CAP: 1460 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1461 mac_prop_info_set_default_uint8(prh, 1462 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1463 break; 1464 case MAC_PROP_EN_1000FDX_CAP: 1465 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1466 mac_prop_info_set_default_uint8(prh, 1467 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1468 break; 1469 case MAC_PROP_ADV_10GFDX_CAP: 1470 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1471 mac_prop_info_set_default_uint8(prh, 1472 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0); 1473 break; 1474 case MAC_PROP_EN_10GFDX_CAP: 1475 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1476 mac_prop_info_set_default_uint8(prh, 1477 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0); 1478 break; 1479 case MAC_PROP_ADV_25GFDX_CAP: 1480 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1481 mac_prop_info_set_default_uint8(prh, 1482 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0); 1483 break; 1484 case MAC_PROP_EN_25GFDX_CAP: 1485 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1486 mac_prop_info_set_default_uint8(prh, 1487 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0); 1488 break; 1489 case MAC_PROP_ADV_40GFDX_CAP: 1490 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1491 mac_prop_info_set_default_uint8(prh, 1492 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0); 1493 break; 1494 case MAC_PROP_EN_40GFDX_CAP: 1495 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1496 mac_prop_info_set_default_uint8(prh, 1497 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0); 1498 break; 1499 case MAC_PROP_PRIVATE: 1500 i40e_m_propinfo_private(i40e, pr_name, prh); 1501 break; 1502 default: 1503 break; 1504 } 1505 1506 mutex_exit(&i40e->i40e_general_lock); 1507 } 1508 1509 #define I40E_M_CALLBACK_FLAGS \ 1510 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 1511 1512 static mac_callbacks_t i40e_m_callbacks = { 1513 I40E_M_CALLBACK_FLAGS, 1514 i40e_m_stat, 1515 i40e_m_start, 1516 i40e_m_stop, 1517 i40e_m_promisc, 1518 i40e_m_multicast, 1519 NULL, 1520 NULL, 1521 NULL, 1522 i40e_m_ioctl, 1523 i40e_m_getcapab, 1524 NULL, 1525 NULL, 1526 i40e_m_setprop, 1527 i40e_m_getprop, 1528 i40e_m_propinfo 1529 }; 1530 1531 boolean_t 1532 i40e_register_mac(i40e_t *i40e) 1533 { 1534 struct i40e_hw *hw = &i40e->i40e_hw_space; 1535 int status; 1536 mac_register_t *mac = mac_alloc(MAC_VERSION); 1537 1538 if (mac == NULL) 1539 return (B_FALSE); 1540 1541 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1542 mac->m_driver = i40e; 1543 mac->m_dip = i40e->i40e_dip; 1544 mac->m_src_addr = hw->mac.addr; 1545 mac->m_callbacks = &i40e_m_callbacks; 1546 mac->m_min_sdu = 0; 1547 mac->m_max_sdu = i40e->i40e_sdu; 1548 mac->m_margin = VLAN_TAGSZ; 1549 mac->m_priv_props = i40e_priv_props; 1550 mac->m_v12n = MAC_VIRT_LEVEL1; 1551 1552 status = mac_register(mac, &i40e->i40e_mac_hdl); 1553 if (status != 0) 1554 i40e_error(i40e, "mac_register() returned %d", status); 1555 mac_free(mac); 1556 1557 return (status == 0); 1558 } 1559