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
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.
13 * Copyright (c) 2017, Joyent, Inc.
14 * Copyright 2017 Tegile Systems, Inc. All rights reserved.
18 * -------------------------
19 * Interrupt Handling Theory
20 * -------------------------
22 * There are a couple different sets of interrupts that we need to worry about:
24 * - Interrupts from receive queues
25 * - Interrupts from transmit queues
26 * - 'Other Interrupts', such as the administrative queue
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.
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
45 * All devices supported by this driver support three kinds of interrupts:
47 * o Extended Message Signaled Interrupts (MSI-X)
48 * o Message Signaled Interrupts (MSI)
49 * o Legacy PCI interrupts (INTx)
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.
56 * --------------------
57 * Interrupt Management
58 * --------------------
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
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.
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
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
85 * Note that this means that both the individual queue and the interrupt as a
86 * whole can be toggled and re-enabled.
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
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.
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).
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.
119 * --------------------
120 * Interrupt Moderation
121 * --------------------
123 * The XL710 hardware has three different interrupt moderation registers per
124 * interrupt. Unsurprisingly, we use these for:
128 * o 'Other interrupts' (link status change, admin queue, etc.)
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
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
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.
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.
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
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.
162 * Based on this, the default values that we have allow for the following
163 * interrupt thresholds:
165 * o 20k interrupts/s for RX
166 * o 5k interrupts/s for TX
167 * o 2k interupts/s for 'Other Interrupts'
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)
180 i40e_intr_set_itr(i40e_t
*i40e
, i40e_itr_index_t itr
, uint_t val
)
183 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
185 VERIFY3U(val
, <=, I40E_MAX_ITR
);
186 VERIFY3U(itr
, <, I40E_ITR_INDEX_NONE
);
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.
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
);
198 for (i
= 0; i
< i40e
->i40e_num_trqpairs
; i
++) {
199 I40E_WRITE_REG(hw
, I40E_PFINT_ITRN(itr
, i
), val
);
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.
210 i40e_intr_adminq_enable(i40e_t
*i40e
)
212 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
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
);
223 i40e_intr_adminq_disable(i40e_t
*i40e
)
225 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
228 reg
= I40E_ITR_INDEX_NONE
<< I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT
;
229 I40E_WRITE_REG(hw
, I40E_PFINT_DYN_CTL0
, reg
);
233 i40e_intr_io_enable(i40e_t
*i40e
, int vector
)
236 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
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
);
245 i40e_intr_io_disable(i40e_t
*i40e
, int vector
)
248 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
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
);
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.
260 i40e_intr_io_enable_all(i40e_t
*i40e
)
262 if (i40e
->i40e_intr_type
== DDI_INTR_TYPE_MSIX
) {
265 for (i
= 1; i
< i40e
->i40e_intr_count
; i
++) {
266 i40e_intr_io_enable(i40e
, i
);
270 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
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
);
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
);
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.
288 i40e_intr_io_disable_all(i40e_t
*i40e
)
290 if (i40e
->i40e_intr_type
== DDI_INTR_TYPE_MSIX
) {
293 for (i
= 1; i
< i40e
->i40e_intr_count
; i
++) {
294 i40e_intr_io_disable(i40e
, i
);
298 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
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
);
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
);
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).
315 * Note all of the FM register access checks are performed by the caller.
318 i40e_intr_io_clear_cause(i40e_t
*i40e
)
321 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
323 if (i40e
->i40e_intr_type
!= DDI_INTR_TYPE_MSIX
) {
325 reg
= I40E_QUEUE_TYPE_EOL
;
326 I40E_WRITE_REG(hw
, I40E_PFINT_LNKLST0
, reg
);
330 for (i
= 0; i
< i40e
->i40e_num_trqpairs
; i
++) {
334 * Verify that the interrupt in question is disabled. This is a
335 * prerequisite of modifying the data in question.
337 reg
= I40E_READ_REG(hw
, I40E_PFINT_DYN_CTLN(i
));
338 VERIFY0(reg
& I40E_PFINT_DYN_CTLN_INTENA_MASK
);
340 reg
= I40E_QUEUE_TYPE_EOL
;
341 I40E_WRITE_REG(hw
, I40E_PFINT_LNKLSTN(i
), reg
);
348 * Finalize interrupt handling. Mostly this disables the admin queue.
351 i40e_intr_chip_fini(i40e_t
*i40e
)
357 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
360 * Take a look and verify that all other interrupts have been disabled
361 * and the interrupt linked lists have been zeroed.
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
);
368 reg
= I40E_READ_REG(hw
, I40E_PFINT_LNKLSTN(i
));
369 VERIFY3U(reg
, ==, I40E_QUEUE_TYPE_EOL
);
374 i40e_intr_adminq_disable(i40e
);
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.
383 i40e_intr_init_queue_msix(i40e_t
*i40e
)
385 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
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.
394 for (i
= 0; i
< i40e
->i40e_num_trqpairs
; i
++) {
395 i40e_trqpair_t
*itrq
= &i40e
->i40e_trqpairs
[i
];
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
);
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
;
409 I40E_WRITE_REG(hw
, I40E_QINT_RQCTL(i
), 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
;
418 I40E_WRITE_REG(hw
, I40E_QINT_TQCTL(i
), reg
);
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
430 i40e_intr_init_queue_shared(i40e_t
*i40e
)
432 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
435 VERIFY(i40e
->i40e_intr_type
== DDI_INTR_TYPE_FIXED
||
436 i40e
->i40e_intr_type
== DDI_INTR_TYPE_MSI
);
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
);
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
);
448 I40E_WRITE_REG(hw
, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE
), reg
);
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
);
456 I40E_WRITE_REG(hw
, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE
), reg
);
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.
465 i40e_intr_rx_queue_enable(i40e_trqpair_t
*itrq
)
468 uint_t queue
= itrq
->itrq_index
;
469 i40e_hw_t
*hw
= &itrq
->itrq_i40e
->i40e_hw_space
;
471 ASSERT(MUTEX_HELD(&itrq
->itrq_rx_lock
));
472 ASSERT(queue
< itrq
->itrq_i40e
->i40e_num_trqpairs
);
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
);
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.
486 i40e_intr_rx_queue_disable(i40e_trqpair_t
*itrq
)
489 uint_t queue
= itrq
->itrq_index
;
490 i40e_hw_t
*hw
= &itrq
->itrq_i40e
->i40e_hw_space
;
492 ASSERT(MUTEX_HELD(&itrq
->itrq_rx_lock
));
493 ASSERT(queue
< itrq
->itrq_i40e
->i40e_num_trqpairs
);
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
);
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.
508 i40e_intr_chip_init(i40e_t
*i40e
)
510 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
514 * Ensure that all non adminq interrupts are disabled at the chip level.
516 i40e_intr_io_disable_all(i40e
);
518 I40E_WRITE_REG(hw
, I40E_PFINT_ICR0_ENA
, 0);
519 (void) I40E_READ_REG(hw
, I40E_PFINT_ICR0
);
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
526 reg
= I40E_ITR_INDEX_OTHER
<< I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT
;
527 I40E_WRITE_REG(hw
, I40E_PFINT_STAT_CTL0
, reg
);
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.
535 reg
= I40E_PFINT_ICR0_ENA_ADMINQ_MASK
;
536 I40E_WRITE_REG(hw
, I40E_PFINT_ICR0_ENA
, reg
);
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.
542 I40E_WRITE_REG(hw
, I40E_PFINT_LNKLST0
, I40E_QUEUE_TYPE_EOL
);
544 i40e_intr_adminq_enable(i40e
);
547 * Set up all of the queues and map them to interrupts based on the bit
550 if (i40e
->i40e_intr_type
== DDI_INTR_TYPE_MSIX
) {
551 i40e_intr_init_queue_msix(i40e
);
553 i40e_intr_init_queue_shared(i40e
);
557 * Finally set all of the default ITRs for the interrupts. Note that the
558 * queues will have been set up above.
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
);
566 i40e_intr_adminq_work(i40e_t
*i40e
)
568 struct i40e_hw
*hw
= &i40e
->i40e_hw_space
;
569 struct i40e_arq_event_info evt
;
572 bzero(&evt
, sizeof (struct i40e_arq_event_info
));
573 evt
.buf_len
= I40E_ADMINQ_BUFSZ
;
574 evt
.msg_buf
= i40e
->i40e_aqbuf
;
576 while (remain
!= 0) {
577 enum i40e_status_code ret
;
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
585 ret
= i40e_clean_arq_element(hw
, &evt
, &remain
);
586 if (ret
!= I40E_SUCCESS
)
589 opcode
= LE_16(evt
.desc
.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
);
598 * Longer term we'll want to enable other causes here
599 * and get these cleaned up and doing something.
607 i40e_intr_rx_work(i40e_t
*i40e
, int queue
)
610 i40e_trqpair_t
*itrq
;
612 ASSERT(queue
< i40e
->i40e_num_trqpairs
);
613 itrq
= &i40e
->i40e_trqpairs
[queue
];
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
);
621 mac_rx_ring(i40e
->i40e_mac_hdl
, itrq
->itrq_macrxring
, mp
,
627 i40e_intr_tx_work(i40e_t
*i40e
, int queue
)
629 i40e_trqpair_t
*itrq
;
631 itrq
= &i40e
->i40e_trqpairs
[queue
];
632 i40e_tx_recycle_ring(itrq
);
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
641 i40e_intr_other_work(i40e_t
*i40e
)
643 struct i40e_hw
*hw
= &i40e
->i40e_hw_space
;
646 reg
= I40E_READ_REG(hw
, I40E_PFINT_ICR0
);
647 if (i40e_check_acc_handle(i40e
->i40e_osdep_space
.ios_reg_handle
) !=
649 ddi_fm_service_impact(i40e
->i40e_dip
, DDI_SERVICE_DEGRADED
);
650 atomic_or_32(&i40e
->i40e_state
, I40E_ERROR
);
654 if (reg
& I40E_PFINT_ICR0_ADMINQ_MASK
)
655 i40e_intr_adminq_work(i40e
);
658 * Make sure that the adminq interrupt is not masked and then explicitly
659 * enable the adminq and thus the other interrupt.
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
);
665 i40e_intr_adminq_enable(i40e
);
669 i40e_intr_msix(void *arg1
, void *arg2
)
671 i40e_t
*i40e
= (i40e_t
*)arg1
;
672 int vector_idx
= (int)(uintptr_t)arg2
;
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
679 if (vector_idx
== 0) {
680 i40e_intr_other_work(i40e
);
681 return (DDI_INTR_CLAIMED
);
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
);
688 return (DDI_INTR_CLAIMED
);
692 i40e_intr_notx(i40e_t
*i40e
, boolean_t shared
)
694 i40e_hw_t
*hw
= &i40e
->i40e_hw_space
;
696 int ret
= DDI_INTR_CLAIMED
;
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
);
704 mutex_exit(&i40e
->i40e_general_lock
);
707 reg
= I40E_READ_REG(hw
, I40E_PFINT_ICR0
);
708 if (i40e_check_acc_handle(i40e
->i40e_osdep_space
.ios_reg_handle
) !=
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
);
716 if (shared
== B_TRUE
)
717 ret
= DDI_INTR_UNCLAIMED
;
721 if (reg
& I40E_PFINT_ICR0_ADMINQ_MASK
)
722 i40e_intr_adminq_work(i40e
);
724 if (reg
& I40E_INTR_NOTX_RX_MASK
)
725 i40e_intr_rx_work(i40e
, 0);
727 if (reg
& I40E_INTR_NOTX_TX_MASK
)
728 i40e_intr_tx_work(i40e
, 0);
731 i40e_intr_adminq_enable(i40e
);
738 i40e_intr_msi(void *arg1
, void *arg2
)
740 i40e_t
*i40e
= (i40e_t
*)arg1
;
742 return (i40e_intr_notx(i40e
, B_FALSE
));
747 i40e_intr_legacy(void *arg1
, void *arg2
)
749 i40e_t
*i40e
= (i40e_t
*)arg1
;
751 return (i40e_intr_notx(i40e
, B_TRUE
));