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 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 "%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_ADV_100FDX_CAP: 1060 case MAC_PROP_ADV_1000FDX_CAP: 1061 case MAC_PROP_ADV_2500FDX_CAP: 1062 case MAC_PROP_ADV_5000FDX_CAP: 1063 case MAC_PROP_ADV_10GFDX_CAP: 1064 case MAC_PROP_ADV_25GFDX_CAP: 1065 case MAC_PROP_ADV_40GFDX_CAP: 1066 ret = ENOTSUP; 1067 break; 1068 /* 1069 * These are read-only at this time as we don't support configuring 1070 * auto-negotiation. See the theory statement in i40e_main.c. 1071 */ 1072 case MAC_PROP_EN_100FDX_CAP: 1073 case MAC_PROP_EN_1000FDX_CAP: 1074 case MAC_PROP_EN_2500FDX_CAP: 1075 case MAC_PROP_EN_5000FDX_CAP: 1076 case MAC_PROP_EN_10GFDX_CAP: 1077 case MAC_PROP_EN_25GFDX_CAP: 1078 case MAC_PROP_EN_40GFDX_CAP: 1079 case MAC_PROP_AUTONEG: 1080 case MAC_PROP_FLOWCTRL: 1081 ret = ENOTSUP; 1082 break; 1083 1084 case MAC_PROP_MTU: 1085 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 1086 if (new_mtu == i40e->i40e_sdu) 1087 break; 1088 1089 if (new_mtu < I40E_MIN_MTU || 1090 new_mtu > I40E_MAX_MTU) { 1091 ret = EINVAL; 1092 break; 1093 } 1094 1095 if (i40e->i40e_state & I40E_STARTED) { 1096 ret = EBUSY; 1097 break; 1098 } 1099 1100 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu); 1101 if (ret == 0) { 1102 i40e->i40e_sdu = new_mtu; 1103 i40e_update_mtu(i40e); 1104 } 1105 break; 1106 1107 case MAC_PROP_EN_FEC_CAP: 1108 bcopy(pr_val, &fec, sizeof (fec)); 1109 1110 ret = i40e_update_fec(i40e, fec); 1111 break; 1112 1113 case MAC_PROP_PRIVATE: 1114 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val); 1115 break; 1116 default: 1117 ret = ENOTSUP; 1118 break; 1119 } 1120 1121 mutex_exit(&i40e->i40e_general_lock); 1122 return (ret); 1123 } 1124 1125 static link_fec_t 1126 i40e_fec_to_linkfec(struct i40e_hw *hw) 1127 { 1128 struct i40e_link_status *ls = &hw->phy.link_info; 1129 1130 if ((ls->fec_info & I40E_AQ_CONFIG_FEC_KR_ENA) != 0) 1131 return (LINK_FEC_BASE_R); 1132 1133 if ((ls->fec_info & I40E_AQ_CONFIG_FEC_RS_ENA) != 0) 1134 return (LINK_FEC_RS); 1135 1136 return (LINK_FEC_NONE); 1137 } 1138 1139 static int 1140 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1141 uint_t pr_valsize, void *pr_val) 1142 { 1143 i40e_t *i40e = arg; 1144 uint64_t speed; 1145 int ret = 0; 1146 uint8_t *u8; 1147 link_flowctrl_t fctl; 1148 1149 mutex_enter(&i40e->i40e_general_lock); 1150 1151 switch (pr_num) { 1152 case MAC_PROP_DUPLEX: 1153 if (pr_valsize < sizeof (link_duplex_t)) { 1154 ret = EOVERFLOW; 1155 break; 1156 } 1157 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t)); 1158 break; 1159 case MAC_PROP_SPEED: 1160 if (pr_valsize < sizeof (uint64_t)) { 1161 ret = EOVERFLOW; 1162 break; 1163 } 1164 speed = i40e->i40e_link_speed * 1000000ULL; 1165 bcopy(&speed, pr_val, sizeof (speed)); 1166 break; 1167 case MAC_PROP_STATUS: 1168 if (pr_valsize < sizeof (link_state_t)) { 1169 ret = EOVERFLOW; 1170 break; 1171 } 1172 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t)); 1173 break; 1174 case MAC_PROP_AUTONEG: 1175 if (pr_valsize < sizeof (uint8_t)) { 1176 ret = EOVERFLOW; 1177 break; 1178 } 1179 u8 = pr_val; 1180 *u8 = 1; 1181 break; 1182 case MAC_PROP_FLOWCTRL: 1183 /* 1184 * Because we don't currently support hardware flow control, we 1185 * just hardcode this to be none. 1186 */ 1187 if (pr_valsize < sizeof (link_flowctrl_t)) { 1188 ret = EOVERFLOW; 1189 break; 1190 } 1191 fctl = LINK_FLOWCTRL_NONE; 1192 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t)); 1193 break; 1194 case MAC_PROP_MTU: 1195 if (pr_valsize < sizeof (uint32_t)) { 1196 ret = EOVERFLOW; 1197 break; 1198 } 1199 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t)); 1200 break; 1201 case MAC_PROP_ADV_FEC_CAP: 1202 if (pr_valsize < sizeof (link_fec_t)) { 1203 ret = EOVERFLOW; 1204 break; 1205 } 1206 *(link_fec_t *)pr_val = 1207 i40e_fec_to_linkfec(&i40e->i40e_hw_space); 1208 break; 1209 case MAC_PROP_EN_FEC_CAP: 1210 if (pr_valsize < sizeof (link_fec_t)) { 1211 ret = EOVERFLOW; 1212 break; 1213 } 1214 *(link_fec_t *)pr_val = i40e->i40e_fec_requested; 1215 break; 1216 1217 /* 1218 * Because we don't let users control the speeds we may auto-negotiate 1219 * to, the values of the ADV_ and EN_ will always be the same. 1220 */ 1221 case MAC_PROP_ADV_100FDX_CAP: 1222 case MAC_PROP_EN_100FDX_CAP: 1223 if (pr_valsize < sizeof (uint8_t)) { 1224 ret = EOVERFLOW; 1225 break; 1226 } 1227 u8 = pr_val; 1228 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0; 1229 break; 1230 case MAC_PROP_ADV_1000FDX_CAP: 1231 case MAC_PROP_EN_1000FDX_CAP: 1232 if (pr_valsize < sizeof (uint8_t)) { 1233 ret = EOVERFLOW; 1234 break; 1235 } 1236 u8 = pr_val; 1237 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0; 1238 break; 1239 case MAC_PROP_ADV_2500FDX_CAP: 1240 case MAC_PROP_EN_2500FDX_CAP: 1241 if (pr_valsize < sizeof (uint8_t)) { 1242 ret = EOVERFLOW; 1243 break; 1244 } 1245 u8 = pr_val; 1246 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_2_5GB) != 0; 1247 break; 1248 case MAC_PROP_ADV_5000FDX_CAP: 1249 case MAC_PROP_EN_5000FDX_CAP: 1250 if (pr_valsize < sizeof (uint8_t)) { 1251 ret = EOVERFLOW; 1252 break; 1253 } 1254 u8 = pr_val; 1255 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_5GB) != 0; 1256 break; 1257 case MAC_PROP_ADV_10GFDX_CAP: 1258 case MAC_PROP_EN_10GFDX_CAP: 1259 if (pr_valsize < sizeof (uint8_t)) { 1260 ret = EOVERFLOW; 1261 break; 1262 } 1263 u8 = pr_val; 1264 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0; 1265 break; 1266 case MAC_PROP_ADV_25GFDX_CAP: 1267 case MAC_PROP_EN_25GFDX_CAP: 1268 if (pr_valsize < sizeof (uint8_t)) { 1269 ret = EOVERFLOW; 1270 break; 1271 } 1272 u8 = pr_val; 1273 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0; 1274 break; 1275 case MAC_PROP_ADV_40GFDX_CAP: 1276 case MAC_PROP_EN_40GFDX_CAP: 1277 if (pr_valsize < sizeof (uint8_t)) { 1278 ret = EOVERFLOW; 1279 break; 1280 } 1281 u8 = pr_val; 1282 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0; 1283 break; 1284 case MAC_PROP_PRIVATE: 1285 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val); 1286 break; 1287 default: 1288 ret = ENOTSUP; 1289 break; 1290 } 1291 1292 mutex_exit(&i40e->i40e_general_lock); 1293 1294 return (ret); 1295 } 1296 1297 static void 1298 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1299 mac_prop_info_handle_t prh) 1300 { 1301 i40e_t *i40e = arg; 1302 1303 mutex_enter(&i40e->i40e_general_lock); 1304 1305 switch (pr_num) { 1306 case MAC_PROP_DUPLEX: 1307 case MAC_PROP_SPEED: 1308 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1309 break; 1310 case MAC_PROP_FLOWCTRL: 1311 /* 1312 * At the moment, the driver doesn't support flow control, hence 1313 * why this is set to read-only and none. 1314 */ 1315 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1316 mac_prop_info_set_default_link_flowctrl(prh, 1317 LINK_FLOWCTRL_NONE); 1318 break; 1319 case MAC_PROP_MTU: 1320 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU); 1321 break; 1322 case MAC_PROP_ADV_FEC_CAP: 1323 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1324 if (i40e_is_25G_device(i40e->i40e_hw_space.device_id)) 1325 mac_prop_info_set_default_fec(prh, LINK_FEC_AUTO); 1326 break; 1327 case MAC_PROP_EN_FEC_CAP: 1328 if (i40e_is_25G_device(i40e->i40e_hw_space.device_id)) { 1329 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 1330 mac_prop_info_set_default_fec(prh, LINK_FEC_AUTO); 1331 } else { 1332 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1333 } 1334 break; 1335 1336 /* 1337 * We set the defaults for these based upon the phy's ability to 1338 * support the speeds. Note, auto-negotiation is required for fiber, 1339 * hence it is read-only and always enabled. When we have access to 1340 * copper phys we can revisit this. 1341 */ 1342 case MAC_PROP_AUTONEG: 1343 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1344 mac_prop_info_set_default_uint8(prh, 1); 1345 break; 1346 case MAC_PROP_ADV_100FDX_CAP: 1347 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1348 mac_prop_info_set_default_uint8(prh, 1349 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1350 break; 1351 case MAC_PROP_EN_100FDX_CAP: 1352 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1353 mac_prop_info_set_default_uint8(prh, 1354 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1355 break; 1356 case MAC_PROP_ADV_1000FDX_CAP: 1357 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1358 mac_prop_info_set_default_uint8(prh, 1359 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1360 break; 1361 case MAC_PROP_EN_1000FDX_CAP: 1362 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1363 mac_prop_info_set_default_uint8(prh, 1364 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1365 break; 1366 case MAC_PROP_ADV_10GFDX_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_10GB) != 0); 1370 break; 1371 case MAC_PROP_EN_10GFDX_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_10GB) != 0); 1375 break; 1376 case MAC_PROP_ADV_25GFDX_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_25GB) != 0); 1380 break; 1381 case MAC_PROP_EN_25GFDX_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_25GB) != 0); 1385 break; 1386 case MAC_PROP_ADV_40GFDX_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_40GB) != 0); 1390 break; 1391 case MAC_PROP_EN_40GFDX_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_40GB) != 0); 1395 break; 1396 case MAC_PROP_PRIVATE: 1397 i40e_m_propinfo_private(i40e, pr_name, prh); 1398 break; 1399 default: 1400 break; 1401 } 1402 1403 mutex_exit(&i40e->i40e_general_lock); 1404 } 1405 1406 #define I40E_M_CALLBACK_FLAGS \ 1407 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 1408 1409 static mac_callbacks_t i40e_m_callbacks = { 1410 I40E_M_CALLBACK_FLAGS, 1411 i40e_m_stat, 1412 i40e_m_start, 1413 i40e_m_stop, 1414 i40e_m_promisc, 1415 i40e_m_multicast, 1416 NULL, 1417 NULL, 1418 NULL, 1419 i40e_m_ioctl, 1420 i40e_m_getcapab, 1421 NULL, 1422 NULL, 1423 i40e_m_setprop, 1424 i40e_m_getprop, 1425 i40e_m_propinfo 1426 }; 1427 1428 boolean_t 1429 i40e_register_mac(i40e_t *i40e) 1430 { 1431 struct i40e_hw *hw = &i40e->i40e_hw_space; 1432 int status; 1433 mac_register_t *mac = mac_alloc(MAC_VERSION); 1434 1435 if (mac == NULL) 1436 return (B_FALSE); 1437 1438 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1439 mac->m_driver = i40e; 1440 mac->m_dip = i40e->i40e_dip; 1441 mac->m_src_addr = hw->mac.addr; 1442 mac->m_callbacks = &i40e_m_callbacks; 1443 mac->m_min_sdu = 0; 1444 mac->m_max_sdu = i40e->i40e_sdu; 1445 mac->m_margin = VLAN_TAGSZ; 1446 mac->m_priv_props = i40e_priv_props; 1447 mac->m_v12n = MAC_VIRT_LEVEL1; 1448 1449 status = mac_register(mac, &i40e->i40e_mac_hdl); 1450 if (status != 0) 1451 i40e_error(i40e, "mac_register() returned %d", status); 1452 mac_free(mac); 1453 1454 return (status == 0); 1455 } 1456