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