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 */ 17 18 /* 19 * For more information, please see the big theory statement in i40e_main.c. 20 */ 21 22 #include "i40e_sw.h" 23 24 #define I40E_PROP_RX_DMA_THRESH "_rx_dma_threshold" 25 #define I40E_PROP_TX_DMA_THRESH "_tx_dma_threshold" 26 #define I40E_PROP_RX_ITR "_rx_intr_throttle" 27 #define I40E_PROP_TX_ITR "_tx_intr_throttle" 28 #define I40E_PROP_OTHER_ITR "_other_intr_throttle" 29 30 char *i40e_priv_props[] = { 31 I40E_PROP_RX_DMA_THRESH, 32 I40E_PROP_TX_DMA_THRESH, 33 I40E_PROP_RX_ITR, 34 I40E_PROP_TX_ITR, 35 I40E_PROP_OTHER_ITR, 36 NULL 37 }; 38 39 static int 40 i40e_group_remove_mac(void *arg, const uint8_t *mac_addr) 41 { 42 i40e_t *i40e = arg; 43 struct i40e_aqc_remove_macvlan_element_data filt; 44 struct i40e_hw *hw = &i40e->i40e_hw_space; 45 int ret, i, last; 46 i40e_uaddr_t *iua; 47 48 if (I40E_IS_MULTICAST(mac_addr)) 49 return (EINVAL); 50 51 mutex_enter(&i40e->i40e_general_lock); 52 53 if (i40e->i40e_state & I40E_SUSPENDED) { 54 ret = ECANCELED; 55 goto done; 56 } 57 58 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) { 59 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac, 60 ETHERADDRL) == 0) 61 break; 62 } 63 64 if (i == i40e->i40e_resources.ifr_nmacfilt_used) { 65 ret = ENOENT; 66 goto done; 67 } 68 69 iua = &i40e->i40e_uaddrs[i]; 70 ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0); 71 72 bzero(&filt, sizeof (filt)); 73 bcopy(mac_addr, filt.mac_addr, ETHERADDRL); 74 filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | 75 I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; 76 77 if (i40e_aq_remove_macvlan(hw, iua->iua_vsi, &filt, 1, NULL) != 78 I40E_SUCCESS) { 79 i40e_error(i40e, "failed to remove mac address " 80 "%2x:%2x:%2x:%2x:%2x:%2x from unicast filter: %d", 81 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], 82 mac_addr[4], mac_addr[5], filt.error_code); 83 ret = EIO; 84 goto done; 85 } 86 87 last = i40e->i40e_resources.ifr_nmacfilt_used - 1; 88 if (i != last) { 89 i40e_uaddr_t *src = &i40e->i40e_uaddrs[last]; 90 bcopy(src, iua, sizeof (i40e_uaddr_t)); 91 } 92 93 /* 94 * Set the multicast bit in the last one to indicate to ourselves that 95 * it's invalid. 96 */ 97 bzero(&i40e->i40e_uaddrs[last], sizeof (i40e_uaddr_t)); 98 i40e->i40e_uaddrs[last].iua_mac[0] = 0x01; 99 i40e->i40e_resources.ifr_nmacfilt_used--; 100 ret = 0; 101 done: 102 mutex_exit(&i40e->i40e_general_lock); 103 104 return (ret); 105 } 106 107 static int 108 i40e_group_add_mac(void *arg, const uint8_t *mac_addr) 109 { 110 i40e_t *i40e = arg; 111 struct i40e_hw *hw = &i40e->i40e_hw_space; 112 int i, ret; 113 i40e_uaddr_t *iua; 114 struct i40e_aqc_add_macvlan_element_data filt; 115 116 if (I40E_IS_MULTICAST(mac_addr)) 117 return (EINVAL); 118 119 mutex_enter(&i40e->i40e_general_lock); 120 if (i40e->i40e_state & I40E_SUSPENDED) { 121 ret = ECANCELED; 122 goto done; 123 } 124 125 if (i40e->i40e_resources.ifr_nmacfilt == 126 i40e->i40e_resources.ifr_nmacfilt_used) { 127 ret = ENOSPC; 128 goto done; 129 } 130 131 for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) { 132 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac, 133 ETHERADDRL) == 0) { 134 ret = EEXIST; 135 goto done; 136 } 137 } 138 139 /* 140 * Note, the general use of the i40e_vsi_id will have to be refactored 141 * when we have proper group support. 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, i40e->i40e_vsi_id, &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 = i40e->i40e_vsi_id; 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, B_TRUE)) { 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, B_TRUE); 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->i40e_vsi_id, 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->i40e_vsi_id, 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, i40e->i40e_vsi_id, 261 !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->i40e_vsi_id, 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->i40e_vsi_id, 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->i40e_vsi_id, &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->i40e_vsi_id, 357 &filt, 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->i40e_vsi_id, 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->i40e_vsi_id, 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 440 /* 441 * GLDv3 requires we keep track of a generation number, as it uses 442 * that number to keep track of whether or not a ring is active. 443 */ 444 mutex_enter(&itrq->itrq_rx_lock); 445 itrq->itrq_rxgen = gen_num; 446 mutex_exit(&itrq->itrq_rx_lock); 447 return (0); 448 } 449 450 /* ARGSUSED */ 451 static int 452 i40e_rx_ring_intr_enable(mac_intr_handle_t intrh) 453 { 454 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh; 455 456 mutex_enter(&itrq->itrq_rx_lock); 457 ASSERT(itrq->itrq_intr_poll == B_TRUE); 458 i40e_intr_rx_queue_enable(itrq); 459 itrq->itrq_intr_poll = B_FALSE; 460 mutex_exit(&itrq->itrq_rx_lock); 461 462 return (0); 463 } 464 465 /* ARGSUSED */ 466 static int 467 i40e_rx_ring_intr_disable(mac_intr_handle_t intrh) 468 { 469 i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh; 470 471 mutex_enter(&itrq->itrq_rx_lock); 472 i40e_intr_rx_queue_disable(itrq); 473 itrq->itrq_intr_poll = B_TRUE; 474 mutex_exit(&itrq->itrq_rx_lock); 475 476 return (0); 477 } 478 479 /* ARGSUSED */ 480 static void 481 i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index, 482 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 483 { 484 i40e_t *i40e = arg; 485 mac_intr_t *mintr = &infop->mri_intr; 486 i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]); 487 488 /* 489 * Note the group index here is expected to be -1 due to the fact that 490 * we're not actually grouping things tx-wise at this time. 491 */ 492 ASSERT(group_index == -1); 493 ASSERT(ring_index < i40e->i40e_num_trqpairs); 494 495 itrq->itrq_mactxring = rh; 496 infop->mri_driver = (mac_ring_driver_t)itrq; 497 infop->mri_start = NULL; 498 infop->mri_stop = NULL; 499 infop->mri_tx = i40e_ring_tx; 500 infop->mri_stat = i40e_tx_ring_stat; 501 502 /* 503 * We only provide the handle in cases where we have MSI-X interrupts, 504 * to indicate that we'd actually support retargetting. 505 */ 506 if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) { 507 mintr->mi_ddi_handle = 508 i40e->i40e_intr_handles[itrq->itrq_tx_intrvec]; 509 } 510 } 511 512 /* ARGSUSED */ 513 static void 514 i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index, 515 const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh) 516 { 517 i40e_t *i40e = arg; 518 mac_intr_t *mintr = &infop->mri_intr; 519 i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[ring_index]; 520 521 /* 522 * We assert the group number and ring index to help sanity check 523 * ourselves and mark that we'll need to rework this when we have 524 * multiple groups. 525 */ 526 ASSERT3S(group_index, ==, 0); 527 ASSERT3S(ring_index, <, i40e->i40e_num_trqpairs); 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 556 if (rtype != MAC_RING_TYPE_RX) 557 return; 558 559 /* 560 * Note, this is a simplified view of a group, given that we only have a 561 * single group and a single ring at the moment. We'll want to expand 562 * upon this as we leverage more hardware functionality. 563 */ 564 i40e->i40e_rx_group_handle = gh; 565 infop->mgi_driver = (mac_group_driver_t)i40e; 566 infop->mgi_start = NULL; 567 infop->mgi_stop = NULL; 568 infop->mgi_addmac = i40e_group_add_mac; 569 infop->mgi_remmac = i40e_group_remove_mac; 570 571 ASSERT(i40e->i40e_num_rx_groups == I40E_GROUP_MAX); 572 infop->mgi_count = i40e->i40e_num_trqpairs; 573 } 574 575 static int 576 i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop) 577 { 578 boolean_t present, usable; 579 i40e_t *i40e = arg; 580 581 if (id != 0 || infop == NULL) 582 return (EINVAL); 583 584 mutex_enter(&i40e->i40e_general_lock); 585 switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { 586 case I40E_MODULE_TYPE_SFP: 587 case I40E_MODULE_TYPE_QSFP: 588 break; 589 default: 590 mutex_exit(&i40e->i40e_general_lock); 591 return (ENOTSUP); 592 } 593 594 present = !!(i40e->i40e_hw_space.phy.link_info.link_info & 595 I40E_AQ_MEDIA_AVAILABLE); 596 if (present) { 597 usable = !!(i40e->i40e_hw_space.phy.link_info.an_info & 598 I40E_AQ_QUALIFIED_MODULE); 599 } else { 600 usable = B_FALSE; 601 } 602 mutex_exit(&i40e->i40e_general_lock); 603 604 mac_transceiver_info_set_usable(infop, usable); 605 mac_transceiver_info_set_present(infop, present); 606 607 return (0); 608 } 609 610 static int 611 i40e_transceiver_read(void *arg, uint_t id, uint_t page, void *buf, 612 size_t nbytes, off_t offset, size_t *nread) 613 { 614 i40e_t *i40e = arg; 615 struct i40e_hw *hw = &i40e->i40e_hw_space; 616 uint8_t *buf8 = buf; 617 size_t i; 618 619 if (id != 0 || buf == NULL || nbytes == 0 || nread == NULL || 620 (page != 0xa0 && page != 0xa2) || offset < 0) 621 return (EINVAL); 622 623 /* 624 * Both supported pages have a length of 256 bytes, ensure nothing asks 625 * us to go beyond that. 626 */ 627 if (nbytes > 256 || offset >= 256 || (offset + nbytes > 256)) { 628 return (EINVAL); 629 } 630 631 mutex_enter(&i40e->i40e_general_lock); 632 switch (i40e->i40e_hw_space.phy.link_info.module_type[0]) { 633 case I40E_MODULE_TYPE_SFP: 634 case I40E_MODULE_TYPE_QSFP: 635 break; 636 default: 637 mutex_exit(&i40e->i40e_general_lock); 638 return (ENOTSUP); 639 } 640 641 /* 642 * Make sure we have a sufficiently new firmware version to run this 643 * command. This was introduced in firmware API 1.7. This is apparently 644 * only supported on the XL710 MAC, not the XL722. 645 */ 646 if (hw->mac.type != I40E_MAC_XL710 || hw->aq.api_maj_ver != 1 || 647 hw->aq.api_min_ver < 7) { 648 mutex_exit(&i40e->i40e_general_lock); 649 return (ENOTSUP); 650 } 651 652 for (i = 0; i < nbytes; i++, offset++) { 653 enum i40e_status_code status; 654 uint32_t val; 655 656 status = i40e_aq_get_phy_register(hw, 657 I40E_AQ_PHY_REG_ACCESS_EXTERNAL_MODULE, page, offset, 658 &val, NULL); 659 if (status != I40E_SUCCESS) { 660 mutex_exit(&i40e->i40e_general_lock); 661 return (EIO); 662 } 663 664 buf8[i] = (uint8_t)val; 665 } 666 667 mutex_exit(&i40e->i40e_general_lock); 668 *nread = nbytes; 669 670 return (0); 671 } 672 673 static int 674 i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags) 675 { 676 i40e_t *i40e = arg; 677 struct i40e_hw *hw = &i40e->i40e_hw_space; 678 679 if (flags != 0) 680 return (EINVAL); 681 682 if (mode != MAC_LED_DEFAULT && 683 mode != MAC_LED_IDENT && 684 mode != MAC_LED_OFF && 685 mode != MAC_LED_ON) 686 return (ENOTSUP); 687 688 if (mode != MAC_LED_DEFAULT && !i40e->i40e_led_saved) { 689 i40e->i40e_led_status = i40e_led_get(hw); 690 i40e->i40e_led_saved = B_TRUE; 691 } 692 693 switch (mode) { 694 case MAC_LED_DEFAULT: 695 if (i40e->i40e_led_saved) { 696 i40e_led_set(hw, i40e->i40e_led_status, B_FALSE); 697 i40e->i40e_led_status = 0; 698 i40e->i40e_led_saved = B_FALSE; 699 } 700 break; 701 case MAC_LED_IDENT: 702 i40e_led_set(hw, 0xf, B_TRUE); 703 break; 704 case MAC_LED_OFF: 705 i40e_led_set(hw, 0x0, B_FALSE); 706 break; 707 case MAC_LED_ON: 708 i40e_led_set(hw, 0xf, B_FALSE); 709 break; 710 default: 711 return (ENOTSUP); 712 } 713 714 return (0); 715 } 716 717 static boolean_t 718 i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data) 719 { 720 i40e_t *i40e = arg; 721 mac_capab_rings_t *cap_rings; 722 mac_capab_transceiver_t *mct; 723 mac_capab_led_t *mcl; 724 725 switch (cap) { 726 case MAC_CAPAB_HCKSUM: { 727 uint32_t *txflags = cap_data; 728 729 *txflags = 0; 730 if (i40e->i40e_tx_hcksum_enable == B_TRUE) 731 *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM; 732 break; 733 } 734 735 case MAC_CAPAB_RINGS: 736 cap_rings = cap_data; 737 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 738 switch (cap_rings->mr_type) { 739 case MAC_RING_TYPE_TX: 740 /* 741 * Note, saying we have no rings, but some number of 742 * groups indicates to MAC that it should create 743 * psuedo-groups with one for each TX ring. This may not 744 * be the long term behavior we want, but it'll work for 745 * now. 746 */ 747 cap_rings->mr_gnum = 0; 748 cap_rings->mr_rnum = i40e->i40e_num_trqpairs; 749 cap_rings->mr_rget = i40e_fill_tx_ring; 750 cap_rings->mr_gget = NULL; 751 cap_rings->mr_gaddring = NULL; 752 cap_rings->mr_gremring = NULL; 753 break; 754 case MAC_RING_TYPE_RX: 755 cap_rings->mr_rnum = i40e->i40e_num_trqpairs; 756 cap_rings->mr_rget = i40e_fill_rx_ring; 757 cap_rings->mr_gnum = I40E_GROUP_MAX; 758 cap_rings->mr_gget = i40e_fill_rx_group; 759 cap_rings->mr_gaddring = NULL; 760 cap_rings->mr_gremring = NULL; 761 break; 762 default: 763 return (B_FALSE); 764 } 765 break; 766 case MAC_CAPAB_TRANSCEIVER: 767 mct = cap_data; 768 769 /* 770 * Firmware doesn't have a great way of telling us in advance 771 * whether we'd expect a SFF transceiver. As such, we always 772 * advertise the support for this capability. 773 */ 774 mct->mct_flags = 0; 775 mct->mct_ntransceivers = 1; 776 mct->mct_info = i40e_transceiver_info; 777 mct->mct_read = i40e_transceiver_read; 778 779 return (B_TRUE); 780 case MAC_CAPAB_LED: 781 mcl = cap_data; 782 783 mcl->mcl_flags = 0; 784 mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT | MAC_LED_OFF | 785 MAC_LED_ON; 786 mcl->mcl_set = i40e_gld_led_set; 787 break; 788 789 default: 790 return (B_FALSE); 791 } 792 793 return (B_TRUE); 794 } 795 796 /* ARGSUSED */ 797 static int 798 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize, 799 const void *pr_val) 800 { 801 int ret; 802 long val; 803 char *eptr; 804 805 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 806 807 if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 || 808 *eptr != '\0') { 809 return (ret); 810 } 811 812 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 813 if (val < I40E_MIN_RX_DMA_THRESH || 814 val > I40E_MAX_RX_DMA_THRESH) { 815 return (EINVAL); 816 } 817 i40e->i40e_rx_dma_min = (uint32_t)val; 818 return (0); 819 } 820 821 if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 822 if (val < I40E_MIN_TX_DMA_THRESH || 823 val > I40E_MAX_TX_DMA_THRESH) { 824 return (EINVAL); 825 } 826 i40e->i40e_tx_dma_min = (uint32_t)val; 827 return (0); 828 } 829 830 if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 831 if (val < I40E_MIN_ITR || 832 val > I40E_MAX_ITR) { 833 return (EINVAL); 834 } 835 i40e->i40e_rx_itr = (uint32_t)val; 836 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr); 837 return (0); 838 } 839 840 if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 841 if (val < I40E_MIN_ITR || 842 val > I40E_MAX_ITR) { 843 return (EINVAL); 844 } 845 i40e->i40e_tx_itr = (uint32_t)val; 846 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr); 847 return (0); 848 } 849 850 if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 851 if (val < I40E_MIN_ITR || 852 val > I40E_MAX_ITR) { 853 return (EINVAL); 854 } 855 i40e->i40e_tx_itr = (uint32_t)val; 856 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER, 857 i40e->i40e_other_itr); 858 return (0); 859 } 860 861 return (ENOTSUP); 862 } 863 864 static int 865 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize, 866 void *pr_val) 867 { 868 uint32_t val; 869 870 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 871 872 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 873 val = i40e->i40e_rx_dma_min; 874 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 875 val = i40e->i40e_tx_dma_min; 876 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 877 val = i40e->i40e_rx_itr; 878 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 879 val = i40e->i40e_tx_itr; 880 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 881 val = i40e->i40e_other_itr; 882 } else { 883 return (ENOTSUP); 884 } 885 886 if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize) 887 return (ERANGE); 888 return (0); 889 } 890 891 /* 892 * Annoyingly for private properties MAC seems to ignore default values that 893 * aren't strings. That means that we have to translate all of these into 894 * uint32_t's and instead we size the buffer to be large enough to hold a 895 * uint32_t. 896 */ 897 /* ARGSUSED */ 898 static void 899 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name, 900 mac_prop_info_handle_t prh) 901 { 902 char buf[64]; 903 uint32_t def; 904 905 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 906 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 907 def = I40E_DEF_RX_DMA_THRESH; 908 mac_prop_info_set_range_uint32(prh, 909 I40E_MIN_RX_DMA_THRESH, 910 I40E_MAX_RX_DMA_THRESH); 911 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 912 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 913 def = I40E_DEF_TX_DMA_THRESH; 914 mac_prop_info_set_range_uint32(prh, 915 I40E_MIN_TX_DMA_THRESH, 916 I40E_MAX_TX_DMA_THRESH); 917 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 918 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 919 def = I40E_DEF_RX_ITR; 920 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 921 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 922 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 923 def = I40E_DEF_TX_ITR; 924 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 925 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 926 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 927 def = I40E_DEF_OTHER_ITR; 928 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 929 } else { 930 return; 931 } 932 933 (void) snprintf(buf, sizeof (buf), "%d", def); 934 mac_prop_info_set_default_str(prh, buf); 935 } 936 937 static int 938 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 939 uint_t pr_valsize, const void *pr_val) 940 { 941 uint32_t new_mtu; 942 i40e_t *i40e = arg; 943 int ret = 0; 944 945 mutex_enter(&i40e->i40e_general_lock); 946 if (i40e->i40e_state & I40E_SUSPENDED) { 947 mutex_exit(&i40e->i40e_general_lock); 948 return (ECANCELED); 949 } 950 951 switch (pr_num) { 952 /* 953 * These properties are always read-only across every device. 954 */ 955 case MAC_PROP_DUPLEX: 956 case MAC_PROP_SPEED: 957 case MAC_PROP_STATUS: 958 case MAC_PROP_ADV_100FDX_CAP: 959 case MAC_PROP_ADV_1000FDX_CAP: 960 case MAC_PROP_ADV_10GFDX_CAP: 961 case MAC_PROP_ADV_25GFDX_CAP: 962 case MAC_PROP_ADV_40GFDX_CAP: 963 ret = ENOTSUP; 964 break; 965 /* 966 * These are read-only at this time as we don't support configuring 967 * auto-negotiation. See the theory statement in i40e_main.c. 968 */ 969 case MAC_PROP_EN_100FDX_CAP: 970 case MAC_PROP_EN_1000FDX_CAP: 971 case MAC_PROP_EN_10GFDX_CAP: 972 case MAC_PROP_EN_25GFDX_CAP: 973 case MAC_PROP_EN_40GFDX_CAP: 974 case MAC_PROP_AUTONEG: 975 case MAC_PROP_FLOWCTRL: 976 ret = ENOTSUP; 977 break; 978 979 case MAC_PROP_MTU: 980 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 981 if (new_mtu == i40e->i40e_sdu) 982 break; 983 984 if (new_mtu < I40E_MIN_MTU || 985 new_mtu > I40E_MAX_MTU) { 986 ret = EINVAL; 987 break; 988 } 989 990 if (i40e->i40e_state & I40E_STARTED) { 991 ret = EBUSY; 992 break; 993 } 994 995 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu); 996 if (ret == 0) { 997 i40e->i40e_sdu = new_mtu; 998 i40e_update_mtu(i40e); 999 } 1000 break; 1001 1002 case MAC_PROP_PRIVATE: 1003 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val); 1004 break; 1005 default: 1006 ret = ENOTSUP; 1007 break; 1008 } 1009 1010 mutex_exit(&i40e->i40e_general_lock); 1011 return (ret); 1012 } 1013 1014 static int 1015 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1016 uint_t pr_valsize, void *pr_val) 1017 { 1018 i40e_t *i40e = arg; 1019 uint64_t speed; 1020 int ret = 0; 1021 uint8_t *u8; 1022 link_flowctrl_t fctl; 1023 1024 mutex_enter(&i40e->i40e_general_lock); 1025 1026 switch (pr_num) { 1027 case MAC_PROP_DUPLEX: 1028 if (pr_valsize < sizeof (link_duplex_t)) { 1029 ret = EOVERFLOW; 1030 break; 1031 } 1032 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t)); 1033 break; 1034 case MAC_PROP_SPEED: 1035 if (pr_valsize < sizeof (uint64_t)) { 1036 ret = EOVERFLOW; 1037 break; 1038 } 1039 speed = i40e->i40e_link_speed * 1000000ULL; 1040 bcopy(&speed, pr_val, sizeof (speed)); 1041 break; 1042 case MAC_PROP_STATUS: 1043 if (pr_valsize < sizeof (link_state_t)) { 1044 ret = EOVERFLOW; 1045 break; 1046 } 1047 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t)); 1048 break; 1049 case MAC_PROP_AUTONEG: 1050 if (pr_valsize < sizeof (uint8_t)) { 1051 ret = EOVERFLOW; 1052 break; 1053 } 1054 u8 = pr_val; 1055 *u8 = 1; 1056 break; 1057 case MAC_PROP_FLOWCTRL: 1058 /* 1059 * Because we don't currently support hardware flow control, we 1060 * just hardcode this to be none. 1061 */ 1062 if (pr_valsize < sizeof (link_flowctrl_t)) { 1063 ret = EOVERFLOW; 1064 break; 1065 } 1066 fctl = LINK_FLOWCTRL_NONE; 1067 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t)); 1068 break; 1069 case MAC_PROP_MTU: 1070 if (pr_valsize < sizeof (uint32_t)) { 1071 ret = EOVERFLOW; 1072 break; 1073 } 1074 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t)); 1075 break; 1076 1077 /* 1078 * Because we don't let users control the speeds we may auto-negotiate 1079 * to, the values of the ADV_ and EN_ will always be the same. 1080 */ 1081 case MAC_PROP_ADV_100FDX_CAP: 1082 case MAC_PROP_EN_100FDX_CAP: 1083 if (pr_valsize < sizeof (uint8_t)) { 1084 ret = EOVERFLOW; 1085 break; 1086 } 1087 u8 = pr_val; 1088 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0; 1089 break; 1090 case MAC_PROP_ADV_1000FDX_CAP: 1091 case MAC_PROP_EN_1000FDX_CAP: 1092 if (pr_valsize < sizeof (uint8_t)) { 1093 ret = EOVERFLOW; 1094 break; 1095 } 1096 u8 = pr_val; 1097 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0; 1098 break; 1099 case MAC_PROP_ADV_10GFDX_CAP: 1100 case MAC_PROP_EN_10GFDX_CAP: 1101 if (pr_valsize < sizeof (uint8_t)) { 1102 ret = EOVERFLOW; 1103 break; 1104 } 1105 u8 = pr_val; 1106 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0; 1107 break; 1108 case MAC_PROP_ADV_25GFDX_CAP: 1109 case MAC_PROP_EN_25GFDX_CAP: 1110 if (pr_valsize < sizeof (uint8_t)) { 1111 ret = EOVERFLOW; 1112 break; 1113 } 1114 u8 = pr_val; 1115 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0; 1116 break; 1117 case MAC_PROP_ADV_40GFDX_CAP: 1118 case MAC_PROP_EN_40GFDX_CAP: 1119 if (pr_valsize < sizeof (uint8_t)) { 1120 ret = EOVERFLOW; 1121 break; 1122 } 1123 u8 = pr_val; 1124 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0; 1125 break; 1126 case MAC_PROP_PRIVATE: 1127 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val); 1128 break; 1129 default: 1130 ret = ENOTSUP; 1131 break; 1132 } 1133 1134 mutex_exit(&i40e->i40e_general_lock); 1135 1136 return (ret); 1137 } 1138 1139 static void 1140 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1141 mac_prop_info_handle_t prh) 1142 { 1143 i40e_t *i40e = arg; 1144 1145 mutex_enter(&i40e->i40e_general_lock); 1146 1147 switch (pr_num) { 1148 case MAC_PROP_DUPLEX: 1149 case MAC_PROP_SPEED: 1150 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1151 break; 1152 case MAC_PROP_FLOWCTRL: 1153 /* 1154 * At the moment, the driver doesn't support flow control, hence 1155 * why this is set to read-only and none. 1156 */ 1157 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1158 mac_prop_info_set_default_link_flowctrl(prh, 1159 LINK_FLOWCTRL_NONE); 1160 break; 1161 case MAC_PROP_MTU: 1162 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU); 1163 break; 1164 1165 /* 1166 * We set the defaults for these based upon the phy's ability to 1167 * support the speeds. Note, auto-negotiation is required for fiber, 1168 * hence it is read-only and always enabled. When we have access to 1169 * copper phys we can revisit this. 1170 */ 1171 case MAC_PROP_AUTONEG: 1172 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1173 mac_prop_info_set_default_uint8(prh, 1); 1174 break; 1175 case MAC_PROP_ADV_100FDX_CAP: 1176 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1177 mac_prop_info_set_default_uint8(prh, 1178 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1179 break; 1180 case MAC_PROP_EN_100FDX_CAP: 1181 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1182 mac_prop_info_set_default_uint8(prh, 1183 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1184 break; 1185 case MAC_PROP_ADV_1000FDX_CAP: 1186 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1187 mac_prop_info_set_default_uint8(prh, 1188 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1189 break; 1190 case MAC_PROP_EN_1000FDX_CAP: 1191 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1192 mac_prop_info_set_default_uint8(prh, 1193 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1194 break; 1195 case MAC_PROP_ADV_10GFDX_CAP: 1196 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1197 mac_prop_info_set_default_uint8(prh, 1198 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0); 1199 break; 1200 case MAC_PROP_EN_10GFDX_CAP: 1201 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1202 mac_prop_info_set_default_uint8(prh, 1203 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0); 1204 break; 1205 case MAC_PROP_ADV_25GFDX_CAP: 1206 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1207 mac_prop_info_set_default_uint8(prh, 1208 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0); 1209 break; 1210 case MAC_PROP_EN_25GFDX_CAP: 1211 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1212 mac_prop_info_set_default_uint8(prh, 1213 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0); 1214 break; 1215 case MAC_PROP_ADV_40GFDX_CAP: 1216 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1217 mac_prop_info_set_default_uint8(prh, 1218 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0); 1219 break; 1220 case MAC_PROP_EN_40GFDX_CAP: 1221 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1222 mac_prop_info_set_default_uint8(prh, 1223 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0); 1224 break; 1225 case MAC_PROP_PRIVATE: 1226 i40e_m_propinfo_private(i40e, pr_name, prh); 1227 break; 1228 default: 1229 break; 1230 } 1231 1232 mutex_exit(&i40e->i40e_general_lock); 1233 } 1234 1235 #define I40E_M_CALLBACK_FLAGS \ 1236 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 1237 1238 static mac_callbacks_t i40e_m_callbacks = { 1239 I40E_M_CALLBACK_FLAGS, 1240 i40e_m_stat, 1241 i40e_m_start, 1242 i40e_m_stop, 1243 i40e_m_promisc, 1244 i40e_m_multicast, 1245 NULL, 1246 NULL, 1247 NULL, 1248 i40e_m_ioctl, 1249 i40e_m_getcapab, 1250 NULL, 1251 NULL, 1252 i40e_m_setprop, 1253 i40e_m_getprop, 1254 i40e_m_propinfo 1255 }; 1256 1257 boolean_t 1258 i40e_register_mac(i40e_t *i40e) 1259 { 1260 struct i40e_hw *hw = &i40e->i40e_hw_space; 1261 int status; 1262 mac_register_t *mac = mac_alloc(MAC_VERSION); 1263 1264 if (mac == NULL) 1265 return (B_FALSE); 1266 1267 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1268 mac->m_driver = i40e; 1269 mac->m_dip = i40e->i40e_dip; 1270 mac->m_src_addr = hw->mac.addr; 1271 mac->m_callbacks = &i40e_m_callbacks; 1272 mac->m_min_sdu = 0; 1273 mac->m_max_sdu = i40e->i40e_sdu; 1274 mac->m_margin = VLAN_TAGSZ; 1275 mac->m_priv_props = i40e_priv_props; 1276 mac->m_v12n = MAC_VIRT_LEVEL1; 1277 1278 status = mac_register(mac, &i40e->i40e_mac_hdl); 1279 if (status != 0) 1280 i40e_error(i40e, "mac_register() returned %d", status); 1281 mac_free(mac); 1282 1283 return (status == 0); 1284 } 1285