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 <sys/cdefs.h>
27__FBSDID("$FreeBSD$");
28
29#include "efsys.h"
30#include "efx.h"
31#include "efx_types.h"
32#include "efx_regs.h"
33#include "efx_impl.h"
34
35	__checkReturn	int
36efx_intr_init(
37	__in		efx_nic_t *enp,
38	__in		efx_intr_type_t type,
39	__in		efsys_mem_t *esmp)
40{
41	efx_intr_t *eip = &(enp->en_intr);
42	efx_oword_t oword;
43	int rc;
44
45	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
46	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
47
48	if (enp->en_mod_flags & EFX_MOD_INTR) {
49		rc = EINVAL;
50		goto fail1;
51	}
52
53	enp->en_mod_flags |= EFX_MOD_INTR;
54
55	eip->ei_type = type;
56	eip->ei_esmp = esmp;
57
58	/*
59	 * bug17213 workaround.
60	 *
61	 * Under legacy interrupts, don't share a level between fatal
62	 * interrupts and event queue interrupts. Under MSI-X, they
63	 * must share, or we won't get an interrupt.
64	 */
65	if (enp->en_family == EFX_FAMILY_SIENA &&
66	    eip->ei_type == EFX_INTR_LINE)
67		eip->ei_level = 0x1f;
68	else
69		eip->ei_level = 0;
70
71	/* Enable all the genuinely fatal interrupts */
72	EFX_SET_OWORD(oword);
73	EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
74	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
75	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
76	if (enp->en_family >= EFX_FAMILY_SIENA)
77		EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
78	EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
79
80	/* Set up the interrupt address register */
81	EFX_POPULATE_OWORD_3(oword,
82	    FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
83	    FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
84	    FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
85	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
86
87	return (0);
88
89fail1:
90	EFSYS_PROBE1(fail1, int, rc);
91
92	return (rc);
93}
94
95			void
96efx_intr_enable(
97	__in		efx_nic_t *enp)
98{
99	efx_intr_t *eip = &(enp->en_intr);
100	efx_oword_t oword;
101
102	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
103	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
104
105	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
106
107	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
108	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
109	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
110}
111
112			void
113efx_intr_disable(
114	__in		efx_nic_t *enp)
115{
116	efx_oword_t oword;
117
118	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
119	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
120
121	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
122	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
123	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
124
125	EFSYS_SPIN(10);
126}
127
128			void
129efx_intr_disable_unlocked(
130	__in		efx_nic_t *enp)
131{
132	efx_oword_t oword;
133
134	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
135	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
136
137	EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
138			&oword, B_FALSE);
139	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
140	EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
141	    &oword, B_FALSE);
142}
143
144	__checkReturn	int
145efx_intr_trigger(
146	__in		efx_nic_t *enp,
147	__in		unsigned int level)
148{
149	efx_intr_t *eip = &(enp->en_intr);
150	efx_oword_t oword;
151	unsigned int count;
152	uint32_t sel;
153	int rc;
154
155	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
156	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
157
158	/* bug16757: No event queues can be initialized */
159	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
160
161	switch (enp->en_family) {
162	case EFX_FAMILY_FALCON:
163		if (level > EFX_NINTR_FALCON) {
164			rc = EINVAL;
165			goto fail1;
166		}
167		break;
168
169	case EFX_FAMILY_SIENA:
170		if (level > EFX_NINTR_SIENA) {
171			rc = EINVAL;
172			goto fail1;
173		}
174		break;
175
176	default:
177		EFSYS_ASSERT(B_FALSE);
178		break;
179	}
180
181	if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
182		return (ENOTSUP); /* avoid EFSYS_PROBE() */
183
184	sel = level;
185
186	/* Trigger a test interrupt */
187	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
188	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
189	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
190	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
191
192	/*
193	 * Wait up to 100ms for the interrupt to be raised before restoring
194	 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
195	 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
196	 */
197	count = 0;
198	do {
199		EFSYS_SPIN(100);	/* 100us */
200
201		EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
202	} while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
203
204	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
205	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
206
207	return (0);
208
209fail1:
210	EFSYS_PROBE1(fail1, int, rc);
211
212	return (rc);
213}
214
215static	__checkReturn	boolean_t
216efx_intr_check_fatal(
217	__in		efx_nic_t *enp)
218{
219	efx_intr_t *eip = &(enp->en_intr);
220	efsys_mem_t *esmp = eip->ei_esmp;
221	efx_oword_t oword;
222
223	/* Read the syndrome */
224	EFSYS_MEM_READO(esmp, 0, &oword);
225
226	if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
227		EFSYS_PROBE(fatal);
228
229		/* Clear the fatal interrupt condition */
230		EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
231		EFSYS_MEM_WRITEO(esmp, 0, &oword);
232
233		return (B_TRUE);
234	}
235
236	return (B_FALSE);
237}
238
239			void
240efx_intr_status_line(
241	__in		efx_nic_t *enp,
242	__out		boolean_t *fatalp,
243	__out		uint32_t *qmaskp)
244{
245	efx_intr_t *eip = &(enp->en_intr);
246	efx_dword_t dword;
247
248	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
249	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
250
251	/*
252	 * Read the queue mask and implicitly acknowledge the
253	 * interrupt.
254	 */
255	EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
256	*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
257
258	EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
259
260	if (*qmaskp & (1U << eip->ei_level))
261		*fatalp = efx_intr_check_fatal(enp);
262	else
263		*fatalp = B_FALSE;
264}
265
266			void
267efx_intr_status_message(
268	__in		efx_nic_t *enp,
269	__in		unsigned int message,
270	__out		boolean_t *fatalp)
271{
272	efx_intr_t *eip = &(enp->en_intr);
273
274	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
275	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
276
277	if (message == eip->ei_level)
278		*fatalp = efx_intr_check_fatal(enp);
279	else
280		*fatalp = B_FALSE;
281}
282
283		void
284efx_intr_fatal(
285	__in	efx_nic_t *enp)
286{
287#if EFSYS_OPT_DECODE_INTR_FATAL
288	efx_oword_t fatal;
289	efx_oword_t mem_per;
290
291	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
292	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
293
294	EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
295	EFX_ZERO_OWORD(mem_per);
296
297	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
298	    EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
299		EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
300
301	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
302		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
303
304	if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
305		EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
306
307	if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
308		EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
309		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
310		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
311
312	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
313		EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
314
315	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
316		EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
317
318	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
319		EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
320
321	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
322		EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
323
324	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
325		EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
326
327	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
328		EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
329
330	if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
331		EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
332
333	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
334		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
335		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
336		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
337#else
338	EFSYS_ASSERT(0);
339#endif
340}
341
342		void
343efx_intr_fini(
344	__in	efx_nic_t *enp)
345{
346	efx_oword_t oword;
347
348	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
349	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
350	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
351
352	/* Clear the interrupt address register */
353	EFX_ZERO_OWORD(oword);
354	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
355
356	enp->en_mod_flags &= ~EFX_MOD_INTR;
357}
358