xref: /titanic_51/usr/src/uts/common/io/i40e/i40e_intr.c (revision c4a685adc15d0783a24999041d7fca9dfd7c83e4)
1da5577f0SRobert Mustacchi /*
2da5577f0SRobert Mustacchi  * This file and its contents are supplied under the terms of the
3da5577f0SRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
4da5577f0SRobert Mustacchi  * You may only use this file in accordance with the terms of version
5da5577f0SRobert Mustacchi  * 1.0 of the CDDL.
6da5577f0SRobert Mustacchi  *
7da5577f0SRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
8da5577f0SRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
9da5577f0SRobert Mustacchi  * http://www.illumos.org/license/CDDL.
10da5577f0SRobert Mustacchi  */
11da5577f0SRobert Mustacchi 
12da5577f0SRobert Mustacchi /*
13*c4a685adSRobert Mustacchi  * Copyright 2019 Joyent, Inc.
1405768666SPaul Winder  * Copyright 2017 Tegile Systems, Inc.  All rights reserved.
15da5577f0SRobert Mustacchi  */
16da5577f0SRobert Mustacchi 
17da5577f0SRobert Mustacchi /*
18da5577f0SRobert Mustacchi  * -------------------------
19da5577f0SRobert Mustacchi  * Interrupt Handling Theory
20da5577f0SRobert Mustacchi  * -------------------------
21da5577f0SRobert Mustacchi  *
22da5577f0SRobert Mustacchi  * There are a couple different sets of interrupts that we need to worry about:
23da5577f0SRobert Mustacchi  *
24da5577f0SRobert Mustacchi  *   - Interrupts from receive queues
25da5577f0SRobert Mustacchi  *   - Interrupts from transmit queues
26da5577f0SRobert Mustacchi  *   - 'Other Interrupts', such as the administrative queue
27da5577f0SRobert Mustacchi  *
28da5577f0SRobert Mustacchi  * 'Other Interrupts' are asynchronous events such as a link status change event
29da5577f0SRobert Mustacchi  * being posted to the administrative queue, unrecoverable ECC errors, and more.
30da5577f0SRobert Mustacchi  * If we have something being posted to the administrative queue, then we go
31da5577f0SRobert Mustacchi  * through and process it, because it's generally enabled as a separate logical
32da5577f0SRobert Mustacchi  * interrupt. Note, we may need to do more here eventually. To re-enable the
33da5577f0SRobert Mustacchi  * interrupts from the 'Other Interrupts' section, we need to clear the PBA and
34da5577f0SRobert Mustacchi  * write ENA to PFINT_ICR0.
35da5577f0SRobert Mustacchi  *
36da5577f0SRobert Mustacchi  * Interrupts from the transmit and receive queues indicates that our requests
37da5577f0SRobert Mustacchi  * have been processed. In the rx case, it means that we have data that we
38da5577f0SRobert Mustacchi  * should take a look at and send up the stack. In the tx case, it means that
39da5577f0SRobert Mustacchi  * data which we got from MAC has now been sent out on the wire and we can free
40da5577f0SRobert Mustacchi  * the associated data. Most of the logic for acting upon the presence of this
41da5577f0SRobert Mustacchi  * data can be found in i40e_transciever.c which handles all of the DMA, rx, and
42da5577f0SRobert Mustacchi  * tx operations. This file is dedicated to handling and dealing with interrupt
43da5577f0SRobert Mustacchi  * processing.
44da5577f0SRobert Mustacchi  *
45da5577f0SRobert Mustacchi  * All devices supported by this driver support three kinds of interrupts:
46da5577f0SRobert Mustacchi  *
47da5577f0SRobert Mustacchi  *   o Extended Message Signaled Interrupts (MSI-X)
48da5577f0SRobert Mustacchi  *   o Message Signaled Interrupts (MSI)
49da5577f0SRobert Mustacchi  *   o Legacy PCI interrupts (INTx)
50da5577f0SRobert Mustacchi  *
51da5577f0SRobert Mustacchi  * Generally speaking the hardware logically handles MSI and INTx the same and
52da5577f0SRobert Mustacchi  * restricts us to only using a single interrupt, which isn't the interesting
53da5577f0SRobert Mustacchi  * case. With MSI-X available, each physical function of the device provides the
54da5577f0SRobert Mustacchi  * opportunity for multiple interrupts which is what we'll focus on.
55da5577f0SRobert Mustacchi  *
56da5577f0SRobert Mustacchi  * --------------------
57da5577f0SRobert Mustacchi  * Interrupt Management
58da5577f0SRobert Mustacchi  * --------------------
59da5577f0SRobert Mustacchi  *
60da5577f0SRobert Mustacchi  * By default, the admin queue, which consists of the asynchronous other
61da5577f0SRobert Mustacchi  * interrupts is always bound to MSI-X vector zero. Next, we spread out all of
62da5577f0SRobert Mustacchi  * the other interrupts that we have available to us over the remaining
63da5577f0SRobert Mustacchi  * interrupt vectors.
64da5577f0SRobert Mustacchi  *
65da5577f0SRobert Mustacchi  * This means that there may be multiple queues, both tx and rx, which are
66da5577f0SRobert Mustacchi  * mapped to the same interrupt. When the interrupt fires, we'll have to check
67da5577f0SRobert Mustacchi  * all of them for servicing, before we go through and indicate that the
68da5577f0SRobert Mustacchi  * interrupt is claimed.
69da5577f0SRobert Mustacchi  *
70da5577f0SRobert Mustacchi  * The hardware provides the means of mapping various queues to MSI-X interrupts
71da5577f0SRobert Mustacchi  * by programming the I40E_QINT_RQCTL() and I4OE_QINT_TQCTL() registers. These
72da5577f0SRobert Mustacchi  * registers can also be used to enable and disable whether or not the queue is
73da5577f0SRobert Mustacchi  * a source of interrupts. As part of this, the hardware requires that we
74da5577f0SRobert Mustacchi  * maintain a linked list of queues for each interrupt vector. While it may seem
75da5577f0SRobert Mustacchi  * like this is only there for the purproses of ITRs, that's not the case. The
76da5577f0SRobert Mustacchi  * first queue must be programmed in I40E_QINT_LNKLSTN(%vector) register. Each
77da5577f0SRobert Mustacchi  * queue defines the next one in either the I40E_QINT_RQCTL or I40E_QINT_TQCTL
78da5577f0SRobert Mustacchi  * register.
79da5577f0SRobert Mustacchi  *
80da5577f0SRobert Mustacchi  * Finally, the individual interrupt vector itself has the ability to be enabled
81da5577f0SRobert Mustacchi  * and disabled. The overall interrupt is controlled through the
82da5577f0SRobert Mustacchi  * I40E_PFINT_DYN_CTLN() register. This is used to turn on and off the interrupt
83da5577f0SRobert Mustacchi  * as a whole.
84da5577f0SRobert Mustacchi  *
85da5577f0SRobert Mustacchi  * Note that this means that both the individual queue and the interrupt as a
86da5577f0SRobert Mustacchi  * whole can be toggled and re-enabled.
87da5577f0SRobert Mustacchi  *
88da5577f0SRobert Mustacchi  * -------------------
89da5577f0SRobert Mustacchi  * Non-MSIX Management
90da5577f0SRobert Mustacchi  * -------------------
91da5577f0SRobert Mustacchi  *
92da5577f0SRobert Mustacchi  * We may have a case where the Operating System is unable to actually allocate
93da5577f0SRobert Mustacchi  * any MSI-X to the system. In such a world, there is only one transmit/receive
94da5577f0SRobert Mustacchi  * queue pair and it is bound to the same interrupt with index zero. The
95da5577f0SRobert Mustacchi  * hardware doesn't allow us access to additional interrupt vectors in these
96da5577f0SRobert Mustacchi  * modes. Note that technically we could support more transmit/receive queues if
97da5577f0SRobert Mustacchi  * we wanted.
98da5577f0SRobert Mustacchi  *
99da5577f0SRobert Mustacchi  * In this world, because the interrupts for the admin queue and traffic are
100da5577f0SRobert Mustacchi  * mixed together, we have to consult ICR0 to determine what has occurred. The
101da5577f0SRobert Mustacchi  * QINT_TQCTL and QINT_RQCTL registers have a field, 'MSI-X 0 index' which
102da5577f0SRobert Mustacchi  * allows us to set a specific bit in ICR0. There are up to seven such bits;
103da5577f0SRobert Mustacchi  * however, we only use the bit 0 and 1 for the rx and tx queue respectively.
104da5577f0SRobert Mustacchi  * These are contained by the I40E_INTR_NOTX_{R|T}X_QUEUE and
105da5577f0SRobert Mustacchi  * I40E_INTR_NOTX_{R|T}X_MASK registers respectively.
106da5577f0SRobert Mustacchi  *
107da5577f0SRobert Mustacchi  * Unfortunately, these corresponding queue bits have no corresponding entry in
108da5577f0SRobert Mustacchi  * the ICR0_ENA register. So instead, when enabling interrupts on the queues, we
109da5577f0SRobert Mustacchi  * end up enabling it on the queue registers rather than on the MSI-X registers.
110da5577f0SRobert Mustacchi  * In the MSI-X world, because they can be enabled and disabled, this is
111da5577f0SRobert Mustacchi  * different and the queues can always be enabled and disabled, but the
112da5577f0SRobert Mustacchi  * interrupts themselves are toggled (ignoring the question of interrupt
113da5577f0SRobert Mustacchi  * blanking for polling on rings).
114da5577f0SRobert Mustacchi  *
115da5577f0SRobert Mustacchi  * Finally, we still have to set up the interrupt linked list, but the list is
116da5577f0SRobert Mustacchi  * instead rooted at the register I40E_PFINT_LNKLST0, rather than being tied to
117da5577f0SRobert Mustacchi  * one of the other MSI-X registers.
118da5577f0SRobert Mustacchi  *
119da5577f0SRobert Mustacchi  * --------------------
120da5577f0SRobert Mustacchi  * Interrupt Moderation
121da5577f0SRobert Mustacchi  * --------------------
122da5577f0SRobert Mustacchi  *
123da5577f0SRobert Mustacchi  * The XL710 hardware has three different interrupt moderation registers per
124da5577f0SRobert Mustacchi  * interrupt. Unsurprisingly, we use these for:
125da5577f0SRobert Mustacchi  *
126da5577f0SRobert Mustacchi  *   o RX interrupts
127da5577f0SRobert Mustacchi  *   o TX interrupts
128da5577f0SRobert Mustacchi  *   o 'Other interrupts' (link status change, admin queue, etc.)
129da5577f0SRobert Mustacchi  *
130da5577f0SRobert Mustacchi  * By default, we throttle 'other interrupts' the most, then TX interrupts, and
131da5577f0SRobert Mustacchi  * then RX interrupts. The default values for these were based on trying to
132da5577f0SRobert Mustacchi  * reason about both the importance and frequency of events. Generally speaking
133da5577f0SRobert Mustacchi  * 'other interrupts' are not very frequent and they're not important for the
134da5577f0SRobert Mustacchi  * I/O data path in and of itself (though they may indicate issues with the I/O
135da5577f0SRobert Mustacchi  * data path).
136da5577f0SRobert Mustacchi  *
137da5577f0SRobert Mustacchi  * On the flip side, when we're not polling, RX interrupts are very important.
138da5577f0SRobert Mustacchi  * The longer we wait for them, the more latency that we inject into the system.
139da5577f0SRobert Mustacchi  * However, if we allow interrupts to occur too frequently, we risk a few
140da5577f0SRobert Mustacchi  * problems:
141da5577f0SRobert Mustacchi  *
142da5577f0SRobert Mustacchi  *  1) Abusing system resources. Without proper interrupt blanking and polling,
143da5577f0SRobert Mustacchi  *     we can see upwards of 200k-300k interrupts per second on the system.
144da5577f0SRobert Mustacchi  *
145da5577f0SRobert Mustacchi  *  2) Not enough data coalescing to enable polling. In other words, the more
146da5577f0SRobert Mustacchi  *     data that we allow to build up, the more likely we'll be able to enable
147da5577f0SRobert Mustacchi  *     polling mode and allowing us to better handle bulk data.
148da5577f0SRobert Mustacchi  *
149da5577f0SRobert Mustacchi  * In-between the 'other interrupts' and the TX interrupts we have the
150da5577f0SRobert Mustacchi  * reclamation of TX buffers. This operation is not quite as important as we
151da5577f0SRobert Mustacchi  * generally size the ring large enough that we should be able to reclaim a
152da5577f0SRobert Mustacchi  * substantial amount of the descriptors that we have used per interrupt. So
153da5577f0SRobert Mustacchi  * while it's important that this interrupt occur, we don't necessarily need it
154da5577f0SRobert Mustacchi  * firing as frequently as RX; it doesn't, on its own, induce additional latency
155da5577f0SRobert Mustacchi  * into the system.
156da5577f0SRobert Mustacchi  *
157da5577f0SRobert Mustacchi  * Based on all this we currently assign static ITR values for the system. While
158da5577f0SRobert Mustacchi  * we could move to a dynamic system (the hardware supports that), we'd want to
159da5577f0SRobert Mustacchi  * make sure that we're seeing problems from this that we believe would be
160da5577f0SRobert Mustacchi  * generally helped by the added complexity.
161da5577f0SRobert Mustacchi  *
162da5577f0SRobert Mustacchi  * Based on this, the default values that we have allow for the following
163da5577f0SRobert Mustacchi  * interrupt thresholds:
164da5577f0SRobert Mustacchi  *
165da5577f0SRobert Mustacchi  *    o 20k interrupts/s for RX
166da5577f0SRobert Mustacchi  *    o 5k interrupts/s for TX
167da5577f0SRobert Mustacchi  *    o 2k interupts/s for 'Other Interrupts'
168da5577f0SRobert Mustacchi  */
169da5577f0SRobert Mustacchi 
170da5577f0SRobert Mustacchi #include "i40e_sw.h"
171da5577f0SRobert Mustacchi 
172da5577f0SRobert Mustacchi #define	I40E_INTR_NOTX_QUEUE	0
173da5577f0SRobert Mustacchi #define	I40E_INTR_NOTX_INTR	0
174da5577f0SRobert Mustacchi #define	I40E_INTR_NOTX_RX_QUEUE	0
175da5577f0SRobert Mustacchi #define	I40E_INTR_NOTX_RX_MASK	(1 << I40E_PFINT_ICR0_QUEUE_0_SHIFT)
176da5577f0SRobert Mustacchi #define	I40E_INTR_NOTX_TX_QUEUE	1
177da5577f0SRobert Mustacchi #define	I40E_INTR_NOTX_TX_MASK	(1 << I40E_PFINT_ICR0_QUEUE_1_SHIFT)
178da5577f0SRobert Mustacchi 
179da5577f0SRobert Mustacchi void
180da5577f0SRobert Mustacchi i40e_intr_set_itr(i40e_t *i40e, i40e_itr_index_t itr, uint_t val)
181da5577f0SRobert Mustacchi {
182da5577f0SRobert Mustacchi 	int i;
183da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
184da5577f0SRobert Mustacchi 
185da5577f0SRobert Mustacchi 	VERIFY3U(val, <=, I40E_MAX_ITR);
186da5577f0SRobert Mustacchi 	VERIFY3U(itr, <, I40E_ITR_INDEX_NONE);
187da5577f0SRobert Mustacchi 
188da5577f0SRobert Mustacchi 	/*
189da5577f0SRobert Mustacchi 	 * No matter the interrupt mode, the ITR for other interrupts is always
190da5577f0SRobert Mustacchi 	 * on interrupt zero and the same is true if we're not using MSI-X.
191da5577f0SRobert Mustacchi 	 */
192da5577f0SRobert Mustacchi 	if (itr == I40E_ITR_INDEX_OTHER ||
193da5577f0SRobert Mustacchi 	    i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
194da5577f0SRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_PFINT_ITR0(itr), val);
195da5577f0SRobert Mustacchi 		return;
196da5577f0SRobert Mustacchi 	}
197da5577f0SRobert Mustacchi 
19805768666SPaul Winder 	for (i = 0; i < i40e->i40e_num_trqpairs; i++) {
19905768666SPaul Winder 		I40E_WRITE_REG(hw, I40E_PFINT_ITRN(itr, i), val);
200da5577f0SRobert Mustacchi 	}
201da5577f0SRobert Mustacchi }
202da5577f0SRobert Mustacchi 
203da5577f0SRobert Mustacchi /*
204da5577f0SRobert Mustacchi  * Re-enable the adminq. Note that the adminq doesn't have a traditional queue
205da5577f0SRobert Mustacchi  * associated with it from an interrupt perspective and just lives on ICR0.
206da5577f0SRobert Mustacchi  * However when MSI-X interrupts are not being used, then this also enables and
207da5577f0SRobert Mustacchi  * disables those interrupts.
208da5577f0SRobert Mustacchi  */
209da5577f0SRobert Mustacchi static void
210da5577f0SRobert Mustacchi i40e_intr_adminq_enable(i40e_t *i40e)
211da5577f0SRobert Mustacchi {
212da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
213da5577f0SRobert Mustacchi 	uint32_t reg;
214da5577f0SRobert Mustacchi 
215da5577f0SRobert Mustacchi 	reg = I40E_PFINT_DYN_CTL0_INTENA_MASK |
216da5577f0SRobert Mustacchi 	    I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
217da5577f0SRobert Mustacchi 	    (I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
218da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, reg);
219da5577f0SRobert Mustacchi 	i40e_flush(hw);
220da5577f0SRobert Mustacchi }
221da5577f0SRobert Mustacchi 
222da5577f0SRobert Mustacchi static void
223da5577f0SRobert Mustacchi i40e_intr_adminq_disable(i40e_t *i40e)
224da5577f0SRobert Mustacchi {
225da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
226da5577f0SRobert Mustacchi 	uint32_t reg;
227da5577f0SRobert Mustacchi 
228da5577f0SRobert Mustacchi 	reg = I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT;
229da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTL0, reg);
230da5577f0SRobert Mustacchi }
231da5577f0SRobert Mustacchi 
2328d5069bcSRyan Zezeski /*
2338d5069bcSRyan Zezeski  * The next two functions enable/disable the reception of interrupts
2348d5069bcSRyan Zezeski  * on the given vector. Only vectors 1..N are programmed by these
2358d5069bcSRyan Zezeski  * functions; vector 0 is special and handled by a different register.
2368d5069bcSRyan Zezeski  * We must subtract one from the vector because i40e implicitly adds
2378d5069bcSRyan Zezeski  * one to the vector value. See section 10.2.2.10.13 for more details.
2388d5069bcSRyan Zezeski  */
239da5577f0SRobert Mustacchi static void
240da5577f0SRobert Mustacchi i40e_intr_io_enable(i40e_t *i40e, int vector)
241da5577f0SRobert Mustacchi {
242da5577f0SRobert Mustacchi 	uint32_t reg;
243da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
244da5577f0SRobert Mustacchi 
2458d5069bcSRyan Zezeski 	ASSERT3S(vector, >, 0);
246da5577f0SRobert Mustacchi 	reg = I40E_PFINT_DYN_CTLN_INTENA_MASK |
247da5577f0SRobert Mustacchi 	    I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
248da5577f0SRobert Mustacchi 	    (I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
249da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vector - 1), reg);
250da5577f0SRobert Mustacchi }
251da5577f0SRobert Mustacchi 
252da5577f0SRobert Mustacchi static void
253da5577f0SRobert Mustacchi i40e_intr_io_disable(i40e_t *i40e, int vector)
254da5577f0SRobert Mustacchi {
255da5577f0SRobert Mustacchi 	uint32_t reg;
256da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
257da5577f0SRobert Mustacchi 
2588d5069bcSRyan Zezeski 	ASSERT3S(vector, >, 0);
259da5577f0SRobert Mustacchi 	reg = I40E_ITR_INDEX_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT;
260da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vector - 1), reg);
261da5577f0SRobert Mustacchi }
262da5577f0SRobert Mustacchi 
263da5577f0SRobert Mustacchi /*
264da5577f0SRobert Mustacchi  * When MSI-X interrupts are being used, then we can enable the actual
265da5577f0SRobert Mustacchi  * interrupts themselves. However, when they are not, we instead have to turn
266da5577f0SRobert Mustacchi  * towards the queue's CAUSE_ENA bit and enable that.
267da5577f0SRobert Mustacchi  */
268da5577f0SRobert Mustacchi void
269da5577f0SRobert Mustacchi i40e_intr_io_enable_all(i40e_t *i40e)
270da5577f0SRobert Mustacchi {
271da5577f0SRobert Mustacchi 	if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
272da5577f0SRobert Mustacchi 		int i;
273da5577f0SRobert Mustacchi 
274da5577f0SRobert Mustacchi 		for (i = 1; i < i40e->i40e_intr_count; i++) {
275da5577f0SRobert Mustacchi 			i40e_intr_io_enable(i40e, i);
276da5577f0SRobert Mustacchi 		}
277da5577f0SRobert Mustacchi 	} else {
278da5577f0SRobert Mustacchi 		uint32_t reg;
279da5577f0SRobert Mustacchi 		i40e_hw_t *hw = &i40e->i40e_hw_space;
280da5577f0SRobert Mustacchi 
281da5577f0SRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE));
282da5577f0SRobert Mustacchi 		reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
283da5577f0SRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
284da5577f0SRobert Mustacchi 
285da5577f0SRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE));
286da5577f0SRobert Mustacchi 		reg |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
287da5577f0SRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
288da5577f0SRobert Mustacchi 	}
289da5577f0SRobert Mustacchi }
290da5577f0SRobert Mustacchi 
291da5577f0SRobert Mustacchi /*
292da5577f0SRobert Mustacchi  * When MSI-X interrupts are being used, then we can disable the actual
293da5577f0SRobert Mustacchi  * interrupts themselves. However, when they are not, we instead have to turn
294da5577f0SRobert Mustacchi  * towards the queue's CAUSE_ENA bit and disable that.
295da5577f0SRobert Mustacchi  */
296da5577f0SRobert Mustacchi void
297da5577f0SRobert Mustacchi i40e_intr_io_disable_all(i40e_t *i40e)
298da5577f0SRobert Mustacchi {
299da5577f0SRobert Mustacchi 	if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
300da5577f0SRobert Mustacchi 		int i;
301da5577f0SRobert Mustacchi 
302da5577f0SRobert Mustacchi 		for (i = 1; i < i40e->i40e_intr_count; i++) {
303da5577f0SRobert Mustacchi 			i40e_intr_io_disable(i40e, i);
304da5577f0SRobert Mustacchi 		}
305da5577f0SRobert Mustacchi 	} else {
306da5577f0SRobert Mustacchi 		uint32_t reg;
307da5577f0SRobert Mustacchi 		i40e_hw_t *hw = &i40e->i40e_hw_space;
308da5577f0SRobert Mustacchi 
309da5577f0SRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE));
310da5577f0SRobert Mustacchi 		reg &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
311da5577f0SRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
312da5577f0SRobert Mustacchi 
313da5577f0SRobert Mustacchi 		reg = I40E_READ_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE));
314da5577f0SRobert Mustacchi 		reg &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK;
315da5577f0SRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
316da5577f0SRobert Mustacchi 	}
317da5577f0SRobert Mustacchi }
318da5577f0SRobert Mustacchi 
319da5577f0SRobert Mustacchi /*
320da5577f0SRobert Mustacchi  * As part of disabling the tx and rx queue's we're technically supposed to
321da5577f0SRobert Mustacchi  * remove the linked list entries. The simplest way is to clear the LNKLSTN
322da5577f0SRobert Mustacchi  * register by setting it to I40E_QUEUE_TYPE_EOL (0x7FF).
323da5577f0SRobert Mustacchi  *
324da5577f0SRobert Mustacchi  * Note all of the FM register access checks are performed by the caller.
325da5577f0SRobert Mustacchi  */
326da5577f0SRobert Mustacchi void
327da5577f0SRobert Mustacchi i40e_intr_io_clear_cause(i40e_t *i40e)
328da5577f0SRobert Mustacchi {
329*c4a685adSRobert Mustacchi 	uint32_t i;
330da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
331da5577f0SRobert Mustacchi 
332da5577f0SRobert Mustacchi 	if (i40e->i40e_intr_type != DDI_INTR_TYPE_MSIX) {
333da5577f0SRobert Mustacchi 		uint32_t reg;
334da5577f0SRobert Mustacchi 		reg = I40E_QUEUE_TYPE_EOL;
335da5577f0SRobert Mustacchi 		I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, reg);
336da5577f0SRobert Mustacchi 		return;
337da5577f0SRobert Mustacchi 	}
338da5577f0SRobert Mustacchi 
339*c4a685adSRobert Mustacchi 	for (i = 0; i < i40e->i40e_intr_count - 1; i++) {
340da5577f0SRobert Mustacchi 		uint32_t reg;
341*c4a685adSRobert Mustacchi 
342da5577f0SRobert Mustacchi 		reg = I40E_QUEUE_TYPE_EOL;
34305768666SPaul Winder 		I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(i), reg);
344da5577f0SRobert Mustacchi 	}
345da5577f0SRobert Mustacchi 
346da5577f0SRobert Mustacchi 	i40e_flush(hw);
347da5577f0SRobert Mustacchi }
348da5577f0SRobert Mustacchi 
349da5577f0SRobert Mustacchi /*
350da5577f0SRobert Mustacchi  * Finalize interrupt handling. Mostly this disables the admin queue.
351da5577f0SRobert Mustacchi  */
352da5577f0SRobert Mustacchi void
353da5577f0SRobert Mustacchi i40e_intr_chip_fini(i40e_t *i40e)
354da5577f0SRobert Mustacchi {
355da5577f0SRobert Mustacchi #ifdef DEBUG
356da5577f0SRobert Mustacchi 	int i;
357da5577f0SRobert Mustacchi 	uint32_t reg;
358da5577f0SRobert Mustacchi 
359da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
360da5577f0SRobert Mustacchi 
361da5577f0SRobert Mustacchi 	/*
362da5577f0SRobert Mustacchi 	 * Take a look and verify that all other interrupts have been disabled
363da5577f0SRobert Mustacchi 	 * and the interrupt linked lists have been zeroed.
364da5577f0SRobert Mustacchi 	 */
365da5577f0SRobert Mustacchi 	if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
366*c4a685adSRobert Mustacchi 		for (i = 0; i < i40e->i40e_intr_count - 1; i++) {
36705768666SPaul Winder 			reg = I40E_READ_REG(hw, I40E_PFINT_DYN_CTLN(i));
368da5577f0SRobert Mustacchi 			VERIFY0(reg & I40E_PFINT_DYN_CTLN_INTENA_MASK);
369da5577f0SRobert Mustacchi 
37005768666SPaul Winder 			reg = I40E_READ_REG(hw, I40E_PFINT_LNKLSTN(i));
371da5577f0SRobert Mustacchi 			VERIFY3U(reg, ==, I40E_QUEUE_TYPE_EOL);
372da5577f0SRobert Mustacchi 		}
373da5577f0SRobert Mustacchi 	}
374da5577f0SRobert Mustacchi #endif
375da5577f0SRobert Mustacchi 
376da5577f0SRobert Mustacchi 	i40e_intr_adminq_disable(i40e);
377da5577f0SRobert Mustacchi }
378da5577f0SRobert Mustacchi 
379da5577f0SRobert Mustacchi /*
3808d5069bcSRyan Zezeski  * Set the head of the interrupt linked list. The PFINT_LNKLSTN[N]
3818d5069bcSRyan Zezeski  * register actually refers to the 'N + 1' interrupt vector. E.g.,
3828d5069bcSRyan Zezeski  * PFINT_LNKLSTN[0] refers to interrupt vector 1.
3838d5069bcSRyan Zezeski  */
3848d5069bcSRyan Zezeski static void
3858d5069bcSRyan Zezeski i40e_set_lnklstn(i40e_t *i40e, uint_t vector, uint_t queue)
3868d5069bcSRyan Zezeski {
3878d5069bcSRyan Zezeski 	uint32_t	reg;
3888d5069bcSRyan Zezeski 	i40e_hw_t	*hw = &i40e->i40e_hw_space;
3898d5069bcSRyan Zezeski 
3908d5069bcSRyan Zezeski 	reg = (queue << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) |
3918d5069bcSRyan Zezeski 	    (I40E_QUEUE_TYPE_RX << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
3928d5069bcSRyan Zezeski 
3938d5069bcSRyan Zezeski 	I40E_WRITE_REG(hw, I40E_PFINT_LNKLSTN(vector), reg);
3948d5069bcSRyan Zezeski 	DEBUGOUT2("PFINT_LNKLSTN[%u] = 0x%x", vector, reg);
3958d5069bcSRyan Zezeski }
3968d5069bcSRyan Zezeski 
3978d5069bcSRyan Zezeski /*
3988d5069bcSRyan Zezeski  * Set the QINT_RQCTL[queue] register. The next queue is always the Tx
3998d5069bcSRyan Zezeski  * queue associated with this Rx queue. Unlike PFINT_LNKLSTN, the
4008d5069bcSRyan Zezeski  * vector should be the actual vector this queue is on -- i.e., it
4018d5069bcSRyan Zezeski  * should be equal to itrq_rx_intrvec.
4028d5069bcSRyan Zezeski  */
4038d5069bcSRyan Zezeski static void
4048d5069bcSRyan Zezeski i40e_set_rqctl(i40e_t *i40e, uint_t vector, uint_t queue)
4058d5069bcSRyan Zezeski {
4068d5069bcSRyan Zezeski 	uint32_t	reg;
4078d5069bcSRyan Zezeski 	i40e_hw_t	*hw = &i40e->i40e_hw_space;
4088d5069bcSRyan Zezeski 
4098d5069bcSRyan Zezeski 	ASSERT3U(vector, ==, i40e->i40e_trqpairs[queue].itrq_rx_intrvec);
4108d5069bcSRyan Zezeski 
4118d5069bcSRyan Zezeski 	reg = (vector << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
4128d5069bcSRyan Zezeski 	    (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
4138d5069bcSRyan Zezeski 	    (queue << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
4148d5069bcSRyan Zezeski 	    (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
4158d5069bcSRyan Zezeski 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK;
4168d5069bcSRyan Zezeski 
4178d5069bcSRyan Zezeski 	I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg);
4188d5069bcSRyan Zezeski 	DEBUGOUT2("QINT_RQCTL[%u] = 0x%x", queue, reg);
4198d5069bcSRyan Zezeski }
4208d5069bcSRyan Zezeski 
4218d5069bcSRyan Zezeski /*
4228d5069bcSRyan Zezeski  * Like i40e_set_rqctl(), but for QINT_TQCTL[queue]. The next queue is
4238d5069bcSRyan Zezeski  * either the Rx queue of another TRQP, or EOL.
4248d5069bcSRyan Zezeski  */
4258d5069bcSRyan Zezeski static void
4268d5069bcSRyan Zezeski i40e_set_tqctl(i40e_t *i40e, uint_t vector, uint_t queue, uint_t next_queue)
4278d5069bcSRyan Zezeski {
4288d5069bcSRyan Zezeski 	uint32_t	reg;
4298d5069bcSRyan Zezeski 	i40e_hw_t	*hw = &i40e->i40e_hw_space;
4308d5069bcSRyan Zezeski 
4318d5069bcSRyan Zezeski 	ASSERT3U(vector, ==, i40e->i40e_trqpairs[queue].itrq_tx_intrvec);
4328d5069bcSRyan Zezeski 
4338d5069bcSRyan Zezeski 	reg = (vector << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
4348d5069bcSRyan Zezeski 	    (I40E_ITR_INDEX_TX << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
4358d5069bcSRyan Zezeski 	    (next_queue << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
4368d5069bcSRyan Zezeski 	    (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) |
4378d5069bcSRyan Zezeski 	    I40E_QINT_TQCTL_CAUSE_ENA_MASK;
4388d5069bcSRyan Zezeski 
4398d5069bcSRyan Zezeski 	I40E_WRITE_REG(hw, I40E_QINT_TQCTL(queue), reg);
4408d5069bcSRyan Zezeski 	DEBUGOUT2("QINT_TQCTL[%u] = 0x%x", queue, reg);
4418d5069bcSRyan Zezeski }
4428d5069bcSRyan Zezeski 
4438d5069bcSRyan Zezeski /*
4448d5069bcSRyan Zezeski  * Program the interrupt linked list. Each vector has a linked list of
4458d5069bcSRyan Zezeski  * queues which act as event sources for that vector. When one of
4468d5069bcSRyan Zezeski  * those sources has an event the associated interrupt vector is
4478d5069bcSRyan Zezeski  * fired. This mapping must match the mapping found in
4488d5069bcSRyan Zezeski  * i40e_map_intrs_to_vectors().
4498d5069bcSRyan Zezeski  *
4508d5069bcSRyan Zezeski  * See section 7.5.3 for more information about the configuration of
4518d5069bcSRyan Zezeski  * the interrupt linked list.
452da5577f0SRobert Mustacchi  */
453da5577f0SRobert Mustacchi static void
454da5577f0SRobert Mustacchi i40e_intr_init_queue_msix(i40e_t *i40e)
455da5577f0SRobert Mustacchi {
4568d5069bcSRyan Zezeski 	uint_t intr_count;
457da5577f0SRobert Mustacchi 
458da5577f0SRobert Mustacchi 	/*
4598d5069bcSRyan Zezeski 	 * The 0th vector is for 'Other Interrupts' only (subject to
4608d5069bcSRyan Zezeski 	 * change in the future).
461da5577f0SRobert Mustacchi 	 */
4628d5069bcSRyan Zezeski 	intr_count = i40e->i40e_intr_count - 1;
463da5577f0SRobert Mustacchi 
4648d5069bcSRyan Zezeski 	for (uint_t vec = 0; vec < intr_count; vec++) {
4658d5069bcSRyan Zezeski 		boolean_t head = B_TRUE;
46605768666SPaul Winder 
4678d5069bcSRyan Zezeski 		for (uint_t qidx = vec; qidx < i40e->i40e_num_trqpairs;
4688d5069bcSRyan Zezeski 		    qidx += intr_count) {
4698d5069bcSRyan Zezeski 			uint_t next_qidx = qidx + intr_count;
470da5577f0SRobert Mustacchi 
4718d5069bcSRyan Zezeski 			next_qidx = (next_qidx > i40e->i40e_num_trqpairs) ?
4728d5069bcSRyan Zezeski 			    I40E_QUEUE_TYPE_EOL : next_qidx;
473da5577f0SRobert Mustacchi 
4748d5069bcSRyan Zezeski 			if (head) {
4758d5069bcSRyan Zezeski 				i40e_set_lnklstn(i40e, vec, qidx);
4768d5069bcSRyan Zezeski 				head = B_FALSE;
47705768666SPaul Winder 			}
478da5577f0SRobert Mustacchi 
4798d5069bcSRyan Zezeski 			i40e_set_rqctl(i40e, vec + 1, qidx);
4808d5069bcSRyan Zezeski 			i40e_set_tqctl(i40e, vec + 1, qidx, next_qidx);
4818d5069bcSRyan Zezeski 		}
4828d5069bcSRyan Zezeski 	}
483da5577f0SRobert Mustacchi }
484da5577f0SRobert Mustacchi 
485da5577f0SRobert Mustacchi /*
486da5577f0SRobert Mustacchi  * Set up a single queue to share the admin queue interrupt in the non-MSI-X
487da5577f0SRobert Mustacchi  * world. Note we do not enable the queue as an interrupt cause at this time. We
488da5577f0SRobert Mustacchi  * don't have any other vector of control here, unlike with the MSI-X interrupt
489da5577f0SRobert Mustacchi  * case.
490da5577f0SRobert Mustacchi  */
491da5577f0SRobert Mustacchi static void
492da5577f0SRobert Mustacchi i40e_intr_init_queue_shared(i40e_t *i40e)
493da5577f0SRobert Mustacchi {
494da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
495da5577f0SRobert Mustacchi 	uint32_t reg;
496da5577f0SRobert Mustacchi 
497da5577f0SRobert Mustacchi 	VERIFY(i40e->i40e_intr_type == DDI_INTR_TYPE_FIXED ||
498da5577f0SRobert Mustacchi 	    i40e->i40e_intr_type == DDI_INTR_TYPE_MSI);
499da5577f0SRobert Mustacchi 
500da5577f0SRobert Mustacchi 	reg = (I40E_INTR_NOTX_QUEUE << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) |
501da5577f0SRobert Mustacchi 	    (I40E_QUEUE_TYPE_RX << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT);
502da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, reg);
503da5577f0SRobert Mustacchi 
504da5577f0SRobert Mustacchi 	reg = (I40E_INTR_NOTX_INTR << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
505da5577f0SRobert Mustacchi 	    (I40E_ITR_INDEX_RX << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
506da5577f0SRobert Mustacchi 	    (I40E_INTR_NOTX_RX_QUEUE << I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) |
507da5577f0SRobert Mustacchi 	    (I40E_INTR_NOTX_QUEUE << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
508da5577f0SRobert Mustacchi 	    (I40E_QUEUE_TYPE_TX << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
509da5577f0SRobert Mustacchi 
510da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE), reg);
511da5577f0SRobert Mustacchi 
512da5577f0SRobert Mustacchi 	reg = (I40E_INTR_NOTX_INTR << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
513da5577f0SRobert Mustacchi 	    (I40E_ITR_INDEX_TX << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
514da5577f0SRobert Mustacchi 	    (I40E_INTR_NOTX_TX_QUEUE << I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) |
515da5577f0SRobert Mustacchi 	    (I40E_QUEUE_TYPE_EOL << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) |
516da5577f0SRobert Mustacchi 	    (I40E_QUEUE_TYPE_RX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
517da5577f0SRobert Mustacchi 
518da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_QINT_TQCTL(I40E_INTR_NOTX_QUEUE), reg);
519da5577f0SRobert Mustacchi }
520da5577f0SRobert Mustacchi 
521da5577f0SRobert Mustacchi /*
522da5577f0SRobert Mustacchi  * Enable the specified queue as a valid source of interrupts. Note, this should
523da5577f0SRobert Mustacchi  * only be used as part of the GLDv3's interrupt blanking routines. The debug
524da5577f0SRobert Mustacchi  * build assertions are specific to that.
525da5577f0SRobert Mustacchi  */
526da5577f0SRobert Mustacchi void
5271b74b674SRobert Mustacchi i40e_intr_rx_queue_enable(i40e_trqpair_t *itrq)
528da5577f0SRobert Mustacchi {
529da5577f0SRobert Mustacchi 	uint32_t reg;
5301b74b674SRobert Mustacchi 	uint_t queue = itrq->itrq_index;
5311b74b674SRobert Mustacchi 	i40e_hw_t *hw = &itrq->itrq_i40e->i40e_hw_space;
532da5577f0SRobert Mustacchi 
5331b74b674SRobert Mustacchi 	ASSERT(MUTEX_HELD(&itrq->itrq_rx_lock));
5341b74b674SRobert Mustacchi 	ASSERT(queue < itrq->itrq_i40e->i40e_num_trqpairs);
535da5577f0SRobert Mustacchi 
536da5577f0SRobert Mustacchi 	reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(queue));
537da5577f0SRobert Mustacchi 	ASSERT0(reg & I40E_QINT_RQCTL_CAUSE_ENA_MASK);
538da5577f0SRobert Mustacchi 	reg |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
539da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg);
540da5577f0SRobert Mustacchi }
541da5577f0SRobert Mustacchi 
542da5577f0SRobert Mustacchi /*
543da5577f0SRobert Mustacchi  * Disable the specified queue as a valid source of interrupts. Note, this
544da5577f0SRobert Mustacchi  * should only be used as part of the GLDv3's interrupt blanking routines. The
545da5577f0SRobert Mustacchi  * debug build assertions are specific to that.
546da5577f0SRobert Mustacchi  */
547da5577f0SRobert Mustacchi void
5481b74b674SRobert Mustacchi i40e_intr_rx_queue_disable(i40e_trqpair_t *itrq)
549da5577f0SRobert Mustacchi {
550da5577f0SRobert Mustacchi 	uint32_t reg;
5511b74b674SRobert Mustacchi 	uint_t queue = itrq->itrq_index;
5521b74b674SRobert Mustacchi 	i40e_hw_t *hw = &itrq->itrq_i40e->i40e_hw_space;
553da5577f0SRobert Mustacchi 
5541b74b674SRobert Mustacchi 	ASSERT(MUTEX_HELD(&itrq->itrq_rx_lock));
5551b74b674SRobert Mustacchi 	ASSERT(queue < itrq->itrq_i40e->i40e_num_trqpairs);
556da5577f0SRobert Mustacchi 
557da5577f0SRobert Mustacchi 	reg = I40E_READ_REG(hw, I40E_QINT_RQCTL(queue));
558da5577f0SRobert Mustacchi 	ASSERT3U(reg & I40E_QINT_RQCTL_CAUSE_ENA_MASK, ==,
559da5577f0SRobert Mustacchi 	    I40E_QINT_RQCTL_CAUSE_ENA_MASK);
560da5577f0SRobert Mustacchi 	reg &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
561da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_QINT_RQCTL(queue), reg);
562da5577f0SRobert Mustacchi }
563da5577f0SRobert Mustacchi 
564da5577f0SRobert Mustacchi /*
565da5577f0SRobert Mustacchi  * Start up the various chip's interrupt handling. We not only configure the
566da5577f0SRobert Mustacchi  * adminq here, but we also go through and configure all of the actual queues,
567da5577f0SRobert Mustacchi  * the interrupt linked lists, and others.
568da5577f0SRobert Mustacchi  */
569da5577f0SRobert Mustacchi void
570da5577f0SRobert Mustacchi i40e_intr_chip_init(i40e_t *i40e)
571da5577f0SRobert Mustacchi {
572da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
573da5577f0SRobert Mustacchi 	uint32_t reg;
574da5577f0SRobert Mustacchi 
575da5577f0SRobert Mustacchi 	/*
576da5577f0SRobert Mustacchi 	 * Ensure that all non adminq interrupts are disabled at the chip level.
577da5577f0SRobert Mustacchi 	 */
578da5577f0SRobert Mustacchi 	i40e_intr_io_disable_all(i40e);
579da5577f0SRobert Mustacchi 
580da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, 0);
581da5577f0SRobert Mustacchi 	(void) I40E_READ_REG(hw, I40E_PFINT_ICR0);
582da5577f0SRobert Mustacchi 
583da5577f0SRobert Mustacchi 	/*
584da5577f0SRobert Mustacchi 	 * Always enable all of the other-class interrupts to be on their own
585da5577f0SRobert Mustacchi 	 * ITR. This only needs to be set on interrupt zero, which has its own
586da5577f0SRobert Mustacchi 	 * special setting.
587da5577f0SRobert Mustacchi 	 */
588da5577f0SRobert Mustacchi 	reg = I40E_ITR_INDEX_OTHER << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT;
589da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_STAT_CTL0, reg);
590da5577f0SRobert Mustacchi 
591da5577f0SRobert Mustacchi 	/*
592da5577f0SRobert Mustacchi 	 * Enable interrupt types we expect to receive. At the moment, this
593da5577f0SRobert Mustacchi 	 * is limited to the adminq; however, we'll want to review 11.2.2.9.22
594da5577f0SRobert Mustacchi 	 * for more types here as we add support for detecting them, handling
595da5577f0SRobert Mustacchi 	 * them, and resetting the device as appropriate.
596da5577f0SRobert Mustacchi 	 */
597da5577f0SRobert Mustacchi 	reg = I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
598da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, reg);
599da5577f0SRobert Mustacchi 
600da5577f0SRobert Mustacchi 	/*
601da5577f0SRobert Mustacchi 	 * Always set the interrupt linked list to empty. We'll come back and
602da5577f0SRobert Mustacchi 	 * change this if MSI-X are actually on the scene.
603da5577f0SRobert Mustacchi 	 */
604da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_TYPE_EOL);
605da5577f0SRobert Mustacchi 
606da5577f0SRobert Mustacchi 	i40e_intr_adminq_enable(i40e);
607da5577f0SRobert Mustacchi 
608da5577f0SRobert Mustacchi 	/*
609da5577f0SRobert Mustacchi 	 * Set up all of the queues and map them to interrupts based on the bit
610da5577f0SRobert Mustacchi 	 * assignments.
611da5577f0SRobert Mustacchi 	 */
612da5577f0SRobert Mustacchi 	if (i40e->i40e_intr_type == DDI_INTR_TYPE_MSIX) {
613da5577f0SRobert Mustacchi 		i40e_intr_init_queue_msix(i40e);
614da5577f0SRobert Mustacchi 	} else {
615da5577f0SRobert Mustacchi 		i40e_intr_init_queue_shared(i40e);
616da5577f0SRobert Mustacchi 	}
617da5577f0SRobert Mustacchi 
618da5577f0SRobert Mustacchi 	/*
619da5577f0SRobert Mustacchi 	 * Finally set all of the default ITRs for the interrupts. Note that the
620da5577f0SRobert Mustacchi 	 * queues will have been set up above.
621da5577f0SRobert Mustacchi 	 */
622da5577f0SRobert Mustacchi 	i40e_intr_set_itr(i40e, I40E_ITR_INDEX_RX, i40e->i40e_rx_itr);
623da5577f0SRobert Mustacchi 	i40e_intr_set_itr(i40e, I40E_ITR_INDEX_TX, i40e->i40e_tx_itr);
624da5577f0SRobert Mustacchi 	i40e_intr_set_itr(i40e, I40E_ITR_INDEX_OTHER, i40e->i40e_other_itr);
625da5577f0SRobert Mustacchi }
626da5577f0SRobert Mustacchi 
627da5577f0SRobert Mustacchi static void
628da5577f0SRobert Mustacchi i40e_intr_adminq_work(i40e_t *i40e)
629da5577f0SRobert Mustacchi {
630da5577f0SRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
631da5577f0SRobert Mustacchi 	struct i40e_arq_event_info evt;
632da5577f0SRobert Mustacchi 	uint16_t remain = 1;
633da5577f0SRobert Mustacchi 
634da5577f0SRobert Mustacchi 	bzero(&evt, sizeof (struct i40e_arq_event_info));
635da5577f0SRobert Mustacchi 	evt.buf_len = I40E_ADMINQ_BUFSZ;
636da5577f0SRobert Mustacchi 	evt.msg_buf = i40e->i40e_aqbuf;
637da5577f0SRobert Mustacchi 
638da5577f0SRobert Mustacchi 	while (remain != 0) {
639da5577f0SRobert Mustacchi 		enum i40e_status_code ret;
640da5577f0SRobert Mustacchi 		uint16_t opcode;
641da5577f0SRobert Mustacchi 
642da5577f0SRobert Mustacchi 		/*
643da5577f0SRobert Mustacchi 		 * At the moment, the only error code that seems to be returned
644da5577f0SRobert Mustacchi 		 * is one saying that there's no work. In such a case we leave
645da5577f0SRobert Mustacchi 		 * this be.
646da5577f0SRobert Mustacchi 		 */
647da5577f0SRobert Mustacchi 		ret = i40e_clean_arq_element(hw, &evt, &remain);
648da5577f0SRobert Mustacchi 		if (ret != I40E_SUCCESS)
649da5577f0SRobert Mustacchi 			break;
650da5577f0SRobert Mustacchi 
651da5577f0SRobert Mustacchi 		opcode = LE_16(evt.desc.opcode);
652da5577f0SRobert Mustacchi 		switch (opcode) {
653da5577f0SRobert Mustacchi 		case i40e_aqc_opc_get_link_status:
654da5577f0SRobert Mustacchi 			mutex_enter(&i40e->i40e_general_lock);
655da5577f0SRobert Mustacchi 			i40e_link_check(i40e);
656da5577f0SRobert Mustacchi 			mutex_exit(&i40e->i40e_general_lock);
657da5577f0SRobert Mustacchi 			break;
658da5577f0SRobert Mustacchi 		default:
659da5577f0SRobert Mustacchi 			/*
660da5577f0SRobert Mustacchi 			 * Longer term we'll want to enable other causes here
661da5577f0SRobert Mustacchi 			 * and get these cleaned up and doing something.
662da5577f0SRobert Mustacchi 			 */
663da5577f0SRobert Mustacchi 			break;
664da5577f0SRobert Mustacchi 		}
665da5577f0SRobert Mustacchi 	}
666da5577f0SRobert Mustacchi }
667da5577f0SRobert Mustacchi 
668da5577f0SRobert Mustacchi static void
6698d5069bcSRyan Zezeski i40e_intr_rx_work(i40e_t *i40e, i40e_trqpair_t *itrq)
670da5577f0SRobert Mustacchi {
67105768666SPaul Winder 	mblk_t *mp = NULL;
672da5577f0SRobert Mustacchi 
673da5577f0SRobert Mustacchi 	mutex_enter(&itrq->itrq_rx_lock);
67405768666SPaul Winder 	if (!itrq->itrq_intr_poll)
675da5577f0SRobert Mustacchi 		mp = i40e_ring_rx(itrq, I40E_POLL_NULL);
676da5577f0SRobert Mustacchi 	mutex_exit(&itrq->itrq_rx_lock);
677da5577f0SRobert Mustacchi 
6788d5069bcSRyan Zezeski 	if (mp == NULL)
6798d5069bcSRyan Zezeski 		return;
6808d5069bcSRyan Zezeski 
681da5577f0SRobert Mustacchi 	mac_rx_ring(i40e->i40e_mac_hdl, itrq->itrq_macrxring, mp,
682da5577f0SRobert Mustacchi 	    itrq->itrq_rxgen);
683da5577f0SRobert Mustacchi }
684da5577f0SRobert Mustacchi 
6858d5069bcSRyan Zezeski /* ARGSUSED */
686da5577f0SRobert Mustacchi static void
6878d5069bcSRyan Zezeski i40e_intr_tx_work(i40e_t *i40e, i40e_trqpair_t *itrq)
688da5577f0SRobert Mustacchi {
689da5577f0SRobert Mustacchi 	i40e_tx_recycle_ring(itrq);
690da5577f0SRobert Mustacchi }
691da5577f0SRobert Mustacchi 
692da5577f0SRobert Mustacchi /*
693da5577f0SRobert Mustacchi  * At the moment, the only 'other' interrupt on ICR0 that we handle is the
694da5577f0SRobert Mustacchi  * adminq. We should go through and support the other notifications at some
695da5577f0SRobert Mustacchi  * point.
696da5577f0SRobert Mustacchi  */
697da5577f0SRobert Mustacchi static void
698da5577f0SRobert Mustacchi i40e_intr_other_work(i40e_t *i40e)
699da5577f0SRobert Mustacchi {
700da5577f0SRobert Mustacchi 	struct i40e_hw *hw = &i40e->i40e_hw_space;
701da5577f0SRobert Mustacchi 	uint32_t reg;
702da5577f0SRobert Mustacchi 
703da5577f0SRobert Mustacchi 	reg = I40E_READ_REG(hw, I40E_PFINT_ICR0);
704da5577f0SRobert Mustacchi 	if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) !=
705da5577f0SRobert Mustacchi 	    DDI_FM_OK) {
706da5577f0SRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_DEGRADED);
707da5577f0SRobert Mustacchi 		atomic_or_32(&i40e->i40e_state, I40E_ERROR);
708da5577f0SRobert Mustacchi 		return;
709da5577f0SRobert Mustacchi 	}
710da5577f0SRobert Mustacchi 
711da5577f0SRobert Mustacchi 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
712da5577f0SRobert Mustacchi 		i40e_intr_adminq_work(i40e);
713da5577f0SRobert Mustacchi 
714da5577f0SRobert Mustacchi 	/*
715da5577f0SRobert Mustacchi 	 * Make sure that the adminq interrupt is not masked and then explicitly
716da5577f0SRobert Mustacchi 	 * enable the adminq and thus the other interrupt.
717da5577f0SRobert Mustacchi 	 */
718da5577f0SRobert Mustacchi 	reg = I40E_READ_REG(hw, I40E_PFINT_ICR0_ENA);
719da5577f0SRobert Mustacchi 	reg |= I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
720da5577f0SRobert Mustacchi 	I40E_WRITE_REG(hw, I40E_PFINT_ICR0_ENA, reg);
721da5577f0SRobert Mustacchi 
722da5577f0SRobert Mustacchi 	i40e_intr_adminq_enable(i40e);
723da5577f0SRobert Mustacchi }
724da5577f0SRobert Mustacchi 
7258d5069bcSRyan Zezeski /*
7268d5069bcSRyan Zezeski  * Handle an MSI-X interrupt. See section 7.5.1.3 for an overview of
7278d5069bcSRyan Zezeski  * the MSI-X interrupt sequence.
7288d5069bcSRyan Zezeski  */
729da5577f0SRobert Mustacchi uint_t
730da5577f0SRobert Mustacchi i40e_intr_msix(void *arg1, void *arg2)
731da5577f0SRobert Mustacchi {
732da5577f0SRobert Mustacchi 	i40e_t *i40e = (i40e_t *)arg1;
7338d5069bcSRyan Zezeski 	uint_t vector_idx = (uint_t)(uintptr_t)arg2;
7348d5069bcSRyan Zezeski 
7358d5069bcSRyan Zezeski 	ASSERT3U(vector_idx, <, i40e->i40e_intr_count);
736da5577f0SRobert Mustacchi 
737da5577f0SRobert Mustacchi 	/*
738da5577f0SRobert Mustacchi 	 * When using MSI-X interrupts, vector 0 is always reserved for the
739da5577f0SRobert Mustacchi 	 * adminq at this time. Though longer term, we'll want to also bridge
740da5577f0SRobert Mustacchi 	 * some I/O to them.
741da5577f0SRobert Mustacchi 	 */
742da5577f0SRobert Mustacchi 	if (vector_idx == 0) {
743da5577f0SRobert Mustacchi 		i40e_intr_other_work(i40e);
744da5577f0SRobert Mustacchi 		return (DDI_INTR_CLAIMED);
745da5577f0SRobert Mustacchi 	}
746da5577f0SRobert Mustacchi 
7478d5069bcSRyan Zezeski 	ASSERT3U(vector_idx, >, 0);
748da5577f0SRobert Mustacchi 
7498d5069bcSRyan Zezeski 	/*
7508d5069bcSRyan Zezeski 	 * We determine the queue indexes via simple arithmetic (as
7518d5069bcSRyan Zezeski 	 * opposed to keeping explicit state like a bitmap). While
7528d5069bcSRyan Zezeski 	 * conveinent, it does mean that i40e_map_intrs_to_vectors(),
7538d5069bcSRyan Zezeski 	 * i40e_intr_init_queue_msix(), and this function must be
7548d5069bcSRyan Zezeski 	 * modified as a unit.
7558d5069bcSRyan Zezeski 	 *
7568d5069bcSRyan Zezeski 	 * We subtract 1 from the vector to offset the addition we
7578d5069bcSRyan Zezeski 	 * performed during i40e_map_intrs_to_vectors().
7588d5069bcSRyan Zezeski 	 */
7598d5069bcSRyan Zezeski 	for (uint_t i = vector_idx - 1; i < i40e->i40e_num_trqpairs;
7608d5069bcSRyan Zezeski 	    i += (i40e->i40e_intr_count - 1)) {
7618d5069bcSRyan Zezeski 		i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[i];
7628d5069bcSRyan Zezeski 
7638d5069bcSRyan Zezeski 		ASSERT3U(i, <, i40e->i40e_num_trqpairs);
7648d5069bcSRyan Zezeski 		ASSERT3P(itrq, !=, NULL);
7658d5069bcSRyan Zezeski 		i40e_intr_rx_work(i40e, itrq);
7668d5069bcSRyan Zezeski 		i40e_intr_tx_work(i40e, itrq);
7678d5069bcSRyan Zezeski 	}
7688d5069bcSRyan Zezeski 
7698d5069bcSRyan Zezeski 	i40e_intr_io_enable(i40e, vector_idx);
770da5577f0SRobert Mustacchi 	return (DDI_INTR_CLAIMED);
771da5577f0SRobert Mustacchi }
772da5577f0SRobert Mustacchi 
773da5577f0SRobert Mustacchi static uint_t
774da5577f0SRobert Mustacchi i40e_intr_notx(i40e_t *i40e, boolean_t shared)
775da5577f0SRobert Mustacchi {
776da5577f0SRobert Mustacchi 	i40e_hw_t *hw = &i40e->i40e_hw_space;
777da5577f0SRobert Mustacchi 	uint32_t reg;
7788d5069bcSRyan Zezeski 	i40e_trqpair_t *itrq = &i40e->i40e_trqpairs[0];
779da5577f0SRobert Mustacchi 	int ret = DDI_INTR_CLAIMED;
780da5577f0SRobert Mustacchi 
781da5577f0SRobert Mustacchi 	if (shared == B_TRUE) {
782da5577f0SRobert Mustacchi 		mutex_enter(&i40e->i40e_general_lock);
783da5577f0SRobert Mustacchi 		if (i40e->i40e_state & I40E_SUSPENDED) {
784da5577f0SRobert Mustacchi 			mutex_exit(&i40e->i40e_general_lock);
785da5577f0SRobert Mustacchi 			return (DDI_INTR_UNCLAIMED);
786da5577f0SRobert Mustacchi 		}
787da5577f0SRobert Mustacchi 		mutex_exit(&i40e->i40e_general_lock);
788da5577f0SRobert Mustacchi 	}
789da5577f0SRobert Mustacchi 
790da5577f0SRobert Mustacchi 	reg = I40E_READ_REG(hw, I40E_PFINT_ICR0);
791da5577f0SRobert Mustacchi 	if (i40e_check_acc_handle(i40e->i40e_osdep_space.ios_reg_handle) !=
792da5577f0SRobert Mustacchi 	    DDI_FM_OK) {
793da5577f0SRobert Mustacchi 		ddi_fm_service_impact(i40e->i40e_dip, DDI_SERVICE_DEGRADED);
794da5577f0SRobert Mustacchi 		atomic_or_32(&i40e->i40e_state, I40E_ERROR);
795da5577f0SRobert Mustacchi 		return (DDI_INTR_CLAIMED);
796da5577f0SRobert Mustacchi 	}
797da5577f0SRobert Mustacchi 
798da5577f0SRobert Mustacchi 	if (reg == 0) {
799da5577f0SRobert Mustacchi 		if (shared == B_TRUE)
800da5577f0SRobert Mustacchi 			ret = DDI_INTR_UNCLAIMED;
801da5577f0SRobert Mustacchi 		goto done;
802da5577f0SRobert Mustacchi 	}
803da5577f0SRobert Mustacchi 
804da5577f0SRobert Mustacchi 	if (reg & I40E_PFINT_ICR0_ADMINQ_MASK)
805da5577f0SRobert Mustacchi 		i40e_intr_adminq_work(i40e);
806da5577f0SRobert Mustacchi 
807da5577f0SRobert Mustacchi 	if (reg & I40E_INTR_NOTX_RX_MASK)
8088d5069bcSRyan Zezeski 		i40e_intr_rx_work(i40e, itrq);
809da5577f0SRobert Mustacchi 
810da5577f0SRobert Mustacchi 	if (reg & I40E_INTR_NOTX_TX_MASK)
8118d5069bcSRyan Zezeski 		i40e_intr_tx_work(i40e, itrq);
812da5577f0SRobert Mustacchi 
813da5577f0SRobert Mustacchi done:
814da5577f0SRobert Mustacchi 	i40e_intr_adminq_enable(i40e);
815da5577f0SRobert Mustacchi 	return (ret);
816da5577f0SRobert Mustacchi 
817da5577f0SRobert Mustacchi }
818da5577f0SRobert Mustacchi 
819da5577f0SRobert Mustacchi /* ARGSUSED */
820da5577f0SRobert Mustacchi uint_t
821da5577f0SRobert Mustacchi i40e_intr_msi(void *arg1, void *arg2)
822da5577f0SRobert Mustacchi {
823da5577f0SRobert Mustacchi 	i40e_t *i40e = (i40e_t *)arg1;
824da5577f0SRobert Mustacchi 
825da5577f0SRobert Mustacchi 	return (i40e_intr_notx(i40e, B_FALSE));
826da5577f0SRobert Mustacchi }
827da5577f0SRobert Mustacchi 
828da5577f0SRobert Mustacchi /* ARGSUSED */
829da5577f0SRobert Mustacchi uint_t
830da5577f0SRobert Mustacchi i40e_intr_legacy(void *arg1, void *arg2)
831da5577f0SRobert Mustacchi {
832da5577f0SRobert Mustacchi 	i40e_t *i40e = (i40e_t *)arg1;
833da5577f0SRobert Mustacchi 
834da5577f0SRobert Mustacchi 	return (i40e_intr_notx(i40e, B_TRUE));
835da5577f0SRobert Mustacchi }
836