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  */
  15 
  16 /*
  17  * Initialization entry points and setup for the Intel XL710 (i40e) family
  18  * of Ethernet NICs.
  19  */
  20 
  21 #include "i40e_sw.h"
  22 
  23 static char i40e_ident[] = "Intel 40Gb Ethernet";
  24 static uint8_t i40e_ether_broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  25 
  26 /*
  27  * Local function prototypes.
  28  */
  29 
  30 static int i40e_attach(dev_info_t *, ddi_attach_cmd_t);
  31 static int i40e_detach(dev_info_t *, ddi_detach_cmd_t);
  32 static int i40e_quiesce(dev_info_t *);
  33 static void i40e_unconfigure(dev_info_t *, i40e_t *);
  34 static void i40e_fm_init(i40e_t *);
  35 static void i40e_fm_fini(i40e_t *);
  36 static boolean_t i40e_identify_hardware(i40e_t *);
  37 static boolean_t i40e_regs_map(i40e_t *);
  38 static void i40e_init_properties(i40e_t *);
  39 static boolean_t i40e_alloc_intrs(i40e_t *, dev_info_t *);
  40 static boolean_t i40e_alloc_trqpairs_locks(i40e_t *);
  41 static boolean_t i40e_map_intrs_to_vectors(i40e_t *);
  42 static void i40e_free_trqpairs_locks(i40e_t *);
  43 static int i40e_intr_callback(dev_info_t *, ddi_cb_action_t, void *, void *,
  44     void *);
  45 static boolean_t i40e_add_intr_handlers(i40e_t *);
  46 static void i40e_timer(void *);
  47 static boolean_t i40e_enable_interrupts(i40e_t *);
  48 static boolean_t i40e_disable_interrupts(i40e_t *);
  49 static int i40e_get_vsi_id(i40e_t *);
  50 
  51 static struct cb_ops i40e_cb_ops = {
  52         nulldev,                /* cb_open */
  53         nulldev,                /* cb_close */
  54         nodev,                  /* cb_strategy */
  55         nodev,                  /* cb_print */
  56         nodev,                  /* cb_dump */
  57         nodev,                  /* cb_read */
  58         nodev,                  /* cb_write */
  59         nodev,                  /* cb_ioctl */
  60         nodev,                  /* cb_devmap */
  61         nodev,                  /* cb_mmap */
  62         nodev,                  /* cb_segmap */
  63         nochpoll,               /* cb_chpoll */
  64         ddi_prop_op,            /* cb_prop_op */
  65         NULL,                   /* cb_stream */
  66         D_MP | D_HOTPLUG,       /* cb_flag */
  67         CB_REV,                 /* cb_rev */
  68         nodev,                  /* cb_aread */
  69         nodev                   /* cb_awrite */
  70 };
  71 
  72 static struct dev_ops i40e_dev_ops = {
  73         DEVO_REV,               /* devo_rev */
  74         0,                      /* devo_refcnt */
  75         NULL,                   /* devo_getinfo */
  76         nulldev,                /* devo_identify */
  77         nulldev,                /* devo_probe */
  78         i40e_attach,            /* devo_attach */
  79         i40e_detach,            /* devo_detach */
  80         nodev,                  /* devo_reset */
  81         &i40e_cb_ops,               /* devo_cb_ops */
  82         NULL,                   /* devo_bus_ops */
  83         ddi_power,              /* devo_power */
  84         i40e_quiesce,           /* devo_quiesce */
  85 };
  86 
  87 static struct modldrv i40e_modldrv = {
  88         &mod_driverops,             /* Type of module.  This one is a driver */
  89         i40e_ident,             /* Description string */
  90         &i40e_dev_ops               /* driver ops */
  91 };
  92 
  93 static struct modlinkage i40e_modlinkage = {
  94         MODREV_1, &i40e_modldrv, NULL
  95 };
  96 
  97 /*
  98  * Access attributes for register mapping
  99  * XXX KEBE ASKS --> Change these? Currently they're stolen from ixgbe...
 100  */
 101 ddi_device_acc_attr_t i40e_regs_acc_attr = {
 102         DDI_DEVICE_ATTR_V1,
 103         DDI_STRUCTURE_LE_ACC,
 104         DDI_STRICTORDER_ACC,
 105         DDI_FLAGERR_ACC
 106 };
 107 
 108 /*
 109  * XXX KEBE SAYS NOTE:  I'm currently using the ixgbe approach to things.
 110  * It's VERY possible the Fortville/i40e world changes the game enough where
 111  * we need to restructure the device capability structure.
 112  * See i40e_common_code_init() for examples of why I NOTE this.
 113  *
 114  * Values pulled will have section number references from:
 115  *
 116  * BEGIN CSTYLED
 117  * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/xl710-10-40-controller-datasheet.pdf
 118  * END CSTYLED
 119  */
 120 static adapter_info_t i40e_XL710_cap = {
 121         1536,           /* maximum number of rx queues */ /* 1.1.2 - LQP */
 122         1,              /* minimum number of rx queues */
 123         256,            /* default number of rx queues */
 124         384,            /* maximum number of rx groups */ /* 1.1.6 */
 125         1,              /* minimum number of rx groups */
 126         1,              /* default number of rx groups */
 127         1536,           /* maximum number of tx queues */ /* 1.1.2 - LQP */
 128         1,              /* minimum number of tx queues */
 129         32,             /* default number of tx queues */
 130         9710,           /* maximum MTU size */ /* 1.2, tbl 1-3 */
 131         0xFF8,          /* maximum interrupt throttle rate */
 132         0,              /* minimum interrupt throttle rate */
 133         200,            /* default interrupt throttle rate */
 134         1024,           /* maximum admin queue size. XXX KEBE SAYS REFERENCE */
 135         256,            /* minimum admin queue size. */
 136         256,            /* default admin queue size. */
 137         4096,           /* maximum admin queue buffer size. XXX REFERENCE */
 138         4096,           /* maximum admin queue buffer size. */
 139         4096,           /* maximum admin queue buffer size. */
 140         129,            /* maximum total msix vectors */ /* 1.2, tbl 1-2 */
 141         48,             /* maximum number of ring vectors */
 142         2,              /* maximum number of other vectors */
 143         (0), /* "other" interrupt types handled */ /* KEBE SAYS FILL ME IN */
 144 
 145         (0), /* "other" interrupt types enable mask */ /* KEBE SAYS FILL IN */
 146 
 147         (I40E_FLAG_DCA_CAPABLE
 148         | I40E_FLAG_RSS_CAPABLE
 149         | I40E_FLAG_VMDQ_CAPABLE
 150         | I40E_FLAG_RSC_CAPABLE) /* capability flags */
 151 };
 152 
 153 /*
 154  * Loopback properties (see sys/netlb.h).
 155  */
 156 /* KEBE SAYS UNCOMMENT ME LATER...
 157 static lb_property_t lb_normal = {
 158         normal, "normal", I40E_LB_NONE
 159 };
 160 
 161 static lb_property_t lb_mac = {
 162         internal, "MAC", I40E_LB_INTERNAL_MAC
 163 };
 164 
 165 static lb_property_t lb_external = {
 166         external, "External", I40E_LB_EXTERNAL
 167 };
 168 ... XXX KEBE */
 169 
 170 /*
 171  * Generic Lan Driver (GLDv3)/MAC definitions and structures should mostly
 172  * be in i40e_gld.c.
 173  */
 174 
 175 /*
 176  * Logging function for this driver.
 177  */
 178 void
 179 i40e_dev_err(i40e_t *i40e, int level, boolean_t console, const char *fmt,
 180     va_list ap)
 181 {
 182         char buf[256];  /* Pardon the constant, seems enough for printing. */
 183 
 184         (void) vsnprintf(buf, sizeof (buf), fmt, ap);
 185 
 186         if (i40e == NULL) {
 187                 cmn_err(level, (console) ? "%s: %s" : "!%s: %s", MODULE_NAME,
 188                     buf);
 189         } else {
 190                 dev_err(i40e->i40e_dip, level, (console) ? "%s" : "!%s",
 191                     buf);
 192         }
 193 }
 194 
 195 /*
 196  * Because there's the stupid trailing-comma problem with the C preprocessor
 197  * and variable arguments, I need to instantiate these.  Pardon the redundant
 198  * code.
 199  */
 200 void
 201 i40e_error(i40e_t *i40e, const char *fmt, ...)
 202 {
 203         va_list ap;
 204 
 205         va_start(ap, fmt);
 206         i40e_dev_err(i40e, CE_WARN, B_FALSE, fmt, ap);
 207         va_end(ap);
 208 }
 209 
 210 void
 211 i40e_log(i40e_t *i40e, const char *fmt, ...)
 212 {
 213         va_list ap;
 214 
 215         va_start(ap, fmt);
 216         i40e_dev_err(i40e, CE_NOTE, B_FALSE, fmt, ap);
 217         va_end(ap);
 218 }
 219 
 220 void
 221 i40e_notice(i40e_t *i40e, const char *fmt, ...)
 222 {
 223         va_list ap;
 224 
 225         va_start(ap, fmt);
 226         i40e_dev_err(i40e, CE_NOTE, B_TRUE, fmt, ap);
 227         va_end(ap);
 228 }
 229 
 230 #define FIRST_TRY_COUNT 40  /* Arbitrary guess at how many elements needed. */
 231 static boolean_t
 232 i40e_get_hw_capabilities(i40e_t *i40e, i40e_hw_t *hw)
 233 {
 234         struct i40e_aqc_list_capabilities_element_resp *buf;
 235         int nelems = FIRST_TRY_COUNT;
 236         int rc, len;
 237         uint16_t needed;
 238 
 239         /*
 240          * The common-code call needs a buffer.  Allocate it, and try.
 241          * if the common-code calls complains the buffer isn't large enough,
 242          * use "needed" to try another allocation.
 243          */
 244         do {
 245                 len = nelems * sizeof (*buf);
 246                 buf = kmem_alloc(len, KM_SLEEP);
 247                 ASSERT(buf != NULL);    /* Safe with KM_SLEEP. */
 248                 rc = i40e_aq_discover_capabilities(hw, buf, len,
 249                     &needed, i40e_aqc_opc_list_func_capabilities, NULL);
 250                 kmem_free(buf, len);
 251                 if (hw->aq.asq_last_status == I40E_AQ_RC_ENOMEM &&
 252                     nelems == FIRST_TRY_COUNT) {
 253                         if (nelems == needed) {
 254                                 /* Measurable in WTFs... */
 255                                 i40e_error(i40e, "Common code is insane.");
 256                                 return (B_FALSE);
 257                         }
 258                         nelems = needed;
 259                         buf = NULL;     /* i.e. Continue the loop. */
 260                 } else if (hw->aq.asq_last_status != I40E_AQ_RC_OK) {
 261                         i40e_error(i40e, "Capability discovery failed: %d", rc);
 262                         return (B_FALSE);
 263                 }
 264                 /* OKAY, we're good, with a freed buffer pointer to exit... */
 265                 ASSERT(buf != NULL);
 266         } while (buf == NULL);
 267 
 268         /*
 269          * XXX KEBE SAYS NOTE: FreeBSD says capture this PF's starting queue
 270          * pair.
 271          */
 272         /* i40e->i40e_qbase = hw->func_caps.base_queue; */ /* TODO? */
 273         i40e_log(i40e, "The base queue pair is %d", hw->func_caps.base_queue);
 274 
 275         return (B_TRUE);
 276 }
 277 #undef  FIRST_TRY_COUNT
 278 
 279 /*
 280  * Unless a .conf file already overrode i40e_t structure values, they will
 281  * be 0, and need to be set in conjuction with the now-available HW report.
 282  */
 283 static void
 284 i40e_hw_to_instance(i40e_t *i40e, i40e_hw_t *hw)
 285 {
 286         if (i40e->i40e_num_trqpairs == 0) {
 287                 i40e->i40e_num_trqpairs =
 288                     min(hw->func_caps.num_tx_qp + hw->func_caps.num_rx_qp,
 289                     MAX_TX_RX_QUEUE_PAIRS);
 290         }
 291         /*
 292          * XXX KEBE ASKS -> Is there an i40e/XL710 version of receive groups?
 293          * For now, let's just set it to 1.
 294          */
 295         i40e->i40e_num_rx_groups = 1;
 296 
 297         /*
 298          * The combination of num_rx_rings and num_rx_groups may be not
 299          * supported by h/w. We need to adjust them to appropriate values.
 300          *
 301          * NOTE:  Right now we only work with XL710, if we get other i40es,
 302          * we may need to adjust.
 303          *
 304          * NOTE2: With only one GLDv3 receive group, we can only do
 305          * "RSS" at the moment.  Also there are two types of VMDQ now in i40e,
 306          * VMDQ and VMDQv2.
 307          */
 308         if (i40e->i40e_num_trqpairs == 1)
 309                 i40e->i40e_classify_mode = I40E_CLASSIFY_NONE;
 310         else
 311                 i40e->i40e_classify_mode = I40E_CLASSIFY_RSS;
 312 }
 313 
 314 /*
 315  * Initialize and call Intel common-code routines, includes some setup
 316  * the common code expects from the driver.  Also prints on failure, so
 317  * the caller doesn't have to.
 318  */
 319 static boolean_t
 320 i40e_common_code_init(i40e_t *i40e, i40e_hw_t *hw)
 321 {
 322         int rc;
 323         
 324         /* Clear & reset hardware, using Intel's code. */
 325         i40e_clear_hw(hw);
 326         rc = i40e_pf_reset(hw);
 327         if (rc != 0) {
 328                 i40e_error(i40e, "i40e_pf_reset() failed: %d\n", rc);
 329                 /* XXX KEBE ASKS FMA report? */
 330                 i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE);
 331                 return (B_FALSE);
 332         }
 333 
 334         /* Initialize the shared code. */
 335         rc = i40e_init_shared_code(hw);
 336         if (rc != 0) {
 337                 i40e_error(i40e, "i40e_init_shared_code() failed: %d\n", rc);
 338                 return (B_FALSE);
 339         }
 340 
 341         /* Set admin queue parameters */
 342         hw->aq.num_arq_entries = i40e->i40e_capab->def_adminq_len;
 343         hw->aq.num_asq_entries = i40e->i40e_capab->def_adminq_len;
 344         hw->aq.arq_buf_size = i40e->i40e_capab->def_adminq_bufsize;
 345         hw->aq.asq_buf_size = i40e->i40e_capab->def_adminq_bufsize;
 346         /* Initialize the admin queue */
 347         rc = i40e_init_adminq(hw);
 348         if (rc != 0) {
 349                 i40e_error(i40e, "i40e_init_adminq() failed: %d\n", rc);
 350                 i40e_error(i40e, "This may be due to a mismatch between "
 351                     "the firmware and the driver.\n");
 352                 /* XXX KEBE ASKS FMA report? */
 353                 i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE);
 354                 return (B_FALSE);
 355         }
 356         /* Check for other firmware mismatches. */
 357         if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
 358             hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR) {
 359                 i40e_notice(i40e, "The driver for the device detected a newer "
 360                     "version of the NVM image (%d.%d) than expected (%d.%d).\n"
 361                     "Please install the most recent version of the network "
 362                     "driver.\n", hw->aq.api_maj_ver, hw->aq.api_min_ver,
 363                     I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR);
 364         } else if (hw->aq.api_maj_ver < I40E_FW_API_VERSION_MAJOR ||
 365             hw->aq.api_min_ver < (I40E_FW_API_VERSION_MINOR - 1)) {
 366                 i40e_notice(i40e, "The driver for the device detected an older"
 367                     " version of the NVM image (%d.%d) than expected (%d.%d)."
 368                     "\nPlease update the NVM image.\n",
 369                     hw->aq.api_maj_ver, hw->aq.api_min_ver,
 370                     I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR - 1);
 371         }
 372 
 373         /* Clear PXE mode */
 374         i40e_clear_pxe_mode(hw);
 375 
 376         /*
 377          * Have the common code discover things about the hardware.
 378          */
 379         if (!i40e_get_hw_capabilities(i40e, hw)) {
 380                 i40e_error(i40e, "Obtaining HW capabilities failed.");
 381                 /* XXX KEBE ASKS FMA report? */
 382                 i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE);
 383                 return (B_FALSE);
 384         }
 385 
 386         /*
 387          * Now that we know some of the HW capabilities, let's initialize
 388          * them if they aren't already in our i40e.
 389          */
 390         i40e_hw_to_instance(i40e, hw);
 391 
 392         /* Set up host memory cache */
 393         rc = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
 394             hw->func_caps.num_rx_qp, 0, 0);
 395         if (rc != 0) {
 396                 i40e_error(i40e, "init_lan_hmc failed: %d\n", rc);
 397                 return (B_FALSE);
 398         }
 399 
 400         rc = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
 401         if (rc != 0) {
 402                 i40e_error(i40e, "configure_lan_hmc failed: %d\n", rc);
 403                 return (B_FALSE);
 404         }
 405 
 406         /* Disable LLDP from the firmware */
 407         i40e_aq_stop_lldp(hw, TRUE, NULL);
 408 
 409         i40e_get_mac_addr(hw, hw->mac.addr);
 410         rc = i40e_validate_mac_addr(hw->mac.addr);
 411         if (rc != 0) {
 412                 i40e_error(i40e, "validate_mac_addr failed: %d\n", rc);
 413                 return (B_FALSE);
 414         }
 415         bcopy(hw->mac.addr, hw->mac.perm_addr, ETHERADDRL);
 416         i40e_get_port_mac_addr(hw, hw->mac.port_addr);
 417 
 418         /*
 419          * We need to obtain the Virtual Station ID (vsi) before we can
 420          * anything else.
 421          */
 422         i40e->i40e_vsi_id = i40e_get_vsi_id(i40e);
 423         if (i40e->i40e_vsi_id == -1) {
 424                 i40e_error(i40e, "Failed to get VSI ID");
 425                 return (B_FALSE);
 426         }
 427 
 428         return (B_TRUE);
 429 }
 430 
 431 /*
 432  * Free any resources required by, or setup by, the Intel common code.
 433  */
 434 static void
 435 i40e_common_code_fini(i40e_t *i40e)
 436 {
 437         i40e_hw_t *hw = &i40e->i40e_hw_space;
 438         int rc;
 439 
 440         rc = i40e_shutdown_adminq(hw);
 441         if (rc != I40E_SUCCESS)
 442                 i40e_error(i40e, "i40e_shutdown_adminq() failed: %d", rc);
 443 
 444         rc = i40e_shutdown_lan_hmc(hw);
 445         if (rc != I40E_SUCCESS)
 446                 i40e_error(i40e, "i40e_shutdown_lan_hmc() failed: %d", rc);
 447 
 448         /* XXX KEBE ASKS ---> more here?!? */
 449 }
 450 
 451 static boolean_t
 452 i40e_final_init(i40e_t *i40e)
 453 {
 454         i40e_hw_t *hw = &i40e->i40e_hw_space;
 455         struct i40e_osdep *osdep = OS_DEP(hw);
 456         uint8_t pbanum[I40E_PBANUM_STRLEN];
 457         enum i40e_status_code irc;
 458 
 459         /* XXX KEBE ASKS enter/exit i40e->i40e_gen_lock here ? */
 460 
 461         pbanum[0] = '\0';
 462         irc = i40e_read_pba_string(hw, pbanum, sizeof (pbanum));
 463         if (irc != I40E_SUCCESS) {
 464                 i40e_error(i40e, "i40e_read_pba_string() failed: %d", irc);
 465                 return (B_FALSE);
 466         }
 467         if (pbanum[0] != '\0') {
 468                 /* (void) this?!? */
 469                 (void) ddi_prop_update_string(DDI_DEV_T_NONE, i40e->i40e_dip,
 470                     "printed-board-assembly", (char *)pbanum);
 471         }
 472 
 473         if (!i40e_set_hw_bus_info(hw))
 474                 return (B_FALSE);
 475 
 476         if (i40e_check_acc_handle(osdep->reg_handle) != DDI_FM_OK) {
 477                 ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
 478                 return (B_FALSE);
 479         }
 480 
 481         return (B_TRUE);
 482 }
 483 
 484 /*
 485  * i40e_attach - Driver attach.
 486  *
 487  * This function is the device specific initialization entry
 488  * point. This entry point is required and must be written.
 489  * The DDI_ATTACH command must be provided in the attach entry
 490  * point. When attach() is called with cmd set to DDI_ATTACH,
 491  * all normal kernel services (such as kmem_alloc(9F)) are
 492  * available for use by the driver.
 493  *
 494  * The attach() function will be called once for each instance
 495  * of  the  device  on  the  system with cmd set to DDI_ATTACH.
 496  * Until attach() succeeds, the only driver entry points which
 497  * may be called are open(9E) and getinfo(9E).
 498  */
 499 static int
 500 i40e_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
 501 {
 502         i40e_t *i40e;
 503         struct i40e_osdep *osdep;
 504         i40e_hw_t *hw;
 505         int instance, rc;
 506         char taskqname[32];
 507 
 508         /* Vector off bad commands or RESUME. */
 509         switch (cmd) {
 510         default:
 511                 return (DDI_FAILURE);
 512         case DDI_RESUME:
 513                 /* return (i40e_resume(devinfo)); */
 514                 goto attach_fail;  /* XXX NUKE ME!!! */
 515         case DDI_ATTACH:
 516                 break;
 517         }
 518 
 519         /* NOW we proceed with the actual attachment code. */
 520 
 521         instance = ddi_get_instance(devinfo);
 522         i40e = kmem_zalloc(sizeof (i40e_t), KM_SLEEP);
 523         /* No NULL check needed for KM_SLEEP... */
 524 
 525         i40e->i40e_instance = instance;
 526         i40e->i40e_dip = devinfo;
 527 
 528         hw = &i40e->i40e_hw_space;
 529         osdep = &i40e->i40e_osdep_space;
 530         hw->back = osdep;
 531         osdep->i40e = i40e;
 532 
 533         ddi_set_driver_private(devinfo, i40e);
 534 
 535         /* Setup FMA support. */
 536         i40e_fm_init(i40e);
 537         i40e->i40e_attach_progress |= ATTACH_PROGRESS_FM_INIT;
 538 
 539         /* Map PCI config space registers. */
 540         if (pci_config_setup(devinfo, &osdep->cfg_handle) != DDI_SUCCESS) {
 541                 i40e_error(i40e, "Failed to map PCI configurations.");
 542                 goto attach_fail;
 543         }
 544         i40e->i40e_attach_progress |= ATTACH_PROGRESS_PCI_CONFIG;
 545 
 546         /*
 547          * Map the device registers.  This involves identifying the
 548          * hardware, followed by the actual mapping.
 549          */
 550         if (!i40e_identify_hardware(i40e)) {
 551                 i40e_error(i40e, "Cannot identify hardware.");
 552                 goto attach_fail;
 553         }
 554 
 555         /* Now the actual mapping. */
 556         if (!i40e_regs_map(i40e)) {
 557                 i40e_error(i40e, "Failed to map device registers.");
 558                 goto attach_fail;
 559         }
 560         i40e->i40e_attach_progress |= ATTACH_PROGRESS_REGS_MAP;
 561 
 562         i40e_init_properties(i40e);
 563         i40e->i40e_attach_progress |= ATTACH_PROGRESS_PROPS;
 564 
 565         if (!i40e_common_code_init(i40e, hw))
 566                 goto attach_fail;
 567         i40e->i40e_attach_progress |= ATTACH_PROGRESS_COMMON_CODE;
 568 
 569         /* Register the interrupt callback and allocate interrupts. */
 570         rc = ddi_cb_register(devinfo, DDI_CB_FLAG_INTR, i40e_intr_callback,
 571             i40e, NULL, &i40e->i40e_callback_handle);
 572         if (rc != DDI_SUCCESS) {
 573                 i40e_error(i40e,
 574                     "Failed to register an interrupt callback: %d.", rc);
 575                 goto attach_fail;
 576         }
 577 
 578         if (!i40e_alloc_intrs(i40e, devinfo)) {
 579                 i40e_error(i40e, "Failed to allocate interrupts.");
 580                 goto attach_fail;
 581         }
 582         i40e->i40e_attach_progress |= ATTACH_PROGRESS_ALLOC_INTR;
 583 
 584         /* Allocate tx/rx queue pairs and initialize locks. */
 585         if (!i40e_alloc_trqpairs_locks(i40e)) {
 586                 i40e_error(i40e,
 587                     "Failed to allocate receive & transmit rings.");
 588                 goto attach_fail;
 589         }
 590         i40e->i40e_attach_progress |= ATTACH_PROGRESS_ALLOC_RINGSLOCKS;
 591 
 592         /* Map trqpairs to interrupts vectors... */
 593         if (!i40e_map_intrs_to_vectors(i40e)) {
 594                 i40e_error(i40e, "Failed to map interrupts to vectors.");
 595                 goto attach_fail;
 596         }
 597         /* ...then add interrupt handlers. */
 598         if (!i40e_add_intr_handlers(i40e)) {
 599                 i40e_error(i40e, "Failed to add the interrupt handlers.");
 600                 goto attach_fail;
 601         }
 602         i40e->i40e_attach_progress |= ATTACH_PROGRESS_ADD_INTR;
 603 
 604         /* Create taskqs for SFP-change & over-temp. */
 605         (void) sprintf(taskqname, "i40e%d_sfp_taskq", instance);
 606         i40e->i40e_sfp_taskq = ddi_taskq_create(devinfo, taskqname, 1,
 607             TASKQ_DEFAULTPRI, 0);
 608         if (i40e->i40e_sfp_taskq == NULL) {
 609                 i40e_error(i40e, "i40e_sfp_taskq creation failed");
 610                 goto attach_fail;
 611         }
 612         i40e->i40e_attach_progress |= ATTACH_PROGRESS_SFP_TASKQ;
 613 
 614         (void) sprintf(taskqname, "i40e%d_overtemp_taskq", instance);
 615         i40e->i40e_overtemp_taskq = ddi_taskq_create(devinfo, taskqname, 1,
 616             TASKQ_DEFAULTPRI, 0);
 617         if (i40e->i40e_overtemp_taskq == NULL) {
 618                 i40e_error(i40e, "i40e_overtemp_taskq creation failed");
 619                 goto attach_fail;
 620         }
 621         i40e->i40e_attach_progress |= ATTACH_PROGRESS_OVERTEMP_TASKQ;
 622 
 623         /* Additional initialization of chipset hardware. */
 624         if (!i40e_final_init(i40e)) {
 625                 i40e_error(i40e, "Final initialization failed.");
 626                 goto attach_fail;
 627         }
 628         i40e->i40e_attach_progress |= ATTACH_PROGRESS_INIT;
 629 
 630         /* Check the FM acc handle.  (No progress needed.) */
 631         if (i40e_check_acc_handle(i40e->i40e_osdep_space.cfg_handle) !=
 632             DDI_FM_OK) {
 633                 ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
 634                 goto attach_fail;
 635         }
 636 
 637         /* XXX KEBE SAYS Initialize the statistics. */
 638 
 639         if (!i40e_init_stats(i40e)) {
 640                 i40e_error(i40e, "Stats initialization failed.");
 641                 goto attach_fail;
 642         }
 643         i40e->i40e_attach_progress |= ATTACH_PROGRESS_STATS;
 644 
 645         /* Register the driver to GLDv3/mac. */
 646         if (!i40e_register_mac(i40e)) {
 647                 i40e_error(i40e, "Failed to register to MAC/GLDv3");
 648                 goto attach_fail;
 649         }
 650         i40e->i40e_attach_progress |= ATTACH_PROGRESS_MAC;
 651 
 652         /* Add a DDI periodic timer. */
 653         i40e->i40e_periodic_id = ddi_periodic_add(i40e_timer, i40e,
 654             I40E_CYCLIC_PERIOD, DDI_IPL_0);
 655         if (i40e->i40e_periodic_id == 0) {
 656                 i40e_error(i40e, "Failed to add the link-check timer");
 657                 goto attach_fail;
 658         }
 659         i40e->i40e_attach_progress |= ATTACH_PROGRESS_LINK_TIMER;
 660 
 661         /* XXX KEBE SAYS Enable the interrupts! */
 662         if (!i40e_enable_interrupts(i40e)) {
 663                 i40e_error(i40e, "Failed to enable DDI interrupts");
 664                 goto attach_fail;
 665         }
 666         i40e->i40e_attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
 667 
 668         /* Atomic-or the I40E_INITIALIZED flag. */
 669         atomic_or_32(&i40e->i40e_state, I40E_INITIALIZED);
 670 
 671         return (DDI_SUCCESS);
 672 
 673 attach_fail:
 674         i40e_unconfigure(devinfo, i40e);
 675         return (DDI_FAILURE);
 676 }
 677 
 678 /*
 679  * i40e_detach - Driver detach.
 680  *
 681  * The detach() function is the complement of the attach routine.
 682  * If cmd is set to DDI_DETACH, detach() is used to remove  the
 683  * state  associated  with  a  given  instance of a device node
 684  * prior to the removal of that instance from the system.
 685  *
 686  * The detach() function will be called once for each  instance
 687  * of the device for which there has been a successful attach()
 688  * once there are no longer  any  opens  on  the  device.
 689  *
 690  * Interrupts routine are disabled, All memory allocated by this
 691  * driver are freed.
 692  */
 693 static int
 694 i40e_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
 695 {
 696         i40e_t *i40e;
 697 
 698         switch (cmd) {
 699         default:
 700                 return (DDI_FAILURE);
 701         case DDI_SUSPEND:
 702                 /* XXX KEBE SAYS FILL ME IN */
 703                 return (DDI_FAILURE);
 704         case DDI_DETACH:
 705                 break;
 706         }
 707 
 708         i40e = (i40e_t *)ddi_get_driver_private(devinfo);
 709         if (i40e == NULL) {
 710                 i40e_log(NULL, "i40e_detach() called with no i40e pointer!");
 711                 return (DDI_FAILURE);
 712         }
 713 
 714         /*
 715          * XXX KEBE SAYS FILL IN still-running checks and drain the rx
 716          * buffers that upper layers may have lying about.
 717          */
 718 
 719         /*
 720         if (i40e->i40e_state & I40E_STARTED...)
 721          */
 722 
 723 
 724         /*
 725         if (!i40e_rx_drain(i40e))
 726                 return (DDI_FAILURE);
 727          */
 728 
 729         i40e_unconfigure(devinfo, i40e);
 730         return (DDI_SUCCESS);
 731 }
 732 
 733 static void
 734 i40e_rem_intrs(i40e_t *i40e)
 735 {
 736         int i, rc;
 737 
 738         for (i = 0; i < i40e->i40e_intr_count; i++) {
 739                 rc = ddi_intr_free(i40e->i40e_intr_handles[i]);
 740                 if (rc != DDI_SUCCESS) {
 741                         i40e_log(i40e, "Can't free i40e_intr_handle[%d]: %d",
 742                             i, rc);
 743                 }
 744         }
 745 
 746         kmem_free(i40e->i40e_intr_handles, i40e->i40e_intr_size);
 747         i40e->i40e_intr_handles = NULL;
 748 }
 749 
 750 static void
 751 i40e_rem_intr_handlers(i40e_t *i40e)
 752 {
 753         int i, rc;
 754 
 755         for (i = 0; i < i40e->i40e_intr_count; i++) {
 756                 rc = ddi_intr_remove_handler(i40e->i40e_intr_handles[i]);
 757                 if (rc != DDI_SUCCESS) {
 758                         i40e_log(i40e, "Can't remove intr_handler[%d]: %d",
 759                             i, rc);
 760                 }
 761         }
 762 }
 763 
 764 static void
 765 i40e_unconfigure(dev_info_t *devinfo, i40e_t *i40e)
 766 {
 767         int rc;
 768 
 769         /*
 770          * Disable interrupts (and ignore the return code since we're
 771          * detaching.
 772          */
 773         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_ENABLE_INTR)
 774                 (void) i40e_disable_interrupts(i40e);
 775 
 776         /* Remove the link check timer. */
 777         if ((i40e->i40e_attach_progress & ATTACH_PROGRESS_LINK_TIMER) &&
 778             i40e->i40e_periodic_id != 0) {
 779                 ddi_periodic_delete(i40e->i40e_periodic_id);
 780                 i40e->i40e_periodic_id = 0;
 781         }
 782 
 783         /* Unregister from GLDv3/mac. */
 784         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_MAC) {
 785                 rc = mac_unregister(i40e->i40e_mac_hdl);
 786                 if (rc != 0)
 787                         i40e_error(i40e, "mac_unregister() failed: %d", rc);
 788         }
 789 
 790         /* Free statistics... */
 791         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_STATS)
 792                 kstat_delete((kstat_t *)i40e->i40e_kstats);
 793 
 794         /* if (i40e->i40e_attach_progress & ATTACH_PROGRESS_INIT)
 795            ; */
 796 
 797         /* Remove the taskqs. */
 798         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_OVERTEMP_TASKQ)
 799                 ddi_taskq_destroy(i40e->i40e_overtemp_taskq);
 800         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_SFP_TASKQ)
 801                 ddi_taskq_destroy(i40e->i40e_sfp_taskq);
 802 
 803         /* XXX KEBE SAYS Remove the interrupt handlers. */
 804         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_ADD_INTR)
 805                 i40e_rem_intr_handlers(i40e);
 806 
 807         /* Remove the tx/rx qpairs and decommission the locks. */
 808         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_ALLOC_RINGSLOCKS)
 809                 i40e_free_trqpairs_locks(i40e);
 810 
 811         /* Remove interrupts and un-register interrupt callback handler. */
 812         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_ALLOC_INTR)
 813                 i40e_rem_intrs(i40e);
 814 
 815         /* Check for unregistering by checking for a NULL callback handle. */
 816         if (i40e->i40e_callback_handle != NULL)
 817                 (void) ddi_cb_unregister(i40e->i40e_callback_handle);
 818 
 819         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_COMMON_CODE)
 820                 i40e_common_code_fini(i40e);
 821 
 822         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_PROPS)
 823                 (void) ddi_prop_remove_all(devinfo);
 824 
 825         /*
 826          * Free the register handle.
 827          */
 828         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_REGS_MAP &&
 829             i40e->i40e_osdep_space.reg_handle != NULL) {
 830                 ddi_regs_map_free(&i40e->i40e_osdep_space.reg_handle);
 831         }
 832 
 833         /*
 834          * Free PCI config handle
 835          */
 836         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_PCI_CONFIG &&
 837             i40e->i40e_osdep_space.cfg_handle != NULL) {
 838                 pci_config_teardown(&i40e->i40e_osdep_space.cfg_handle);
 839         }
 840 
 841         /*
 842          * Unregister FMA capabilities
 843          */
 844         if (i40e->i40e_attach_progress & ATTACH_PROGRESS_FM_INIT)
 845                 i40e_fm_fini(i40e);
 846 
 847         /*
 848          * Free the driver data structure
 849          */
 850         kmem_free(i40e, sizeof (i40e_t));
 851 
 852         ddi_set_driver_private(devinfo, NULL);
 853 }
 854 
 855 /*
 856  * quiesce(9E) entry point.
 857  *
 858  * This function is called when the system is single-threaded at high
 859  * PIL with preemption disabled. Therefore, this function must not be
 860  * blocked.
 861  *
 862  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
 863  * DDI_FAILURE indicates an error condition and should almost never happen.
 864  */
 865 static int
 866 i40e_quiesce(dev_info_t *devinfo)
 867 {
 868         return (DDI_FAILURE); /* For now. */
 869 }
 870 
 871 /*
 872  * illumos Fault Management Architecture (FMA) support.
 873  */
 874 
 875 int
 876 i40e_check_acc_handle(ddi_acc_handle_t handle)
 877 {
 878         ddi_fm_error_t de;
 879 
 880         ddi_fm_acc_err_get(handle, &de, DDI_FME_VERSION);
 881         ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
 882         return (de.fme_status);
 883 }
 884 
 885 int
 886 i40e_check_dma_handle(ddi_dma_handle_t handle)
 887 {
 888         ddi_fm_error_t de;
 889 
 890         ddi_fm_dma_err_get(handle, &de, DDI_FME_VERSION);
 891         return (de.fme_status);
 892 }
 893 
 894 /*
 895  * Fault service error handling callback function.
 896  */
 897 static int
 898 i40e_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data)
 899 {
 900         _NOTE(ARGUNUSED(impl_data));
 901         /*
 902          * as the driver can always deal with an error in any dma or
 903          * access handle, we can just return the fme_status value.
 904          */
 905         pci_ereport_post(dip, err, NULL);
 906         return (err->fme_status);
 907 }
 908 
 909 static void
 910 i40e_fm_init(i40e_t *i40e)
 911 {
 912         ddi_iblock_cookie_t iblk;
 913 
 914         /*
 915          * Gather up capabilities. In ixgbe (this driver's inspiration) this
 916          * was done in the caller. For i40e it's being encapsulated here.
 917          * NOTE: We have a looper for most i40e.conf entries, but we need to
 918          * do "fm_capable" early.
 919          */
 920         i40e->i40e_fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY,
 921             i40e->i40e_dip, DDI_PROP_DONTPASS, "fm_capable",
 922             DDI_FM_EREPORT_CAPABLE | DDI_FM_ACCCHK_CAPABLE |
 923             DDI_FM_DMACHK_CAPABLE | DDI_FM_ERRCB_CAPABLE);
 924 
 925         if (i40e->i40e_fm_capabilities < 0) {
 926                 i40e->i40e_fm_capabilities = 0;
 927         } else if (i40e->i40e_fm_capabilities > 0xf) {
 928                 i40e->i40e_fm_capabilities = DDI_FM_EREPORT_CAPABLE |
 929                     DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE |
 930                     DDI_FM_ERRCB_CAPABLE;
 931         }
 932 
 933         /*
 934          * Only register with IO Fault Services if we have some capability
 935          */
 936         if (i40e->i40e_fm_capabilities & DDI_FM_ACCCHK_CAPABLE) {
 937                 i40e_regs_acc_attr.devacc_attr_access = DDI_FLAGERR_ACC;
 938         } else {
 939                 i40e_regs_acc_attr.devacc_attr_access = DDI_DEFAULT_ACC;
 940         }
 941 
 942         i40e_set_fma_flags(
 943             (i40e->i40e_fm_capabilities & DDI_FM_DMACHK_CAPABLE) != 0);
 944 
 945         if (i40e->i40e_fm_capabilities) {
 946                 /*
 947                  * Register capabilities with IO Fault Services
 948                  */
 949                 ddi_fm_init(i40e->i40e_dip, &i40e->i40e_fm_capabilities, &iblk);
 950 
 951                 /*
 952                  * Initialize pci ereport capabilities if ereport capable
 953                  */
 954                 if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) ||
 955                     DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) {
 956                         pci_ereport_setup(i40e->i40e_dip);
 957                 }
 958 
 959                 /*
 960                  * Register error callback if error callback capable
 961                  */
 962                 if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities)) {
 963                         ddi_fm_handler_register(i40e->i40e_dip,
 964                             i40e_fm_error_cb, (void*)i40e);
 965                 }
 966         }
 967 }
 968 
 969 static void
 970 i40e_fm_fini(i40e_t *i40e)
 971 {
 972         /*
 973          * Only unregister FMA capabilities if they are registered
 974          */
 975         if (i40e->i40e_fm_capabilities) {
 976 
 977                 /*
 978                  * Release any resources allocated by pci_ereport_setup()
 979                  */
 980                 if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities) ||
 981                     DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities))
 982                         pci_ereport_teardown(i40e->i40e_dip);
 983 
 984                 /*
 985                  * Un-register error callback if error callback capable
 986                  */
 987                 if (DDI_FM_ERRCB_CAP(i40e->i40e_fm_capabilities))
 988                         ddi_fm_handler_unregister(i40e->i40e_dip);
 989 
 990                 /*
 991                  * Unregister from IO Fault Service
 992                  */
 993                 ddi_fm_fini(i40e->i40e_dip);
 994         }
 995 }
 996 
 997 void
 998 i40e_fm_ereport(i40e_t *i40e, char *detail)
 999 {
1000         uint64_t ena;
1001         char buf[FM_MAX_CLASS];
1002 
1003         (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE, detail);
1004         ena = fm_ena_generate(0, FM_ENA_FMT1);
1005         if (DDI_FM_EREPORT_CAP(i40e->i40e_fm_capabilities)) {
1006                 ddi_fm_ereport_post(i40e->i40e_dip, buf, ena, DDI_NOSLEEP,
1007                     FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0, NULL);
1008         }
1009 }
1010 
1011 /*
1012  * Identify the chipset to which we're attaching, and make necessary records.
1013  * B_TRUE == success.
1014  */
1015 static boolean_t
1016 i40e_identify_hardware(i40e_t *i40e)
1017 {
1018         i40e_hw_t *hw = &i40e->i40e_hw_space;
1019         struct i40e_osdep *osdep = &i40e->i40e_osdep_space;
1020 
1021         hw->vendor_id = pci_config_get16(osdep->cfg_handle, PCI_CONF_VENID);
1022         hw->device_id = pci_config_get16(osdep->cfg_handle, PCI_CONF_DEVID);
1023         hw->revision_id = pci_config_get8(osdep->cfg_handle, PCI_CONF_REVID);
1024         hw->subsystem_device_id =
1025             pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBSYSID);
1026         hw->subsystem_vendor_id =
1027             pci_config_get16(osdep->cfg_handle, PCI_CONF_SUBVENID);
1028         /*
1029          * XXX KEBE SAYS FreeBSD sets bus.device with the slot, and bus.func
1030          * with "pci_get_function()".  Do we need this in illumos?
1031          */
1032 
1033         /* Call common code to set the MAC type for this adapter. */
1034         if (i40e_set_mac_type(hw) != I40E_SUCCESS)
1035                 return (B_FALSE);
1036 
1037         /*
1038          * Now that we have the MAC type, use it to inform our view of the
1039          * capabilities.
1040          */
1041         switch (hw->mac.type) {
1042         case I40E_MAC_XL710:
1043                 /* XXX KEBE SAYS FILL ME IN!!! */
1044                 /* XXX KEBE ASKS - do we need to do this? */
1045                 i40e->i40e_capab = &i40e_XL710_cap;
1046                 break;
1047 #ifdef X722_SUPPORT
1048         case I40E_MAC_X722:
1049                 break;
1050         case I40E_MAC_X722_VF:
1051 #endif /* X722_SUPPORT */
1052         case I40E_MAC_VF:
1053                 /* illumos does not support the _VF types. */
1054                 i40e_error(i40e,
1055                     "i40e_attach() to _VF configuration not supported.");
1056                 return (B_FALSE);
1057         case I40E_MAC_GENERIC:
1058                 /*
1059                  * Unsure what to do with devices the Intel common code
1060                  * doesn't know what to do with.  Bail, for now.
1061                  */
1062                 i40e_error(i40e, "i40e doesn't support I40E_MAC_GENERIC.");
1063                 return (B_FALSE);
1064         default:
1065                 /* Should never reach here, but inform and fail anyway. */
1066                 i40e_error(i40e, "Unknown i40e MAC type.");
1067                 return (B_FALSE);
1068         }
1069 
1070         return (B_TRUE);
1071 }
1072 
1073 static boolean_t
1074 i40e_regs_map(i40e_t *i40e)
1075 {
1076         dev_info_t *devinfo = i40e->i40e_dip;
1077         i40e_hw_t *hw = &i40e->i40e_hw_space;
1078         struct i40e_osdep *osdep = &i40e->i40e_osdep_space;
1079         off_t memsize;
1080 
1081         if (ddi_dev_regsize(devinfo, I40E_ADAPTER_REGSET, &memsize) !=
1082             DDI_SUCCESS) {
1083                 return (B_FALSE);
1084         }
1085 
1086         if (ddi_regs_map_setup(devinfo, I40E_ADAPTER_REGSET,
1087             (caddr_t *)&hw->hw_addr, 0, memsize, &i40e_regs_acc_attr,
1088             &osdep->reg_handle) != DDI_SUCCESS) {
1089                 return (B_FALSE);
1090         }
1091 
1092         return (B_TRUE);
1093 }
1094 
1095 /*
1096  * Two parts of i40e_init_properties().
1097  */
1098 
1099 /* Part 1 - read i40e.conf. */
1100 static void
1101 i40e_get_conf(i40e_t *i40e)
1102 {
1103         struct adapter_info *capab = i40e->i40e_capab;
1104         struct i40e_proplist {
1105                 char *name;     /* Property name. */
1106                 int min;        /* Property minimum value. */
1107                 int max;        /* Property maximum value. */
1108                 int def;        /* Property default value. */
1109                 int offset;     /* Offset into i40e_t for the value. */
1110         } props[] = {
1111                 /*
1112                  * Just add entries to this table for any integer value.
1113                  * XXX KEBE ASKS - should I enforce uint_t instead?
1114                  */
1115 
1116                 /* Default MTU size. */
1117                 { "default_mtu", ETHERMIN, capab->max_mtu, capab->max_mtu,
1118                   offsetof(i40e_t, i40e_default_mtu) },
1119 
1120                 /* Flow control... */
1121                 { "flow_control", I40E_FC_NONE, I40E_FC_DEFAULT, I40E_FC_NONE,
1122                   offsetof(i40e_t, i40e_hw_space) +
1123                   offsetof(struct i40e_hw, fc) +
1124                   offsetof(struct i40e_fc_info, requested_mode) },
1125 
1126                 /* Interrupt forcing. */
1127                 { "intr_force", I40E_INTR_NONE, I40E_INTR_LEGACY,
1128                   I40E_INTR_NONE, offsetof(i40e_t, i40e_intr_force) },
1129 
1130                 /*
1131                  * HW ring enable/disable.
1132                  * (Assume sizeof (boolean_t) == sizeof (uint_t).)
1133                  */
1134                 { "mr_enable", B_FALSE, B_TRUE, B_TRUE,
1135                   offsetof(i40e_t, i40e_mr_enable) },
1136 
1137                 /* Number of transmit/receive queue pairs */
1138                 /* XXX KEBE SAYS SET TO 2 for BRINGUP... */
1139                 { "tx_rx_queue_pairs", 0, MAX_TX_RX_QUEUE_PAIRS,
1140                   1, offsetof(i40e_t, i40e_num_trqpairs) },
1141 
1142                 /*
1143                  * Various enables/disables.
1144                  * Assume sizeof (boolean_t) == sizeof (uint_t).
1145                  * XXX KEBE SAYS - some of these may/should become dladm(1M)
1146                  * link properties.
1147                  */
1148                 { "tx_hcksum_enable", B_FALSE, B_TRUE, B_TRUE,
1149                   offsetof(i40e_t, i40e_tx_hcksum_enable) },
1150                 { "rx_hcksum_enable", B_FALSE, B_TRUE, B_TRUE,
1151                   offsetof(i40e_t, i40e_rx_hcksum_enable) },
1152                 /* XXX KEBE ASKS - lso_enable set to true by default?!? */
1153                 { "lso_enable", B_FALSE, B_TRUE, B_TRUE,
1154                   offsetof(i40e_t, i40e_lso_enable) },
1155                 { "lro_enable", B_FALSE, B_TRUE, B_FALSE,
1156                   offsetof(i40e_t, i40e_lro_enable) },
1157 
1158                 /* Must end with a NULL string... */
1159                 { NULL, 0, 0, 0, 0}
1160         };
1161         int i, propval;
1162 
1163 #define PTROF(i40e, offset) ((int *)((uint8_t *)(i40e) + (offset)))
1164         for (i = 0; props[i].name != NULL; i++) {
1165                 struct i40e_proplist *pvp = &(props[i]);
1166 
1167                 propval = ddi_prop_get_int(DDI_DEV_T_ANY, i40e->i40e_dip,
1168                     DDI_PROP_DONTPASS, pvp->name, pvp->def);
1169 
1170                 if (propval > pvp->max)
1171                         propval = pvp->max;
1172 
1173                 if (propval < pvp->min)
1174                         propval = pvp->min;
1175 
1176                 ASSERT(IS_P2ALIGNED(PTROF(i40e, pvp->offset), 4));
1177                 *PTROF(i40e, pvp->offset) = propval;
1178         }
1179 #undef PTROF
1180 
1181         /* Make additional decisions based on properties initialized above. */
1182 
1183         if (!i40e->i40e_mr_enable) {
1184                 i40e->i40e_num_trqpairs = 1;
1185                 i40e->i40e_classify_mode = I40E_CLASSIFY_NONE;
1186         }
1187         /*
1188          * Else we'll have to do this later, after we grab things from the
1189          * hardware.
1190          */
1191 
1192         /* Some reality checks. */
1193 
1194         /* Can't do LRO unless you have receive HW checksum enabled. */
1195         i40e->i40e_lro_enable &= i40e->i40e_rx_hcksum_enable;
1196 
1197         /* XXX KEBE SAYS FILL ME IN! */
1198 }
1199 
1200 /* Part 2 - Set up other parameters in the i40 instance. */
1201 static void
1202 i40e_init_params(i40e_t *i40e)
1203 {
1204         /* XXX KEBE SAYS FILL ME IN! */
1205         /*
1206          * Wow, lots to fill in here.  ixgbe has 100, 1000, 10000fdx stuff,
1207          * both enable, advertised, and "lp".  We'll have to add 20000 and
1208          * 40000 to that as well, I believe.
1209          */
1210 }
1211 
1212 /* Initialize driver properties... */
1213 static void
1214 i40e_init_properties(i40e_t *i40e)
1215 {
1216         /* Split into two parts for easier reading & organization. See above. */
1217         i40e_get_conf(i40e);
1218         i40e_init_params(i40e);
1219 }
1220 
1221 /*
1222  * i40e_alloc_intr_handles - Allocate interrupt handles. Called further down
1223  * by the higher-level interrupt allocator: i40e_alloc_intrs().
1224  *
1225  * For legacy and MSI, only 1 handle is needed.  For MSI-X, if fewer than 2
1226  * handles are available, return failure.  Upon success, this maps the vectors
1227  * to rx and tx rings for interrupts.
1228  */
1229 static boolean_t
1230 i40e_alloc_intr_handles(i40e_t *i40e, dev_info_t *devinfo, int intr_type)
1231 {
1232         int request, count, actual, rc;
1233         /*
1234          * XXX KEBE ASKS --> should this even be here?
1235          * ixgbe sets this, but it's ALWAYS 1. Instead of cargo-culting, should
1236          * we be smarter and always assume minimum == 1?
1237          */
1238         int minimum = 1;
1239 
1240         switch (intr_type) {
1241         case DDI_INTR_TYPE_FIXED:
1242         case DDI_INTR_TYPE_MSI:
1243                 request = 1;
1244                 break;
1245         case DDI_INTR_TYPE_MSIX:
1246                 /*
1247                  * XXX KEBE SAYS FILL ME IN, and consider best number
1248                  * of vectors the way ixgbe considered it (or better).
1249                  */
1250 
1251                 /* XXX KEBE SAYS CONSULT "hw" now! */
1252 
1253                 /*
1254                  * KEBE SAYS Cap as a function of how many CPU cores are
1255                  * available.  Is this a preferred use of ncpus_online?
1256                  * KEBE ASKS what happens when more/less go?  Is that an
1257                  * interrupt change event?
1258                  */
1259 #if 0
1260                 /* XXX KEBE ASKS two interrupts for each pair?  Or just one? */
1261                 request = min(ncpus_online, 2 * i40e->i40e_num_trqpairs + 1);
1262                 if (request > i40e->i40e_capab->max_ring_vect)
1263                         request = i40e->i40e_capab->max_ring_vect;
1264 #else
1265                 /*
1266                  * XXX KEBE SAYS BRINGUP TEST - just do two (adminq and one
1267                  * trqpair).
1268                  */
1269                 ASSERT(i40e->i40e_num_trqpairs == 1);
1270                 request = 2;
1271 #endif
1272                 break;
1273         default:
1274                 i40e_log(i40e,
1275                     "Who called i40e_alloc_intr_handles() w/%d?", intr_type);
1276                 return (B_FALSE);
1277         }
1278 
1279         /* Counting on left->right evaluation and short-circuiting... */
1280         rc = ddi_intr_get_nintrs(devinfo, intr_type, &count);
1281         if (rc != DDI_SUCCESS || count < minimum) {
1282                 i40e_log(i40e, "Get interrupt number failed, "
1283                     "returned %d, count %d\n", rc, count);
1284                 return (B_FALSE);
1285         }
1286 
1287         rc = ddi_intr_get_navail(devinfo, intr_type, &count);
1288         if (rc != DDI_SUCCESS || count < minimum) {
1289                 i40e_log(i40e, "Get AVAILABLE interrupt number failed, "
1290                     "returned %d, count %d\n", rc, count);
1291                 return (B_FALSE);
1292         }
1293 
1294         actual = 0;
1295         i40e->i40e_intr_count = 0;
1296         i40e->i40e_intr_count_max = 0;
1297         i40e->i40e_intr_count_min = 0;
1298 
1299         /* Actually allocate the array of interrupt handles. */
1300         i40e->i40e_intr_size = request * sizeof (ddi_intr_handle_t);
1301         i40e->i40e_intr_handles = kmem_alloc(i40e->i40e_intr_size, KM_SLEEP);
1302         /*
1303          * KM_SLEEP allocation is okay during attach() and during a
1304          * reallocation.
1305          */
1306 
1307         rc = ddi_intr_alloc(devinfo, i40e->i40e_intr_handles, intr_type, 0,
1308             min(request, count), &actual, DDI_INTR_ALLOC_NORMAL);
1309         if (rc != DDI_SUCCESS) {
1310                 i40e_log(i40e, "Interrupt allocation failed with %d.", rc);
1311                 goto alloc_handle_fail;
1312         }
1313 
1314         i40e->i40e_intr_count = actual;
1315         i40e->i40e_intr_count_max = request;
1316         i40e->i40e_intr_count_min = minimum;
1317 
1318         /*
1319          * (re)adjust rss number per group & the rss ring count, depending
1320          * on how interrupt allocation went.
1321          */
1322         if (actual < i40e->i40e_num_trqpairs + 1) {
1323                 /* Remember, we need one for the adminq. */
1324                 i40e->i40e_num_trqpairs = (actual - 1) / 2;
1325                 if (i40e->i40e_num_trqpairs == 1)
1326                         i40e->i40e_classify_mode = I40E_CLASSIFY_NONE;
1327                 else
1328                         i40e->i40e_classify_mode = I40E_CLASSIFY_RSS;
1329         }
1330 
1331         /* Time to map the number of interrupt vectors we have. */
1332         if (actual < minimum) {
1333                 /* XXX KEBE SAYS See cargo-culting comment re: minimum above */
1334                 i40e_log(i40e, "actual (%d) is less than minimum (%d).",
1335                     actual, minimum);
1336                 goto alloc_handle_fail;
1337         }
1338 
1339         /*
1340          * Get & record priority and capabilities for first vector.  Once
1341          * we have it, that's our priority until detach time.  Even if we
1342          * get IRM requests (see i40e_intr_callback()), our priority won't
1343          * change.
1344          */
1345         rc = ddi_intr_get_pri(i40e->i40e_intr_handles[0], &i40e->i40e_intr_pri);
1346         if (rc != DDI_SUCCESS) {
1347                 i40e_log(i40e,
1348                     "Getting interrupt priority failed with %d.", rc);
1349                 goto alloc_handle_fail;
1350         }
1351 
1352         rc = ddi_intr_get_cap(i40e->i40e_intr_handles[0], &i40e->i40e_intr_cap);
1353         if (rc != DDI_SUCCESS) {
1354                 i40e_log(i40e,
1355                     "Getting interrupt capabilities failed with %d.", rc);
1356                 goto alloc_handle_fail;
1357         }
1358         
1359         /* Okay, we made it! */
1360         i40e->i40e_intr_type = intr_type;
1361         return (B_TRUE);
1362 
1363 alloc_handle_fail:
1364 
1365         i40e_rem_intrs(i40e);
1366         return (B_FALSE);
1367 }
1368 
1369 /* Allocate the driver's interrupts. */
1370 static boolean_t
1371 i40e_alloc_intrs(i40e_t *i40e, dev_info_t *devinfo)
1372 {
1373         int intr_types, rc;
1374 
1375         rc = ddi_intr_get_supported_types(devinfo, &intr_types);
1376         if (rc != DDI_SUCCESS) {
1377                 i40e_log(i40e, "Get supported interrupt types failed: %d", rc);
1378                 return (B_FALSE);
1379         }
1380 
1381         i40e->i40e_intr_type = 0;
1382 
1383         /* Try installing MSI-X interrupts first. */
1384         if ((intr_types & DDI_INTR_TYPE_MSIX) &&
1385             (i40e->i40e_intr_force <= I40E_INTR_MSIX)) {
1386                 if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSIX))
1387                         return (B_TRUE);
1388                 i40e_log(i40e, "Failed MSI-X attempt, trying MSI...");
1389         }
1390 
1391         /*
1392          * If I reach here, I failed to allocate MSI-X interrupts.
1393          * Instead, force all rings & groups to 1, and first try MSI.
1394          */
1395         i40e->i40e_num_trqpairs = 1;
1396         i40e->i40e_classify_mode = I40E_CLASSIFY_NONE;
1397 
1398         /* Actually attempt an MSI interrupt allocation. */
1399         if ((intr_types & DDI_INTR_TYPE_MSI) &&
1400             (i40e->i40e_intr_force <= I40E_INTR_MSI)) {
1401                 if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_MSI))
1402                         return (B_TRUE);
1403 
1404                 i40e_log(i40e, "Failed MSI attempt, trying legacy...");
1405         }
1406 
1407         /* And if I reach here, try a legacy interrupt allocation. */
1408         if (intr_types & DDI_INTR_TYPE_FIXED) {
1409                 if (i40e_alloc_intr_handles(i40e, devinfo, DDI_INTR_TYPE_FIXED))
1410                         return (B_TRUE);
1411 
1412                 i40e_log(i40e, "Failed Legacy attempt. Giving up.");
1413         }
1414 
1415         /* If I reach here, none of the interrupt allocations succeeded. */
1416         return (B_FALSE);
1417 }
1418 
1419 /* ARGSUSED */
1420 static int
1421 i40e_intr_callback(dev_info_t *dip, ddi_cb_action_t cbaction, void *cbarg,
1422     void *arg, void *unused)
1423 {
1424         i40e_t *i40e = (i40e_t *)arg;
1425         /* int count = (int)(uintptr_t)cbarg; */
1426 
1427         VERIFY(i40e->i40e_dip == dip); /* XXX KEBE SAYS change to ASSERT(). */
1428 
1429         switch (cbaction) {
1430         case DDI_CB_INTR_ADD:
1431         case DDI_CB_INTR_REMOVE:
1432                 /* Interrupt Resource Management (IRM) requests. */
1433                 /* XXX KEBE SAYS FILL ME IN WITH ADJUSTMENT CODE! */
1434                 /* XXX KEBE SAYS that'll use "count" above. */
1435                 break;
1436         default:
1437                 /* Don't know this cbaction. */
1438                 return (DDI_ENOTSUP);
1439         }
1440 
1441         /* If I make it here, I'm good! */
1442         return (DDI_SUCCESS);
1443 }
1444 
1445 /*
1446  * Free receive & transmit rings.
1447  */
1448 static void
1449 i40e_free_trqpairs_locks(i40e_t *i40e)
1450 {
1451         int i;
1452         i40e_trqpair_t *itrq;
1453 
1454         if (i40e->i40e_trqpairs != NULL) {
1455                 itrq = &i40e->i40e_trqpairs[0];
1456                 for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
1457                         mutex_destroy(&itrq->itrq_rx_lock);
1458                         mutex_destroy(&itrq->itrq_tx_lock);
1459                         /* XXX KEBE SAYS more mutexes and other frees... */
1460                         itrq++;
1461                 }
1462         
1463                 kmem_free(i40e->i40e_trqpairs,
1464                     sizeof (i40e_trqpair_t) * i40e->i40e_num_trqpairs);
1465                 i40e->i40e_trqpairs = NULL;
1466         }
1467 
1468         mutex_destroy(&i40e->i40e_general_lock);
1469         /* mutex_destroy(&i40e->i40e_watchdog_lock); */
1470 }
1471 
1472 /*
1473  * Allocate receive & transmit rings.
1474  */
1475 static boolean_t
1476 i40e_alloc_trqpairs_locks(i40e_t *i40e)
1477 {
1478         int i;
1479         void *mutexpri = DDI_INTR_PRI(i40e->i40e_intr_pri);
1480         i40e_trqpair_t *itrq;
1481 
1482         /*
1483          * Now that we have the priority for the interrupts, initialize
1484          * all relevant locks.
1485          */
1486         mutex_init(&i40e->i40e_general_lock, NULL, MUTEX_DRIVER, mutexpri);
1487         /*
1488          * mutex_init(&i40e->i40e_watchdog_lock, NULL, MUTEX_DRIVER, mutexpri);
1489          */
1490 
1491         /*
1492          * Can call with KM_SLEEP because we're attach()-ing.
1493          * If in some future we can't, call instead with NOSLEEP and return
1494          * B_FALSE after any allocations failures & cleanups.
1495          */
1496         i40e->i40e_trqpairs = kmem_zalloc(
1497             sizeof (i40e_trqpair_t) * i40e->i40e_num_trqpairs, KM_SLEEP);
1498         itrq = &(i40e->i40e_trqpairs[0]);
1499         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
1500                 itrq->itrq_i40e = i40e;
1501                 mutex_init(&itrq->itrq_rx_lock, NULL, MUTEX_DRIVER, mutexpri);
1502                 mutex_init(&itrq->itrq_tx_lock, NULL, MUTEX_DRIVER, mutexpri);
1503                 itrq->itrq_index = i;
1504                 /* XXX KEBE SAYS more mutexes and other allocs... */
1505                 itrq++;
1506         }
1507 
1508         return (B_TRUE);
1509 }
1510 
1511 /*
1512  * ixgbe_map_rxring_to_vector - Map given rx ring to given interrupt vector.
1513  */
1514 static inline void
1515 i40e_map_rx_to_vector(i40e_t *i40e, int qp_idx, int v_idx)
1516 {
1517         /*
1518          * Set bit in map
1519          */
1520         BT_SET(i40e->i40e_vector_map[v_idx].iv_rx_map, qp_idx);
1521 
1522         /*
1523          * Count bits set
1524          */
1525         i40e->i40e_vector_map[v_idx].iv_rx_count++;
1526 
1527         /*
1528          * Remember bit position
1529          */
1530         i40e->i40e_trqpairs[qp_idx].itrq_rx_intrvec = v_idx;
1531         i40e->i40e_trqpairs[qp_idx].itrq_rx_vectorbit = 1 << v_idx;
1532 }
1533 
1534 static inline void
1535 i40e_map_tx_to_vector(i40e_t *i40e, int qp_idx, int v_idx)
1536 {
1537         /*
1538          * Set bit in map
1539          */
1540         BT_SET(i40e->i40e_vector_map[v_idx].iv_tx_map, qp_idx);
1541 
1542         /*
1543          * Count bits set
1544          */
1545         i40e->i40e_vector_map[v_idx].iv_tx_count++;
1546 
1547         /*
1548          * Remember bit position
1549          */
1550         i40e->i40e_trqpairs[qp_idx].itrq_tx_intrvec = v_idx;
1551         i40e->i40e_trqpairs[qp_idx].itrq_tx_vectorbit = 1 << v_idx;
1552 }
1553 
1554 /*
1555  * Map different interrupts to MSI-X vectors.
1556  */
1557 static boolean_t
1558 i40e_map_intrs_to_vectors(i40e_t *i40e)
1559 {
1560         int i, vectornum;
1561 
1562         bzero(&i40e->i40e_vector_map, sizeof (i40e->i40e_vector_map));
1563 
1564         if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
1565                 /*
1566                  * We have adminq, plus rx & tx to concern ourselves with.
1567                  * XXX KEBE SAYS FIGURE THAT OUT.
1568                  */
1569                 i40e_error(i40e, "Can't support MSI or LEGACY yet.");
1570                 return (B_FALSE);       /* For now, bail. */
1571         }
1572 
1573         /*
1574          * We should have an odd number of MSI-X interrupts.  0 is for the
1575          * adminq, and...
1576          *
1577          * XXXX 1-N is for N/2 qpairs, where rx & tx get their own
1578          * interrupts. XXXX
1579          *
1580          * XXX KEBE ASKS (and maybe BRINGUP) - do rx & tx actually get
1581          * their own interrupts?!?  RIght now, they share.
1582          */
1583 
1584         /* The adminq. */
1585         BT_SET(i40e->i40e_vector_map[0].iv_other_map, 0);
1586         i40e->i40e_vector_map[0].iv_other_count++;
1587 
1588         vectornum = 1;
1589         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
1590                 /* Map tx & rx qpairs to the same interrupt vector for now. */
1591                 i40e_map_tx_to_vector(i40e, i, vectornum);
1592                 i40e_map_rx_to_vector(i40e, i, vectornum);
1593                 vectornum = (vectornum + 1) % i40e->i40e_intr_count;
1594                 if (vectornum == 0)
1595                         vectornum++;    /* Skip 0, that's for adminq only. */
1596         }
1597 
1598         return (B_TRUE);
1599 }
1600 
1601 /*
1602  * Add appropriate interrupt handlers based on the interrupt type.
1603  * Caller must have added rx/tx rings and interrupt vectors to "i40e" prior
1604  * to calling here.
1605  *
1606  * Interrupt handlers are in their own file:  i40e_intr.c.
1607  */
1608 static boolean_t
1609 i40e_add_intr_handlers(i40e_t *i40e)
1610 {
1611         int rc, vector;
1612 
1613         switch (i40e->i40e_intr_type) {
1614         case DDI_INTR_TYPE_MSIX:
1615                 for (vector = 0; vector < i40e->i40e_intr_count; vector++) {
1616                         rc = ddi_intr_add_handler(
1617                             i40e->i40e_intr_handles[vector],
1618                             (ddi_intr_handler_t *)i40e_intr_msix, i40e,
1619                             (void *)(uintptr_t)vector);
1620                         if (rc != DDI_SUCCESS) {
1621                                 i40e_log(i40e, "Add interrupt handler (MSI-X) "
1622                                     "failed: return %d, vector %d", rc, vector);
1623                                 for (vector--; vector >= 0; vector--) {
1624                                         (void) ddi_intr_remove_handler(
1625                                             i40e->i40e_intr_handles[vector]);
1626                                 }
1627                                 return (B_FALSE);
1628                         }
1629                 }
1630                 break;
1631         case DDI_INTR_TYPE_MSI:
1632                 rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0],
1633                     (ddi_intr_handler_t *)i40e_intr_msi, i40e, NULL);
1634                 if (rc != DDI_SUCCESS) {
1635                         i40e_log(i40e, "Add interrupt handler (MSI) failed: "
1636                             "return %d", rc);
1637                         return (B_FALSE);
1638                 }
1639                 break;
1640         case DDI_INTR_TYPE_FIXED:
1641                 rc = ddi_intr_add_handler(i40e->i40e_intr_handles[0],
1642                     (ddi_intr_handler_t *)i40e_intr_legacy, i40e, NULL);
1643                 if (rc != DDI_SUCCESS) {
1644                         i40e_log(i40e, "Add interrupt handler (legacy) failed:"
1645                             " return %d", rc);
1646                         return (B_FALSE);
1647                 }
1648                 break;
1649         default:
1650                 i40e_error(i40e,
1651                     "i40e_add_intr_handlers() called where intr_type is %d.",
1652                     i40e->i40e_intr_type);
1653                 return (B_FALSE);
1654         }
1655 
1656         return (B_TRUE);
1657 }
1658 
1659 static boolean_t
1660 i40e_enable_interrupts(i40e_t *i40e)
1661 {
1662         int i, rc;
1663 
1664         if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) {
1665                 /* MSI/MSI-X block-enable */
1666                 rc = ddi_intr_block_enable(i40e->i40e_intr_handles,
1667                     i40e->i40e_intr_count);
1668                 if (rc != DDI_SUCCESS) {
1669                         i40e_error(i40e, "interrupts block-enable failed: %d",
1670                             rc);
1671                         return (B_FALSE);
1672                 }
1673         } else {
1674                 for (i = 0; i < i40e->i40e_intr_count; i++) {
1675                         rc = ddi_intr_enable(i40e->i40e_intr_handles[i]);
1676                         if (rc != DDI_SUCCESS) {
1677                                 i40e_error(i40e,
1678                                     "Enable interrupt %d failed: %d", i, rc);
1679                                 /* Just Disable It (TM) for the earlier ones. */
1680                                 while (--i >= 0) {
1681                                         (void) ddi_intr_disable(
1682                                             i40e->i40e_intr_handles[i]);
1683                                 }
1684                                 return (B_FALSE);
1685                         }
1686                 }
1687         }
1688 
1689         return (B_TRUE);
1690 }
1691 
1692 static boolean_t
1693 i40e_disable_interrupts(i40e_t *i40e)
1694 {
1695         int i, rc;
1696 
1697         if (i40e->i40e_intr_cap & DDI_INTR_FLAG_BLOCK) {
1698                 rc = ddi_intr_block_disable(i40e->i40e_intr_handles,
1699                     i40e->i40e_intr_count);
1700                 if (rc != DDI_SUCCESS) {
1701                         i40e_error(i40e,
1702                             "interrupts block-disabled failed: %d", rc);
1703                         return (B_FALSE);
1704                             
1705                 }
1706         } else {
1707                 for (i = 0; i < i40e->i40e_intr_count; i++) {
1708                         rc = ddi_intr_disable(i40e->i40e_intr_handles[i]);
1709                         if (rc != DDI_SUCCESS) {
1710                                 i40e_error(i40e,
1711                                     "Disable interrupts %d failed: %d", i, rc);
1712                                 return (B_FALSE);
1713                         }
1714                 }
1715         }
1716 
1717         return (B_TRUE);
1718 }
1719 
1720 /*
1721  * Timer functions.
1722  */
1723 static void
1724 i40e_timer(void *arg)
1725 {
1726         i40e_t *i40e = arg;
1727 
1728         mutex_enter(&i40e->i40e_general_lock);
1729         /* XXX KEBE SAYS FILL ME IN XXX */
1730         /*
1731          * A generic link-check function (that can be called elsewhere) is in
1732          * order.
1733          */
1734         mutex_exit(&i40e->i40e_general_lock);
1735 
1736         if ((i40e->i40e_state & I40E_WATCHDOG) == 0)
1737                 return;
1738 
1739         /* Perform watchdog bits while not holding i40e_general_lock. */
1740         /*
1741          * Check state for OVERTEMP or ERROR.  Attempt reset on ERROR.
1742          * If reset succeeds, service-impact with DDI_SERVICE_RESTORED.
1743          */
1744         /* Perform a stall check, degrade if need be. */
1745 }
1746 
1747 /*
1748  * Watchdog timer functions.
1749  */
1750 void
1751 i40e_disable_watchdog_timer(i40e_t *i40e)
1752 {
1753         /*
1754          * NOP for now -> disable a bit in i40e to inform the periodic timer
1755          * NOT to do watchdog things.
1756          */
1757 }
1758 
1759 void
1760 i40e_enable_watchdog_timer(i40e_t *i40e)
1761 {
1762         /*
1763          * NOP for now -> enable a bit in i40e to let the periodic timer
1764          * do watchdog things.
1765          */
1766 }
1767 
1768 /*
1769  * Get the hardware state, and scribble away anything that needs scribbling.
1770  */
1771 static void
1772 i40e_get_hw_state(i40e_t *i40e, i40e_hw_t *hw)
1773 {
1774         int rc;
1775         struct i40e_aq_get_phy_abilities_resp abilities;
1776 
1777         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
1778         
1779         i40e_aq_get_link_info(hw, TRUE, NULL, NULL);
1780         i40e_get_link_status(hw, (bool *)&i40e->i40e_link_state);
1781 
1782         rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE, &abilities,
1783             NULL);
1784         /* Intel or FreeBSD say we may need delay to detect fiber correctly */
1785         if (rc == I40E_ERR_UNKNOWN_PHY) {
1786                 i40e_msec_delay(200);
1787                 rc = i40e_aq_get_phy_capabilities(hw, B_FALSE, B_TRUE,
1788                     &abilities, NULL);
1789         }
1790 
1791         if (rc != I40E_SUCCESS) {
1792                 i40e_error(i40e, "Get physical capabilities failed: %d", rc);
1793                 /* XXX KEBE ASKS FM faulty? */
1794         }
1795 
1796         rc = i40e_update_link_info(hw);
1797         if (rc != I40E_SUCCESS) {
1798                 i40e_error(i40e, "Update link info failed: %d", rc);
1799                 /* XXX KEBE ASKS FM faulty? */
1800         }
1801 
1802         /* Limit phy interrupts to link and modules failure */
1803         rc = i40e_aq_set_phy_int_mask(hw,
1804             I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL);
1805         if (rc != I40E_SUCCESS) {
1806                 /* XXX KEBE ASKS FMA? */
1807                 i40e_error(i40e, "set phy mask failed: %d\n", rc);
1808         }
1809 }
1810 
1811 /*
1812  * Used at re-init time, AND by the GLD addmac/remmac code.
1813  */
1814 boolean_t
1815 i40e_hwadd_mac(i40e_t *i40e, i40e_hw_t *hw, const uint8_t *mac_addr)
1816 {
1817         uint8_t buffer[I40E_AQ_LARGE_BUF];
1818         struct i40e_aqc_add_macvlan_element_data *mvlist =
1819             (struct i40e_aqc_add_macvlan_element_data *)buffer;
1820 
1821         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
1822 
1823         bcopy(mac_addr, mvlist->mac_addr, ETHERADDRL);
1824         mvlist->vlan_tag = 0;        /* No VLAN... we do that some other way... */
1825         mvlist->flags = I40E_AQC_MACVLAN_ADD_PERFECT_MATCH |
1826             I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
1827         /* Be conservative in what you send... */
1828         mvlist->queue_number = 0;
1829         return (i40e_aq_add_macvlan(hw, i40e->i40e_vsi_id, mvlist, 1, NULL) ==
1830             I40E_SUCCESS);
1831 }
1832 
1833 /*
1834  * Initialize or reset the unicast addresses for our (currently just one) VSI.
1835  */
1836 static void
1837 i40e_init_macaddrs(i40e_t *i40e, i40e_hw_t *hw)
1838 {
1839         int i;
1840         i40e_ether_addr_t *i40eth, *lastone;
1841 
1842         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
1843 
1844         if (i40e->i40e_mac_total > 0) {
1845                 /*
1846                  * We are up and running already, and just need to kick things
1847                  * in the pants again.
1848                  */
1849                 /* NOTE:  Skip slot 1 as it's the board's MAC address... */
1850                 for (i = 1; i < i40e->i40e_mac_used; i++) {
1851                         i40eth = &(i40e->i40e_mac_addrs[i]);
1852                         if (!i40e_hwadd_mac(i40e, hw, i40eth->i40eth_mac)) {
1853                                 /*
1854                                  * Oh shoot, we failed on reset.  Warn loudly,
1855                                  * and drop ones we can't initialize.
1856                                  * Do a swap of the last one to this slot,
1857                                  * so we can continue. Or if we're the last
1858                                  * slot, do nothing.
1859                                  *
1860                                  * Either way, the last slot is emptied, and
1861                                  * the number of unicast MACs used drops by 1.
1862                                  */
1863                                 i40e_notice(i40e, "WARNING: <fill me in>");
1864                                 lastone = &(i40e->i40e_mac_addrs[
1865                                     i40e->i40e_mac_used - 1]);
1866                                 if (lastone != i40eth) {
1867                                         /* Do the swap if we have more... */
1868                                         *i40eth = *lastone;
1869                                         lastone->i40eth_used = 0;
1870                                         i--;
1871                                 } else {
1872                                         /*
1873                                          * ... or if we're the last one,
1874                                          * simply mark this as unused.
1875                                          */
1876                                         i40eth->i40eth_used = 0;
1877                                 }
1878                                 i40e->i40e_mac_used--;
1879                         }
1880                 }
1881                 return;
1882         }
1883 
1884         /*
1885          * Actually initialize things.
1886          */
1887         i40e->i40e_mac_total = I40E_MAX_MAC;
1888 
1889         /*
1890          * XXX KEBE WARNS...
1891          *
1892          * If there's a way to query the HW for what's left, we'll need to
1893          * do that dynamically.  For now, just cap at I40E_MAX_UNICAST.
1894          * See its definition for whole-board vs. per-port/PF problems.
1895          */
1896 #if 0
1897         /*
1898          * Put the board's ethernet address in for slot #0.
1899          */
1900         i40e->i40e_mac_used = 1;
1901         i40e->i40e_mac_addrs[0].i40eth_used = 1;
1902         /* I hope this is where the port's/board's/PF's MAC address is... */
1903         bcopy(hw->mac.addr, i40e->i40e_mac_addrs[0].i40eth_mac, ETHERADDRL);
1904 #endif
1905 }
1906 
1907 /*
1908  * Configure the hardware for the Virtual Station Interface (VSI).  Currently
1909  * we only support one, but in the future we could instantiate more than one
1910  * per attach-point.
1911  */
1912 static boolean_t
1913 i40e_config_vsi(i40e_t *i40e, i40e_hw_t *hw)
1914 {
1915         /* Let's hope C99's initializers do the right thing. */
1916         struct i40e_vsi_context context = {0};
1917         int err;
1918 
1919         context.seid = i40e->i40e_vsi_id;
1920         context.pf_num = hw->pf_id;
1921         err = i40e_aq_get_vsi_params(hw, &context, NULL);
1922         if (err != I40E_SUCCESS) {
1923                 i40e_error(i40e, "get VSI params failed with %d\n", err);
1924                 return (B_FALSE);
1925         }
1926 
1927         /*
1928          * Set the queue and traffic class bits.  Keep it simple for now.
1929          */
1930         context.info.valid_sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
1931         context.info.mapping_flags |= I40E_AQ_VSI_QUE_MAP_CONTIG;
1932         context.info.queue_mapping[0] = 0; 
1933         context.info.tc_mapping[0] = 0x0800; 
1934 
1935 #if 0   /* XXX KEBE IS Not sure about this... I thought mac did this. */
1936         /* Set VLAN receive stripping mode */
1937         context.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
1938         context.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL;
1939         if (<some-nemo-thing>)
1940             context.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
1941         else
1942             context.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
1943 #else
1944         /* XXX KEBE SAYS he's more sure about these... */
1945         context.info.valid_sections |= I40E_AQ_VSI_PROP_VLAN_VALID;
1946         context.info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
1947             I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
1948 #endif
1949         context.flags = LE_16(I40E_AQ_VSI_TYPE_PF);
1950         err = i40e_aq_update_vsi_params(hw, &context, NULL);
1951         if (err != I40E_SUCCESS) {
1952                 i40e_error(i40e, "Update VSI params failed with %d", err);
1953                 return (B_FALSE);
1954         }
1955 
1956         /*
1957          * XXX KEBE SAYS Iterate through the trqpairs, setting up pointers
1958          * to DMA memory.  
1959          */
1960         /* XXX KEBE SAYS CHECKPOINT --> GET BACK TO ME */
1961 
1962         return (B_TRUE);
1963 }
1964 
1965 /*
1966  * Wrapper to kick the chipset on.
1967  */
1968 static boolean_t
1969 i40e_chip_start(i40e_t *i40e)
1970 {
1971         i40e_hw_t *hw = &i40e->i40e_hw_space;
1972         /* Let's hope C99-initializing does the right thing. */
1973         struct i40e_filter_control_settings filter = {0};
1974         int i, rc;
1975 
1976         if (((hw->aq.fw_maj_ver == 4) && (hw->aq.fw_min_ver < 33)) ||
1977             (hw->aq.fw_maj_ver < 4)) {
1978                 i40e_msec_delay(75);
1979                 if (i40e_aq_set_link_restart_an(hw, TRUE, NULL) !=
1980                     I40E_SUCCESS) {
1981                         i40e_error(i40e, "link restart failed, aq_err=%d\n",
1982                             hw->aq.asq_last_status);
1983                         /* XXX KEBE ASKS FMA? */
1984                         return (B_FALSE);
1985                 }
1986         }
1987 
1988         /* Determine hardware state */
1989         i40e_get_hw_state(i40e, hw);
1990 
1991         /* Initialize mac addresses. */
1992         i40e_init_macaddrs(i40e, hw);
1993 
1994         /*
1995          * Set up the filter control.
1996          */
1997         filter.enable_ethtype = TRUE;
1998         filter.enable_macvlan = TRUE;
1999 
2000         rc = i40e_set_filter_control(hw, &filter);
2001         if (rc != I40E_SUCCESS) {
2002                 i40e_error(i40e, "i40e_set_filter_control() returned %d", rc);
2003                 return (B_FALSE);
2004         }
2005 
2006 #if 0
2007         /*
2008          * XXX KEBE SAYS for BRINGUP, skip this, but configure the RSS
2009          * parameters.  See FreeBSD's ixl_config_rss().
2010          */
2011         if (!i40e_config_rss(i40e, hw))
2012                 return (B_FALSE);
2013 #endif
2014 
2015         /*
2016          * XXX KEBE SAYS FILL IN vsi information, some of which can be pushed
2017          * down to the trqpairs below, except if/when we become multi-VSI
2018          * aware.  See ixl_initialize_vsi().
2019          */
2020         if (!i40e_config_vsi(i40e, hw))
2021                 return (B_FALSE);
2022 
2023         /* Add the ethernet broadcast address to the HW filter list. */
2024         if (!i40e_hwadd_mac(i40e, hw, i40e_ether_broadcast))
2025                 return (B_FALSE);
2026 
2027         /*
2028          * Each interrupt vector needs to be explicitly enabled.
2029          * NOTE:  Vector 0 is admin-queue/CTL0, rest are CTLN.
2030          */
2031 
2032         /* First, the adminq. */
2033 
2034         wr32(hw, I40E_PFINT_DYN_CTL0,
2035             I40E_PFINT_DYN_CTL0_INTENA_MASK |
2036             I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
2037             (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT));
2038         i40e_flush(hw);
2039         /*
2040          * SO MUCH TO FILL IN!
2041          * - ICR0_ENA disable
2042          * - ICR0 read-to-clear
2043          * - ITR for adminq (set to I40E_ITR_8K)
2044          * - XXX KEBE ASKS more?
2045          */
2046 
2047         /* Then the others. */
2048         /* XXX KEBE ASKS -- use vector number instead?!? */
2049         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2050                 /*
2051                  * SO MUCH TO FILL IN!
2052                  * - ITR state
2053                  * - DYN_CTLN(i)
2054                  * - LNKLSTN(i)
2055                  * - QINT_[TR]QCTL(i)
2056                  * - Various rx/tx bits relating to things we set here.
2057                  */
2058 
2059                 wr32(hw, I40E_PFINT_DYN_CTLN(i),
2060                     I40E_PFINT_DYN_CTLN_INTENA_MASK |
2061                     I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
2062                     (I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT));
2063         }
2064         i40e_flush(hw); /* XXX FreeBSD doesn't do this... */
2065 
2066         return (B_TRUE);
2067 }
2068 
2069 void
2070 i40e_chip_stop(i40e_t *i40e)
2071 {
2072         i40e_hw_t *hw = &i40e->i40e_hw_space;
2073         int i;
2074 
2075         /* XXX KEBE SAYS FILL ME IN XXX */
2076         /*
2077          * Each interrupt vector needs to be explicitly disabled.
2078          * NOTE:  Vector 0 is admin-queue/CTL0, rest are CTLN.
2079          */
2080 
2081         /* First, the adminq. */
2082         wr32(hw, I40E_PFINT_DYN_CTL0,
2083             I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
2084         /* XXX KEBE ASKS -  flush? */
2085 
2086         /* Then the others. */
2087         /* XXX KEBE ASKS -- use vector number instead?!? */
2088         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2089                 wr32(hw, I40E_PFINT_DYN_CTLN(i),
2090                     I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
2091         }
2092         /* XXX KEBE ASKS -  flush? */
2093 }
2094 
2095 /*
2096  * Actually stop the chipset.  This also includes various buffer frees.
2097  */
2098 void
2099 i40e_stop(i40e_t *i40e, boolean_t free_allocations)
2100 {
2101         int i;
2102 
2103         /* XXX KEBE SAYS FILL ME IN! */
2104         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
2105 
2106         /* XXX KEBE SAYS Disable all of the interrupts. */
2107 
2108         /* XXX KEBE SAYS drain any pending tx packets. */
2109 
2110         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2111                 mutex_enter(&i40e->i40e_trqpairs[i].itrq_rx_lock);
2112                 mutex_enter(&i40e->i40e_trqpairs[i].itrq_tx_lock);
2113         }
2114 
2115         i40e_chip_stop(i40e);
2116 
2117         /* XXX KEBE SAYS Clean pending tx resources. */
2118 
2119         for (i = i40e->i40e_num_trqpairs - 1; i >= 0; i--) {
2120                 mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock);
2121                 mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock);
2122         }
2123 
2124         if (i40e->i40e_link_state == LINK_STATE_UP) {
2125                 i40e->i40e_link_state = LINK_STATE_UNKNOWN;
2126                 mac_link_update(i40e->i40e_mac_hdl, i40e->i40e_link_state);
2127         }
2128 
2129         if (free_allocations) {
2130                 i40e_free_dma(i40e);
2131                 i40e_free_rx_data(i40e);
2132         }
2133 }
2134 
2135 /*
2136  * Return -1 on failure, let caller deal with it.
2137  */
2138 static int
2139 i40e_get_vsi_id(i40e_t *i40e)
2140 {
2141         i40e_hw_t *hw = &i40e->i40e_hw_space;
2142         struct i40e_aqc_get_switch_config_resp *sw_config;
2143         uint8_t aq_buf[I40E_AQ_LARGE_BUF];
2144         uint16_t next;  /* Needed for common-code call. */
2145         int rc;
2146 
2147         sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
2148         rc = i40e_aq_get_switch_config(hw, sw_config, sizeof(aq_buf), &next,
2149             NULL);
2150         if (rc != I40E_SUCCESS) {
2151                 i40e_error(i40e, "i40e_aq_get_switch_config() failed %d\n", rc);
2152                 return (-1);
2153         }
2154 
2155         /*
2156          * XXX KEBE SAYS - there may be other elements we need later,
2157          * but for now, we just want the basic seid.
2158          */
2159         return (sw_config->element[0].seid);
2160 }
2161 
2162 /*
2163  * Actually start the chipset.  This also includes various buffer allocations.
2164  */
2165 boolean_t
2166 i40e_start(i40e_t *i40e, boolean_t alloc)
2167 {
2168         boolean_t rc = B_TRUE;
2169         int i;
2170 
2171         /* XXX KEBE SAYS FILL ME IN! */
2172         ASSERT(MUTEX_HELD(&i40e->i40e_general_lock));
2173 
2174         if (alloc) {
2175                 if (!i40e_alloc_rx_data(i40e)) {
2176                         i40e_error(i40e,
2177                             "Failed to allocate receive-ring data");
2178                         return (B_FALSE);
2179                 }
2180                 if (!i40e_alloc_dma(i40e)) {
2181                         i40e_error(i40e, "Failed to allocate DMA data");
2182                         return (B_FALSE);
2183                 }
2184         }
2185 
2186         /* Big batch of mutex enters to block things... */
2187         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
2188                 mutex_enter(&i40e->i40e_trqpairs[i].itrq_rx_lock);
2189                 mutex_enter(&i40e->i40e_trqpairs[i].itrq_tx_lock);
2190         }
2191 
2192 
2193         /*
2194          * XXX KEBE SAYS ixgbe calls chip_start() here. Did we do that
2195          * already?
2196          */
2197         if (!i40e_chip_start(i40e)) {
2198                 i40e_fm_ereport(i40e, DDI_FM_DEVICE_INVAL_STATE);
2199                 rc = B_FALSE;
2200                 goto done;
2201         }
2202 
2203         if (i40e_check_acc_handle(i40e->i40e_osdep_space.reg_handle) !=
2204             DDI_FM_OK) {
2205                 rc = B_FALSE;
2206                 goto done;
2207         }
2208 
2209         /* XXX KEBE SAYS set up the rx/tx rings (including rx/tx buffers?) */
2210 
2211         /* Clear state bits prior to final interrupt enabling. */
2212         atomic_and_32(&i40e->i40e_state,
2213             ~(I40E_ERROR | I40E_STALL | I40E_OVERTEMP));
2214 
2215         /* XXX KEBE SAYS enable the interrupts here (really?)! */
2216 
2217 done:
2218         for (i = i40e->i40e_num_trqpairs - 1; i >= 0; i--) {
2219                 mutex_exit(&i40e->i40e_trqpairs[i].itrq_tx_lock);
2220                 mutex_exit(&i40e->i40e_trqpairs[i].itrq_rx_lock);
2221         }
2222         if (!rc)
2223                 ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_LOST);
2224 
2225         return (rc);
2226 }
2227 
2228 /*
2229  * Module Initialization Functions.
2230  */
2231 int
2232 _init(void)
2233 {
2234         int status;
2235 
2236         mac_init_ops(&i40e_dev_ops, MODULE_NAME);
2237 
2238         status = mod_install(&i40e_modlinkage);
2239 
2240         if (status != DDI_SUCCESS) {
2241                 mac_fini_ops(&i40e_dev_ops);
2242         }
2243 
2244         return (status);
2245 }
2246 
2247 int
2248 _fini(void)
2249 {
2250         int status;
2251 
2252         status = mod_remove(&i40e_modlinkage);
2253 
2254         if (status == DDI_SUCCESS) {
2255                 mac_fini_ops(&i40e_dev_ops);
2256         }
2257 
2258         return (status);
2259 }
2260 
2261 int
2262 _info(struct modinfo *modinfop)
2263 {
2264         int status;
2265 
2266         status = mod_info(&i40e_modlinkage, modinfop);
2267 
2268         return (status);
2269 }