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 LSO_TX_BASIC_TCP_IPV6; 738 cap_lso->lso_basic_tcp_ipv4.lso_max = I40E_LSO_MAXLEN; 739 cap_lso->lso_basic_tcp_ipv6.lso_max = I40E_LSO_MAXLEN; 740 } else { 741 return (B_FALSE); 742 } 743 break; 744 } 745 746 case MAC_CAPAB_RINGS: 747 cap_rings = cap_data; 748 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC; 749 switch (cap_rings->mr_type) { 750 case MAC_RING_TYPE_TX: 751 /* 752 * Note, saying we have no groups, but some 753 * number of rings indicates to MAC that it 754 * should create psuedo-groups with one for 755 * each TX ring. This may not be the long term 756 * behavior we want, but it'll work for now. 757 */ 758 cap_rings->mr_gnum = 0; 759 cap_rings->mr_rnum = i40e->i40e_num_trqpairs_per_vsi; 760 cap_rings->mr_rget = i40e_fill_tx_ring; 761 cap_rings->mr_gget = NULL; 762 cap_rings->mr_gaddring = NULL; 763 cap_rings->mr_gremring = NULL; 764 break; 765 case MAC_RING_TYPE_RX: 766 cap_rings->mr_rnum = i40e->i40e_num_trqpairs; 767 cap_rings->mr_rget = i40e_fill_rx_ring; 768 cap_rings->mr_gnum = i40e->i40e_num_rx_groups; 769 cap_rings->mr_gget = i40e_fill_rx_group; 770 cap_rings->mr_gaddring = NULL; 771 cap_rings->mr_gremring = NULL; 772 break; 773 default: 774 return (B_FALSE); 775 } 776 break; 777 case MAC_CAPAB_TRANSCEIVER: 778 mct = cap_data; 779 780 /* 781 * Firmware doesn't have a great way of telling us in advance 782 * whether we'd expect a SFF transceiver. As such, we always 783 * advertise the support for this capability. 784 */ 785 mct->mct_flags = 0; 786 mct->mct_ntransceivers = 1; 787 mct->mct_info = i40e_transceiver_info; 788 mct->mct_read = i40e_transceiver_read; 789 790 return (B_TRUE); 791 case MAC_CAPAB_LED: 792 mcl = cap_data; 793 794 mcl->mcl_flags = 0; 795 mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT | MAC_LED_OFF | 796 MAC_LED_ON; 797 mcl->mcl_set = i40e_gld_led_set; 798 break; 799 800 default: 801 return (B_FALSE); 802 } 803 804 return (B_TRUE); 805 } 806 807 /* ARGSUSED */ 808 static int 809 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize, 810 const void *pr_val) 811 { 812 int ret; 813 long val; 814 char *eptr; 815 816 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 817 818 if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 || 819 *eptr != '\0') { 820 return (ret); 821 } 822 823 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 824 if (val < I40E_MIN_RX_DMA_THRESH || 825 val > I40E_MAX_RX_DMA_THRESH) { 826 return (EINVAL); 827 } 828 i40e->i40e_rx_dma_min = (uint32_t)val; 829 return (0); 830 } 831 832 if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 833 if (val < I40E_MIN_TX_DMA_THRESH || 834 val > I40E_MAX_TX_DMA_THRESH) { 835 return (EINVAL); 836 } 837 i40e->i40e_tx_dma_min = (uint32_t)val; 838 return (0); 839 } 840 841 if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 842 if (val < I40E_MIN_ITR || 843 val > I40E_MAX_ITR) { 844 return (EINVAL); 845 } 846 i40e->i40e_rx_itr = (uint32_t)val; 847 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr); 848 return (0); 849 } 850 851 if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 852 if (val < I40E_MIN_ITR || 853 val > I40E_MAX_ITR) { 854 return (EINVAL); 855 } 856 i40e->i40e_tx_itr = (uint32_t)val; 857 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr); 858 return (0); 859 } 860 861 if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 862 if (val < I40E_MIN_ITR || 863 val > I40E_MAX_ITR) { 864 return (EINVAL); 865 } 866 i40e->i40e_tx_itr = (uint32_t)val; 867 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER, 868 i40e->i40e_other_itr); 869 return (0); 870 } 871 872 return (ENOTSUP); 873 } 874 875 static int 876 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize, 877 void *pr_val) 878 { 879 uint32_t val; 880 881 ASSERT(MUTEX_HELD(&i40e->i40e_general_lock)); 882 883 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 884 val = i40e->i40e_rx_dma_min; 885 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 886 val = i40e->i40e_tx_dma_min; 887 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 888 val = i40e->i40e_rx_itr; 889 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 890 val = i40e->i40e_tx_itr; 891 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 892 val = i40e->i40e_other_itr; 893 } else { 894 return (ENOTSUP); 895 } 896 897 if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize) 898 return (ERANGE); 899 return (0); 900 } 901 902 /* 903 * Annoyingly for private properties MAC seems to ignore default values that 904 * aren't strings. That means that we have to translate all of these into 905 * uint32_t's and instead we size the buffer to be large enough to hold a 906 * uint32_t. 907 */ 908 /* ARGSUSED */ 909 static void 910 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name, 911 mac_prop_info_handle_t prh) 912 { 913 char buf[64]; 914 uint32_t def; 915 916 if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) { 917 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 918 def = I40E_DEF_RX_DMA_THRESH; 919 mac_prop_info_set_range_uint32(prh, 920 I40E_MIN_RX_DMA_THRESH, 921 I40E_MAX_RX_DMA_THRESH); 922 } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) { 923 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 924 def = I40E_DEF_TX_DMA_THRESH; 925 mac_prop_info_set_range_uint32(prh, 926 I40E_MIN_TX_DMA_THRESH, 927 I40E_MAX_TX_DMA_THRESH); 928 } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) { 929 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 930 def = I40E_DEF_RX_ITR; 931 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 932 } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) { 933 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 934 def = I40E_DEF_TX_ITR; 935 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 936 } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) { 937 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW); 938 def = I40E_DEF_OTHER_ITR; 939 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR); 940 } else { 941 return; 942 } 943 944 (void) snprintf(buf, sizeof (buf), "%d", def); 945 mac_prop_info_set_default_str(prh, buf); 946 } 947 948 static int 949 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 950 uint_t pr_valsize, const void *pr_val) 951 { 952 uint32_t new_mtu; 953 i40e_t *i40e = arg; 954 int ret = 0; 955 956 mutex_enter(&i40e->i40e_general_lock); 957 if (i40e->i40e_state & I40E_SUSPENDED) { 958 mutex_exit(&i40e->i40e_general_lock); 959 return (ECANCELED); 960 } 961 962 switch (pr_num) { 963 /* 964 * These properties are always read-only across every device. 965 */ 966 case MAC_PROP_DUPLEX: 967 case MAC_PROP_SPEED: 968 case MAC_PROP_STATUS: 969 case MAC_PROP_ADV_100FDX_CAP: 970 case MAC_PROP_ADV_1000FDX_CAP: 971 case MAC_PROP_ADV_10GFDX_CAP: 972 case MAC_PROP_ADV_25GFDX_CAP: 973 case MAC_PROP_ADV_40GFDX_CAP: 974 ret = ENOTSUP; 975 break; 976 /* 977 * These are read-only at this time as we don't support configuring 978 * auto-negotiation. See the theory statement in i40e_main.c. 979 */ 980 case MAC_PROP_EN_100FDX_CAP: 981 case MAC_PROP_EN_1000FDX_CAP: 982 case MAC_PROP_EN_10GFDX_CAP: 983 case MAC_PROP_EN_25GFDX_CAP: 984 case MAC_PROP_EN_40GFDX_CAP: 985 case MAC_PROP_AUTONEG: 986 case MAC_PROP_FLOWCTRL: 987 ret = ENOTSUP; 988 break; 989 990 case MAC_PROP_MTU: 991 bcopy(pr_val, &new_mtu, sizeof (new_mtu)); 992 if (new_mtu == i40e->i40e_sdu) 993 break; 994 995 if (new_mtu < I40E_MIN_MTU || 996 new_mtu > I40E_MAX_MTU) { 997 ret = EINVAL; 998 break; 999 } 1000 1001 if (i40e->i40e_state & I40E_STARTED) { 1002 ret = EBUSY; 1003 break; 1004 } 1005 1006 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu); 1007 if (ret == 0) { 1008 i40e->i40e_sdu = new_mtu; 1009 i40e_update_mtu(i40e); 1010 } 1011 break; 1012 1013 case MAC_PROP_PRIVATE: 1014 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val); 1015 break; 1016 default: 1017 ret = ENOTSUP; 1018 break; 1019 } 1020 1021 mutex_exit(&i40e->i40e_general_lock); 1022 return (ret); 1023 } 1024 1025 static int 1026 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1027 uint_t pr_valsize, void *pr_val) 1028 { 1029 i40e_t *i40e = arg; 1030 uint64_t speed; 1031 int ret = 0; 1032 uint8_t *u8; 1033 link_flowctrl_t fctl; 1034 1035 mutex_enter(&i40e->i40e_general_lock); 1036 1037 switch (pr_num) { 1038 case MAC_PROP_DUPLEX: 1039 if (pr_valsize < sizeof (link_duplex_t)) { 1040 ret = EOVERFLOW; 1041 break; 1042 } 1043 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t)); 1044 break; 1045 case MAC_PROP_SPEED: 1046 if (pr_valsize < sizeof (uint64_t)) { 1047 ret = EOVERFLOW; 1048 break; 1049 } 1050 speed = i40e->i40e_link_speed * 1000000ULL; 1051 bcopy(&speed, pr_val, sizeof (speed)); 1052 break; 1053 case MAC_PROP_STATUS: 1054 if (pr_valsize < sizeof (link_state_t)) { 1055 ret = EOVERFLOW; 1056 break; 1057 } 1058 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t)); 1059 break; 1060 case MAC_PROP_AUTONEG: 1061 if (pr_valsize < sizeof (uint8_t)) { 1062 ret = EOVERFLOW; 1063 break; 1064 } 1065 u8 = pr_val; 1066 *u8 = 1; 1067 break; 1068 case MAC_PROP_FLOWCTRL: 1069 /* 1070 * Because we don't currently support hardware flow control, we 1071 * just hardcode this to be none. 1072 */ 1073 if (pr_valsize < sizeof (link_flowctrl_t)) { 1074 ret = EOVERFLOW; 1075 break; 1076 } 1077 fctl = LINK_FLOWCTRL_NONE; 1078 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t)); 1079 break; 1080 case MAC_PROP_MTU: 1081 if (pr_valsize < sizeof (uint32_t)) { 1082 ret = EOVERFLOW; 1083 break; 1084 } 1085 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t)); 1086 break; 1087 1088 /* 1089 * Because we don't let users control the speeds we may auto-negotiate 1090 * to, the values of the ADV_ and EN_ will always be the same. 1091 */ 1092 case MAC_PROP_ADV_100FDX_CAP: 1093 case MAC_PROP_EN_100FDX_CAP: 1094 if (pr_valsize < sizeof (uint8_t)) { 1095 ret = EOVERFLOW; 1096 break; 1097 } 1098 u8 = pr_val; 1099 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0; 1100 break; 1101 case MAC_PROP_ADV_1000FDX_CAP: 1102 case MAC_PROP_EN_1000FDX_CAP: 1103 if (pr_valsize < sizeof (uint8_t)) { 1104 ret = EOVERFLOW; 1105 break; 1106 } 1107 u8 = pr_val; 1108 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0; 1109 break; 1110 case MAC_PROP_ADV_10GFDX_CAP: 1111 case MAC_PROP_EN_10GFDX_CAP: 1112 if (pr_valsize < sizeof (uint8_t)) { 1113 ret = EOVERFLOW; 1114 break; 1115 } 1116 u8 = pr_val; 1117 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0; 1118 break; 1119 case MAC_PROP_ADV_25GFDX_CAP: 1120 case MAC_PROP_EN_25GFDX_CAP: 1121 if (pr_valsize < sizeof (uint8_t)) { 1122 ret = EOVERFLOW; 1123 break; 1124 } 1125 u8 = pr_val; 1126 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0; 1127 break; 1128 case MAC_PROP_ADV_40GFDX_CAP: 1129 case MAC_PROP_EN_40GFDX_CAP: 1130 if (pr_valsize < sizeof (uint8_t)) { 1131 ret = EOVERFLOW; 1132 break; 1133 } 1134 u8 = pr_val; 1135 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0; 1136 break; 1137 case MAC_PROP_PRIVATE: 1138 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val); 1139 break; 1140 default: 1141 ret = ENOTSUP; 1142 break; 1143 } 1144 1145 mutex_exit(&i40e->i40e_general_lock); 1146 1147 return (ret); 1148 } 1149 1150 static void 1151 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num, 1152 mac_prop_info_handle_t prh) 1153 { 1154 i40e_t *i40e = arg; 1155 1156 mutex_enter(&i40e->i40e_general_lock); 1157 1158 switch (pr_num) { 1159 case MAC_PROP_DUPLEX: 1160 case MAC_PROP_SPEED: 1161 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1162 break; 1163 case MAC_PROP_FLOWCTRL: 1164 /* 1165 * At the moment, the driver doesn't support flow control, hence 1166 * why this is set to read-only and none. 1167 */ 1168 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1169 mac_prop_info_set_default_link_flowctrl(prh, 1170 LINK_FLOWCTRL_NONE); 1171 break; 1172 case MAC_PROP_MTU: 1173 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU); 1174 break; 1175 1176 /* 1177 * We set the defaults for these based upon the phy's ability to 1178 * support the speeds. Note, auto-negotiation is required for fiber, 1179 * hence it is read-only and always enabled. When we have access to 1180 * copper phys we can revisit this. 1181 */ 1182 case MAC_PROP_AUTONEG: 1183 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1184 mac_prop_info_set_default_uint8(prh, 1); 1185 break; 1186 case MAC_PROP_ADV_100FDX_CAP: 1187 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1188 mac_prop_info_set_default_uint8(prh, 1189 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1190 break; 1191 case MAC_PROP_EN_100FDX_CAP: 1192 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1193 mac_prop_info_set_default_uint8(prh, 1194 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0); 1195 break; 1196 case MAC_PROP_ADV_1000FDX_CAP: 1197 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1198 mac_prop_info_set_default_uint8(prh, 1199 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1200 break; 1201 case MAC_PROP_EN_1000FDX_CAP: 1202 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1203 mac_prop_info_set_default_uint8(prh, 1204 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0); 1205 break; 1206 case MAC_PROP_ADV_10GFDX_CAP: 1207 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1208 mac_prop_info_set_default_uint8(prh, 1209 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0); 1210 break; 1211 case MAC_PROP_EN_10GFDX_CAP: 1212 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1213 mac_prop_info_set_default_uint8(prh, 1214 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0); 1215 break; 1216 case MAC_PROP_ADV_25GFDX_CAP: 1217 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1218 mac_prop_info_set_default_uint8(prh, 1219 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0); 1220 break; 1221 case MAC_PROP_EN_25GFDX_CAP: 1222 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1223 mac_prop_info_set_default_uint8(prh, 1224 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0); 1225 break; 1226 case MAC_PROP_ADV_40GFDX_CAP: 1227 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1228 mac_prop_info_set_default_uint8(prh, 1229 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0); 1230 break; 1231 case MAC_PROP_EN_40GFDX_CAP: 1232 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ); 1233 mac_prop_info_set_default_uint8(prh, 1234 (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0); 1235 break; 1236 case MAC_PROP_PRIVATE: 1237 i40e_m_propinfo_private(i40e, pr_name, prh); 1238 break; 1239 default: 1240 break; 1241 } 1242 1243 mutex_exit(&i40e->i40e_general_lock); 1244 } 1245 1246 #define I40E_M_CALLBACK_FLAGS \ 1247 (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO) 1248 1249 static mac_callbacks_t i40e_m_callbacks = { 1250 I40E_M_CALLBACK_FLAGS, 1251 i40e_m_stat, 1252 i40e_m_start, 1253 i40e_m_stop, 1254 i40e_m_promisc, 1255 i40e_m_multicast, 1256 NULL, 1257 NULL, 1258 NULL, 1259 i40e_m_ioctl, 1260 i40e_m_getcapab, 1261 NULL, 1262 NULL, 1263 i40e_m_setprop, 1264 i40e_m_getprop, 1265 i40e_m_propinfo 1266 }; 1267 1268 boolean_t 1269 i40e_register_mac(i40e_t *i40e) 1270 { 1271 struct i40e_hw *hw = &i40e->i40e_hw_space; 1272 int status; 1273 mac_register_t *mac = mac_alloc(MAC_VERSION); 1274 1275 if (mac == NULL) 1276 return (B_FALSE); 1277 1278 mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 1279 mac->m_driver = i40e; 1280 mac->m_dip = i40e->i40e_dip; 1281 mac->m_src_addr = hw->mac.addr; 1282 mac->m_callbacks = &i40e_m_callbacks; 1283 mac->m_min_sdu = 0; 1284 mac->m_max_sdu = i40e->i40e_sdu; 1285 mac->m_margin = VLAN_TAGSZ; 1286 mac->m_priv_props = i40e_priv_props; 1287 mac->m_v12n = MAC_VIRT_LEVEL1; 1288 1289 status = mac_register(mac, &i40e->i40e_mac_hdl); 1290 if (status != 0) 1291 i40e_error(i40e, "mac_register() returned %d", status); 1292 mac_free(mac); 1293 1294 return (status == 0); 1295 } 1296