1227569Sphilip/*-
2300607Sarybchik * Copyright (c) 2007-2016 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$");
33228078Sphilip
34227569Sphilip#include "efx.h"
35227569Sphilip#include "efx_impl.h"
36227569Sphilip
37283514Sarybchik
38299320Sarybchik#if EFSYS_OPT_SIENA
39283514Sarybchik
40291436Sarybchikstatic	__checkReturn	efx_rc_t
41299608Sarybchiksiena_intr_init(
42283514Sarybchik	__in		efx_nic_t *enp,
43283514Sarybchik	__in		efx_intr_type_t type,
44283514Sarybchik	__in		efsys_mem_t *esmp);
45283514Sarybchik
46283514Sarybchikstatic			void
47299608Sarybchiksiena_intr_enable(
48283514Sarybchik	__in		efx_nic_t *enp);
49283514Sarybchik
50283514Sarybchikstatic			void
51299608Sarybchiksiena_intr_disable(
52283514Sarybchik	__in		efx_nic_t *enp);
53283514Sarybchik
54283514Sarybchikstatic			void
55299608Sarybchiksiena_intr_disable_unlocked(
56283514Sarybchik	__in		efx_nic_t *enp);
57283514Sarybchik
58291436Sarybchikstatic	__checkReturn	efx_rc_t
59299608Sarybchiksiena_intr_trigger(
60283514Sarybchik	__in		efx_nic_t *enp,
61283514Sarybchik	__in		unsigned int level);
62283514Sarybchik
63283514Sarybchikstatic			void
64299608Sarybchiksiena_intr_fini(
65283514Sarybchik	__in		efx_nic_t *enp);
66283514Sarybchik
67293769Sarybchikstatic			void
68299608Sarybchiksiena_intr_status_line(
69293769Sarybchik	__in		efx_nic_t *enp,
70293769Sarybchik	__out		boolean_t *fatalp,
71293769Sarybchik	__out		uint32_t *qmaskp);
72283514Sarybchik
73293769Sarybchikstatic			void
74299608Sarybchiksiena_intr_status_message(
75293769Sarybchik	__in		efx_nic_t *enp,
76293769Sarybchik	__in		unsigned int message,
77293769Sarybchik	__out		boolean_t *fatalp);
78283514Sarybchik
79283514Sarybchikstatic			void
80299608Sarybchiksiena_intr_fatal(
81283514Sarybchik	__in		efx_nic_t *enp);
82283514Sarybchik
83293769Sarybchikstatic	__checkReturn	boolean_t
84299608Sarybchiksiena_intr_check_fatal(
85293769Sarybchik	__in		efx_nic_t *enp);
86293769Sarybchik
87293769Sarybchik
88299320Sarybchik#endif /* EFSYS_OPT_SIENA */
89283514Sarybchik
90283514Sarybchik
91283514Sarybchik#if EFSYS_OPT_SIENA
92299517Sarybchikstatic const efx_intr_ops_t	__efx_intr_siena_ops = {
93299608Sarybchik	siena_intr_init,		/* eio_init */
94299608Sarybchik	siena_intr_enable,		/* eio_enable */
95299608Sarybchik	siena_intr_disable,		/* eio_disable */
96299608Sarybchik	siena_intr_disable_unlocked,	/* eio_disable_unlocked */
97299608Sarybchik	siena_intr_trigger,		/* eio_trigger */
98299608Sarybchik	siena_intr_status_line,		/* eio_status_line */
99299608Sarybchik	siena_intr_status_message,	/* eio_status_message */
100299608Sarybchik	siena_intr_fatal,		/* eio_fatal */
101299608Sarybchik	siena_intr_fini,		/* eio_fini */
102283514Sarybchik};
103283514Sarybchik#endif	/* EFSYS_OPT_SIENA */
104283514Sarybchik
105293751Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
106299517Sarybchikstatic const efx_intr_ops_t	__efx_intr_ef10_ops = {
107293751Sarybchik	ef10_intr_init,			/* eio_init */
108293751Sarybchik	ef10_intr_enable,		/* eio_enable */
109293751Sarybchik	ef10_intr_disable,		/* eio_disable */
110293751Sarybchik	ef10_intr_disable_unlocked,	/* eio_disable_unlocked */
111293751Sarybchik	ef10_intr_trigger,		/* eio_trigger */
112293769Sarybchik	ef10_intr_status_line,		/* eio_status_line */
113293769Sarybchik	ef10_intr_status_message,	/* eio_status_message */
114293769Sarybchik	ef10_intr_fatal,		/* eio_fatal */
115293751Sarybchik	ef10_intr_fini,			/* eio_fini */
116283514Sarybchik};
117293751Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
118283514Sarybchik
119291436Sarybchik	__checkReturn	efx_rc_t
120227569Sphilipefx_intr_init(
121227569Sphilip	__in		efx_nic_t *enp,
122227569Sphilip	__in		efx_intr_type_t type,
123227569Sphilip	__in		efsys_mem_t *esmp)
124227569Sphilip{
125227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
126299517Sarybchik	const efx_intr_ops_t *eiop;
127291436Sarybchik	efx_rc_t rc;
128227569Sphilip
129227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
130227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
131227569Sphilip
132227569Sphilip	if (enp->en_mod_flags & EFX_MOD_INTR) {
133227569Sphilip		rc = EINVAL;
134227569Sphilip		goto fail1;
135227569Sphilip	}
136227569Sphilip
137283514Sarybchik	eip->ei_esmp = esmp;
138283514Sarybchik	eip->ei_type = type;
139283514Sarybchik	eip->ei_level = 0;
140283514Sarybchik
141227569Sphilip	enp->en_mod_flags |= EFX_MOD_INTR;
142227569Sphilip
143283514Sarybchik	switch (enp->en_family) {
144283514Sarybchik#if EFSYS_OPT_SIENA
145283514Sarybchik	case EFX_FAMILY_SIENA:
146299517Sarybchik		eiop = &__efx_intr_siena_ops;
147283514Sarybchik		break;
148283514Sarybchik#endif	/* EFSYS_OPT_SIENA */
149283514Sarybchik
150283514Sarybchik#if EFSYS_OPT_HUNTINGTON
151283514Sarybchik	case EFX_FAMILY_HUNTINGTON:
152299517Sarybchik		eiop = &__efx_intr_ef10_ops;
153283514Sarybchik		break;
154283514Sarybchik#endif	/* EFSYS_OPT_HUNTINGTON */
155283514Sarybchik
156293751Sarybchik#if EFSYS_OPT_MEDFORD
157293751Sarybchik	case EFX_FAMILY_MEDFORD:
158299517Sarybchik		eiop = &__efx_intr_ef10_ops;
159293751Sarybchik		break;
160293751Sarybchik#endif	/* EFSYS_OPT_MEDFORD */
161293751Sarybchik
162283514Sarybchik	default:
163283514Sarybchik		EFSYS_ASSERT(B_FALSE);
164283514Sarybchik		rc = ENOTSUP;
165283514Sarybchik		goto fail2;
166283514Sarybchik	}
167283514Sarybchik
168283514Sarybchik	if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
169283514Sarybchik		goto fail3;
170283514Sarybchik
171283514Sarybchik	eip->ei_eiop = eiop;
172283514Sarybchik
173283514Sarybchik	return (0);
174283514Sarybchik
175283514Sarybchikfail3:
176283514Sarybchik	EFSYS_PROBE(fail3);
177283514Sarybchikfail2:
178283514Sarybchik	EFSYS_PROBE(fail2);
179283514Sarybchikfail1:
180291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
181283514Sarybchik
182283514Sarybchik	return (rc);
183283514Sarybchik}
184283514Sarybchik
185283514Sarybchik		void
186283514Sarybchikefx_intr_fini(
187283514Sarybchik	__in	efx_nic_t *enp)
188283514Sarybchik{
189283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
190299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
191283514Sarybchik
192283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
194283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
195283514Sarybchik
196283514Sarybchik	eiop->eio_fini(enp);
197283514Sarybchik
198283514Sarybchik	enp->en_mod_flags &= ~EFX_MOD_INTR;
199283514Sarybchik}
200283514Sarybchik
201283514Sarybchik			void
202283514Sarybchikefx_intr_enable(
203283514Sarybchik	__in		efx_nic_t *enp)
204283514Sarybchik{
205283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
206299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
207283514Sarybchik
208283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
209283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
210283514Sarybchik
211283514Sarybchik	eiop->eio_enable(enp);
212283514Sarybchik}
213283514Sarybchik
214283514Sarybchik			void
215283514Sarybchikefx_intr_disable(
216283514Sarybchik	__in		efx_nic_t *enp)
217283514Sarybchik{
218283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
219299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
220283514Sarybchik
221283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
222283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
223283514Sarybchik
224283514Sarybchik	eiop->eio_disable(enp);
225283514Sarybchik}
226283514Sarybchik
227283514Sarybchik			void
228283514Sarybchikefx_intr_disable_unlocked(
229283514Sarybchik	__in		efx_nic_t *enp)
230283514Sarybchik{
231283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
232299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
233283514Sarybchik
234283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
235283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
236283514Sarybchik
237283514Sarybchik	eiop->eio_disable_unlocked(enp);
238283514Sarybchik}
239283514Sarybchik
240283514Sarybchik
241291436Sarybchik	__checkReturn	efx_rc_t
242283514Sarybchikefx_intr_trigger(
243283514Sarybchik	__in		efx_nic_t *enp,
244283514Sarybchik	__in		unsigned int level)
245283514Sarybchik{
246283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
247299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
248283514Sarybchik
249283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
250283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
251283514Sarybchik
252283514Sarybchik	return (eiop->eio_trigger(enp, level));
253283514Sarybchik}
254283514Sarybchik
255283514Sarybchik			void
256283514Sarybchikefx_intr_status_line(
257283514Sarybchik	__in		efx_nic_t *enp,
258283514Sarybchik	__out		boolean_t *fatalp,
259283514Sarybchik	__out		uint32_t *qmaskp)
260283514Sarybchik{
261283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
262299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
263283514Sarybchik
264283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
266283514Sarybchik
267293769Sarybchik	eiop->eio_status_line(enp, fatalp, qmaskp);
268283514Sarybchik}
269283514Sarybchik
270283514Sarybchik			void
271283514Sarybchikefx_intr_status_message(
272283514Sarybchik	__in		efx_nic_t *enp,
273283514Sarybchik	__in		unsigned int message,
274283514Sarybchik	__out		boolean_t *fatalp)
275283514Sarybchik{
276283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
277299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
278283514Sarybchik
279283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
280283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
281283514Sarybchik
282293769Sarybchik	eiop->eio_status_message(enp, message, fatalp);
283283514Sarybchik}
284283514Sarybchik
285283514Sarybchik		void
286283514Sarybchikefx_intr_fatal(
287283514Sarybchik	__in	efx_nic_t *enp)
288283514Sarybchik{
289293769Sarybchik	efx_intr_t *eip = &(enp->en_intr);
290299517Sarybchik	const efx_intr_ops_t *eiop = eip->ei_eiop;
291293769Sarybchik
292283514Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
293283514Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
294283514Sarybchik
295293769Sarybchik	eiop->eio_fatal(enp);
296283514Sarybchik}
297283514Sarybchik
298283514Sarybchik
299283514Sarybchik/* ************************************************************************* */
300283514Sarybchik/* ************************************************************************* */
301283514Sarybchik/* ************************************************************************* */
302283514Sarybchik
303299320Sarybchik#if EFSYS_OPT_SIENA
304283514Sarybchik
305291436Sarybchikstatic	__checkReturn	efx_rc_t
306299608Sarybchiksiena_intr_init(
307283514Sarybchik	__in		efx_nic_t *enp,
308283514Sarybchik	__in		efx_intr_type_t type,
309283514Sarybchik	__in		efsys_mem_t *esmp)
310283514Sarybchik{
311283514Sarybchik	efx_intr_t *eip = &(enp->en_intr);
312283514Sarybchik	efx_oword_t oword;
313283514Sarybchik
314283514Sarybchik	/*
315227569Sphilip	 * bug17213 workaround.
316227569Sphilip	 *
317227569Sphilip	 * Under legacy interrupts, don't share a level between fatal
318227569Sphilip	 * interrupts and event queue interrupts. Under MSI-X, they
319227569Sphilip	 * must share, or we won't get an interrupt.
320227569Sphilip	 */
321227569Sphilip	if (enp->en_family == EFX_FAMILY_SIENA &&
322227569Sphilip	    eip->ei_type == EFX_INTR_LINE)
323227569Sphilip		eip->ei_level = 0x1f;
324227569Sphilip	else
325227569Sphilip		eip->ei_level = 0;
326227569Sphilip
327227569Sphilip	/* Enable all the genuinely fatal interrupts */
328227569Sphilip	EFX_SET_OWORD(oword);
329227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
330227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
331227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
332227569Sphilip	if (enp->en_family >= EFX_FAMILY_SIENA)
333227569Sphilip		EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
334227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
335227569Sphilip
336227569Sphilip	/* Set up the interrupt address register */
337227569Sphilip	EFX_POPULATE_OWORD_3(oword,
338227569Sphilip	    FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
339227569Sphilip	    FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
340227569Sphilip	    FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
341227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
342227569Sphilip
343227569Sphilip	return (0);
344227569Sphilip}
345227569Sphilip
346283514Sarybchikstatic			void
347299608Sarybchiksiena_intr_enable(
348227569Sphilip	__in		efx_nic_t *enp)
349227569Sphilip{
350227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
351227569Sphilip	efx_oword_t oword;
352227569Sphilip
353227569Sphilip	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
354227569Sphilip
355227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
356227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
357227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
358227569Sphilip}
359227569Sphilip
360283514Sarybchikstatic			void
361299608Sarybchiksiena_intr_disable(
362227569Sphilip	__in		efx_nic_t *enp)
363227569Sphilip{
364227569Sphilip	efx_oword_t oword;
365227569Sphilip
366227569Sphilip	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
367227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
368227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
369227569Sphilip
370227569Sphilip	EFSYS_SPIN(10);
371227569Sphilip}
372227569Sphilip
373283514Sarybchikstatic			void
374299608Sarybchiksiena_intr_disable_unlocked(
375227569Sphilip	__in		efx_nic_t *enp)
376227569Sphilip{
377227569Sphilip	efx_oword_t oword;
378227569Sphilip
379227569Sphilip	EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
380227569Sphilip			&oword, B_FALSE);
381227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
382227569Sphilip	EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
383227569Sphilip	    &oword, B_FALSE);
384227569Sphilip}
385227569Sphilip
386291436Sarybchikstatic	__checkReturn	efx_rc_t
387299608Sarybchiksiena_intr_trigger(
388227569Sphilip	__in		efx_nic_t *enp,
389227569Sphilip	__in		unsigned int level)
390227569Sphilip{
391227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
392227569Sphilip	efx_oword_t oword;
393227569Sphilip	unsigned int count;
394227569Sphilip	uint32_t sel;
395291436Sarybchik	efx_rc_t rc;
396227569Sphilip
397227569Sphilip	/* bug16757: No event queues can be initialized */
398227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
399227569Sphilip
400299403Sarybchik	if (level >= EFX_NINTR_SIENA) {
401299403Sarybchik		rc = EINVAL;
402299403Sarybchik		goto fail1;
403227569Sphilip	}
404227569Sphilip
405227569Sphilip	if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
406227569Sphilip		return (ENOTSUP); /* avoid EFSYS_PROBE() */
407227569Sphilip
408227569Sphilip	sel = level;
409227569Sphilip
410227569Sphilip	/* Trigger a test interrupt */
411227569Sphilip	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
412227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
413227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
414227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
415227569Sphilip
416227569Sphilip	/*
417227569Sphilip	 * Wait up to 100ms for the interrupt to be raised before restoring
418227569Sphilip	 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
419227569Sphilip	 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
420227569Sphilip	 */
421227569Sphilip	count = 0;
422227569Sphilip	do {
423227569Sphilip		EFSYS_SPIN(100);	/* 100us */
424227569Sphilip
425227569Sphilip		EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
426227569Sphilip	} while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
427227569Sphilip
428227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
429227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
430227569Sphilip
431227569Sphilip	return (0);
432227569Sphilip
433227569Sphilipfail1:
434291436Sarybchik	EFSYS_PROBE1(fail1, efx_rc_t, rc);
435227569Sphilip
436227569Sphilip	return (rc);
437227569Sphilip}
438227569Sphilip
439227569Sphilipstatic	__checkReturn	boolean_t
440299608Sarybchiksiena_intr_check_fatal(
441227569Sphilip	__in		efx_nic_t *enp)
442227569Sphilip{
443227569Sphilip	efx_intr_t *eip = &(enp->en_intr);
444227569Sphilip	efsys_mem_t *esmp = eip->ei_esmp;
445227569Sphilip	efx_oword_t oword;
446227569Sphilip
447227569Sphilip	/* Read the syndrome */
448227569Sphilip	EFSYS_MEM_READO(esmp, 0, &oword);
449227569Sphilip
450227569Sphilip	if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
451227569Sphilip		EFSYS_PROBE(fatal);
452227569Sphilip
453227569Sphilip		/* Clear the fatal interrupt condition */
454227569Sphilip		EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
455227569Sphilip		EFSYS_MEM_WRITEO(esmp, 0, &oword);
456227569Sphilip
457227569Sphilip		return (B_TRUE);
458227569Sphilip	}
459227569Sphilip
460227569Sphilip	return (B_FALSE);
461227569Sphilip}
462227569Sphilip
463293769Sarybchikstatic			void
464299608Sarybchiksiena_intr_status_line(
465293769Sarybchik	__in		efx_nic_t *enp,
466293769Sarybchik	__out		boolean_t *fatalp,
467293769Sarybchik	__out		uint32_t *qmaskp)
468293769Sarybchik{
469293769Sarybchik	efx_intr_t *eip = &(enp->en_intr);
470293769Sarybchik	efx_dword_t dword;
471293769Sarybchik
472293769Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
473293769Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
474293769Sarybchik
475293769Sarybchik	/*
476293769Sarybchik	 * Read the queue mask and implicitly acknowledge the
477293769Sarybchik	 * interrupt.
478293769Sarybchik	 */
479293769Sarybchik	EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
480293769Sarybchik	*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
481293769Sarybchik
482293769Sarybchik	EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
483293769Sarybchik
484293769Sarybchik	if (*qmaskp & (1U << eip->ei_level))
485299608Sarybchik		*fatalp = siena_intr_check_fatal(enp);
486293769Sarybchik	else
487293769Sarybchik		*fatalp = B_FALSE;
488293769Sarybchik}
489293769Sarybchik
490293769Sarybchikstatic			void
491299608Sarybchiksiena_intr_status_message(
492293769Sarybchik	__in		efx_nic_t *enp,
493293769Sarybchik	__in		unsigned int message,
494293769Sarybchik	__out		boolean_t *fatalp)
495293769Sarybchik{
496293769Sarybchik	efx_intr_t *eip = &(enp->en_intr);
497293769Sarybchik
498293769Sarybchik	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
499293769Sarybchik	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
500293769Sarybchik
501293769Sarybchik	if (message == eip->ei_level)
502299608Sarybchik		*fatalp = siena_intr_check_fatal(enp);
503293769Sarybchik	else
504293769Sarybchik		*fatalp = B_FALSE;
505293769Sarybchik}
506293769Sarybchik
507293769Sarybchik
508283514Sarybchikstatic		void
509299608Sarybchiksiena_intr_fatal(
510227569Sphilip	__in	efx_nic_t *enp)
511227569Sphilip{
512227569Sphilip#if EFSYS_OPT_DECODE_INTR_FATAL
513227569Sphilip	efx_oword_t fatal;
514227569Sphilip	efx_oword_t mem_per;
515227569Sphilip
516227569Sphilip	EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
517227569Sphilip	EFX_ZERO_OWORD(mem_per);
518227569Sphilip
519227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
520227569Sphilip	    EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
521227569Sphilip		EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
522227569Sphilip
523227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
524227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
525227569Sphilip
526227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
527227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
528227569Sphilip
529227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
530227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
531227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
532227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
533227569Sphilip
534227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
535227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
536227569Sphilip
537227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
538227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
539227569Sphilip
540227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
541227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
542227569Sphilip
543227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
544227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
545227569Sphilip
546227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
547227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
548227569Sphilip
549227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
550227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
551227569Sphilip
552227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
553227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
554227569Sphilip
555227569Sphilip	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
556227569Sphilip		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
557227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
558227569Sphilip		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
559227569Sphilip#else
560227569Sphilip	EFSYS_ASSERT(0);
561227569Sphilip#endif
562227569Sphilip}
563227569Sphilip
564283514Sarybchikstatic		void
565299608Sarybchiksiena_intr_fini(
566227569Sphilip	__in	efx_nic_t *enp)
567227569Sphilip{
568227569Sphilip	efx_oword_t oword;
569227569Sphilip
570227569Sphilip	/* Clear the interrupt address register */
571227569Sphilip	EFX_ZERO_OWORD(oword);
572227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
573283514Sarybchik}
574227569Sphilip
575299320Sarybchik#endif /* EFSYS_OPT_SIENA */
576