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 (c) 2017, Joyent, Inc.
  14  * Copyright 2017 Tegile Systems, Inc.  All rights reserved.
  15  */
  16 
  17 /*
  18  * -------------------------
  19  * Interrupt Handling Theory
  20  * -------------------------
  21  *
  22  * There are a couple different sets of interrupts that we need to worry about:
  23  *
  24  *   - Interrupts from receive queues
  25  *   - Interrupts from transmit queues
  26  *   - 'Other Interrupts', such as the administrative queue
  27  *
  28  * 'Other Interrupts' are asynchronous events such as a link status change event
  29  * being posted to the administrative queue, unrecoverable ECC errors, and more.
  30  * If we have something being posted to the administrative queue, then we go
  31  * through and process it, because it's generally enabled as a separate logical
  32  * interrupt. Note, we may need to do more here eventually. To re-enable the
  33  * interrupts from the 'Other Interrupts' section, we need to clear the PBA and
  34  * write ENA to PFINT_ICR0.
  35  *
  36  * Interrupts from the transmit and receive queues indicates that our requests
  37  * have been processed. In the rx case, it means that we have data that we
  38  * should take a look at and send up the stack. In the tx case, it means that
  39  * data which we got from MAC has now been sent out on the wire and we can free
  40  * the associated data. Most of the logic for acting upon the presence of this
  41  * data can be found in i40e_transciever.c which handles all of the DMA, rx, and
  42  * tx operations. This file is dedicated to handling and dealing with interrupt
  43  * processing.
  44  *
  45  * All devices supported by this driver support three kinds of interrupts:
  46  *
  47  *   o Extended Message Signaled Interrupts (MSI-X)
  48  *   o Message Signaled Interrupts (MSI)
  49  *   o Legacy PCI interrupts (INTx)
  50  *
  51  * Generally speaking the hardware logically handles MSI and INTx the same and
  52  * restricts us to only using a single interrupt, which isn't the interesting
  53  * case. With MSI-X available, each physical function of the device provides the
  54  * opportunity for multiple interrupts which is what we'll focus on.
  55  *
  56  * --------------------
  57  * Interrupt Management
  58  * --------------------
  59  *
  60  * By default, the admin queue, which consists of the asynchronous other
  61  * interrupts is always bound to MSI-X vector zero. Next, we spread out all of
  62  * the other interrupts that we have available to us over the remaining
  63  * interrupt vectors.
  64  *
  65  * This means that there may be multiple queues, both tx and rx, which are
  66  * mapped to the same interrupt. When the interrupt fires, we'll have to check
  67  * all of them for servicing, before we go through and indicate that the
  68  * interrupt is claimed.
  69  *
  70  * The hardware provides the means of mapping various queues to MSI-X interrupts
  71  * by programming the I40E_QINT_RQCTL() and I4OE_QINT_TQCTL() registers. These
  72  * registers can also be used to enable and disable whether or not the queue is
  73  * a source of interrupts. As part of this, the hardware requires that we
  74  * maintain a linked list of queues for each interrupt vector. While it may seem
  75  * like this is only there for the purproses of ITRs, that's not the case. The
  76  * first queue must be programmed in I40E_QINT_LNKLSTN(%vector) register. Each
  77  * queue defines the next one in either the I40E_QINT_RQCTL or I40E_QINT_TQCTL
  78  * register.
  79  *
  80  * Finally, the individual interrupt vector itself has the ability to be enabled
  81  * and disabled. The overall interrupt is controlled through the
  82  * I40E_PFINT_DYN_CTLN() register. This is used to turn on and off the interrupt
  83  * as a whole.
  84  *
  85  * Note that this means that both the individual queue and the interrupt as a
  86  * whole can be toggled and re-enabled.
  87  *
  88  * -------------------
  89  * Non-MSIX Management
  90  * -------------------
  91  *
  92  * We may have a case where the Operating System is unable to actually allocate
  93  * any MSI-X to the system. In such a world, there is only one transmit/receive
  94  * queue pair and it is bound to the same interrupt with index zero. The
  95  * hardware doesn't allow us access to additional interrupt vectors in these
  96  * modes. Note that technically we could support more transmit/receive queues if
  97  * we wanted.
  98  *
  99  * In this world, because the interrupts for the admin queue and traffic are
 100  * mixed together, we have to consult ICR0 to determine what has occurred. The
 101  * QINT_TQCTL and QINT_RQCTL registers have a field, 'MSI-X 0 index' which
 102  * allows us to set a specific bit in ICR0. There are up to seven such bits;
 103  * however, we only use the bit 0 and 1 for the rx and tx queue respectively.
 104  * These are contained by the I40E_INTR_NOTX_{R|T}X_QUEUE and
 105  * I40E_INTR_NOTX_{R|T}X_MASK registers respectively.
 106  *
 107  * Unfortunately, these corresponding queue bits have no corresponding entry in
 108  * the ICR0_ENA register. So instead, when enabling interrupts on the queues, we
 109  * end up enabling it on the queue registers rather than on the MSI-X registers.
 110  * In the MSI-X world, because they can be enabled and disabled, this is
 111  * different and the queues can always be enabled and disabled, but the
 112  * interrupts themselves are toggled (ignoring the question of interrupt
 113  * blanking for polling on rings).
 114  *
 115  * Finally, we still have to set up the interrupt linked list, but the list is
 116  * instead rooted at the register I40E_PFINT_LNKLST0, rather than being tied to
 117  * one of the other MSI-X registers.
 118  *
 119  * --------------------
 120  * Interrupt Moderation
 121  * --------------------
 122  *
 123  * The XL710 hardware has three different interrupt moderation registers per
 124  * interrupt. Unsurprisingly, we use these for:
 125  *
 126  *   o RX interrupts
 127  *   o TX interrupts
 128  *   o 'Other interrupts' (link status change, admin queue, etc.)
 129  *
 130  * By default, we throttle 'other interrupts' the most, then TX interrupts, and
 131  * then RX interrupts. The default values for these were based on trying to
 132  * reason about both the importance and frequency of events. Generally speaking
 133  * 'other interrupts' are not very frequent and they're not important for the
 134  * I/O data path in and of itself (though they may indicate issues with the I/O
 135  * data path).
 136  *
 137  * On the flip side, when we're not polling, RX interrupts are very important.
 138  * The longer we wait for them, the more latency that we inject into the system.
 139  * However, if we allow interrupts to occur too frequently, we risk a few
 140  * problems:
 141  *
 142  *  1) Abusing system resources. Without proper interrupt blanking and polling,
 143  *     we can see upwards of 200k-300k interrupts per second on the system.
 144  *
 145  *  2) Not enough data coalescing to enable polling. In other words, the more
 146  *     data that we allow to build up, the more likely we'll be able to enable
 147  *     polling mode and allowing us to better handle bulk data.
 148  *
 149  * In-between the 'other interrupts' and the TX interrupts we have the
 150  * reclamation of TX buffers. This operation is not quite as important as we
 151  * generally size the ring large enough that we should be able to reclaim a
 152  * substantial amount of the descriptors that we have used per interrupt. So
 153  * while it's important that this interrupt occur, we don't necessarily need it
 154  * firing as frequently as RX; it doesn't, on its own, induce additional latency
 155  * into the system.
 156  *
 157  * Based on all this we currently assign static ITR values for the system. While
 158  * we could move to a dynamic system (the hardware supports that), we'd want to
 159  * make sure that we're seeing problems from this that we believe would be
 160  * generally helped by the added complexity.
 161  *
 162  * Based on this, the default values that we have allow for the following
 163  * interrupt thresholds:
 164  *
 165  *    o 20k interrupts/s for RX
 166  *    o 5k interrupts/s for TX
 167  *    o 2k interupts/s for 'Other Interrupts'
 168  */
 169 
 170 #include "i40e_sw.h"
 171 
 172 #define I40E_INTR_NOTX_QUEUE    0
 173 #define I40E_INTR_NOTX_INTR     0
 174 #define I40E_INTR_NOTX_RX_QUEUE 0
 175 #define I40E_INTR_NOTX_RX_MASK  (1 << I40E_PFINT_ICR0_QUEUE_0_SHIFT)
 176 #define I40E_INTR_NOTX_TX_QUEUE 1
 177 #define I40E_INTR_NOTX_TX_MASK  (1 << I40E_PFINT_ICR0_QUEUE_1_SHIFT)
 178 
 179 void
 180 i40e_intr_set_itr(i40e_t *i40e, i40e_itr_index_t itr, uint_t val)
 181 {
 182         int i;
 183         i40e_hw_t *hw = &i40e->i40e_hw_space;
 184 
 185         VERIFY3U(val, <=, I40E_MAX_ITR);
 186         VERIFY3U(itr, <, I40E_ITR_INDEX_NONE);
 187 
 188         /*
 189          * No matter the interrupt mode, the ITR for other interrupts is always
 190          * on interrupt zero and the same is true if we're not using MSI-X.
 191          */
 192         if (itr == I40E_ITR_INDEX_OTHER ||
 193             i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
 194                 I40E_WRITE_REG(hw, I40E_PFINT_ITR0(itr), val);
 195                 return;
 196         }
 197 
 198         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
 199                 I40E_WRITE_REG(hw, I40E_PFINT_ITRN(itr, i), val);
 200         }
 201 }
 202 
 203 /*
 204  * Re-enable the adminq. Note that the adminq doesn't have a traditional queue
 205  * associated with it from an interrupt perspective and just lives on ICR0.
 206  * However when MSI-X interrupts are not being used, then this also enables and
 207  * disables those interrupts.
 208  */
 209 static void
 210 i40e_intr_adminq_enable(i40e_t *i40e)
 211 {
 212         i40e_hw_t *hw = &i40e->i40e_hw_space;
 213         uint32_t reg;
 214 
 215         reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
 216             I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
 217             (I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
 218         I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, reg);
 219         i40e_flush(hw);
 220 }
 221 
 222 static void
 223 i40e_intr_adminq_disable(i40e_t *i40e)
 224 {
 225         i40e_hw_t *hw = &i40e->i40e_hw_space;
 226         uint32_t reg;
 227 
 228         reg = I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
 229         I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, reg);
 230 }
 231 
 232 static void
 233 i40e_intr_io_enable(i40e_t *i40e, int vector)
 234 {
 235         uint32_t reg;
 236         i40e_hw_t *hw = &i40e->i40e_hw_space;
 237 
 238         reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
 239             I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
 240             (I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
 241         I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vector - 1), reg);
 242 }
 243 
 244 static void
 245 i40e_intr_io_disable(i40e_t *i40e, int vector)
 246 {
 247         uint32_t reg;
 248         i40e_hw_t *hw = &i40e->i40e_hw_space;
 249 
 250         reg = I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
 251         I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vector - 1), reg);
 252 }
 253 
 254 /*
 255  * When MSI-X interrupts are being used, then we can enable the actual
 256  * interrupts themselves. However, when they are not, we instead have to turn
 257  * towards the queue's CAUSE_ENA bit and enable that.
 258  */
 259 void
 260 i40e_intr_io_enable_all(i40e_t *i40e)
 261 {
 262         if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
 263                 int i;
 264 
 265                 for (i = 1; i < i40e->i40e_intr_count; i++) {
 266                         i40e_intr_io_enable(i40e, i);
 267                 }
 268         } else {
 269                 uint32_t reg;
 270                 i40e_hw_t *hw = &i40e->i40e_hw_space;
 271 
 272                 reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE));
 273                 reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
 274                 I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
 275 
 276                 reg = I40E_READ_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE));
 277                 reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
 278                 I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
 279         }
 280 }
 281 
 282 /*
 283  * When MSI-X interrupts are being used, then we can disable the actual
 284  * interrupts themselves. However, when they are not, we instead have to turn
 285  * towards the queue's CAUSE_ENA bit and disable that.
 286  */
 287 void
 288 i40e_intr_io_disable_all(i40e_t *i40e)
 289 {
 290         if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
 291                 int i;
 292 
 293                 for (i = 1; i < i40e->i40e_intr_count; i++) {
 294                         i40e_intr_io_disable(i40e, i);
 295                 }
 296         } else {
 297                 uint32_t reg;
 298                 i40e_hw_t *hw = &i40e->i40e_hw_space;
 299 
 300                 reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE));
 301                 reg &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
 302                 I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
 303 
 304                 reg = I40E_READ_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE));
 305                 reg &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK;
 306                 I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
 307         }
 308 }
 309 
 310 /*
 311  * As part of disabling the tx and rx queue's we're technically supposed to
 312  * remove the linked list entries. The simplest way is to clear the LNKLSTN
 313  * register by setting it to I40E_QUEUE_TYPE_EOL (0x7FF).
 314  *
 315  * Note all of the FM register access checks are performed by the caller.
 316  */
 317 void
 318 i40e_intr_io_clear_cause(i40e_t *i40e)
 319 {
 320         int i;
 321         i40e_hw_t *hw = &i40e->i40e_hw_space;
 322 
 323         if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
 324                 uint32_t reg;
 325                 reg = I40E_QUEUE_TYPE_EOL;
 326                 I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, reg);
 327                 return;
 328         }
 329 
 330         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
 331                 uint32_t reg;
 332 #ifdef DEBUG
 333                 /*
 334                  * Verify that the interrupt in question is disabled. This is a
 335                  * prerequisite of modifying the data in question.
 336                  */
 337                 reg = I40E_READ_REG(hw, I40E_PFINT_DYN_CTLN(i));
 338                 VERIFY0(reg & I40E_PFINT_DYN_CTLN_INTENA_MASK);
 339 #endif
 340                 reg = I40E_QUEUE_TYPE_EOL;
 341                 I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(i), reg);
 342         }
 343 
 344         i40e_flush(hw);
 345 }
 346 
 347 /*
 348  * Finalize interrupt handling. Mostly this disables the admin queue.
 349  */
 350 void
 351 i40e_intr_chip_fini(i40e_t *i40e)
 352 {
 353 #ifdef DEBUG
 354         int i;
 355         uint32_t reg;
 356 
 357         i40e_hw_t *hw = &i40e->i40e_hw_space;
 358 
 359         /*
 360          * Take a look and verify that all other interrupts have been disabled
 361          * and the interrupt linked lists have been zeroed.
 362          */
 363         if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
 364                 for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
 365                         reg = I40E_READ_REG(hw, I40E_PFINT_DYN_CTLN(i));
 366                         VERIFY0(reg & I40E_PFINT_DYN_CTLN_INTENA_MASK);
 367 
 368                         reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i));
 369                         VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL);
 370                 }
 371         }
 372 #endif
 373 
 374         i40e_intr_adminq_disable(i40e);
 375 }
 376 
 377 /*
 378  * Enable all of the queues and set the corresponding LNKLSTN registers. Note
 379  * that we always enable queues as interrupt sources, even though we don't
 380  * enable the MSI-X interrupt vectors.
 381  */
 382 static void
 383 i40e_intr_init_queue_msix(i40e_t *i40e)
 384 {
 385         i40e_hw_t *hw = &i40e->i40e_hw_space;
 386         uint32_t reg;
 387         int i;
 388 
 389         /*
 390          * Map queues to MSI-X interrupts. Queue i is mapped to vector i + 1.
 391          * Note that we skip the ITR logic for the moment, just to make our
 392          * lives as explicit and simple as possible.
 393          */
 394         for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
 395                 i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
 396 
 397                 reg = (i << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
 398                     (I40E_QUEUE_TYPE_RX <<
 399                     I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
 400                 I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(i), reg);
 401 
 402                 reg =
 403                     (itrq->itrq_rx_intrvec << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
 404                     (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
 405                     (i << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
 406                     (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
 407                     I40E_QINT_RQCTL_CAUSE_ENA_MASK;
 408 
 409                 I40E_WRITE_REG(hw, I40E_QINT_RQCTL(i), reg);
 410 
 411                 reg =
 412                     (itrq->itrq_tx_intrvec << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
 413                     (I40E_ITR_INDEX_TX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
 414                     (I40E_QUEUE_TYPE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
 415                     (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) |
 416                     I40E_QINT_TQCTL_CAUSE_ENA_MASK;
 417 
 418                 I40E_WRITE_REG(hw, I40E_QINT_TQCTL(i), reg);
 419         }
 420 
 421 }
 422 
 423 /*
 424  * Set up a single queue to share the admin queue interrupt in the non-MSI-X
 425  * world. Note we do not enable the queue as an interrupt cause at this time. We
 426  * don't have any other vector of control here, unlike with the MSI-X interrupt
 427  * case.
 428  */
 429 static void
 430 i40e_intr_init_queue_shared(i40e_t *i40e)
 431 {
 432         i40e_hw_t *hw = &i40e->i40e_hw_space;
 433         uint32_t reg;
 434 
 435         VERIFY(i40e->i40e_intr_type == DDI_INTR_TYPE_FIXED ||
 436             i40e->i40e_intr_type == DDI_INTR_TYPE_MSI);
 437 
 438         reg = (I40E_INTR_NOTX_QUEUE << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
 439             (I40E_QUEUE_TYPE_RX << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
 440         I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, reg);
 441 
 442         reg = (I40E_INTR_NOTX_INTR << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
 443             (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
 444             (I40E_INTR_NOTX_RX_QUEUE << I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) |
 445             (I40E_INTR_NOTX_QUEUE << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
 446             (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
 447 
 448         I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
 449 
 450         reg = (I40E_INTR_NOTX_INTR << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
 451             (I40E_ITR_INDEX_TX << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
 452             (I40E_INTR_NOTX_TX_QUEUE << I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) |
 453             (I40E_QUEUE_TYPE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
 454             (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
 455 
 456         I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
 457 }
 458 
 459 /*
 460  * Enable the specified queue as a valid source of interrupts. Note, this should
 461  * only be used as part of the GLDv3's interrupt blanking routines. The debug
 462  * build assertions are specific to that.
 463  */
 464 void
 465 i40e_intr_rx_queue_enable(i40e_trqpair_t *itrq)
 466 {
 467         uint32_t reg;
 468         uint_t queue = itrq->itrq_index;
 469         i40e_hw_t *hw = &itrq->itrq_i40e->i40e_hw_space;
 470 
 471         ASSERT(MUTEX_HELD(&itrq->itrq_rx_lock));
 472         ASSERT(queue < itrq->itrq_i40e->i40e_num_trqpairs);
 473 
 474         reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(queue));
 475         ASSERT0(reg & I40E_QINT_RQCTL_CAUSE_ENA_MASK);
 476         reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
 477         I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg);
 478 }
 479 
 480 /*
 481  * Disable the specified queue as a valid source of interrupts. Note, this
 482  * should only be used as part of the GLDv3's interrupt blanking routines. The
 483  * debug build assertions are specific to that.
 484  */
 485 void
 486 i40e_intr_rx_queue_disable(i40e_trqpair_t *itrq)
 487 {
 488         uint32_t reg;
 489         uint_t queue = itrq->itrq_index;
 490         i40e_hw_t *hw = &itrq->itrq_i40e->i40e_hw_space;
 491 
 492         ASSERT(MUTEX_HELD(&itrq->itrq_rx_lock));
 493         ASSERT(queue < itrq->itrq_i40e->i40e_num_trqpairs);
 494 
 495         reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(queue));
 496         ASSERT3U(reg & I40E_QINT_RQCTL_CAUSE_ENA_MASK, ==,
 497             I40E_QINT_RQCTL_CAUSE_ENA_MASK);
 498         reg &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
 499         I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg);
 500 }
 501 
 502 /*
 503  * Start up the various chip's interrupt handling. We not only configure the
 504  * adminq here, but we also go through and configure all of the actual queues,
 505  * the interrupt linked lists, and others.
 506  */
 507 void
 508 i40e_intr_chip_init(i40e_t *i40e)
 509 {
 510         i40e_hw_t *hw = &i40e->i40e_hw_space;
 511         uint32_t reg;
 512 
 513         /*
 514          * Ensure that all non adminq interrupts are disabled at the chip level.
 515          */
 516         i40e_intr_io_disable_all(i40e);
 517 
 518         I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, 0);
 519         (void) I40E_READ_REG(hw, I40E_PFINT_ICR0);
 520 
 521         /*
 522          * Always enable all of the other-class interrupts to be on their own
 523          * ITR. This only needs to be set on interrupt zero, which has its own
 524          * special setting.
 525          */
 526         reg = I40E_ITR_INDEX_OTHER << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT;
 527         I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0, reg);
 528 
 529         /*
 530          * Enable interrupt types we expect to receive. At the moment, this
 531          * is limited to the adminq; however, we'll want to review 11.2.2.9.22
 532          * for more types here as we add support for detecting them, handling
 533          * them, and resetting the device as appropriate.
 534          */
 535         reg = I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
 536         I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, reg);
 537 
 538         /*
 539          * Always set the interrupt linked list to empty. We'll come back and
 540          * change this if MSI-X are actually on the scene.
 541          */
 542         I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_TYPE_EOL);
 543 
 544         i40e_intr_adminq_enable(i40e);
 545 
 546         /*
 547          * Set up all of the queues and map them to interrupts based on the bit
 548          * assignments.
 549          */
 550         if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
 551                 i40e_intr_init_queue_msix(i40e);
 552         } else {
 553                 i40e_intr_init_queue_shared(i40e);
 554         }
 555 
 556         /*
 557          * Finally set all of the default ITRs for the interrupts. Note that the
 558          * queues will have been set up above.
 559          */
 560         i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr);
 561         i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr);
 562         i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER, i40e->i40e_other_itr);
 563 }
 564 
 565 static void
 566 i40e_intr_adminq_work(i40e_t *i40e)
 567 {
 568         struct i40e_hw *hw = &i40e->i40e_hw_space;
 569         struct i40e_arq_event_info evt;
 570         uint16_t remain = 1;
 571 
 572         bzero(&evt, sizeof (struct i40e_arq_event_info));
 573         evt.buf_len = I40E_ADMINQ_BUFSZ;
 574         evt.msg_buf = i40e->i40e_aqbuf;
 575 
 576         while (remain != 0) {
 577                 enum i40e_status_code ret;
 578                 uint16_t opcode;
 579 
 580                 /*
 581                  * At the moment, the only error code that seems to be returned
 582                  * is one saying that there's no work. In such a case we leave
 583                  * this be.
 584                  */
 585                 ret = i40e_clean_arq_element(hw, &evt, &remain);
 586                 if (ret != I40E_SUCCESS)
 587                         break;
 588 
 589                 opcode = LE_16(evt.desc.opcode);
 590                 switch (opcode) {
 591                 case i40e_aqc_opc_get_link_status:
 592                         mutex_enter(&i40e->i40e_general_lock);
 593                         i40e_link_check(i40e);
 594                         mutex_exit(&i40e->i40e_general_lock);
 595                         break;
 596                 default:
 597                         /*
 598                          * Longer term we'll want to enable other causes here
 599                          * and get these cleaned up and doing something.
 600                          */
 601                         break;
 602                 }
 603         }
 604 }
 605 
 606 static void
 607 i40e_intr_rx_work(i40e_t *i40e, int queue)
 608 {
 609         mblk_t *mp = NULL;
 610         i40e_trqpair_t *itrq;
 611 
 612         ASSERT(queue < i40e->i40e_num_trqpairs);
 613         itrq = &i40e->i40e_trqpairs[queue];
 614 
 615         mutex_enter(&itrq->itrq_rx_lock);
 616         if (!itrq->itrq_intr_poll)
 617                 mp = i40e_ring_rx(itrq, I40E_POLL_NULL);
 618         mutex_exit(&itrq->itrq_rx_lock);
 619 
 620         if (mp != NULL) {
 621                 mac_rx_ring(i40e->i40e_mac_hdl, itrq->itrq_macrxring, mp,
 622                     itrq->itrq_rxgen);
 623         }
 624 }
 625 
 626 static void
 627 i40e_intr_tx_work(i40e_t *i40e, int queue)
 628 {
 629         i40e_trqpair_t *itrq;
 630 
 631         itrq = &i40e->i40e_trqpairs[queue];
 632         i40e_tx_recycle_ring(itrq);
 633 }
 634 
 635 /*
 636  * At the moment, the only 'other' interrupt on ICR0 that we handle is the
 637  * adminq. We should go through and support the other notifications at some
 638  * point.
 639  */
 640 static void
 641 i40e_intr_other_work(i40e_t *i40e)
 642 {
 643         struct i40e_hw *hw = &i40e->i40e_hw_space;
 644         uint32_t reg;
 645 
 646         reg = I40E_READ_REG(hw, I40E_PFINT_ICR0);
 647         if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) !=
 648             DDI_FM_OK) {
 649                 ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_DEGRADED);
 650                 atomic_or_32(&i40e->i40e_state, I40E_ERROR);
 651                 return;
 652         }
 653 
 654         if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
 655                 i40e_intr_adminq_work(i40e);
 656 
 657         /*
 658          * Make sure that the adminq interrupt is not masked and then explicitly
 659          * enable the adminq and thus the other interrupt.
 660          */
 661         reg = I40E_READ_REG(hw, I40E_PFINT_ICR0_ENA);
 662         reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
 663         I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, reg);
 664 
 665         i40e_intr_adminq_enable(i40e);
 666 }
 667 
 668 uint_t
 669 i40e_intr_msix(void *arg1, void *arg2)
 670 {
 671         i40e_t *i40e = (i40e_t *)arg1;
 672         int vector_idx = (int)(uintptr_t)arg2;
 673 
 674         /*
 675          * When using MSI-X interrupts, vector 0 is always reserved for the
 676          * adminq at this time. Though longer term, we'll want to also bridge
 677          * some I/O to them.
 678          */
 679         if (vector_idx == 0) {
 680                 i40e_intr_other_work(i40e);
 681                 return (DDI_INTR_CLAIMED);
 682         }
 683 
 684         i40e_intr_rx_work(i40e, vector_idx - 1);
 685         i40e_intr_tx_work(i40e, vector_idx - 1);
 686         i40e_intr_io_enable(i40e, vector_idx);
 687 
 688         return (DDI_INTR_CLAIMED);
 689 }
 690 
 691 static uint_t
 692 i40e_intr_notx(i40e_t *i40e, boolean_t shared)
 693 {
 694         i40e_hw_t *hw = &i40e->i40e_hw_space;
 695         uint32_t reg;
 696         int ret = DDI_INTR_CLAIMED;
 697 
 698         if (shared == B_TRUE) {
 699                 mutex_enter(&i40e->i40e_general_lock);
 700                 if (i40e->i40e_state & I40E_SUSPENDED) {
 701                         mutex_exit(&i40e->i40e_general_lock);
 702                         return (DDI_INTR_UNCLAIMED);
 703                 }
 704                 mutex_exit(&i40e->i40e_general_lock);
 705         }
 706 
 707         reg = I40E_READ_REG(hw, I40E_PFINT_ICR0);
 708         if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) !=
 709             DDI_FM_OK) {
 710                 ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_DEGRADED);
 711                 atomic_or_32(&i40e->i40e_state, I40E_ERROR);
 712                 return (DDI_INTR_CLAIMED);
 713         }
 714 
 715         if (reg == 0) {
 716                 if (shared == B_TRUE)
 717                         ret = DDI_INTR_UNCLAIMED;
 718                 goto done;
 719         }
 720 
 721         if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
 722                 i40e_intr_adminq_work(i40e);
 723 
 724         if (reg & I40E_INTR_NOTX_RX_MASK)
 725                 i40e_intr_rx_work(i40e, 0);
 726 
 727         if (reg & I40E_INTR_NOTX_TX_MASK)
 728                 i40e_intr_tx_work(i40e, 0);
 729 
 730 done:
 731         i40e_intr_adminq_enable(i40e);
 732         return (ret);
 733 
 734 }
 735 
 736 /* ARGSUSED */
 737 uint_t
 738 i40e_intr_msi(void *arg1, void *arg2)
 739 {
 740         i40e_t *i40e = (i40e_t *)arg1;
 741 
 742         return (i40e_intr_notx(i40e, B_FALSE));
 743 }
 744 
 745 /* ARGSUSED */
 746 uint_t
 747 i40e_intr_legacy(void *arg1, void *arg2)
 748 {
 749         i40e_t *i40e = (i40e_t *)arg1;
 750 
 751         return (i40e_intr_notx(i40e, B_TRUE));
 752 }