efx_intr.c revision 293769
1227569Sphilip/*-
2283514Sarybchik * Copyright (c) 2007-2015 Solarflare Communications Inc.
3283514Sarybchik * All rights reserved.
4227569Sphilip *
5227569Sphilip * Redistribution and use in source and binary forms, with or without
6283514Sarybchik * modification, are permitted provided that the following conditions are met:
7227569Sphilip *
8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice,
9283514Sarybchik *    this list of conditions and the following disclaimer.
10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice,
11283514Sarybchik *    this list of conditions and the following disclaimer in the documentation
12283514Sarybchik *    and/or other materials provided with the distribution.
13283514Sarybchik *
14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25283514Sarybchik *
26283514Sarybchik * The views and conclusions contained in the software and documentation are
27283514Sarybchik * those of the authors and should not be interpreted as representing official
28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project.
29227569Sphilip */
30227569Sphilip
31228078Sphilip#include <sys/cdefs.h>
32228078Sphilip__FBSDID("$FreeBSD: head/sys/dev/sfxge/common/efx_intr.c 293769 2016-01-12 15:28:59Z arybchik $");
33228078Sphilip
34227569Sphilip#include "efsys.h"
35227569Sphilip#include "efx.h"
36227569Sphilip#include "efx_types.h"
37227569Sphilip#include "efx_regs.h"
38227569Sphilip#include "efx_impl.h"
39227569Sphilip
40283514Sarybchik
41283514Sarybchik#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
42283514Sarybchik
43291436Sarybchikstatic	__checkReturn	efx_rc_t
44283514Sarybchikfalconsiena_intr_init(
45283514Sarybchik	__in		efx_nic_t *enp,
46283514Sarybchik	__in		efx_intr_type_t type,
47283514Sarybchik	__in		efsys_mem_t *esmp);
48283514Sarybchik
49283514Sarybchikstatic			void
50283514Sarybchikfalconsiena_intr_enable(
51283514Sarybchik	__in		efx_nic_t *enp);
52283514Sarybchik
53283514Sarybchikstatic			void
54283514Sarybchikfalconsiena_intr_disable(
55283514Sarybchik	__in		efx_nic_t *enp);
56283514Sarybchik
57283514Sarybchikstatic			void
58283514Sarybchikfalconsiena_intr_disable_unlocked(
59283514Sarybchik	__in		efx_nic_t *enp);
60283514Sarybchik
61291436Sarybchikstatic	__checkReturn	efx_rc_t
62283514Sarybchikfalconsiena_intr_trigger(
63283514Sarybchik	__in		efx_nic_t *enp,
64283514Sarybchik	__in		unsigned int level);
65283514Sarybchik
66283514Sarybchikstatic			void
67283514Sarybchikfalconsiena_intr_fini(
68283514Sarybchik	__in		efx_nic_t *enp);
69283514Sarybchik
70293769Sarybchikstatic			void
71293769Sarybchikfalconsiena_intr_status_line(
72293769Sarybchik	__in		efx_nic_t *enp,
73293769Sarybchik	__out		boolean_t *fatalp,
74293769Sarybchik	__out		uint32_t *qmaskp);
75283514Sarybchik
76293769Sarybchikstatic			void
77293769Sarybchikfalconsiena_intr_status_message(
78293769Sarybchik	__in		efx_nic_t *enp,
79293769Sarybchik	__in		unsigned int message,
80293769Sarybchik	__out		boolean_t *fatalp);
81283514Sarybchik
82283514Sarybchikstatic			void
83283514Sarybchikfalconsiena_intr_fatal(
84283514Sarybchik	__in		efx_nic_t *enp);
85283514Sarybchik
86293769Sarybchikstatic	__checkReturn	boolean_t
87293769Sarybchikfalconsiena_intr_check_fatal(
88293769Sarybchik	__in		efx_nic_t *enp);
89293769Sarybchik
90293769Sarybchik
91283514Sarybchik#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
92283514Sarybchik
93283514Sarybchik
94283514Sarybchik#if EFSYS_OPT_FALCON
95283514Sarybchikstatic efx_intr_ops_t	__efx_intr_falcon_ops = {
96283514Sarybchik	falconsiena_intr_init,			/* eio_init */
97283514Sarybchik	falconsiena_intr_enable,		/* eio_enable */
98283514Sarybchik	falconsiena_intr_disable,		/* eio_disable */
99283514Sarybchik	falconsiena_intr_disable_unlocked,	/* eio_disable_unlocked */
100283514Sarybchik	falconsiena_intr_trigger,		/* eio_trigger */
101293769Sarybchik	falconsiena_intr_status_line,		/* eio_status_line */
102293769Sarybchik	falconsiena_intr_status_message,	/* eio_status_message */
103293769Sarybchik	falconsiena_intr_fatal,			/* eio_fatal */
104283514Sarybchik	falconsiena_intr_fini,			/* eio_fini */
105283514Sarybchik};
106283514Sarybchik#endif	/* EFSYS_OPT_FALCON */
107283514Sarybchik
108283514Sarybchik#if EFSYS_OPT_SIENA
109283514Sarybchikstatic efx_intr_ops_t	__efx_intr_siena_ops = {
110283514Sarybchik	falconsiena_intr_init,			/* eio_init */
111283514Sarybchik	falconsiena_intr_enable,		/* eio_enable */
112283514Sarybchik	falconsiena_intr_disable,		/* eio_disable */
113283514Sarybchik	falconsiena_intr_disable_unlocked,	/* eio_disable_unlocked */
114283514Sarybchik	falconsiena_intr_trigger,		/* eio_trigger */
115293769Sarybchik	falconsiena_intr_status_line,		/* eio_status_line */
116293769Sarybchik	falconsiena_intr_status_message,	/* eio_status_message */
117293769Sarybchik	falconsiena_intr_fatal,			/* eio_fatal */
118283514Sarybchik	falconsiena_intr_fini,			/* eio_fini */
119283514Sarybchik};
120283514Sarybchik#endif	/* EFSYS_OPT_SIENA */
121283514Sarybchik
122293751Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
123293751Sarybchikstatic efx_intr_ops_t	__efx_intr_ef10_ops = {
124293751Sarybchik	ef10_intr_init,			/* eio_init */
125293751Sarybchik	ef10_intr_enable,		/* eio_enable */
126293751Sarybchik	ef10_intr_disable,		/* eio_disable */
127293751Sarybchik	ef10_intr_disable_unlocked,	/* eio_disable_unlocked */
128293751Sarybchik	ef10_intr_trigger,		/* eio_trigger */
129293769Sarybchik	ef10_intr_status_line,		/* eio_status_line */
130293769Sarybchik	ef10_intr_status_message,	/* eio_status_message */
131293769Sarybchik	ef10_intr_fatal,		/* eio_fatal */
132293751Sarybchik	ef10_intr_fini,			/* eio_fini */
133283514Sarybchik};
134293751Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
135283514Sarybchik
136291436Sarybchik	__checkReturn	efx_rc_t
137227569Sphilipefx_intr_init(
138227569Sphilip	__in		efx_nic_t *enp,
139227569Sphilip	__in		efx_intr_type_t type,
140227569Sphilip	__in		efsys_mem_t *esmp)
141227569Sphilip{
142227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
143283514Sarybchik	efx_intr_ops_t *eiop;
144291436Sarybchik	efx_rc_t rc;
145227569Sphilip
146227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
147227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
148227569Sphilip
149227569Sphilip	if (enp->en_mod_flags & EFX_MOD_INTR) {
150227569Sphilip		rc = EINVAL;
151227569Sphilip		goto fail1;
152227569Sphilip	}
153227569Sphilip
154283514Sarybchik	eip->ei_esmp = esmp;
155283514Sarybchik	eip->ei_type = type;
156283514Sarybchik	eip->ei_level = 0;
157283514Sarybchik
158227569Sphilip	enp->en_mod_flags |= EFX_MOD_INTR;
159227569Sphilip
160283514Sarybchik	switch (enp->en_family) {
161283514Sarybchik#if EFSYS_OPT_FALCON
162283514Sarybchik	case EFX_FAMILY_FALCON:
163283514Sarybchik		eiop = (efx_intr_ops_t *)&__efx_intr_falcon_ops;
164283514Sarybchik		break;
165283514Sarybchik#endif	/* EFSYS_OPT_FALCON */
166227569Sphilip
167283514Sarybchik#if EFSYS_OPT_SIENA
168283514Sarybchik	case EFX_FAMILY_SIENA:
169283514Sarybchik		eiop = (efx_intr_ops_t *)&__efx_intr_siena_ops;
170283514Sarybchik		break;
171283514Sarybchik#endif	/* EFSYS_OPT_SIENA */
172283514Sarybchik
173283514Sarybchik#if EFSYS_OPT_HUNTINGTON
174283514Sarybchik	case EFX_FAMILY_HUNTINGTON:
175293751Sarybchik		eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops;
176283514Sarybchik		break;
177283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
178283514Sarybchik
179293751Sarybchik#if EFSYS_OPT_MEDFORD
180293751Sarybchik	case EFX_FAMILY_MEDFORD:
181293751Sarybchik		eiop = (efx_intr_ops_t *)&__efx_intr_ef10_ops;
182293751Sarybchik		break;
183293751Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
184293751Sarybchik
185283514Sarybchik	default:
186283514Sarybchik		EFSYS_ASSERT(B_FALSE);
187283514Sarybchik		rc = ENOTSUP;
188283514Sarybchik		goto fail2;
189283514Sarybchik	}
190283514Sarybchik
191283514Sarybchik	if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
192283514Sarybchik		goto fail3;
193283514Sarybchik
194283514Sarybchik	eip->ei_eiop = eiop;
195283514Sarybchik
196283514Sarybchik	return (0);
197283514Sarybchik
198283514Sarybchikfail3:
199283514Sarybchik	EFSYS_PROBE(fail3);
200283514Sarybchikfail2:
201283514Sarybchik	EFSYS_PROBE(fail2);
202283514Sarybchikfail1:
203291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
204283514Sarybchik
205283514Sarybchik	return (rc);
206283514Sarybchik}
207283514Sarybchik
208283514Sarybchik		void
209283514Sarybchikefx_intr_fini(
210283514Sarybchik	__in	efx_nic_t *enp)
211283514Sarybchik{
212283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
213283514Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
214283514Sarybchik
215283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
216283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
217283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
218283514Sarybchik
219283514Sarybchik	eiop->eio_fini(enp);
220283514Sarybchik
221283514Sarybchik	enp->en_mod_flags &= ~EFX_MOD_INTR;
222283514Sarybchik}
223283514Sarybchik
224283514Sarybchik			void
225283514Sarybchikefx_intr_enable(
226283514Sarybchik	__in		efx_nic_t *enp)
227283514Sarybchik{
228283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
229283514Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
230283514Sarybchik
231283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
232283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
233283514Sarybchik
234283514Sarybchik	eiop->eio_enable(enp);
235283514Sarybchik}
236283514Sarybchik
237283514Sarybchik			void
238283514Sarybchikefx_intr_disable(
239283514Sarybchik	__in		efx_nic_t *enp)
240283514Sarybchik{
241283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
242283514Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
243283514Sarybchik
244283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
245283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
246283514Sarybchik
247283514Sarybchik	eiop->eio_disable(enp);
248283514Sarybchik}
249283514Sarybchik
250283514Sarybchik			void
251283514Sarybchikefx_intr_disable_unlocked(
252283514Sarybchik	__in		efx_nic_t *enp)
253283514Sarybchik{
254283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
255283514Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
256283514Sarybchik
257283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
258283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
259283514Sarybchik
260283514Sarybchik	eiop->eio_disable_unlocked(enp);
261283514Sarybchik}
262283514Sarybchik
263283514Sarybchik
264291436Sarybchik	__checkReturn	efx_rc_t
265283514Sarybchikefx_intr_trigger(
266283514Sarybchik	__in		efx_nic_t *enp,
267283514Sarybchik	__in		unsigned int level)
268283514Sarybchik{
269283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
270283514Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
271283514Sarybchik
272283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
273283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
274283514Sarybchik
275283514Sarybchik	return (eiop->eio_trigger(enp, level));
276283514Sarybchik}
277283514Sarybchik
278283514Sarybchik			void
279283514Sarybchikefx_intr_status_line(
280283514Sarybchik	__in		efx_nic_t *enp,
281283514Sarybchik	__out		boolean_t *fatalp,
282283514Sarybchik	__out		uint32_t *qmaskp)
283283514Sarybchik{
284283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
285293769Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
286283514Sarybchik
287283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
288283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
289283514Sarybchik
290293769Sarybchik	eiop->eio_status_line(enp, fatalp, qmaskp);
291283514Sarybchik}
292283514Sarybchik
293283514Sarybchik			void
294283514Sarybchikefx_intr_status_message(
295283514Sarybchik	__in		efx_nic_t *enp,
296283514Sarybchik	__in		unsigned int message,
297283514Sarybchik	__out		boolean_t *fatalp)
298283514Sarybchik{
299283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
300293769Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
301283514Sarybchik
302283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
303283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
304283514Sarybchik
305293769Sarybchik	eiop->eio_status_message(enp, message, fatalp);
306283514Sarybchik}
307283514Sarybchik
308283514Sarybchik		void
309283514Sarybchikefx_intr_fatal(
310283514Sarybchik	__in	efx_nic_t *enp)
311283514Sarybchik{
312293769Sarybchik	efx_intr_t *eip = &(enp->en_intr);
313293769Sarybchik	efx_intr_ops_t *eiop = eip->ei_eiop;
314293769Sarybchik
315283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
316283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
317283514Sarybchik
318293769Sarybchik	eiop->eio_fatal(enp);
319283514Sarybchik}
320283514Sarybchik
321283514Sarybchik
322283514Sarybchik/* ************************************************************************* */
323283514Sarybchik/* ************************************************************************* */
324283514Sarybchik/* ************************************************************************* */
325283514Sarybchik
326283514Sarybchik#if EFSYS_OPT_FALCON || EFSYS_OPT_SIENA
327283514Sarybchik
328291436Sarybchikstatic	__checkReturn	efx_rc_t
329283514Sarybchikfalconsiena_intr_init(
330283514Sarybchik	__in		efx_nic_t *enp,
331283514Sarybchik	__in		efx_intr_type_t type,
332283514Sarybchik	__in		efsys_mem_t *esmp)
333283514Sarybchik{
334283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
335283514Sarybchik	efx_oword_t oword;
336283514Sarybchik
337283514Sarybchik	/*
338227569Sphilip	 * bug17213 workaround.
339227569Sphilip	 *
340227569Sphilip	 * Under legacy interrupts, don't share a level between fatal
341227569Sphilip	 * interrupts and event queue interrupts. Under MSI-X, they
342227569Sphilip	 * must share, or we won't get an interrupt.
343227569Sphilip	 */
344227569Sphilip	if (enp->en_family == EFX_FAMILY_SIENA &&
345227569Sphilip	    eip->ei_type == EFX_INTR_LINE)
346227569Sphilip		eip->ei_level = 0x1f;
347227569Sphilip	else
348227569Sphilip		eip->ei_level = 0;
349227569Sphilip
350227569Sphilip	/* Enable all the genuinely fatal interrupts */
351227569Sphilip	EFX_SET_OWORD(oword);
352227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
353227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
354227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
355227569Sphilip	if (enp->en_family >= EFX_FAMILY_SIENA)
356227569Sphilip		EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
357227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
358227569Sphilip
359227569Sphilip	/* Set up the interrupt address register */
360227569Sphilip	EFX_POPULATE_OWORD_3(oword,
361227569Sphilip	    FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
362227569Sphilip	    FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
363227569Sphilip	    FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
364227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
365227569Sphilip
366227569Sphilip	return (0);
367227569Sphilip}
368227569Sphilip
369283514Sarybchikstatic			void
370283514Sarybchikfalconsiena_intr_enable(
371227569Sphilip	__in		efx_nic_t *enp)
372227569Sphilip{
373227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
374227569Sphilip	efx_oword_t oword;
375227569Sphilip
376227569Sphilip	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
377227569Sphilip
378227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
379227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
380227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
381227569Sphilip}
382227569Sphilip
383283514Sarybchikstatic			void
384283514Sarybchikfalconsiena_intr_disable(
385227569Sphilip	__in		efx_nic_t *enp)
386227569Sphilip{
387227569Sphilip	efx_oword_t oword;
388227569Sphilip
389227569Sphilip	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
390227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
391227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
392227569Sphilip
393227569Sphilip	EFSYS_SPIN(10);
394227569Sphilip}
395227569Sphilip
396283514Sarybchikstatic			void
397283514Sarybchikfalconsiena_intr_disable_unlocked(
398227569Sphilip	__in		efx_nic_t *enp)
399227569Sphilip{
400227569Sphilip	efx_oword_t oword;
401227569Sphilip
402227569Sphilip	EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
403227569Sphilip			&oword, B_FALSE);
404227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
405227569Sphilip	EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
406227569Sphilip	    &oword, B_FALSE);
407227569Sphilip}
408227569Sphilip
409291436Sarybchikstatic	__checkReturn	efx_rc_t
410283514Sarybchikfalconsiena_intr_trigger(
411227569Sphilip	__in		efx_nic_t *enp,
412227569Sphilip	__in		unsigned int level)
413227569Sphilip{
414227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
415227569Sphilip	efx_oword_t oword;
416227569Sphilip	unsigned int count;
417227569Sphilip	uint32_t sel;
418291436Sarybchik	efx_rc_t rc;
419227569Sphilip
420227569Sphilip	/* bug16757: No event queues can be initialized */
421227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
422227569Sphilip
423227569Sphilip	switch (enp->en_family) {
424227569Sphilip	case EFX_FAMILY_FALCON:
425283514Sarybchik		if (level >= EFX_NINTR_FALCON) {
426227569Sphilip			rc = EINVAL;
427227569Sphilip			goto fail1;
428227569Sphilip		}
429227569Sphilip		break;
430227569Sphilip
431227569Sphilip	case EFX_FAMILY_SIENA:
432283514Sarybchik		if (level >= EFX_NINTR_SIENA) {
433227569Sphilip			rc = EINVAL;
434227569Sphilip			goto fail1;
435227569Sphilip		}
436227569Sphilip		break;
437227569Sphilip
438227569Sphilip	default:
439227569Sphilip		EFSYS_ASSERT(B_FALSE);
440227569Sphilip		break;
441227569Sphilip	}
442227569Sphilip
443227569Sphilip	if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
444227569Sphilip		return (ENOTSUP); /* avoid EFSYS_PROBE() */
445227569Sphilip
446227569Sphilip	sel = level;
447227569Sphilip
448227569Sphilip	/* Trigger a test interrupt */
449227569Sphilip	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
450227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
451227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
452227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
453227569Sphilip
454227569Sphilip	/*
455227569Sphilip	 * Wait up to 100ms for the interrupt to be raised before restoring
456227569Sphilip	 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
457227569Sphilip	 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
458227569Sphilip	 */
459227569Sphilip	count = 0;
460227569Sphilip	do {
461227569Sphilip		EFSYS_SPIN(100);	/* 100us */
462227569Sphilip
463227569Sphilip		EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
464227569Sphilip	} while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
465227569Sphilip
466227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
467227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
468227569Sphilip
469227569Sphilip	return (0);
470227569Sphilip
471227569Sphilipfail1:
472291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
473227569Sphilip
474227569Sphilip	return (rc);
475227569Sphilip}
476227569Sphilip
477227569Sphilipstatic	__checkReturn	boolean_t
478283514Sarybchikfalconsiena_intr_check_fatal(
479227569Sphilip	__in		efx_nic_t *enp)
480227569Sphilip{
481227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
482227569Sphilip	efsys_mem_t *esmp = eip->ei_esmp;
483227569Sphilip	efx_oword_t oword;
484227569Sphilip
485227569Sphilip	/* Read the syndrome */
486227569Sphilip	EFSYS_MEM_READO(esmp, 0, &oword);
487227569Sphilip
488227569Sphilip	if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
489227569Sphilip		EFSYS_PROBE(fatal);
490227569Sphilip
491227569Sphilip		/* Clear the fatal interrupt condition */
492227569Sphilip		EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
493227569Sphilip		EFSYS_MEM_WRITEO(esmp, 0, &oword);
494227569Sphilip
495227569Sphilip		return (B_TRUE);
496227569Sphilip	}
497227569Sphilip
498227569Sphilip	return (B_FALSE);
499227569Sphilip}
500227569Sphilip
501293769Sarybchikstatic			void
502293769Sarybchikfalconsiena_intr_status_line(
503293769Sarybchik	__in		efx_nic_t *enp,
504293769Sarybchik	__out		boolean_t *fatalp,
505293769Sarybchik	__out		uint32_t *qmaskp)
506293769Sarybchik{
507293769Sarybchik	efx_intr_t *eip = &(enp->en_intr);
508293769Sarybchik	efx_dword_t dword;
509293769Sarybchik
510293769Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
511293769Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
512293769Sarybchik
513293769Sarybchik	/*
514293769Sarybchik	 * Read the queue mask and implicitly acknowledge the
515293769Sarybchik	 * interrupt.
516293769Sarybchik	 */
517293769Sarybchik	EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
518293769Sarybchik	*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
519293769Sarybchik
520293769Sarybchik	EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
521293769Sarybchik
522293769Sarybchik	if (*qmaskp & (1U << eip->ei_level))
523293769Sarybchik		*fatalp = falconsiena_intr_check_fatal(enp);
524293769Sarybchik	else
525293769Sarybchik		*fatalp = B_FALSE;
526293769Sarybchik}
527293769Sarybchik
528293769Sarybchikstatic			void
529293769Sarybchikfalconsiena_intr_status_message(
530293769Sarybchik	__in		efx_nic_t *enp,
531293769Sarybchik	__in		unsigned int message,
532293769Sarybchik	__out		boolean_t *fatalp)
533293769Sarybchik{
534293769Sarybchik	efx_intr_t *eip = &(enp->en_intr);
535293769Sarybchik
536293769Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
537293769Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
538293769Sarybchik
539293769Sarybchik	if (message == eip->ei_level)
540293769Sarybchik		*fatalp = falconsiena_intr_check_fatal(enp);
541293769Sarybchik	else
542293769Sarybchik		*fatalp = B_FALSE;
543293769Sarybchik}
544293769Sarybchik
545293769Sarybchik
546283514Sarybchikstatic		void
547283514Sarybchikfalconsiena_intr_fatal(
548227569Sphilip	__in	efx_nic_t *enp)
549227569Sphilip{
550227569Sphilip#if EFSYS_OPT_DECODE_INTR_FATAL
551227569Sphilip	efx_oword_t fatal;
552227569Sphilip	efx_oword_t mem_per;
553227569Sphilip
554227569Sphilip	EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
555227569Sphilip	EFX_ZERO_OWORD(mem_per);
556227569Sphilip
557227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
558227569Sphilip	    EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
559227569Sphilip		EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
560227569Sphilip
561227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
562227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
563227569Sphilip
564227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
565227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
566227569Sphilip
567227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
568227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
569227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
570227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
571227569Sphilip
572227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
573227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
574227569Sphilip
575227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
576227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
577227569Sphilip
578227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
579227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
580227569Sphilip
581227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
582227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
583227569Sphilip
584227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
585227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
586227569Sphilip
587227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
588227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
589227569Sphilip
590227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
591227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
592227569Sphilip
593227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
594227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
595227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
596227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
597227569Sphilip#else
598227569Sphilip	EFSYS_ASSERT(0);
599227569Sphilip#endif
600227569Sphilip}
601227569Sphilip
602283514Sarybchikstatic		void
603283514Sarybchikfalconsiena_intr_fini(
604227569Sphilip	__in	efx_nic_t *enp)
605227569Sphilip{
606227569Sphilip	efx_oword_t oword;
607227569Sphilip
608227569Sphilip	/* Clear the interrupt address register */
609227569Sphilip	EFX_ZERO_OWORD(oword);
610227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
611283514Sarybchik}
612227569Sphilip
613283514Sarybchik#endif /* EFSYS_OPT_FALCON || EFSYS_OPT_SIENA */
614