xref: /freebsd/sys/dev/sfxge/common/efx_intr.c (revision 10b59a9b4add0320d52c15ce057dd697261e7dfc)
1 /*-
2  * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25 
26 #include "efsys.h"
27 #include "efx.h"
28 #include "efx_types.h"
29 #include "efx_regs.h"
30 #include "efx_impl.h"
31 
32 	__checkReturn	int
33 efx_intr_init(
34 	__in		efx_nic_t *enp,
35 	__in		efx_intr_type_t type,
36 	__in		efsys_mem_t *esmp)
37 {
38 	efx_intr_t *eip = &(enp->en_intr);
39 	efx_oword_t oword;
40 	int rc;
41 
42 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
43 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
44 
45 	if (enp->en_mod_flags & EFX_MOD_INTR) {
46 		rc = EINVAL;
47 		goto fail1;
48 	}
49 
50 	enp->en_mod_flags |= EFX_MOD_INTR;
51 
52 	eip->ei_type = type;
53 	eip->ei_esmp = esmp;
54 
55 	/*
56 	 * bug17213 workaround.
57 	 *
58 	 * Under legacy interrupts, don't share a level between fatal
59 	 * interrupts and event queue interrupts. Under MSI-X, they
60 	 * must share, or we won't get an interrupt.
61 	 */
62 	if (enp->en_family == EFX_FAMILY_SIENA &&
63 	    eip->ei_type == EFX_INTR_LINE)
64 		eip->ei_level = 0x1f;
65 	else
66 		eip->ei_level = 0;
67 
68 	/* Enable all the genuinely fatal interrupts */
69 	EFX_SET_OWORD(oword);
70 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
71 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
72 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
73 	if (enp->en_family >= EFX_FAMILY_SIENA)
74 		EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
75 	EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
76 
77 	/* Set up the interrupt address register */
78 	EFX_POPULATE_OWORD_3(oword,
79 	    FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
80 	    FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
81 	    FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
82 	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
83 
84 	return (0);
85 
86 fail1:
87 	EFSYS_PROBE1(fail1, int, rc);
88 
89 	return (rc);
90 }
91 
92 			void
93 efx_intr_enable(
94 	__in		efx_nic_t *enp)
95 {
96 	efx_intr_t *eip = &(enp->en_intr);
97 	efx_oword_t oword;
98 
99 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
100 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
101 
102 	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
103 
104 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
105 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
106 	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
107 }
108 
109 			void
110 efx_intr_disable(
111 	__in		efx_nic_t *enp)
112 {
113 	efx_oword_t oword;
114 
115 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
116 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
117 
118 	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
119 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
120 	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
121 
122 	EFSYS_SPIN(10);
123 }
124 
125 			void
126 efx_intr_disable_unlocked(
127 	__in		efx_nic_t *enp)
128 {
129 	efx_oword_t oword;
130 
131 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
132 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
133 
134 	EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
135 			&oword, B_FALSE);
136 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
137 	EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
138 	    &oword, B_FALSE);
139 }
140 
141 	__checkReturn	int
142 efx_intr_trigger(
143 	__in		efx_nic_t *enp,
144 	__in		unsigned int level)
145 {
146 	efx_intr_t *eip = &(enp->en_intr);
147 	efx_oword_t oword;
148 	unsigned int count;
149 	uint32_t sel;
150 	int rc;
151 
152 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
153 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
154 
155 	/* bug16757: No event queues can be initialized */
156 	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
157 
158 	switch (enp->en_family) {
159 	case EFX_FAMILY_FALCON:
160 		if (level > EFX_NINTR_FALCON) {
161 			rc = EINVAL;
162 			goto fail1;
163 		}
164 		break;
165 
166 	case EFX_FAMILY_SIENA:
167 		if (level > EFX_NINTR_SIENA) {
168 			rc = EINVAL;
169 			goto fail1;
170 		}
171 		break;
172 
173 	default:
174 		EFSYS_ASSERT(B_FALSE);
175 		break;
176 	}
177 
178 	if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
179 		return (ENOTSUP); /* avoid EFSYS_PROBE() */
180 
181 	sel = level;
182 
183 	/* Trigger a test interrupt */
184 	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
185 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
186 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
187 	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
188 
189 	/*
190 	 * Wait up to 100ms for the interrupt to be raised before restoring
191 	 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
192 	 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
193 	 */
194 	count = 0;
195 	do {
196 		EFSYS_SPIN(100);	/* 100us */
197 
198 		EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
199 	} while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
200 
201 	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
202 	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
203 
204 	return (0);
205 
206 fail1:
207 	EFSYS_PROBE1(fail1, int, rc);
208 
209 	return (rc);
210 }
211 
212 static	__checkReturn	boolean_t
213 efx_intr_check_fatal(
214 	__in		efx_nic_t *enp)
215 {
216 	efx_intr_t *eip = &(enp->en_intr);
217 	efsys_mem_t *esmp = eip->ei_esmp;
218 	efx_oword_t oword;
219 
220 	/* Read the syndrome */
221 	EFSYS_MEM_READO(esmp, 0, &oword);
222 
223 	if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
224 		EFSYS_PROBE(fatal);
225 
226 		/* Clear the fatal interrupt condition */
227 		EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
228 		EFSYS_MEM_WRITEO(esmp, 0, &oword);
229 
230 		return (B_TRUE);
231 	}
232 
233 	return (B_FALSE);
234 }
235 
236 			void
237 efx_intr_status_line(
238 	__in		efx_nic_t *enp,
239 	__out		boolean_t *fatalp,
240 	__out		uint32_t *qmaskp)
241 {
242 	efx_intr_t *eip = &(enp->en_intr);
243 	efx_dword_t dword;
244 
245 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
246 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
247 
248 	/*
249 	 * Read the queue mask and implicitly acknowledge the
250 	 * interrupt.
251 	 */
252 	EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
253 	*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
254 
255 	EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
256 
257 	if (*qmaskp & (1U << eip->ei_level))
258 		*fatalp = efx_intr_check_fatal(enp);
259 	else
260 		*fatalp = B_FALSE;
261 }
262 
263 			void
264 efx_intr_status_message(
265 	__in		efx_nic_t *enp,
266 	__in		unsigned int message,
267 	__out		boolean_t *fatalp)
268 {
269 	efx_intr_t *eip = &(enp->en_intr);
270 
271 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
272 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
273 
274 	if (message == eip->ei_level)
275 		*fatalp = efx_intr_check_fatal(enp);
276 	else
277 		*fatalp = B_FALSE;
278 }
279 
280 		void
281 efx_intr_fatal(
282 	__in	efx_nic_t *enp)
283 {
284 #if EFSYS_OPT_DECODE_INTR_FATAL
285 	efx_oword_t fatal;
286 	efx_oword_t mem_per;
287 
288 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
289 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
290 
291 	EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
292 	EFX_ZERO_OWORD(mem_per);
293 
294 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
295 	    EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
296 		EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
297 
298 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
299 		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
300 
301 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
302 		EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
303 
304 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
305 		EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
306 		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
307 		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
308 
309 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
310 		EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
311 
312 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
313 		EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
314 
315 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
316 		EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
317 
318 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
319 		EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
320 
321 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
322 		EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
323 
324 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
325 		EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
326 
327 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
328 		EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
329 
330 	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
331 		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
332 		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
333 		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
334 #else
335 	EFSYS_ASSERT(0);
336 #endif
337 }
338 
339 		void
340 efx_intr_fini(
341 	__in	efx_nic_t *enp)
342 {
343 	efx_oword_t oword;
344 
345 	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
346 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
347 	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
348 
349 	/* Clear the interrupt address register */
350 	EFX_ZERO_OWORD(oword);
351 	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
352 
353 	enp->en_mod_flags &= ~EFX_MOD_INTR;
354 }
355