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