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