Print this page
MFV: illumos-joyent@61dc3dec4f82a3e13e94609a0a83d5f66c64e760
OS-6846 want i40e multi-group support
OS-7372 i40e_alloc_ring_mem() unwinds when it shouldn't
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Robert Mustacchi <rm@joyent.com>
Author: Ryan Zezeski <rpz@joyent.com>
MFV: illumos-joyent@9e30beee2f0c127bf41868db46257124206e28d6
OS-5225 Want Fortville TSO support
Reviewed by: Ryan Zezeski <rpz@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Patrick Mooney <patrick.mooney@joyent.com>
Author: Rob Johnston <rob.johnston@joyent.com>
MFV: illumos-gate@286d309c80aad9eac1fdbcb0388ed194d995d837
9805 i40e should read SFP data when firmware supports it
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Rob Johnston <rob.johnston@joyent.com>
Reviewed by: Dale Ghent <dale.ghent@joyent.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Robert Mustacchi <rm@joyent.com>
NEX-13226 xvv710 25Gb NIC panics system under load
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-7822 40Gb Intel XL710 NIC performance data
Reviewed by: Steve Peng <steve.peng@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
   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) 2017, 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         }


  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         }


 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) {


 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         present = !!(i40e->i40e_hw_space.phy.link_info.link_info &
 586             I40E_AQ_MEDIA_AVAILABLE);
 587         if (present) {
 588                 usable = !!(i40e->i40e_hw_space.phy.link_info.an_info &
 589                     I40E_AQ_QUALIFIED_MODULE);
 590         } else {
 591                 usable = B_FALSE;
 592         }
 593         mutex_exit(&i40e->i40e_general_lock);
 594 
 595         mac_transceiver_info_set_usable(infop, usable);
 596         mac_transceiver_info_set_present(infop, present);
 597 
 598         return (0);
 599 }
 600 
 601 static int































































 602 i40e_gld_led_set(void *arg, mac_led_mode_t mode, uint_t flags)
 603 {
 604         i40e_t *i40e = arg;
 605         struct i40e_hw *hw = &i40e->i40e_hw_space;
 606 
 607         if (flags != 0)
 608                 return (EINVAL);
 609 
 610         if (mode != MAC_LED_DEFAULT &&
 611             mode != MAC_LED_IDENT &&
 612             mode != MAC_LED_OFF &&
 613             mode != MAC_LED_ON)
 614                 return (ENOTSUP);
 615 
 616         if (mode != MAC_LED_DEFAULT && !i40e->i40e_led_saved) {
 617                 i40e->i40e_led_status = i40e_led_get(hw);
 618                 i40e->i40e_led_saved = B_TRUE;
 619         }
 620 
 621         switch (mode) {


 643 }
 644 
 645 static boolean_t
 646 i40e_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
 647 {
 648         i40e_t *i40e = arg;
 649         mac_capab_rings_t *cap_rings;
 650         mac_capab_transceiver_t *mct;
 651         mac_capab_led_t *mcl;
 652 
 653         switch (cap) {
 654         case MAC_CAPAB_HCKSUM: {
 655                 uint32_t *txflags = cap_data;
 656 
 657                 *txflags = 0;
 658                 if (i40e->i40e_tx_hcksum_enable == B_TRUE)
 659                         *txflags = HCKSUM_INET_PARTIAL | HCKSUM_IPHDRCKSUM;
 660                 break;
 661         }
 662 












 663         case MAC_CAPAB_RINGS:
 664                 cap_rings = cap_data;
 665                 cap_rings->mr_group_type = MAC_GROUP_TYPE_STATIC;
 666                 switch (cap_rings->mr_type) {
 667                 case MAC_RING_TYPE_TX:
 668                         /*
 669                          * Note, saying we have no rings, but some number of
 670                          * groups indicates to MAC that it should create
 671                          * psuedo-groups with one for each TX ring. This may not
 672                          * be the long term behavior we want, but it'll work for
 673                          * now.
 674                          */
 675                         cap_rings->mr_gnum = 0;
 676                         cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
 677                         cap_rings->mr_rget = i40e_fill_tx_ring;
 678                         cap_rings->mr_gget = NULL;
 679                         cap_rings->mr_gaddring = NULL;
 680                         cap_rings->mr_gremring = NULL;
 681                         break;
 682                 case MAC_RING_TYPE_RX:
 683                         cap_rings->mr_rnum = i40e->i40e_num_trqpairs;
 684                         cap_rings->mr_rget = i40e_fill_rx_ring;
 685                         cap_rings->mr_gnum = I40E_GROUP_MAX;
 686                         cap_rings->mr_gget = i40e_fill_rx_group;
 687                         cap_rings->mr_gaddring = NULL;
 688                         cap_rings->mr_gremring = NULL;
 689                         break;
 690                 default:
 691                         return (B_FALSE);
 692                 }
 693                 break;
 694         case MAC_CAPAB_TRANSCEIVER:
 695                 mct = cap_data;
 696 
 697                 /*
 698                  * Firmware doesn't have a great way of telling us in advance
 699                  * whether we'd expect a SFF transceiver. As such, we always
 700                  * advertise the support for this capability.
 701                  */
 702                 mct->mct_flags = 0;
 703                 mct->mct_ntransceivers = 1;
 704                 mct->mct_info = i40e_transceiver_info;
 705                 mct->mct_read = NULL;
 706 
 707                 return (B_TRUE);
 708         case MAC_CAPAB_LED:
 709                 mcl = cap_data;
 710 
 711                 mcl->mcl_flags = 0;
 712                 mcl->mcl_modes = MAC_LED_DEFAULT | MAC_LED_IDENT | MAC_LED_OFF |
 713                     MAC_LED_ON;
 714                 mcl->mcl_set = i40e_gld_led_set;
 715                 break;
 716 
 717         default:
 718                 return (B_FALSE);
 719         }
 720 
 721         return (B_TRUE);
 722 }
 723 
 724 /* ARGSUSED */
 725 static int


   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         }


  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         }


 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) {


 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) {


 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