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