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