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