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         }
  63 
  64         if (i == i40e->i40e_resources.ifr_nmacfilt_used) {
  65                 ret = ENOENT;
  66                 goto done;
  67         }
  68 
  69         iua = &i40e->i40e_uaddrs[i];
  70         ASSERT(i40e->i40e_resources.ifr_nmacfilt_used > 0);
  71 
  72         bzero(&filt, sizeof (filt));
  73         bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
  74         filt.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
  75             I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
  76 
  77         if (i40e_aq_remove_macvlan(hw, iua->iua_vsi, &filt, 1, NULL) !=
  78             I40E_SUCCESS) {
  79                 i40e_error(i40e, "failed to remove mac address "
  80                     "%2x:%2x:%2x:%2x:%2x:%2x from unicast filter: %d",
  81                     mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
  82                     mac_addr[4], mac_addr[5], filt.error_code);
  83                 ret = EIO;
  84                 goto done;
  85         }
  86 
  87         last = i40e->i40e_resources.ifr_nmacfilt_used - 1;
  88         if (i != last) {
  89                 i40e_uaddr_t *src = &i40e->i40e_uaddrs[last];
  90                 bcopy(src, iua, sizeof (i40e_uaddr_t));
  91         }
  92 
  93         /*
  94          * Set the multicast bit in the last one to indicate to ourselves that
  95          * it's invalid.
  96          */
  97         bzero(&i40e->i40e_uaddrs[last], sizeof (i40e_uaddr_t));
  98         i40e->i40e_uaddrs[last].iua_mac[0] = 0x01;
  99         i40e->i40e_resources.ifr_nmacfilt_used--;
 100         ret = 0;
 101 done:
 102         mutex_exit(&i40e->i40e_general_lock);
 103 
 104         return (ret);
 105 }
 106 
 107 static int
 108 i40e_group_add_mac(void *arg, const uint8_t *mac_addr)
 109 {
 110         i40e_t *i40e = arg;
 111         struct i40e_hw *hw = &i40e->i40e_hw_space;
 112         int i, ret;
 113         i40e_uaddr_t *iua;
 114         struct i40e_aqc_add_macvlan_element_data filt;
 115 
 116         if (I40E_IS_MULTICAST(mac_addr))
 117                 return (EINVAL);
 118 
 119         mutex_enter(&i40e->i40e_general_lock);
 120         if (i40e->i40e_state & I40E_SUSPENDED) {
 121                 ret = ECANCELED;
 122                 goto done;
 123         }
 124 
 125         if (i40e->i40e_resources.ifr_nmacfilt ==
 126             i40e->i40e_resources.ifr_nmacfilt_used) {
 127                 ret = ENOSPC;
 128                 goto done;
 129         }
 130 
 131         for (i = 0; i < i40e->i40e_resources.ifr_nmacfilt_used; i++) {
 132                 if (bcmp(mac_addr, i40e->i40e_uaddrs[i].iua_mac,
 133                     ETHERADDRL) == 0) {
 134                         ret = EEXIST;
 135                         goto done;
 136                 }
 137         }
 138 
 139         /*
 140          * Note, the general use of the i40e_vsi_id will have to be refactored
 141          * when we have proper group support.
 142          */
 143         bzero(&filt, sizeof (filt));
 144         bcopy(mac_addr, filt.mac_addr, ETHERADDRL);
 145         filt.flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH |
 146             I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
 147 
 148         if ((ret = i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, &filt, 1,
 149             NULL)) != I40E_SUCCESS) {
 150                 i40e_error(i40e, "failed to add mac address "
 151                     "%2x:%2x:%2x:%2x:%2x:%2x to unicast filter: %d",
 152                     mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
 153                     mac_addr[4], mac_addr[5], ret);
 154                 ret = EIO;
 155                 goto done;
 156         }
 157 
 158         iua = &i40e->i40e_uaddrs[i40e->i40e_resources.ifr_nmacfilt_used];
 159         bcopy(mac_addr, iua->iua_mac, ETHERADDRL);
 160         iua->iua_vsi = i40e->i40e_vsi_id;
 161         i40e->i40e_resources.ifr_nmacfilt_used++;
 162         ASSERT(i40e->i40e_resources.ifr_nmacfilt_used <=
 163             i40e->i40e_resources.ifr_nmacfilt);
 164         ret = 0;
 165 done:
 166         mutex_exit(&i40e->i40e_general_lock);
 167         return (ret);
 168 }
 169 
 170 static int
 171 i40e_m_start(void *arg)
 172 {
 173         i40e_t *i40e = arg;
 174         int rc = 0;
 175 
 176         mutex_enter(&i40e->i40e_general_lock);
 177         if (i40e->i40e_state & I40E_SUSPENDED) {
 178                 rc = ECANCELED;
 179                 goto done;
 180         }
 181 
 182         if (!i40e_start(i40e, B_TRUE)) {
 183                 rc = EIO;
 184                 goto done;
 185         }
 186 
 187         atomic_or_32(&i40e->i40e_state, I40E_STARTED);
 188 done:
 189         mutex_exit(&i40e->i40e_general_lock);
 190 
 191         return (rc);
 192 }
 193 
 194 static void
 195 i40e_m_stop(void *arg)
 196 {
 197         i40e_t *i40e = arg;
 198 
 199         mutex_enter(&i40e->i40e_general_lock);
 200 
 201         if (i40e->i40e_state & I40E_SUSPENDED)
 202                 goto done;
 203 
 204         atomic_and_32(&i40e->i40e_state, ~I40E_STARTED);
 205         i40e_stop(i40e, B_TRUE);
 206 done:
 207         mutex_exit(&i40e->i40e_general_lock);
 208 }
 209 
 210 /*
 211  * Enable and disable promiscuous mode as requested. We have to toggle both
 212  * unicast and multicast. Note that multicast may already be enabled due to the
 213  * i40e_m_multicast may toggle it itself. See i40e_main.c for more information
 214  * on this.
 215  */
 216 static int
 217 i40e_m_promisc(void *arg, boolean_t on)
 218 {
 219         i40e_t *i40e = arg;
 220         struct i40e_hw *hw = &i40e->i40e_hw_space;
 221         int ret = 0, err = 0;
 222 
 223         mutex_enter(&i40e->i40e_general_lock);
 224         if (i40e->i40e_state & I40E_SUSPENDED) {
 225                 ret = ECANCELED;
 226                 goto done;
 227         }
 228 
 229 
 230         ret = i40e_aq_set_vsi_unicast_promiscuous(hw, i40e->i40e_vsi_id,
 231             on, NULL, B_FALSE);
 232         if (ret != I40E_SUCCESS) {
 233                 i40e_error(i40e, "failed to %s unicast promiscuity on "
 234                     "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
 235                     ret);
 236                 err = EIO;
 237                 goto done;
 238         }
 239 
 240         /*
 241          * If we have a non-zero mcast_promisc_count, then it has already been
 242          * enabled or we need to leave it that way and not touch it.
 243          */
 244         if (i40e->i40e_mcast_promisc_count > 0) {
 245                 i40e->i40e_promisc_on = on;
 246                 goto done;
 247         }
 248 
 249         ret = i40e_aq_set_vsi_multicast_promiscuous(hw, i40e->i40e_vsi_id,
 250             on, NULL);
 251         if (ret != I40E_SUCCESS) {
 252                 i40e_error(i40e, "failed to %s multicast promiscuity on "
 253                     "the default VSI: %d", on == B_TRUE ? "enable" : "disable",
 254                     ret);
 255 
 256                 /*
 257                  * Try our best to put us back into a state that MAC expects us
 258                  * to be in.
 259                  */
 260                 ret = i40e_aq_set_vsi_unicast_promiscuous(hw, i40e->i40e_vsi_id,
 261                     !on, NULL, B_FALSE);
 262                 if (ret != I40E_SUCCESS) {
 263                         i40e_error(i40e, "failed to %s unicast promiscuity on "
 264                             "the default VSI after toggling multicast failed: "
 265                             "%d", on == B_TRUE ? "disable" : "enable", ret);
 266                 }
 267 
 268                 err = EIO;
 269                 goto done;
 270         } else {
 271                 i40e->i40e_promisc_on = on;
 272         }
 273 
 274 done:
 275         mutex_exit(&i40e->i40e_general_lock);
 276         return (err);
 277 }
 278 
 279 /*
 280  * See the big theory statement in i40e_main.c for multicast address management.
 281  */
 282 static int
 283 i40e_multicast_add(i40e_t *i40e, const uint8_t *multicast_address)
 284 {
 285         struct i40e_hw *hw = &i40e->i40e_hw_space;
 286         struct i40e_aqc_add_macvlan_element_data filt;
 287         i40e_maddr_t *mc;
 288         int ret;
 289 
 290         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
 291 
 292         if (i40e->i40e_resources.ifr_nmcastfilt_used ==
 293             i40e->i40e_resources.ifr_nmcastfilt) {
 294                 if (i40e->i40e_mcast_promisc_count == 0 &&
 295                     i40e->i40e_promisc_on == B_FALSE) {
 296                         ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
 297                             i40e->i40e_vsi_id, B_TRUE, NULL);
 298                         if (ret != I40E_SUCCESS) {
 299                                 i40e_error(i40e, "failed to enable multicast "
 300                                     "promiscuous mode on VSI %d: %d",
 301                                     i40e->i40e_vsi_id, ret);
 302                                 return (EIO);
 303                         }
 304                 }
 305                 i40e->i40e_mcast_promisc_count++;
 306                 return (0);
 307         }
 308 
 309         mc = &i40e->i40e_maddrs[i40e->i40e_resources.ifr_nmcastfilt_used];
 310         bzero(&filt, sizeof (filt));
 311         bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
 312         filt.flags = I40E_AQC_MACVLAN_ADD_HASH_MATCH |
 313             I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
 314 
 315         if ((ret = i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, &filt, 1,
 316             NULL)) != I40E_SUCCESS) {
 317                 i40e_error(i40e, "failed to add mac address "
 318                     "%2x:%2x:%2x:%2x:%2x:%2x to multicast filter: %d",
 319                     multicast_address[0], multicast_address[1],
 320                     multicast_address[2], multicast_address[3],
 321                     multicast_address[4], multicast_address[5],
 322                     ret);
 323                 return (EIO);
 324         }
 325 
 326         bcopy(multicast_address, mc->ima_mac, ETHERADDRL);
 327         i40e->i40e_resources.ifr_nmcastfilt_used++;
 328         return (0);
 329 }
 330 
 331 /*
 332  * See the big theory statement in i40e_main.c for multicast address management.
 333  */
 334 static int
 335 i40e_multicast_remove(i40e_t *i40e, const uint8_t *multicast_address)
 336 {
 337         int i, ret;
 338         struct i40e_hw *hw = &i40e->i40e_hw_space;
 339 
 340         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
 341 
 342         for (i = 0; i < i40e->i40e_resources.ifr_nmcastfilt_used; i++) {
 343                 struct i40e_aqc_remove_macvlan_element_data filt;
 344                 int last;
 345 
 346                 if (bcmp(multicast_address, i40e->i40e_maddrs[i].ima_mac,
 347                     ETHERADDRL) != 0) {
 348                         continue;
 349                 }
 350 
 351                 bzero(&filt, sizeof (filt));
 352                 bcopy(multicast_address, filt.mac_addr, ETHERADDRL);
 353                 filt.flags = I40E_AQC_MACVLAN_DEL_HASH_MATCH |
 354                     I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
 355 
 356                 if (i40e_aq_remove_macvlan(hw, i40e->i40e_vsi_id,
 357                     &filt, 1, NULL) != I40E_SUCCESS) {
 358                         i40e_error(i40e, "failed to remove mac address "
 359                             "%2x:%2x:%2x:%2x:%2x:%2x from multicast "
 360                             "filter: %d",
 361                             multicast_address[0], multicast_address[1],
 362                             multicast_address[2], multicast_address[3],
 363                             multicast_address[4], multicast_address[5],
 364                             filt.error_code);
 365                         return (EIO);
 366                 }
 367 
 368                 last = i40e->i40e_resources.ifr_nmcastfilt_used - 1;
 369                 if (i != last) {
 370                         bcopy(&i40e->i40e_maddrs[last], &i40e->i40e_maddrs[i],
 371                             sizeof (i40e_maddr_t));
 372                         bzero(&i40e->i40e_maddrs[last], sizeof (i40e_maddr_t));
 373                 }
 374 
 375                 ASSERT(i40e->i40e_resources.ifr_nmcastfilt_used > 0);
 376                 i40e->i40e_resources.ifr_nmcastfilt_used--;
 377                 return (0);
 378         }
 379 
 380         if (i40e->i40e_mcast_promisc_count > 0) {
 381                 if (i40e->i40e_mcast_promisc_count == 1 &&
 382                     i40e->i40e_promisc_on == B_FALSE) {
 383                         ret = i40e_aq_set_vsi_multicast_promiscuous(hw,
 384                             i40e->i40e_vsi_id, B_FALSE, NULL);
 385                         if (ret != I40E_SUCCESS) {
 386                                 i40e_error(i40e, "failed to disable "
 387                                     "multicast promiscuous mode on VSI %d: %d",
 388                                     i40e->i40e_vsi_id, ret);
 389                                 return (EIO);
 390                         }
 391                 }
 392                 i40e->i40e_mcast_promisc_count--;
 393 
 394                 return (0);
 395         }
 396 
 397         return (ENOENT);
 398 }
 399 
 400 static int
 401 i40e_m_multicast(void *arg, boolean_t add, const uint8_t *multicast_address)
 402 {
 403         i40e_t *i40e = arg;
 404         int rc;
 405 
 406         mutex_enter(&i40e->i40e_general_lock);
 407 
 408         if (i40e->i40e_state & I40E_SUSPENDED) {
 409                 mutex_exit(&i40e->i40e_general_lock);
 410                 return (ECANCELED);
 411         }
 412 
 413         if (add == B_TRUE) {
 414                 rc = i40e_multicast_add(i40e, multicast_address);
 415         } else {
 416                 rc = i40e_multicast_remove(i40e, multicast_address);
 417         }
 418 
 419         mutex_exit(&i40e->i40e_general_lock);
 420         return (rc);
 421 }
 422 
 423 /* ARGSUSED */
 424 static void
 425 i40e_m_ioctl(void *arg, queue_t *q, mblk_t *mp)
 426 {
 427         /*
 428          * At this time, we don't support toggling i40e into loopback mode. It's
 429          * questionable how much value this has when there's no clear way to
 430          * toggle this behavior from a supported way in userland.
 431          */
 432         miocnak(q, mp, 0, EINVAL);
 433 }
 434 
 435 static int
 436 i40e_ring_start(mac_ring_driver_t rh, uint64_t gen_num)
 437 {
 438         i40e_trqpair_t *itrq = (i40e_trqpair_t *)rh;
 439 
 440         /*
 441          * GLDv3 requires we keep track of a generation number, as it uses
 442          * that number to keep track of whether or not a ring is active.
 443          */
 444         mutex_enter(&itrq->itrq_rx_lock);
 445         itrq->itrq_rxgen = gen_num;
 446         mutex_exit(&itrq->itrq_rx_lock);
 447         return (0);
 448 }
 449 
 450 /* ARGSUSED */
 451 static int
 452 i40e_rx_ring_intr_enable(mac_intr_handle_t intrh)
 453 {
 454         i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
 455 
 456         mutex_enter(&itrq->itrq_rx_lock);
 457         ASSERT(itrq->itrq_intr_poll == B_TRUE);
 458         i40e_intr_rx_queue_enable(itrq);
 459         itrq->itrq_intr_poll = B_FALSE;
 460         mutex_exit(&itrq->itrq_rx_lock);
 461 
 462         return (0);
 463 }
 464 
 465 /* ARGSUSED */
 466 static int
 467 i40e_rx_ring_intr_disable(mac_intr_handle_t intrh)
 468 {
 469         i40e_trqpair_t *itrq = (i40e_trqpair_t *)intrh;
 470 
 471         mutex_enter(&itrq->itrq_rx_lock);
 472         i40e_intr_rx_queue_disable(itrq);
 473         itrq->itrq_intr_poll = B_TRUE;
 474         mutex_exit(&itrq->itrq_rx_lock);
 475 
 476         return (0);
 477 }
 478 
 479 /* ARGSUSED */
 480 static void
 481 i40e_fill_tx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
 482     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
 483 {
 484         i40e_t *i40e = arg;
 485         mac_intr_t *mintr = &infop->mri_intr;
 486         i40e_trqpair_t *itrq = &(i40e->i40e_trqpairs[ring_index]);
 487 
 488         /*
 489          * Note the group index here is expected to be -1 due to the fact that
 490          * we're not actually grouping things tx-wise at this time.
 491          */
 492         ASSERT(group_index == -1);
 493         ASSERT(ring_index < i40e->i40e_num_trqpairs);
 494 
 495         itrq->itrq_mactxring = rh;
 496         infop->mri_driver = (mac_ring_driver_t)itrq;
 497         infop->mri_start = NULL;
 498         infop->mri_stop = NULL;
 499         infop->mri_tx = i40e_ring_tx;
 500         infop->mri_stat = i40e_tx_ring_stat;
 501 
 502         /*
 503          * We only provide the handle in cases where we have MSI-X interrupts,
 504          * to indicate that we'd actually support retargetting.
 505          */
 506         if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
 507                 mintr->mi_ddi_handle =
 508                     i40e->i40e_intr_handles[itrq->itrq_tx_intrvec];
 509         }
 510 }
 511 
 512 /* ARGSUSED */
 513 static void
 514 i40e_fill_rx_ring(void *arg, mac_ring_type_t rtype, const int group_index,
 515     const int ring_index, mac_ring_info_t *infop, mac_ring_handle_t rh)
 516 {
 517         i40e_t *i40e = arg;
 518         mac_intr_t *mintr = &infop->mri_intr;
 519         i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[ring_index];
 520 
 521         /*
 522          * We assert the group number and ring index to help sanity check
 523          * ourselves and mark that we'll need to rework this when we have
 524          * multiple groups.
 525          */
 526         ASSERT3S(group_index, ==, 0);
 527         ASSERT3S(ring_index, <, i40e->i40e_num_trqpairs);
 528 
 529         itrq->itrq_macrxring = rh;
 530         infop->mri_driver = (mac_ring_driver_t)itrq;
 531         infop->mri_start = i40e_ring_start;
 532         infop->mri_stop = NULL;
 533         infop->mri_poll = i40e_ring_rx_poll;
 534         infop->mri_stat = i40e_rx_ring_stat;
 535         mintr->mi_handle = (mac_intr_handle_t)itrq;
 536         mintr->mi_enable = i40e_rx_ring_intr_enable;
 537         mintr->mi_disable = i40e_rx_ring_intr_disable;
 538 
 539         /*
 540          * We only provide the handle in cases where we have MSI-X interrupts,
 541          * to indicate that we'd actually support retargetting.
 542          */
 543         if (i40e->i40e_intr_type & DDI_INTR_TYPE_MSIX) {
 544                 mintr->mi_ddi_handle =
 545                     i40e->i40e_intr_handles[itrq->itrq_rx_intrvec];
 546         }
 547 }
 548 
 549 /* ARGSUSED */
 550 static void
 551 i40e_fill_rx_group(void *arg, mac_ring_type_t rtype, const int index,
 552     mac_group_info_t *infop, mac_group_handle_t gh)
 553 {
 554         i40e_t *i40e = arg;
 555 
 556         if (rtype != MAC_RING_TYPE_RX)
 557                 return;
 558 
 559         /*
 560          * Note, this is a simplified view of a group, given that we only have a
 561          * single group and a single ring at the moment. We'll want to expand
 562          * upon this as we leverage more hardware functionality.
 563          */
 564         i40e->i40e_rx_group_handle = gh;
 565         infop->mgi_driver = (mac_group_driver_t)i40e;
 566         infop->mgi_start = NULL;
 567         infop->mgi_stop = NULL;
 568         infop->mgi_addmac = i40e_group_add_mac;
 569         infop->mgi_remmac = i40e_group_remove_mac;
 570 
 571         ASSERT(i40e->i40e_num_rx_groups == I40E_GROUP_MAX);
 572         infop->mgi_count = i40e->i40e_num_trqpairs;
 573 }
 574 
 575 static int
 576 i40e_transceiver_info(void *arg, uint_t id, mac_transceiver_info_t *infop)
 577 {
 578         boolean_t present, usable;
 579         i40e_t *i40e = arg;
 580 
 581         if (id != 0 || infop == NULL)
 582                 return (EINVAL);
 583 
 584         mutex_enter(&i40e->i40e_general_lock);
 585         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) {
 622         case MAC_LED_DEFAULT:
 623                 if (i40e->i40e_led_saved) {
 624                         i40e_led_set(hw, i40e->i40e_led_status, B_FALSE);
 625                         i40e->i40e_led_status = 0;
 626                         i40e->i40e_led_saved = B_FALSE;
 627                 }
 628                 break;
 629         case MAC_LED_IDENT:
 630                 i40e_led_set(hw, 0xf, B_TRUE);
 631                 break;
 632         case MAC_LED_OFF:
 633                 i40e_led_set(hw, 0x0, B_FALSE);
 634                 break;
 635         case MAC_LED_ON:
 636                 i40e_led_set(hw, 0xf, B_FALSE);
 637                 break;
 638         default:
 639                 return (ENOTSUP);
 640         }
 641 
 642         return (0);
 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
 726 i40e_m_setprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
 727     const void *pr_val)
 728 {
 729         int ret;
 730         long val;
 731         char *eptr;
 732 
 733         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
 734 
 735         if ((ret = ddi_strtol(pr_val, &eptr, 10, &val)) != 0 ||
 736             *eptr != '\0') {
 737                 return (ret);
 738         }
 739 
 740         if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
 741                 if (val < I40E_MIN_RX_DMA_THRESH ||
 742                     val > I40E_MAX_RX_DMA_THRESH) {
 743                         return (EINVAL);
 744                 }
 745                 i40e->i40e_rx_dma_min = (uint32_t)val;
 746                 return (0);
 747         }
 748 
 749         if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
 750                 if (val < I40E_MIN_TX_DMA_THRESH ||
 751                     val > I40E_MAX_TX_DMA_THRESH) {
 752                         return (EINVAL);
 753                 }
 754                 i40e->i40e_tx_dma_min = (uint32_t)val;
 755                 return (0);
 756         }
 757 
 758         if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
 759                 if (val < I40E_MIN_ITR ||
 760                     val > I40E_MAX_ITR) {
 761                         return (EINVAL);
 762                 }
 763                 i40e->i40e_rx_itr = (uint32_t)val;
 764                 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr);
 765                 return (0);
 766         }
 767 
 768         if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
 769                 if (val < I40E_MIN_ITR ||
 770                     val > I40E_MAX_ITR) {
 771                         return (EINVAL);
 772                 }
 773                 i40e->i40e_tx_itr = (uint32_t)val;
 774                 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr);
 775                 return (0);
 776         }
 777 
 778         if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
 779                 if (val < I40E_MIN_ITR ||
 780                     val > I40E_MAX_ITR) {
 781                         return (EINVAL);
 782                 }
 783                 i40e->i40e_tx_itr = (uint32_t)val;
 784                 i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER,
 785                     i40e->i40e_other_itr);
 786                 return (0);
 787         }
 788 
 789         return (ENOTSUP);
 790 }
 791 
 792 static int
 793 i40e_m_getprop_private(i40e_t *i40e, const char *pr_name, uint_t pr_valsize,
 794     void *pr_val)
 795 {
 796         uint32_t val;
 797 
 798         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
 799 
 800         if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
 801                 val = i40e->i40e_rx_dma_min;
 802         } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
 803                 val = i40e->i40e_tx_dma_min;
 804         } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
 805                 val = i40e->i40e_rx_itr;
 806         } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
 807                 val = i40e->i40e_tx_itr;
 808         } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
 809                 val = i40e->i40e_other_itr;
 810         } else {
 811                 return (ENOTSUP);
 812         }
 813 
 814         if (snprintf(pr_val, pr_valsize, "%d", val) >= pr_valsize)
 815                 return (ERANGE);
 816         return (0);
 817 }
 818 
 819 /*
 820  * Annoyingly for private properties MAC seems to ignore default values that
 821  * aren't strings. That means that we have to translate all of these into
 822  * uint32_t's and instead we size the buffer to be large enough to hold a
 823  * uint32_t.
 824  */
 825 /* ARGSUSED */
 826 static void
 827 i40e_m_propinfo_private(i40e_t *i40e, const char *pr_name,
 828     mac_prop_info_handle_t prh)
 829 {
 830         char buf[64];
 831         uint32_t def;
 832 
 833         if (strcmp(pr_name, I40E_PROP_RX_DMA_THRESH) == 0) {
 834                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
 835                 def = I40E_DEF_RX_DMA_THRESH;
 836                 mac_prop_info_set_range_uint32(prh,
 837                     I40E_MIN_RX_DMA_THRESH,
 838                     I40E_MAX_RX_DMA_THRESH);
 839         } else if (strcmp(pr_name, I40E_PROP_TX_DMA_THRESH) == 0) {
 840                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
 841                 def = I40E_DEF_TX_DMA_THRESH;
 842                 mac_prop_info_set_range_uint32(prh,
 843                     I40E_MIN_TX_DMA_THRESH,
 844                     I40E_MAX_TX_DMA_THRESH);
 845         } else if (strcmp(pr_name, I40E_PROP_RX_ITR) == 0) {
 846                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
 847                 def = I40E_DEF_RX_ITR;
 848                 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
 849         } else if (strcmp(pr_name, I40E_PROP_TX_ITR) == 0) {
 850                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
 851                 def = I40E_DEF_TX_ITR;
 852                 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
 853         } else if (strcmp(pr_name, I40E_PROP_OTHER_ITR) == 0) {
 854                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_RW);
 855                 def = I40E_DEF_OTHER_ITR;
 856                 mac_prop_info_set_range_uint32(prh, I40E_MIN_ITR, I40E_MAX_ITR);
 857         } else {
 858                 return;
 859         }
 860 
 861         (void) snprintf(buf, sizeof (buf), "%d", def);
 862         mac_prop_info_set_default_str(prh, buf);
 863 }
 864 
 865 static int
 866 i40e_m_setprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
 867     uint_t pr_valsize, const void *pr_val)
 868 {
 869         uint32_t new_mtu;
 870         i40e_t *i40e = arg;
 871         int ret = 0;
 872 
 873         mutex_enter(&i40e->i40e_general_lock);
 874         if (i40e->i40e_state & I40E_SUSPENDED) {
 875                 mutex_exit(&i40e->i40e_general_lock);
 876                 return (ECANCELED);
 877         }
 878 
 879         switch (pr_num) {
 880         /*
 881          * These properties are always read-only across every device.
 882          */
 883         case MAC_PROP_DUPLEX:
 884         case MAC_PROP_SPEED:
 885         case MAC_PROP_STATUS:
 886         case MAC_PROP_ADV_100FDX_CAP:
 887         case MAC_PROP_ADV_1000FDX_CAP:
 888         case MAC_PROP_ADV_10GFDX_CAP:
 889         case MAC_PROP_ADV_25GFDX_CAP:
 890         case MAC_PROP_ADV_40GFDX_CAP:
 891                 ret = ENOTSUP;
 892                 break;
 893         /*
 894          * These are read-only at this time as we don't support configuring
 895          * auto-negotiation. See the theory statement in i40e_main.c.
 896          */
 897         case MAC_PROP_EN_100FDX_CAP:
 898         case MAC_PROP_EN_1000FDX_CAP:
 899         case MAC_PROP_EN_10GFDX_CAP:
 900         case MAC_PROP_EN_25GFDX_CAP:
 901         case MAC_PROP_EN_40GFDX_CAP:
 902         case MAC_PROP_AUTONEG:
 903         case MAC_PROP_FLOWCTRL:
 904                 ret = ENOTSUP;
 905                 break;
 906 
 907         case MAC_PROP_MTU:
 908                 bcopy(pr_val, &new_mtu, sizeof (new_mtu));
 909                 if (new_mtu == i40e->i40e_sdu)
 910                         break;
 911 
 912                 if (new_mtu < I40E_MIN_MTU ||
 913                     new_mtu > I40E_MAX_MTU) {
 914                         ret = EINVAL;
 915                         break;
 916                 }
 917 
 918                 if (i40e->i40e_state & I40E_STARTED) {
 919                         ret = EBUSY;
 920                         break;
 921                 }
 922 
 923                 ret = mac_maxsdu_update(i40e->i40e_mac_hdl, new_mtu);
 924                 if (ret == 0) {
 925                         i40e->i40e_sdu = new_mtu;
 926                         i40e_update_mtu(i40e);
 927                 }
 928                 break;
 929 
 930         case MAC_PROP_PRIVATE:
 931                 ret = i40e_m_setprop_private(i40e, pr_name, pr_valsize, pr_val);
 932                 break;
 933         default:
 934                 ret = ENOTSUP;
 935                 break;
 936         }
 937 
 938         mutex_exit(&i40e->i40e_general_lock);
 939         return (ret);
 940 }
 941 
 942 static int
 943 i40e_m_getprop(void *arg, const char *pr_name, mac_prop_id_t pr_num,
 944     uint_t pr_valsize, void *pr_val)
 945 {
 946         i40e_t *i40e = arg;
 947         uint64_t speed;
 948         int ret = 0;
 949         uint8_t *u8;
 950         link_flowctrl_t fctl;
 951 
 952         mutex_enter(&i40e->i40e_general_lock);
 953 
 954         switch (pr_num) {
 955         case MAC_PROP_DUPLEX:
 956                 if (pr_valsize < sizeof (link_duplex_t)) {
 957                         ret = EOVERFLOW;
 958                         break;
 959                 }
 960                 bcopy(&i40e->i40e_link_duplex, pr_val, sizeof (link_duplex_t));
 961                 break;
 962         case MAC_PROP_SPEED:
 963                 if (pr_valsize < sizeof (uint64_t)) {
 964                         ret = EOVERFLOW;
 965                         break;
 966                 }
 967                 speed = i40e->i40e_link_speed * 1000000ULL;
 968                 bcopy(&speed, pr_val, sizeof (speed));
 969                 break;
 970         case MAC_PROP_STATUS:
 971                 if (pr_valsize < sizeof (link_state_t)) {
 972                         ret = EOVERFLOW;
 973                         break;
 974                 }
 975                 bcopy(&i40e->i40e_link_state, pr_val, sizeof (link_state_t));
 976                 break;
 977         case MAC_PROP_AUTONEG:
 978                 if (pr_valsize < sizeof (uint8_t)) {
 979                         ret = EOVERFLOW;
 980                         break;
 981                 }
 982                 u8 = pr_val;
 983                 *u8 = 1;
 984                 break;
 985         case MAC_PROP_FLOWCTRL:
 986                 /*
 987                  * Because we don't currently support hardware flow control, we
 988                  * just hardcode this to be none.
 989                  */
 990                 if (pr_valsize < sizeof (link_flowctrl_t)) {
 991                         ret = EOVERFLOW;
 992                         break;
 993                 }
 994                 fctl = LINK_FLOWCTRL_NONE;
 995                 bcopy(&fctl, pr_val, sizeof (link_flowctrl_t));
 996                 break;
 997         case MAC_PROP_MTU:
 998                 if (pr_valsize < sizeof (uint32_t)) {
 999                         ret = EOVERFLOW;
1000                         break;
1001                 }
1002                 bcopy(&i40e->i40e_sdu, pr_val, sizeof (uint32_t));
1003                 break;
1004 
1005         /*
1006          * Because we don't let users control the speeds we may auto-negotiate
1007          * to, the values of the ADV_ and EN_ will always be the same.
1008          */
1009         case MAC_PROP_ADV_100FDX_CAP:
1010         case MAC_PROP_EN_100FDX_CAP:
1011                 if (pr_valsize < sizeof (uint8_t)) {
1012                         ret = EOVERFLOW;
1013                         break;
1014                 }
1015                 u8 = pr_val;
1016                 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0;
1017                 break;
1018         case MAC_PROP_ADV_1000FDX_CAP:
1019         case MAC_PROP_EN_1000FDX_CAP:
1020                 if (pr_valsize < sizeof (uint8_t)) {
1021                         ret = EOVERFLOW;
1022                         break;
1023                 }
1024                 u8 = pr_val;
1025                 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0;
1026                 break;
1027         case MAC_PROP_ADV_10GFDX_CAP:
1028         case MAC_PROP_EN_10GFDX_CAP:
1029                 if (pr_valsize < sizeof (uint8_t)) {
1030                         ret = EOVERFLOW;
1031                         break;
1032                 }
1033                 u8 = pr_val;
1034                 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0;
1035                 break;
1036         case MAC_PROP_ADV_25GFDX_CAP:
1037         case MAC_PROP_EN_25GFDX_CAP:
1038                 if (pr_valsize < sizeof (uint8_t)) {
1039                         ret = EOVERFLOW;
1040                         break;
1041                 }
1042                 u8 = pr_val;
1043                 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0;
1044                 break;
1045         case MAC_PROP_ADV_40GFDX_CAP:
1046         case MAC_PROP_EN_40GFDX_CAP:
1047                 if (pr_valsize < sizeof (uint8_t)) {
1048                         ret = EOVERFLOW;
1049                         break;
1050                 }
1051                 u8 = pr_val;
1052                 *u8 = (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0;
1053                 break;
1054         case MAC_PROP_PRIVATE:
1055                 ret = i40e_m_getprop_private(i40e, pr_name, pr_valsize, pr_val);
1056                 break;
1057         default:
1058                 ret = ENOTSUP;
1059                 break;
1060         }
1061 
1062         mutex_exit(&i40e->i40e_general_lock);
1063 
1064         return (ret);
1065 }
1066 
1067 static void
1068 i40e_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t pr_num,
1069     mac_prop_info_handle_t prh)
1070 {
1071         i40e_t *i40e = arg;
1072 
1073         mutex_enter(&i40e->i40e_general_lock);
1074 
1075         switch (pr_num) {
1076         case MAC_PROP_DUPLEX:
1077         case MAC_PROP_SPEED:
1078                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1079                 break;
1080         case MAC_PROP_FLOWCTRL:
1081                 /*
1082                  * At the moment, the driver doesn't support flow control, hence
1083                  * why this is set to read-only and none.
1084                  */
1085                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1086                 mac_prop_info_set_default_link_flowctrl(prh,
1087                     LINK_FLOWCTRL_NONE);
1088                 break;
1089         case MAC_PROP_MTU:
1090                 mac_prop_info_set_range_uint32(prh, I40E_MIN_MTU, I40E_MAX_MTU);
1091                 break;
1092 
1093         /*
1094          * We set the defaults for these based upon the phy's ability to
1095          * support the speeds. Note, auto-negotiation is required for fiber,
1096          * hence it is read-only and always enabled. When we have access to
1097          * copper phys we can revisit this.
1098          */
1099         case MAC_PROP_AUTONEG:
1100                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1101                 mac_prop_info_set_default_uint8(prh, 1);
1102                 break;
1103         case MAC_PROP_ADV_100FDX_CAP:
1104                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1105                 mac_prop_info_set_default_uint8(prh,
1106                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1107                 break;
1108         case MAC_PROP_EN_100FDX_CAP:
1109                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1110                 mac_prop_info_set_default_uint8(prh,
1111                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_100MB) != 0);
1112                 break;
1113         case MAC_PROP_ADV_1000FDX_CAP:
1114                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1115                 mac_prop_info_set_default_uint8(prh,
1116                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1117                 break;
1118         case MAC_PROP_EN_1000FDX_CAP:
1119                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1120                 mac_prop_info_set_default_uint8(prh,
1121                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_1GB) != 0);
1122                 break;
1123         case MAC_PROP_ADV_10GFDX_CAP:
1124                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1125                 mac_prop_info_set_default_uint8(prh,
1126                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1127                 break;
1128         case MAC_PROP_EN_10GFDX_CAP:
1129                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1130                 mac_prop_info_set_default_uint8(prh,
1131                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_10GB) != 0);
1132                 break;
1133         case MAC_PROP_ADV_25GFDX_CAP:
1134                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1135                 mac_prop_info_set_default_uint8(prh,
1136                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1137                 break;
1138         case MAC_PROP_EN_25GFDX_CAP:
1139                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1140                 mac_prop_info_set_default_uint8(prh,
1141                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_25GB) != 0);
1142                 break;
1143         case MAC_PROP_ADV_40GFDX_CAP:
1144                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1145                 mac_prop_info_set_default_uint8(prh,
1146                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1147                 break;
1148         case MAC_PROP_EN_40GFDX_CAP:
1149                 mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
1150                 mac_prop_info_set_default_uint8(prh,
1151                     (i40e->i40e_phy.link_speed & I40E_LINK_SPEED_40GB) != 0);
1152                 break;
1153         case MAC_PROP_PRIVATE:
1154                 i40e_m_propinfo_private(i40e, pr_name, prh);
1155                 break;
1156         default:
1157                 break;
1158         }
1159 
1160         mutex_exit(&i40e->i40e_general_lock);
1161 }
1162 
1163 #define I40E_M_CALLBACK_FLAGS \
1164         (MC_IOCTL | MC_GETCAPAB | MC_SETPROP | MC_GETPROP | MC_PROPINFO)
1165 
1166 static mac_callbacks_t i40e_m_callbacks = {
1167         I40E_M_CALLBACK_FLAGS,
1168         i40e_m_stat,
1169         i40e_m_start,
1170         i40e_m_stop,
1171         i40e_m_promisc,
1172         i40e_m_multicast,
1173         NULL,
1174         NULL,
1175         NULL,
1176         i40e_m_ioctl,
1177         i40e_m_getcapab,
1178         NULL,
1179         NULL,
1180         i40e_m_setprop,
1181         i40e_m_getprop,
1182         i40e_m_propinfo
1183 };
1184 
1185 boolean_t
1186 i40e_register_mac(i40e_t *i40e)
1187 {
1188         struct i40e_hw *hw = &i40e->i40e_hw_space;
1189         int status;
1190         mac_register_t *mac = mac_alloc(MAC_VERSION);
1191 
1192         if (mac == NULL)
1193                 return (B_FALSE);
1194 
1195         mac->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
1196         mac->m_driver = i40e;
1197         mac->m_dip = i40e->i40e_dip;
1198         mac->m_src_addr = hw->mac.addr;
1199         mac->m_callbacks = &i40e_m_callbacks;
1200         mac->m_min_sdu = 0;
1201         mac->m_max_sdu = i40e->i40e_sdu;
1202         mac->m_margin = VLAN_TAGSZ;
1203         mac->m_priv_props = i40e_priv_props;
1204         mac->m_v12n = MAC_VIRT_LEVEL1;
1205 
1206         status = mac_register(mac, &i40e->i40e_mac_hdl);
1207         if (status != 0)
1208                 i40e_error(i40e, "mac_register() returned %d", status);
1209         mac_free(mac);
1210 
1211         return (status == 0);
1212 }