gic.c revision 289548
1/*-
2 * Copyright (c) 2011 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * Developed by Damjan Marion <damjan.marion@gmail.com>
6 *
7 * Based on OMAP4 GIC code by Ben Gray
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. The name of the company nor the name of the author may be used to
18 *    endorse or promote products derived from this software without specific
19 *    prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sys/arm/arm/gic.c 289548 2015-10-18 20:37:10Z ian $");
36
37#include "opt_platform.h"
38
39#include "opt_platform.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/bus.h>
44#include <sys/kernel.h>
45#include <sys/ktr.h>
46#include <sys/module.h>
47#include <sys/malloc.h>
48#include <sys/rman.h>
49#include <sys/pcpu.h>
50#include <sys/proc.h>
51#include <sys/cpuset.h>
52#include <sys/lock.h>
53#include <sys/mutex.h>
54#include <sys/smp.h>
55#ifdef ARM_INTRNG
56#include <sys/sched.h>
57#endif
58#include <machine/bus.h>
59#include <machine/intr.h>
60#include <machine/smp.h>
61
62#include <dev/fdt/fdt_common.h>
63#include <dev/ofw/openfirm.h>
64#include <dev/ofw/ofw_bus.h>
65#include <dev/ofw/ofw_bus_subr.h>
66
67#ifdef ARM_INTRNG
68#include "pic_if.h"
69#endif
70
71/* We are using GICv2 register naming */
72
73/* Distributor Registers */
74#define GICD_CTLR		0x000			/* v1 ICDDCR */
75#define GICD_TYPER		0x004			/* v1 ICDICTR */
76#define GICD_IIDR		0x008			/* v1 ICDIIDR */
77#define GICD_IGROUPR(n)		(0x0080 + ((n) * 4))	/* v1 ICDISER */
78#define GICD_ISENABLER(n)	(0x0100 + ((n) * 4))	/* v1 ICDISER */
79#define GICD_ICENABLER(n)	(0x0180 + ((n) * 4))	/* v1 ICDICER */
80#define GICD_ISPENDR(n)		(0x0200 + ((n) * 4))	/* v1 ICDISPR */
81#define GICD_ICPENDR(n)		(0x0280 + ((n) * 4))	/* v1 ICDICPR */
82#define GICD_ICACTIVER(n)	(0x0380 + ((n) * 4))	/* v1 ICDABR */
83#define GICD_IPRIORITYR(n)	(0x0400 + ((n) * 4))	/* v1 ICDIPR */
84#define GICD_ITARGETSR(n)	(0x0800 + ((n) * 4))	/* v1 ICDIPTR */
85#define GICD_ICFGR(n)		(0x0C00 + ((n) * 4))	/* v1 ICDICFR */
86#define GICD_SGIR(n)		(0x0F00 + ((n) * 4))	/* v1 ICDSGIR */
87
88/* CPU Registers */
89#define GICC_CTLR		0x0000			/* v1 ICCICR */
90#define GICC_PMR		0x0004			/* v1 ICCPMR */
91#define GICC_BPR		0x0008			/* v1 ICCBPR */
92#define GICC_IAR		0x000C			/* v1 ICCIAR */
93#define GICC_EOIR		0x0010			/* v1 ICCEOIR */
94#define GICC_RPR		0x0014			/* v1 ICCRPR */
95#define GICC_HPPIR		0x0018			/* v1 ICCHPIR */
96#define GICC_ABPR		0x001C			/* v1 ICCABPR */
97#define GICC_IIDR		0x00FC			/* v1 ICCIIDR*/
98
99#define	GIC_FIRST_SGI		 0	/* Irqs 0-15 are SGIs/IPIs. */
100#define	GIC_LAST_SGI		15
101#define	GIC_FIRST_PPI		16	/* Irqs 16-31 are private (per */
102#define	GIC_LAST_PPI		31	/* core) peripheral interrupts. */
103#define	GIC_FIRST_SPI		32	/* Irqs 32+ are shared peripherals. */
104
105/* First bit is a polarity bit (0 - low, 1 - high) */
106#define GICD_ICFGR_POL_LOW	(0 << 0)
107#define GICD_ICFGR_POL_HIGH	(1 << 0)
108#define GICD_ICFGR_POL_MASK	0x1
109/* Second bit is a trigger bit (0 - level, 1 - edge) */
110#define GICD_ICFGR_TRIG_LVL	(0 << 1)
111#define GICD_ICFGR_TRIG_EDGE	(1 << 1)
112#define GICD_ICFGR_TRIG_MASK	0x2
113
114#ifndef	GIC_DEFAULT_ICFGR_INIT
115#define	GIC_DEFAULT_ICFGR_INIT	0x00000000
116#endif
117
118#ifdef ARM_INTRNG
119static u_int gic_irq_cpu;
120static int arm_gic_intr(void *);
121static int arm_gic_bind(device_t dev, struct arm_irqsrc *isrc);
122#endif
123
124struct arm_gic_softc {
125	device_t		gic_dev;
126#ifdef ARM_INTRNG
127	void *			gic_intrhand;
128	struct arm_irqsrc **	gic_irqs;
129#endif
130	struct resource *	gic_res[3];
131	bus_space_tag_t		gic_c_bst;
132	bus_space_tag_t		gic_d_bst;
133	bus_space_handle_t	gic_c_bsh;
134	bus_space_handle_t	gic_d_bsh;
135	uint8_t			ver;
136	struct mtx		mutex;
137	uint32_t		nirqs;
138};
139
140static struct resource_spec arm_gic_spec[] = {
141	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Distributor registers */
142	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* CPU Interrupt Intf. registers */
143#ifdef ARM_INTRNG
144	{ SYS_RES_IRQ,	  0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */
145#endif
146	{ -1, 0 }
147};
148
149static struct arm_gic_softc *gic_sc = NULL;
150
151#define	gic_c_read_4(_sc, _reg)		\
152    bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
153#define	gic_c_write_4(_sc, _reg, _val)		\
154    bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
155#define	gic_d_read_4(_sc, _reg)		\
156    bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
157#define	gic_d_write_1(_sc, _reg, _val)		\
158    bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
159#define	gic_d_write_4(_sc, _reg, _val)		\
160    bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
161
162#ifndef ARM_INTRNG
163static int gic_config_irq(int irq, enum intr_trigger trig,
164    enum intr_polarity pol);
165static void gic_post_filter(void *);
166#endif
167
168static struct ofw_compat_data compat_data[] = {
169	{"arm,gic",		true},	/* Non-standard, used in FreeBSD dts. */
170	{"arm,gic-400",		true},
171	{"arm,cortex-a15-gic",	true},
172	{"arm,cortex-a9-gic",	true},
173	{"arm,cortex-a7-gic",	true},
174	{"arm,arm11mp-gic",	true},
175	{"brcm,brahma-b15-gic",	true},
176	{NULL,			false}
177};
178
179static int
180arm_gic_probe(device_t dev)
181{
182
183	if (!ofw_bus_status_okay(dev))
184		return (ENXIO);
185
186	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
187		return (ENXIO);
188	device_set_desc(dev, "ARM Generic Interrupt Controller");
189	return (BUS_PROBE_DEFAULT);
190}
191
192#ifdef ARM_INTRNG
193static inline void
194gic_irq_unmask(struct arm_gic_softc *sc, u_int irq)
195{
196
197	gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
198}
199
200static inline void
201gic_irq_mask(struct arm_gic_softc *sc, u_int irq)
202{
203
204	gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
205}
206#endif
207
208#ifdef SMP
209#ifdef ARM_INTRNG
210static void
211arm_gic_init_secondary(device_t dev)
212{
213	struct arm_gic_softc *sc = device_get_softc(dev);
214	struct arm_irqsrc *isrc;
215	u_int irq;
216
217	for (irq = 0; irq < sc->nirqs; irq += 4)
218		gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0);
219
220	/* Set all the interrupts to be in Group 0 (secure) */
221	for (irq = 0; irq < sc->nirqs; irq += 32) {
222		gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0);
223	}
224
225	/* Enable CPU interface */
226	gic_c_write_4(sc, GICC_CTLR, 1);
227
228	/* Set priority mask register. */
229	gic_c_write_4(sc, GICC_PMR, 0xff);
230
231	/* Enable interrupt distribution */
232	gic_d_write_4(sc, GICD_CTLR, 0x01);
233
234	/* Unmask attached SGI interrupts. */
235	for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) {
236		isrc = sc->gic_irqs[irq];
237		if (isrc != NULL && isrc->isrc_handlers != 0) {
238			CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
239			gic_irq_unmask(sc, irq);
240		}
241	}
242
243	/* Unmask attached PPI interrupts. */
244	for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) {
245		isrc = sc->gic_irqs[irq];
246		if (isrc == NULL || isrc->isrc_handlers == 0)
247			continue;
248		if (isrc->isrc_flags & ARM_ISRCF_BOUND) {
249			if (CPU_ISSET(PCPU_GET(cpuid), &isrc->isrc_cpu))
250				gic_irq_unmask(sc, irq);
251		} else {
252			CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
253			gic_irq_unmask(sc, irq);
254		}
255	}
256}
257#else
258static void
259arm_gic_init_secondary(device_t dev)
260{
261	struct arm_gic_softc *sc = device_get_softc(dev);
262	int i;
263
264	for (i = 0; i < sc->nirqs; i += 4)
265		gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
266
267	/* Set all the interrupts to be in Group 0 (secure) */
268	for (i = 0; i < sc->nirqs; i += 32) {
269		gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
270	}
271
272	/* Enable CPU interface */
273	gic_c_write_4(sc, GICC_CTLR, 1);
274
275	/* Set priority mask register. */
276	gic_c_write_4(sc, GICC_PMR, 0xff);
277
278	/* Enable interrupt distribution */
279	gic_d_write_4(sc, GICD_CTLR, 0x01);
280
281	/*
282	 * Activate the timer interrupts: virtual, secure, and non-secure.
283	 */
284	gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
285	gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
286	gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
287}
288#endif /* ARM_INTRNG */
289#endif /* SMP */
290
291#ifndef ARM_INTRNG
292int
293gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt,
294    int *trig, int *pol)
295{
296	static u_int num_intr_cells;
297	static phandle_t self;
298	struct ofw_compat_data *ocd;
299
300	if (self == 0) {
301		for (ocd = compat_data; ocd->ocd_str != NULL; ocd++) {
302			if (fdt_is_compatible(iparent, ocd->ocd_str)) {
303				self = iparent;
304				break;
305			}
306		}
307	}
308	if (self != iparent)
309		return (ENXIO);
310
311	if (num_intr_cells == 0) {
312		if (OF_searchencprop(OF_node_from_xref(iparent),
313		    "#interrupt-cells", &num_intr_cells,
314		    sizeof(num_intr_cells)) == -1) {
315			num_intr_cells = 1;
316		}
317	}
318
319	if (num_intr_cells == 1) {
320		*interrupt = fdt32_to_cpu(intr[0]);
321		*trig = INTR_TRIGGER_CONFORM;
322		*pol = INTR_POLARITY_CONFORM;
323	} else {
324		if (fdt32_to_cpu(intr[0]) == 0)
325			*interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI;
326		else
327			*interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI;
328		/*
329		 * In intr[2], bits[3:0] are trigger type and level flags.
330		 *   1 = low-to-high edge triggered
331		 *   2 = high-to-low edge triggered
332		 *   4 = active high level-sensitive
333		 *   8 = active low level-sensitive
334		 * The hardware only supports active-high-level or rising-edge.
335		 */
336		if (fdt32_to_cpu(intr[2]) & 0x0a) {
337			printf("unsupported trigger/polarity configuration "
338			    "0x%2x\n", fdt32_to_cpu(intr[2]) & 0x0f);
339			return (ENOTSUP);
340		}
341		*pol  = INTR_POLARITY_CONFORM;
342		if (fdt32_to_cpu(intr[2]) & 0x01)
343			*trig = INTR_TRIGGER_EDGE;
344		else
345			*trig = INTR_TRIGGER_LEVEL;
346	}
347	return (0);
348}
349#endif
350
351#ifdef ARM_INTRNG
352static inline intptr_t
353gic_xref(device_t dev)
354{
355#ifdef FDT
356	return (OF_xref_from_node(ofw_bus_get_node(dev)));
357#else
358	return (0);
359#endif
360}
361#endif
362
363static int
364arm_gic_attach(device_t dev)
365{
366	struct		arm_gic_softc *sc;
367	int		i;
368	uint32_t	icciidr;
369#ifdef ARM_INTRNG
370	intptr_t	xref = gic_xref(dev);
371#endif
372
373	if (gic_sc)
374		return (ENXIO);
375
376	sc = device_get_softc(dev);
377
378	if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
379		device_printf(dev, "could not allocate resources\n");
380		return (ENXIO);
381	}
382
383	sc->gic_dev = dev;
384	gic_sc = sc;
385
386	/* Initialize mutex */
387	mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
388
389	/* Distributor Interface */
390	sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
391	sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
392
393	/* CPU Interface */
394	sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
395	sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
396
397	/* Disable interrupt forwarding to the CPU interface */
398	gic_d_write_4(sc, GICD_CTLR, 0x00);
399
400	/* Get the number of interrupts */
401	sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
402	sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
403
404#ifdef ARM_INTRNG
405	sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF,
406	    M_WAITOK | M_ZERO);
407#else
408	/* Set up function pointers */
409	arm_post_filter = gic_post_filter;
410	arm_config_irq = gic_config_irq;
411#endif
412
413	icciidr = gic_c_read_4(sc, GICC_IIDR);
414	device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
415			icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
416			(icciidr & 0xfff), sc->nirqs);
417
418	/* Set all global interrupts to be level triggered, active low. */
419	for (i = 32; i < sc->nirqs; i += 16) {
420		gic_d_write_4(sc, GICD_ICFGR(i >> 4), GIC_DEFAULT_ICFGR_INIT);
421	}
422
423	/* Disable all interrupts. */
424	for (i = 32; i < sc->nirqs; i += 32) {
425		gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
426	}
427
428	for (i = 0; i < sc->nirqs; i += 4) {
429		gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
430		gic_d_write_4(sc, GICD_ITARGETSR(i >> 2),
431		    1 << 0 | 1 << 8 | 1 << 16 | 1 << 24);
432	}
433
434	/* Set all the interrupts to be in Group 0 (secure) */
435	for (i = 0; i < sc->nirqs; i += 32) {
436		gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
437	}
438
439	/* Enable CPU interface */
440	gic_c_write_4(sc, GICC_CTLR, 1);
441
442	/* Set priority mask register. */
443	gic_c_write_4(sc, GICC_PMR, 0xff);
444
445	/* Enable interrupt distribution */
446	gic_d_write_4(sc, GICD_CTLR, 0x01);
447#ifndef ARM_INTRNG
448	return (0);
449#else
450	/*
451	 * Now, when everything is initialized, it's right time to
452	 * register interrupt controller to interrupt framefork.
453	 */
454	if (arm_pic_register(dev, xref) != 0) {
455		device_printf(dev, "could not register PIC\n");
456		goto cleanup;
457	}
458
459	if (sc->gic_res[2] == NULL) {
460		if (arm_pic_claim_root(dev, xref, arm_gic_intr, sc,
461		    GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) {
462			device_printf(dev, "could not set PIC as a root\n");
463			arm_pic_unregister(dev, xref);
464			goto cleanup;
465		}
466	} else {
467		if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK,
468		    arm_gic_intr, NULL, sc, &sc->gic_intrhand)) {
469			device_printf(dev, "could not setup irq handler\n");
470			arm_pic_unregister(dev, xref);
471			goto cleanup;
472		}
473	}
474
475	return (0);
476
477cleanup:
478	/*
479	 * XXX - not implemented arm_gic_detach() should be called !
480	 */
481	if (sc->gic_irqs != NULL)
482		free(sc->gic_irqs, M_DEVBUF);
483	bus_release_resources(dev, arm_gic_spec, sc->gic_res);
484	return(ENXIO);
485#endif
486}
487
488#ifdef ARM_INTRNG
489static int
490arm_gic_intr(void *arg)
491{
492	struct arm_gic_softc *sc = arg;
493	struct arm_irqsrc *isrc;
494	uint32_t irq_active_reg, irq;
495	struct trapframe *tf;
496
497	irq_active_reg = gic_c_read_4(sc, GICC_IAR);
498	irq = irq_active_reg & 0x3FF;
499
500	/*
501	 * 1. We do EOI here because recent read value from active interrupt
502	 *    register must be used for it. Another approach is to save this
503	 *    value into associated interrupt source.
504	 * 2. EOI must be done on same CPU where interrupt has fired. Thus
505	 *    we must ensure that interrupted thread does not migrate to
506	 *    another CPU.
507	 * 3. EOI cannot be delayed by any preemption which could happen on
508	 *    critical_exit() used in MI intr code, when interrupt thread is
509	 *    scheduled. See next point.
510	 * 4. IPI_RENDEZVOUS assumes that no preemption is permitted during
511	 *    an action and any use of critical_exit() could break this
512	 *    assumption. See comments within smp_rendezvous_action().
513	 * 5. We always return FILTER_HANDLED as this is an interrupt
514	 *    controller dispatch function. Otherwise, in cascaded interrupt
515	 *    case, the whole interrupt subtree would be masked.
516	 */
517
518	if (irq >= sc->nirqs) {
519		device_printf(sc->gic_dev, "Spurious interrupt detected\n");
520		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
521		return (FILTER_HANDLED);
522	}
523
524	tf = curthread->td_intr_frame;
525dispatch_irq:
526	isrc = sc->gic_irqs[irq];
527	if (isrc == NULL) {
528		device_printf(sc->gic_dev, "Stray interrupt %u detected\n", irq);
529		gic_irq_mask(sc, irq);
530		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
531		goto next_irq;
532	}
533
534	/*
535	 * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement
536	 * as compiler complains that comparing u_int >= 0 is always true.
537	 */
538	if (irq <= GIC_LAST_SGI) {
539#ifdef SMP
540		/* Call EOI for all IPI before dispatch. */
541		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
542		arm_ipi_dispatch(isrc, tf);
543		goto next_irq;
544#else
545		printf("SGI %u on UP system detected\n", irq - GIC_FIRST_SGI);
546		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
547		goto next_irq;
548#endif
549	}
550
551	if (isrc->isrc_trig == INTR_TRIGGER_EDGE)
552		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
553
554	arm_irq_dispatch(isrc, tf);
555
556next_irq:
557//      arm_irq_memory_barrier(irq); /* XXX */
558//      irq_active_reg = gic_c_read_4(sc, GICC_IAR);
559//      irq = irq_active_reg & 0x3FF;
560	if (0 && irq < sc->nirqs)
561		goto dispatch_irq;
562
563	return (FILTER_HANDLED);
564}
565
566static int
567gic_attach_isrc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int irq)
568{
569	const char *name;
570
571	/*
572	 * 1. The link between ISRC and controller must be set atomically.
573	 * 2. Just do things only once in rare case when consumers
574	 *    of shared interrupt came here at the same moment.
575	 */
576	mtx_lock_spin(&sc->mutex);
577	if (sc->gic_irqs[irq] != NULL) {
578		mtx_unlock_spin(&sc->mutex);
579		return (sc->gic_irqs[irq] == isrc ? 0 : EEXIST);
580	}
581	sc->gic_irqs[irq] = isrc;
582	isrc->isrc_data = irq;
583	mtx_unlock_spin(&sc->mutex);
584
585	name = device_get_nameunit(sc->gic_dev);
586	if (irq <= GIC_LAST_SGI)
587		arm_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI);
588	else if (irq <= GIC_LAST_PPI)
589		arm_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI);
590	else
591		arm_irq_set_name(isrc, "%s,s%u", name, irq - GIC_FIRST_SPI);
592	return (0);
593}
594
595static int
596gic_detach_isrc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int irq)
597{
598
599	mtx_lock_spin(&sc->mutex);
600	if (sc->gic_irqs[irq] != isrc) {
601		mtx_unlock_spin(&sc->mutex);
602		return (sc->gic_irqs[irq] == NULL ? 0 : EINVAL);
603	}
604	sc->gic_irqs[irq] = NULL;
605	isrc->isrc_data = 0;
606	mtx_unlock_spin(&sc->mutex);
607
608	arm_irq_set_name(isrc, "");
609	return (0);
610}
611
612static void
613gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig,
614    enum intr_polarity pol)
615{
616	uint32_t reg;
617	uint32_t mask;
618
619	if (irq < GIC_FIRST_SPI)
620		return;
621
622	mtx_lock_spin(&sc->mutex);
623
624	reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
625	mask = (reg >> 2*(irq % 16)) & 0x3;
626
627	if (pol == INTR_POLARITY_LOW) {
628		mask &= ~GICD_ICFGR_POL_MASK;
629		mask |= GICD_ICFGR_POL_LOW;
630	} else if (pol == INTR_POLARITY_HIGH) {
631		mask &= ~GICD_ICFGR_POL_MASK;
632		mask |= GICD_ICFGR_POL_HIGH;
633	}
634
635	if (trig == INTR_TRIGGER_LEVEL) {
636		mask &= ~GICD_ICFGR_TRIG_MASK;
637		mask |= GICD_ICFGR_TRIG_LVL;
638	} else if (trig == INTR_TRIGGER_EDGE) {
639		mask &= ~GICD_ICFGR_TRIG_MASK;
640		mask |= GICD_ICFGR_TRIG_EDGE;
641	}
642
643	/* Set mask */
644	reg = reg & ~(0x3 << 2*(irq % 16));
645	reg = reg | (mask << 2*(irq % 16));
646	gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
647
648	mtx_unlock_spin(&sc->mutex);
649}
650
651static int
652gic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus)
653{
654	uint32_t cpu, end, mask;
655
656	end = min(mp_ncpus, 8);
657	for (cpu = end; cpu < MAXCPU; cpu++)
658		if (CPU_ISSET(cpu, cpus))
659			return (EINVAL);
660
661	for (mask = 0, cpu = 0; cpu < end; cpu++)
662		if (CPU_ISSET(cpu, cpus))
663			mask |= 1 << cpu;
664
665	gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask);
666	return (0);
667}
668
669static int
670gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp)
671{
672
673	switch (type) {
674	case ARM_IRQ_NSPC_PLAIN:
675		*irqp = num;
676		return (*irqp < sc->nirqs ? 0 : EINVAL);
677
678	case ARM_IRQ_NSPC_IRQ:
679		*irqp = num + GIC_FIRST_PPI;
680		return (*irqp < sc->nirqs ? 0 : EINVAL);
681
682	case ARM_IRQ_NSPC_IPI:
683		*irqp = num + GIC_FIRST_SGI;
684		return (*irqp < GIC_LAST_SGI ? 0 : EINVAL);
685
686	default:
687		return (EINVAL);
688	}
689}
690
691static int
692gic_map_nspc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp)
693{
694	int error;
695
696	error = gic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num,
697	    irqp);
698	if (error != 0)
699		return (error);
700	return (gic_attach_isrc(sc, isrc, *irqp));
701}
702
703#ifdef FDT
704static int
705gic_map_fdt(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp)
706{
707	u_int irq, tripol;
708	enum intr_trigger trig;
709	enum intr_polarity pol;
710	int error;
711
712	if (isrc->isrc_ncells == 1) {
713		irq = isrc->isrc_cells[0];
714		pol = INTR_POLARITY_CONFORM;
715		trig = INTR_TRIGGER_CONFORM;
716	} else if (isrc->isrc_ncells == 3) {
717		if (isrc->isrc_cells[0] == 0)
718			irq = isrc->isrc_cells[1] + GIC_FIRST_SPI;
719		else
720			irq = isrc->isrc_cells[1] + GIC_FIRST_PPI;
721
722		/*
723		 * In intr[2], bits[3:0] are trigger type and level flags.
724		 *   1 = low-to-high edge triggered
725		 *   2 = high-to-low edge triggered
726		 *   4 = active high level-sensitive
727		 *   8 = active low level-sensitive
728		 * The hardware only supports active-high-level or rising-edge.
729		 */
730		tripol = isrc->isrc_cells[2];
731		if (tripol & 0x0a) {
732			printf("unsupported trigger/polarity configuration "
733			    "0x%2x\n", tripol & 0x0f);
734			return (ENOTSUP);
735		}
736		pol = INTR_POLARITY_CONFORM;
737		if (tripol & 0x01)
738			trig = INTR_TRIGGER_EDGE;
739		else
740			trig = INTR_TRIGGER_LEVEL;
741	} else
742		return (EINVAL);
743
744	if (irq >= sc->nirqs)
745		return (EINVAL);
746
747	error = gic_attach_isrc(sc, isrc, irq);
748	if (error != 0)
749		return (error);
750
751	isrc->isrc_nspc_type = ARM_IRQ_NSPC_PLAIN;
752	isrc->isrc_nspc_num = irq;
753	isrc->isrc_trig = trig;
754	isrc->isrc_pol = pol;
755
756	*irqp = irq;
757	return (0);
758}
759#endif
760
761static int
762arm_gic_register(device_t dev, struct arm_irqsrc *isrc, boolean_t *is_percpu)
763{
764	struct arm_gic_softc *sc = device_get_softc(dev);
765	u_int irq;
766	int error;
767
768	if (isrc->isrc_type == ARM_ISRCT_NAMESPACE)
769		error = gic_map_nspc(sc, isrc, &irq);
770#ifdef FDT
771	else if (isrc->isrc_type == ARM_ISRCT_FDT)
772		error = gic_map_fdt(sc, isrc, &irq);
773#endif
774	else
775		return (EINVAL);
776
777	if (error == 0)
778		*is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE;
779	return (error);
780}
781
782static void
783arm_gic_enable_intr(device_t dev, struct arm_irqsrc *isrc)
784{
785	struct arm_gic_softc *sc = device_get_softc(dev);
786	u_int irq = isrc->isrc_data;
787
788	if (isrc->isrc_trig == INTR_TRIGGER_CONFORM)
789		isrc->isrc_trig = INTR_TRIGGER_LEVEL;
790
791	/*
792	 * XXX - In case that per CPU interrupt is going to be enabled in time
793	 *       when SMP is already started, we need some IPI call which
794	 *       enables it on others CPUs. Further, it's more complicated as
795	 *       pic_enable_source() and pic_disable_source() should act on
796	 *       per CPU basis only. Thus, it should be solved here somehow.
797	 */
798	if (isrc->isrc_flags & ARM_ISRCF_PERCPU)
799		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
800
801	gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol);
802	arm_gic_bind(dev, isrc);
803}
804
805static void
806arm_gic_enable_source(device_t dev, struct arm_irqsrc *isrc)
807{
808	struct arm_gic_softc *sc = device_get_softc(dev);
809	u_int irq = isrc->isrc_data;
810
811	arm_irq_memory_barrier(irq);
812	gic_irq_unmask(sc, irq);
813}
814
815static void
816arm_gic_disable_source(device_t dev, struct arm_irqsrc *isrc)
817{
818	struct arm_gic_softc *sc = device_get_softc(dev);
819	u_int irq = isrc->isrc_data;
820
821	gic_irq_mask(sc, irq);
822}
823
824static int
825arm_gic_unregister(device_t dev, struct arm_irqsrc *isrc)
826{
827	struct arm_gic_softc *sc = device_get_softc(dev);
828	u_int irq = isrc->isrc_data;
829
830	return (gic_detach_isrc(sc, isrc, irq));
831}
832
833static void
834arm_gic_pre_ithread(device_t dev, struct arm_irqsrc *isrc)
835{
836	struct arm_gic_softc *sc = device_get_softc(dev);
837
838	arm_gic_disable_source(dev, isrc);
839	gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data);
840}
841
842static void
843arm_gic_post_ithread(device_t dev, struct arm_irqsrc *isrc)
844{
845
846	arm_irq_memory_barrier(0);
847	arm_gic_enable_source(dev, isrc);
848}
849
850static void
851arm_gic_post_filter(device_t dev, struct arm_irqsrc *isrc)
852{
853	struct arm_gic_softc *sc = device_get_softc(dev);
854
855        /* EOI for edge-triggered done earlier. */
856	if (isrc->isrc_trig == INTR_TRIGGER_EDGE)
857		return;
858
859	arm_irq_memory_barrier(0);
860	gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data);
861}
862
863#ifdef SMP
864static int
865arm_gic_bind(device_t dev, struct arm_irqsrc *isrc)
866{
867	struct arm_gic_softc *sc = device_get_softc(dev);
868	uint32_t irq = isrc->isrc_data;
869
870	if (irq < GIC_FIRST_SPI)
871		return (EINVAL);
872
873	if (CPU_EMPTY(&isrc->isrc_cpu)) {
874		gic_irq_cpu = arm_irq_next_cpu(gic_irq_cpu, &all_cpus);
875		CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu);
876	}
877	return (gic_bind(sc, irq, &isrc->isrc_cpu));
878}
879
880static void
881arm_gic_ipi_send(device_t dev, struct arm_irqsrc *isrc, cpuset_t cpus)
882{
883	struct arm_gic_softc *sc = device_get_softc(dev);
884	uint32_t irq, val = 0, i;
885
886	irq = isrc->isrc_data;
887
888	for (i = 0; i < MAXCPU; i++)
889		if (CPU_ISSET(i, &cpus))
890			val |= 1 << (16 + i);
891
892	gic_d_write_4(sc, GICD_SGIR(0), val | irq);
893}
894#endif
895#else
896static int
897arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq)
898{
899	uint32_t active_irq;
900
901	active_irq = gic_c_read_4(sc, GICC_IAR);
902
903	/*
904	 * Immediatly EOIR the SGIs, because doing so requires the other
905	 * bits (ie CPU number), not just the IRQ number, and we do not
906	 * have this information later.
907	 */
908	if ((active_irq & 0x3ff) <= GIC_LAST_SGI)
909		gic_c_write_4(sc, GICC_EOIR, active_irq);
910	active_irq &= 0x3FF;
911
912	if (active_irq == 0x3FF) {
913		if (last_irq == -1)
914			printf("Spurious interrupt detected\n");
915		return -1;
916	}
917
918	return active_irq;
919}
920
921static int
922arm_gic_config(device_t dev, int irq, enum intr_trigger trig,
923    enum intr_polarity pol)
924{
925	struct arm_gic_softc *sc = device_get_softc(dev);
926	uint32_t reg;
927	uint32_t mask;
928
929	/* Function is public-accessible, so validate input arguments */
930	if ((irq < 0) || (irq >= sc->nirqs))
931		goto invalid_args;
932	if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) &&
933	    (trig != INTR_TRIGGER_CONFORM))
934		goto invalid_args;
935	if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) &&
936	    (pol != INTR_POLARITY_CONFORM))
937		goto invalid_args;
938
939	mtx_lock_spin(&sc->mutex);
940
941	reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
942	mask = (reg >> 2*(irq % 16)) & 0x3;
943
944	if (pol == INTR_POLARITY_LOW) {
945		mask &= ~GICD_ICFGR_POL_MASK;
946		mask |= GICD_ICFGR_POL_LOW;
947	} else if (pol == INTR_POLARITY_HIGH) {
948		mask &= ~GICD_ICFGR_POL_MASK;
949		mask |= GICD_ICFGR_POL_HIGH;
950	}
951
952	if (trig == INTR_TRIGGER_LEVEL) {
953		mask &= ~GICD_ICFGR_TRIG_MASK;
954		mask |= GICD_ICFGR_TRIG_LVL;
955	} else if (trig == INTR_TRIGGER_EDGE) {
956		mask &= ~GICD_ICFGR_TRIG_MASK;
957		mask |= GICD_ICFGR_TRIG_EDGE;
958	}
959
960	/* Set mask */
961	reg = reg & ~(0x3 << 2*(irq % 16));
962	reg = reg | (mask << 2*(irq % 16));
963	gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
964
965	mtx_unlock_spin(&sc->mutex);
966
967	return (0);
968
969invalid_args:
970	device_printf(dev, "gic_config_irg, invalid parameters\n");
971	return (EINVAL);
972}
973
974
975static void
976arm_gic_mask(device_t dev, int irq)
977{
978	struct arm_gic_softc *sc = device_get_softc(dev);
979
980	gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
981	gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */
982}
983
984static void
985arm_gic_unmask(device_t dev, int irq)
986{
987	struct arm_gic_softc *sc = device_get_softc(dev);
988
989	if (irq > GIC_LAST_SGI)
990		arm_irq_memory_barrier(irq);
991
992	gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
993}
994
995#ifdef SMP
996static void
997arm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
998{
999	struct arm_gic_softc *sc = device_get_softc(dev);
1000	uint32_t val = 0, i;
1001
1002	for (i = 0; i < MAXCPU; i++)
1003		if (CPU_ISSET(i, &cpus))
1004			val |= 1 << (16 + i);
1005
1006	gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
1007}
1008
1009static int
1010arm_gic_ipi_read(device_t dev, int i)
1011{
1012
1013	if (i != -1) {
1014		/*
1015		 * The intr code will automagically give the frame pointer
1016		 * if the interrupt argument is 0.
1017		 */
1018		if ((unsigned int)i > 16)
1019			return (0);
1020		return (i);
1021	}
1022
1023	return (0x3ff);
1024}
1025
1026static void
1027arm_gic_ipi_clear(device_t dev, int ipi)
1028{
1029	/* no-op */
1030}
1031#endif
1032
1033static void
1034gic_post_filter(void *arg)
1035{
1036	struct arm_gic_softc *sc = gic_sc;
1037	uintptr_t irq = (uintptr_t) arg;
1038
1039	if (irq > GIC_LAST_SGI)
1040		arm_irq_memory_barrier(irq);
1041	gic_c_write_4(sc, GICC_EOIR, irq);
1042}
1043
1044static int
1045gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol)
1046{
1047
1048	return (arm_gic_config(gic_sc->gic_dev, irq, trig, pol));
1049}
1050
1051void
1052arm_mask_irq(uintptr_t nb)
1053{
1054
1055	arm_gic_mask(gic_sc->gic_dev, nb);
1056}
1057
1058void
1059arm_unmask_irq(uintptr_t nb)
1060{
1061
1062	arm_gic_unmask(gic_sc->gic_dev, nb);
1063}
1064
1065int
1066arm_get_next_irq(int last_irq)
1067{
1068
1069	return (arm_gic_next_irq(gic_sc, last_irq));
1070}
1071
1072#ifdef SMP
1073void
1074arm_pic_init_secondary(void)
1075{
1076
1077	arm_gic_init_secondary(gic_sc->gic_dev);
1078}
1079
1080void
1081pic_ipi_send(cpuset_t cpus, u_int ipi)
1082{
1083
1084	arm_gic_ipi_send(gic_sc->gic_dev, cpus, ipi);
1085}
1086
1087int
1088pic_ipi_read(int i)
1089{
1090
1091	return (arm_gic_ipi_read(gic_sc->gic_dev, i));
1092}
1093
1094void
1095pic_ipi_clear(int ipi)
1096{
1097
1098	arm_gic_ipi_clear(gic_sc->gic_dev, ipi);
1099}
1100#endif
1101#endif /* ARM_INTRNG */
1102
1103static device_method_t arm_gic_methods[] = {
1104	/* Device interface */
1105	DEVMETHOD(device_probe,		arm_gic_probe),
1106	DEVMETHOD(device_attach,	arm_gic_attach),
1107#ifdef ARM_INTRNG
1108	/* Interrupt controller interface */
1109	DEVMETHOD(pic_disable_source,	arm_gic_disable_source),
1110	DEVMETHOD(pic_enable_intr,	arm_gic_enable_intr),
1111	DEVMETHOD(pic_enable_source,	arm_gic_enable_source),
1112	DEVMETHOD(pic_post_filter,	arm_gic_post_filter),
1113	DEVMETHOD(pic_post_ithread,	arm_gic_post_ithread),
1114	DEVMETHOD(pic_pre_ithread,	arm_gic_pre_ithread),
1115	DEVMETHOD(pic_register,		arm_gic_register),
1116	DEVMETHOD(pic_unregister,	arm_gic_unregister),
1117#ifdef SMP
1118	DEVMETHOD(pic_bind,		arm_gic_bind),
1119	DEVMETHOD(pic_init_secondary,	arm_gic_init_secondary),
1120	DEVMETHOD(pic_ipi_send,		arm_gic_ipi_send),
1121#endif
1122#endif
1123	{ 0, 0 }
1124};
1125
1126static driver_t arm_gic_driver = {
1127	"gic",
1128	arm_gic_methods,
1129	sizeof(struct arm_gic_softc),
1130};
1131
1132static devclass_t arm_gic_devclass;
1133
1134EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0,
1135    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
1136EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0,
1137    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
1138