1/*-
2 * Copyright (c) 2007-2016 Solarflare Communications Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 *    this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 *    this list of conditions and the following disclaimer in the documentation
12 *    and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * The views and conclusions contained in the software and documentation are
27 * those of the authors and should not be interpreted as representing official
28 * policies, either expressed or implied, of the FreeBSD Project.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD$");
33
34#include "efx.h"
35#include "efx_impl.h"
36
37
38#if EFSYS_OPT_SIENA
39
40static	__checkReturn	efx_rc_t
41siena_intr_init(
42	__in		efx_nic_t *enp,
43	__in		efx_intr_type_t type,
44	__in		efsys_mem_t *esmp);
45
46static			void
47siena_intr_enable(
48	__in		efx_nic_t *enp);
49
50static			void
51siena_intr_disable(
52	__in		efx_nic_t *enp);
53
54static			void
55siena_intr_disable_unlocked(
56	__in		efx_nic_t *enp);
57
58static	__checkReturn	efx_rc_t
59siena_intr_trigger(
60	__in		efx_nic_t *enp,
61	__in		unsigned int level);
62
63static			void
64siena_intr_fini(
65	__in		efx_nic_t *enp);
66
67static			void
68siena_intr_status_line(
69	__in		efx_nic_t *enp,
70	__out		boolean_t *fatalp,
71	__out		uint32_t *qmaskp);
72
73static			void
74siena_intr_status_message(
75	__in		efx_nic_t *enp,
76	__in		unsigned int message,
77	__out		boolean_t *fatalp);
78
79static			void
80siena_intr_fatal(
81	__in		efx_nic_t *enp);
82
83static	__checkReturn	boolean_t
84siena_intr_check_fatal(
85	__in		efx_nic_t *enp);
86
87
88#endif /* EFSYS_OPT_SIENA */
89
90
91#if EFSYS_OPT_SIENA
92static const efx_intr_ops_t	__efx_intr_siena_ops = {
93	siena_intr_init,		/* eio_init */
94	siena_intr_enable,		/* eio_enable */
95	siena_intr_disable,		/* eio_disable */
96	siena_intr_disable_unlocked,	/* eio_disable_unlocked */
97	siena_intr_trigger,		/* eio_trigger */
98	siena_intr_status_line,		/* eio_status_line */
99	siena_intr_status_message,	/* eio_status_message */
100	siena_intr_fatal,		/* eio_fatal */
101	siena_intr_fini,		/* eio_fini */
102};
103#endif	/* EFSYS_OPT_SIENA */
104
105#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
106static const efx_intr_ops_t	__efx_intr_ef10_ops = {
107	ef10_intr_init,			/* eio_init */
108	ef10_intr_enable,		/* eio_enable */
109	ef10_intr_disable,		/* eio_disable */
110	ef10_intr_disable_unlocked,	/* eio_disable_unlocked */
111	ef10_intr_trigger,		/* eio_trigger */
112	ef10_intr_status_line,		/* eio_status_line */
113	ef10_intr_status_message,	/* eio_status_message */
114	ef10_intr_fatal,		/* eio_fatal */
115	ef10_intr_fini,			/* eio_fini */
116};
117#endif	/* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
118
119	__checkReturn	efx_rc_t
120efx_intr_init(
121	__in		efx_nic_t *enp,
122	__in		efx_intr_type_t type,
123	__in		efsys_mem_t *esmp)
124{
125	efx_intr_t *eip = &(enp->en_intr);
126	const efx_intr_ops_t *eiop;
127	efx_rc_t rc;
128
129	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
130	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
131
132	if (enp->en_mod_flags & EFX_MOD_INTR) {
133		rc = EINVAL;
134		goto fail1;
135	}
136
137	eip->ei_esmp = esmp;
138	eip->ei_type = type;
139	eip->ei_level = 0;
140
141	enp->en_mod_flags |= EFX_MOD_INTR;
142
143	switch (enp->en_family) {
144#if EFSYS_OPT_SIENA
145	case EFX_FAMILY_SIENA:
146		eiop = &__efx_intr_siena_ops;
147		break;
148#endif	/* EFSYS_OPT_SIENA */
149
150#if EFSYS_OPT_HUNTINGTON
151	case EFX_FAMILY_HUNTINGTON:
152		eiop = &__efx_intr_ef10_ops;
153		break;
154#endif	/* EFSYS_OPT_HUNTINGTON */
155
156#if EFSYS_OPT_MEDFORD
157	case EFX_FAMILY_MEDFORD:
158		eiop = &__efx_intr_ef10_ops;
159		break;
160#endif	/* EFSYS_OPT_MEDFORD */
161
162	default:
163		EFSYS_ASSERT(B_FALSE);
164		rc = ENOTSUP;
165		goto fail2;
166	}
167
168	if ((rc = eiop->eio_init(enp, type, esmp)) != 0)
169		goto fail3;
170
171	eip->ei_eiop = eiop;
172
173	return (0);
174
175fail3:
176	EFSYS_PROBE(fail3);
177fail2:
178	EFSYS_PROBE(fail2);
179fail1:
180	EFSYS_PROBE1(fail1, efx_rc_t, rc);
181
182	return (rc);
183}
184
185		void
186efx_intr_fini(
187	__in	efx_nic_t *enp)
188{
189	efx_intr_t *eip = &(enp->en_intr);
190	const efx_intr_ops_t *eiop = eip->ei_eiop;
191
192	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
193	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_NIC);
194	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
195
196	eiop->eio_fini(enp);
197
198	enp->en_mod_flags &= ~EFX_MOD_INTR;
199}
200
201			void
202efx_intr_enable(
203	__in		efx_nic_t *enp)
204{
205	efx_intr_t *eip = &(enp->en_intr);
206	const efx_intr_ops_t *eiop = eip->ei_eiop;
207
208	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
209	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
210
211	eiop->eio_enable(enp);
212}
213
214			void
215efx_intr_disable(
216	__in		efx_nic_t *enp)
217{
218	efx_intr_t *eip = &(enp->en_intr);
219	const efx_intr_ops_t *eiop = eip->ei_eiop;
220
221	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
222	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
223
224	eiop->eio_disable(enp);
225}
226
227			void
228efx_intr_disable_unlocked(
229	__in		efx_nic_t *enp)
230{
231	efx_intr_t *eip = &(enp->en_intr);
232	const efx_intr_ops_t *eiop = eip->ei_eiop;
233
234	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
235	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
236
237	eiop->eio_disable_unlocked(enp);
238}
239
240
241	__checkReturn	efx_rc_t
242efx_intr_trigger(
243	__in		efx_nic_t *enp,
244	__in		unsigned int level)
245{
246	efx_intr_t *eip = &(enp->en_intr);
247	const efx_intr_ops_t *eiop = eip->ei_eiop;
248
249	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
250	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
251
252	return (eiop->eio_trigger(enp, level));
253}
254
255			void
256efx_intr_status_line(
257	__in		efx_nic_t *enp,
258	__out		boolean_t *fatalp,
259	__out		uint32_t *qmaskp)
260{
261	efx_intr_t *eip = &(enp->en_intr);
262	const efx_intr_ops_t *eiop = eip->ei_eiop;
263
264	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
265	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
266
267	eiop->eio_status_line(enp, fatalp, qmaskp);
268}
269
270			void
271efx_intr_status_message(
272	__in		efx_nic_t *enp,
273	__in		unsigned int message,
274	__out		boolean_t *fatalp)
275{
276	efx_intr_t *eip = &(enp->en_intr);
277	const efx_intr_ops_t *eiop = eip->ei_eiop;
278
279	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
280	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
281
282	eiop->eio_status_message(enp, message, fatalp);
283}
284
285		void
286efx_intr_fatal(
287	__in	efx_nic_t *enp)
288{
289	efx_intr_t *eip = &(enp->en_intr);
290	const efx_intr_ops_t *eiop = eip->ei_eiop;
291
292	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
293	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
294
295	eiop->eio_fatal(enp);
296}
297
298
299/* ************************************************************************* */
300/* ************************************************************************* */
301/* ************************************************************************* */
302
303#if EFSYS_OPT_SIENA
304
305static	__checkReturn	efx_rc_t
306siena_intr_init(
307	__in		efx_nic_t *enp,
308	__in		efx_intr_type_t type,
309	__in		efsys_mem_t *esmp)
310{
311	efx_intr_t *eip = &(enp->en_intr);
312	efx_oword_t oword;
313
314	/*
315	 * bug17213 workaround.
316	 *
317	 * Under legacy interrupts, don't share a level between fatal
318	 * interrupts and event queue interrupts. Under MSI-X, they
319	 * must share, or we won't get an interrupt.
320	 */
321	if (enp->en_family == EFX_FAMILY_SIENA &&
322	    eip->ei_type == EFX_INTR_LINE)
323		eip->ei_level = 0x1f;
324	else
325		eip->ei_level = 0;
326
327	/* Enable all the genuinely fatal interrupts */
328	EFX_SET_OWORD(oword);
329	EFX_SET_OWORD_FIELD(oword, FRF_AZ_ILL_ADR_INT_KER_EN, 0);
330	EFX_SET_OWORD_FIELD(oword, FRF_AZ_RBUF_OWN_INT_KER_EN, 0);
331	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TBUF_OWN_INT_KER_EN, 0);
332	if (enp->en_family >= EFX_FAMILY_SIENA)
333		EFX_SET_OWORD_FIELD(oword, FRF_CZ_SRAM_PERR_INT_P_KER_EN, 0);
334	EFX_BAR_WRITEO(enp, FR_AZ_FATAL_INTR_REG_KER, &oword);
335
336	/* Set up the interrupt address register */
337	EFX_POPULATE_OWORD_3(oword,
338	    FRF_AZ_NORM_INT_VEC_DIS_KER, (type == EFX_INTR_MESSAGE) ? 1 : 0,
339	    FRF_AZ_INT_ADR_KER_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
340	    FRF_AZ_INT_ADR_KER_DW1, EFSYS_MEM_ADDR(esmp) >> 32);
341	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
342
343	return (0);
344}
345
346static			void
347siena_intr_enable(
348	__in		efx_nic_t *enp)
349{
350	efx_intr_t *eip = &(enp->en_intr);
351	efx_oword_t oword;
352
353	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
354
355	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
356	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 1);
357	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
358}
359
360static			void
361siena_intr_disable(
362	__in		efx_nic_t *enp)
363{
364	efx_oword_t oword;
365
366	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
367	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
368	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
369
370	EFSYS_SPIN(10);
371}
372
373static			void
374siena_intr_disable_unlocked(
375	__in		efx_nic_t *enp)
376{
377	efx_oword_t oword;
378
379	EFSYS_BAR_READO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
380			&oword, B_FALSE);
381	EFX_SET_OWORD_FIELD(oword, FRF_AZ_DRV_INT_EN_KER, 0);
382	EFSYS_BAR_WRITEO(enp->en_esbp, FR_AZ_INT_EN_REG_KER_OFST,
383	    &oword, B_FALSE);
384}
385
386static	__checkReturn	efx_rc_t
387siena_intr_trigger(
388	__in		efx_nic_t *enp,
389	__in		unsigned int level)
390{
391	efx_intr_t *eip = &(enp->en_intr);
392	efx_oword_t oword;
393	unsigned int count;
394	uint32_t sel;
395	efx_rc_t rc;
396
397	/* bug16757: No event queues can be initialized */
398	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EV));
399
400	if (level >= EFX_NINTR_SIENA) {
401		rc = EINVAL;
402		goto fail1;
403	}
404
405	if (level > EFX_MASK32(FRF_AZ_KER_INT_LEVE_SEL))
406		return (ENOTSUP); /* avoid EFSYS_PROBE() */
407
408	sel = level;
409
410	/* Trigger a test interrupt */
411	EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
412	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, sel);
413	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER, 1);
414	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
415
416	/*
417	 * Wait up to 100ms for the interrupt to be raised before restoring
418	 * KER_INT_LEVE_SEL. Ignore a failure to raise (the caller will
419	 * observe this soon enough anyway), but always reset KER_INT_LEVE_SEL
420	 */
421	count = 0;
422	do {
423		EFSYS_SPIN(100);	/* 100us */
424
425		EFX_BAR_READO(enp, FR_AZ_INT_EN_REG_KER, &oword);
426	} while (EFX_OWORD_FIELD(oword, FRF_AZ_KER_INT_KER) && ++count < 1000);
427
428	EFX_SET_OWORD_FIELD(oword, FRF_AZ_KER_INT_LEVE_SEL, eip->ei_level);
429	EFX_BAR_WRITEO(enp, FR_AZ_INT_EN_REG_KER, &oword);
430
431	return (0);
432
433fail1:
434	EFSYS_PROBE1(fail1, efx_rc_t, rc);
435
436	return (rc);
437}
438
439static	__checkReturn	boolean_t
440siena_intr_check_fatal(
441	__in		efx_nic_t *enp)
442{
443	efx_intr_t *eip = &(enp->en_intr);
444	efsys_mem_t *esmp = eip->ei_esmp;
445	efx_oword_t oword;
446
447	/* Read the syndrome */
448	EFSYS_MEM_READO(esmp, 0, &oword);
449
450	if (EFX_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT) != 0) {
451		EFSYS_PROBE(fatal);
452
453		/* Clear the fatal interrupt condition */
454		EFX_SET_OWORD_FIELD(oword, FSF_AZ_NET_IVEC_FATAL_INT, 0);
455		EFSYS_MEM_WRITEO(esmp, 0, &oword);
456
457		return (B_TRUE);
458	}
459
460	return (B_FALSE);
461}
462
463static			void
464siena_intr_status_line(
465	__in		efx_nic_t *enp,
466	__out		boolean_t *fatalp,
467	__out		uint32_t *qmaskp)
468{
469	efx_intr_t *eip = &(enp->en_intr);
470	efx_dword_t dword;
471
472	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
473	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
474
475	/*
476	 * Read the queue mask and implicitly acknowledge the
477	 * interrupt.
478	 */
479	EFX_BAR_READD(enp, FR_BZ_INT_ISR0_REG, &dword, B_FALSE);
480	*qmaskp = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
481
482	EFSYS_PROBE1(qmask, uint32_t, *qmaskp);
483
484	if (*qmaskp & (1U << eip->ei_level))
485		*fatalp = siena_intr_check_fatal(enp);
486	else
487		*fatalp = B_FALSE;
488}
489
490static			void
491siena_intr_status_message(
492	__in		efx_nic_t *enp,
493	__in		unsigned int message,
494	__out		boolean_t *fatalp)
495{
496	efx_intr_t *eip = &(enp->en_intr);
497
498	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
499	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_INTR);
500
501	if (message == eip->ei_level)
502		*fatalp = siena_intr_check_fatal(enp);
503	else
504		*fatalp = B_FALSE;
505}
506
507
508static		void
509siena_intr_fatal(
510	__in	efx_nic_t *enp)
511{
512#if EFSYS_OPT_DECODE_INTR_FATAL
513	efx_oword_t fatal;
514	efx_oword_t mem_per;
515
516	EFX_BAR_READO(enp, FR_AZ_FATAL_INTR_REG_KER, &fatal);
517	EFX_ZERO_OWORD(mem_per);
518
519	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0 ||
520	    EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
521		EFX_BAR_READO(enp, FR_AZ_MEM_STAT_REG, &mem_per);
522
523	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRAM_OOB_INT_KER) != 0)
524		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_OOB, 0, 0);
525
526	if (EFX_OWORD_FIELD(fatal, FRF_AZ_BUFID_DC_OOB_INT_KER) != 0)
527		EFSYS_ERR(enp->en_esip, EFX_ERR_BUFID_DC_OOB, 0, 0);
528
529	if (EFX_OWORD_FIELD(fatal, FRF_AZ_MEM_PERR_INT_KER) != 0)
530		EFSYS_ERR(enp->en_esip, EFX_ERR_MEM_PERR,
531		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
532		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
533
534	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RBUF_OWN_INT_KER) != 0)
535		EFSYS_ERR(enp->en_esip, EFX_ERR_RBUF_OWN, 0, 0);
536
537	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TBUF_OWN_INT_KER) != 0)
538		EFSYS_ERR(enp->en_esip, EFX_ERR_TBUF_OWN, 0, 0);
539
540	if (EFX_OWORD_FIELD(fatal, FRF_AZ_RDESCQ_OWN_INT_KER) != 0)
541		EFSYS_ERR(enp->en_esip, EFX_ERR_RDESQ_OWN, 0, 0);
542
543	if (EFX_OWORD_FIELD(fatal, FRF_AZ_TDESCQ_OWN_INT_KER) != 0)
544		EFSYS_ERR(enp->en_esip, EFX_ERR_TDESQ_OWN, 0, 0);
545
546	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVQ_OWN_INT_KER) != 0)
547		EFSYS_ERR(enp->en_esip, EFX_ERR_EVQ_OWN, 0, 0);
548
549	if (EFX_OWORD_FIELD(fatal, FRF_AZ_EVF_OFLO_INT_KER) != 0)
550		EFSYS_ERR(enp->en_esip, EFX_ERR_EVFF_OFLO, 0, 0);
551
552	if (EFX_OWORD_FIELD(fatal, FRF_AZ_ILL_ADR_INT_KER) != 0)
553		EFSYS_ERR(enp->en_esip, EFX_ERR_ILL_ADDR, 0, 0);
554
555	if (EFX_OWORD_FIELD(fatal, FRF_AZ_SRM_PERR_INT_KER) != 0)
556		EFSYS_ERR(enp->en_esip, EFX_ERR_SRAM_PERR,
557		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_0),
558		    EFX_OWORD_FIELD(mem_per, EFX_DWORD_1));
559#else
560	EFSYS_ASSERT(0);
561#endif
562}
563
564static		void
565siena_intr_fini(
566	__in	efx_nic_t *enp)
567{
568	efx_oword_t oword;
569
570	/* Clear the interrupt address register */
571	EFX_ZERO_OWORD(oword);
572	EFX_BAR_WRITEO(enp, FR_AZ_INT_ADR_REG_KER, &oword);
573}
574
575#endif /* EFSYS_OPT_SIENA */
576