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
33efx_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
86fail1:
87	EFSYS_PROBE1(fail1, int, rc);
88
89	return (rc);
90}
91
92			void
93efx_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
110efx_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
126efx_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
142efx_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
206fail1:
207	EFSYS_PROBE1(fail1, int, rc);
208
209	return (rc);
210}
211
212static	__checkReturn	boolean_t
213efx_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
237efx_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
264efx_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
281efx_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
340efx_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