1239268Sgonzo/*-
2239268Sgonzo * Copyright (c) 2011 The FreeBSD Foundation
3239268Sgonzo * All rights reserved.
4239268Sgonzo *
5239268Sgonzo * Developed by Damjan Marion <damjan.marion@gmail.com>
6239268Sgonzo *
7239268Sgonzo * Based on OMAP4 GIC code by Ben Gray
8239268Sgonzo *
9239268Sgonzo * Redistribution and use in source and binary forms, with or without
10239268Sgonzo * modification, are permitted provided that the following conditions
11239268Sgonzo * are met:
12239268Sgonzo * 1. Redistributions of source code must retain the above copyright
13239268Sgonzo *    notice, this list of conditions and the following disclaimer.
14239268Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
15239268Sgonzo *    notice, this list of conditions and the following disclaimer in the
16239268Sgonzo *    documentation and/or other materials provided with the distribution.
17239268Sgonzo * 3. The name of the company nor the name of the author may be used to
18239268Sgonzo *    endorse or promote products derived from this software without specific
19239268Sgonzo *    prior written permission.
20239268Sgonzo *
21239268Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22239268Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23239268Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24239268Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25239268Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26239268Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27239268Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28239268Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29239268Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30239268Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31239268Sgonzo * SUCH DAMAGE.
32239268Sgonzo */
33239268Sgonzo
34239268Sgonzo#include <sys/cdefs.h>
35239268Sgonzo__FBSDID("$FreeBSD: stable/11/sys/arm/arm/gic.c 329280 2018-02-14 21:39:10Z gonzo $");
36239268Sgonzo
37289529Sian#include "opt_platform.h"
38289529Sian
39239268Sgonzo#include <sys/param.h>
40239268Sgonzo#include <sys/systm.h>
41239268Sgonzo#include <sys/bus.h>
42239268Sgonzo#include <sys/kernel.h>
43239268Sgonzo#include <sys/ktr.h>
44239268Sgonzo#include <sys/module.h>
45289529Sian#include <sys/malloc.h>
46239268Sgonzo#include <sys/rman.h>
47239268Sgonzo#include <sys/pcpu.h>
48239268Sgonzo#include <sys/proc.h>
49239268Sgonzo#include <sys/cpuset.h>
50239268Sgonzo#include <sys/lock.h>
51239268Sgonzo#include <sys/mutex.h>
52289529Sian#include <sys/smp.h>
53298068Sandrew#ifdef INTRNG
54289529Sian#include <sys/sched.h>
55289529Sian#endif
56299928Sandrew
57299928Sandrew#include <vm/vm.h>
58299928Sandrew#include <vm/pmap.h>
59299928Sandrew
60239268Sgonzo#include <machine/bus.h>
61239268Sgonzo#include <machine/intr.h>
62239268Sgonzo#include <machine/smp.h>
63239268Sgonzo
64239268Sgonzo#include <dev/fdt/fdt_common.h>
65239268Sgonzo#include <dev/ofw/openfirm.h>
66239268Sgonzo#include <dev/ofw/ofw_bus.h>
67239268Sgonzo#include <dev/ofw/ofw_bus_subr.h>
68239268Sgonzo
69298068Sandrew#ifdef INTRNG
70289529Sian#include "pic_if.h"
71299928Sandrew#include "msi_if.h"
72289529Sian#endif
73289529Sian
74291424Smmel#define GIC_DEBUG_SPURIOUS
75291424Smmel
76239268Sgonzo/* We are using GICv2 register naming */
77239268Sgonzo
78239268Sgonzo/* Distributor Registers */
79239268Sgonzo#define GICD_CTLR		0x000			/* v1 ICDDCR */
80239268Sgonzo#define GICD_TYPER		0x004			/* v1 ICDICTR */
81239268Sgonzo#define GICD_IIDR		0x008			/* v1 ICDIIDR */
82239268Sgonzo#define GICD_IGROUPR(n)		(0x0080 + ((n) * 4))	/* v1 ICDISER */
83239268Sgonzo#define GICD_ISENABLER(n)	(0x0100 + ((n) * 4))	/* v1 ICDISER */
84239268Sgonzo#define GICD_ICENABLER(n)	(0x0180 + ((n) * 4))	/* v1 ICDICER */
85239268Sgonzo#define GICD_ISPENDR(n)		(0x0200 + ((n) * 4))	/* v1 ICDISPR */
86239268Sgonzo#define GICD_ICPENDR(n)		(0x0280 + ((n) * 4))	/* v1 ICDICPR */
87239268Sgonzo#define GICD_ICACTIVER(n)	(0x0380 + ((n) * 4))	/* v1 ICDABR */
88239268Sgonzo#define GICD_IPRIORITYR(n)	(0x0400 + ((n) * 4))	/* v1 ICDIPR */
89239268Sgonzo#define GICD_ITARGETSR(n)	(0x0800 + ((n) * 4))	/* v1 ICDIPTR */
90239268Sgonzo#define GICD_ICFGR(n)		(0x0C00 + ((n) * 4))	/* v1 ICDICFR */
91239268Sgonzo#define GICD_SGIR(n)		(0x0F00 + ((n) * 4))	/* v1 ICDSGIR */
92297561Sandrew#define  GICD_SGI_TARGET_SHIFT	16
93239268Sgonzo
94239268Sgonzo/* CPU Registers */
95239268Sgonzo#define GICC_CTLR		0x0000			/* v1 ICCICR */
96239268Sgonzo#define GICC_PMR		0x0004			/* v1 ICCPMR */
97239268Sgonzo#define GICC_BPR		0x0008			/* v1 ICCBPR */
98239268Sgonzo#define GICC_IAR		0x000C			/* v1 ICCIAR */
99239268Sgonzo#define GICC_EOIR		0x0010			/* v1 ICCEOIR */
100239268Sgonzo#define GICC_RPR		0x0014			/* v1 ICCRPR */
101239268Sgonzo#define GICC_HPPIR		0x0018			/* v1 ICCHPIR */
102239268Sgonzo#define GICC_ABPR		0x001C			/* v1 ICCABPR */
103239268Sgonzo#define GICC_IIDR		0x00FC			/* v1 ICCIIDR*/
104239268Sgonzo
105289529Sian#define	GIC_FIRST_SGI		 0	/* Irqs 0-15 are SGIs/IPIs. */
106289529Sian#define	GIC_LAST_SGI		15
107271630Sian#define	GIC_FIRST_PPI		16	/* Irqs 16-31 are private (per */
108271630Sian#define	GIC_LAST_PPI		31	/* core) peripheral interrupts. */
109271630Sian#define	GIC_FIRST_SPI		32	/* Irqs 32+ are shared peripherals. */
110266621Sian
111300051Sbz/* TYPER Registers */
112300051Sbz#define	GICD_TYPER_SECURITYEXT	0x400
113300051Sbz#define	GIC_SUPPORT_SECEXT(_sc)	\
114300051Sbz    ((_sc->typer & GICD_TYPER_SECURITYEXT) == GICD_TYPER_SECURITYEXT)
115300051Sbz
116260161Szbb/* First bit is a polarity bit (0 - low, 1 - high) */
117260161Szbb#define GICD_ICFGR_POL_LOW	(0 << 0)
118260161Szbb#define GICD_ICFGR_POL_HIGH	(1 << 0)
119260161Szbb#define GICD_ICFGR_POL_MASK	0x1
120260161Szbb/* Second bit is a trigger bit (0 - level, 1 - edge) */
121260161Szbb#define GICD_ICFGR_TRIG_LVL	(0 << 1)
122260161Szbb#define GICD_ICFGR_TRIG_EDGE	(1 << 1)
123260161Szbb#define GICD_ICFGR_TRIG_MASK	0x2
124260161Szbb
125280905Sganbold#ifndef	GIC_DEFAULT_ICFGR_INIT
126280905Sganbold#define	GIC_DEFAULT_ICFGR_INIT	0x00000000
127280905Sganbold#endif
128280905Sganbold
129298068Sandrew#ifdef INTRNG
130297539Sskrastruct gic_irqsrc {
131297539Sskra	struct intr_irqsrc	gi_isrc;
132297539Sskra	uint32_t		gi_irq;
133297539Sskra	enum intr_polarity	gi_pol;
134297539Sskra	enum intr_trigger	gi_trig;
135298054Sandrew#define GI_FLAG_EARLY_EOI	(1 << 0)
136299928Sandrew#define GI_FLAG_MSI		(1 << 1) /* This interrupt source should only */
137299928Sandrew					 /* be used for MSI/MSI-X interrupts */
138299928Sandrew#define GI_FLAG_MSI_USED	(1 << 2) /* This irq is already allocated */
139299928Sandrew					 /* for a MSI/MSI-X interrupt */
140298054Sandrew	u_int			gi_flags;
141297539Sskra};
142297539Sskra
143289529Sianstatic u_int gic_irq_cpu;
144289529Sianstatic int arm_gic_intr(void *);
145297539Sskrastatic int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc);
146297230Sskra
147297230Sskra#ifdef SMP
148298403Sandrewstatic u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1];
149298403Sandrewstatic u_int sgi_first_unused = GIC_FIRST_SGI;
150289529Sian#endif
151297230Sskra#endif
152289529Sian
153298068Sandrew#ifdef INTRNG
154298051Sandrewstruct arm_gic_range {
155298051Sandrew	uint64_t bus;
156298051Sandrew	uint64_t host;
157298051Sandrew	uint64_t size;
158298051Sandrew};
159298051Sandrew
160298051Sandrewstruct arm_gic_devinfo {
161298051Sandrew	struct ofw_bus_devinfo	obdinfo;
162298051Sandrew	struct resource_list	rl;
163298051Sandrew};
164298051Sandrew#endif
165298051Sandrew
166239268Sgonzostruct arm_gic_softc {
167276028Sandrew	device_t		gic_dev;
168298068Sandrew#ifdef INTRNG
169289529Sian	void *			gic_intrhand;
170297539Sskra	struct gic_irqsrc *	gic_irqs;
171289529Sian#endif
172239268Sgonzo	struct resource *	gic_res[3];
173239268Sgonzo	bus_space_tag_t		gic_c_bst;
174239268Sgonzo	bus_space_tag_t		gic_d_bst;
175239268Sgonzo	bus_space_handle_t	gic_c_bsh;
176239268Sgonzo	bus_space_handle_t	gic_d_bsh;
177239268Sgonzo	uint8_t			ver;
178260161Szbb	struct mtx		mutex;
179260161Szbb	uint32_t		nirqs;
180300051Sbz	uint32_t		typer;
181291424Smmel#ifdef GIC_DEBUG_SPURIOUS
182291424Smmel	uint32_t		last_irq[MAXCPU];
183291424Smmel#endif
184298051Sandrew
185298068Sandrew#ifdef INTRNG
186298051Sandrew	/* FDT child data */
187298051Sandrew	pcell_t			addr_cells;
188298051Sandrew	pcell_t			size_cells;
189298051Sandrew	int			nranges;
190298051Sandrew	struct arm_gic_range *	ranges;
191298051Sandrew#endif
192239268Sgonzo};
193239268Sgonzo
194298068Sandrew#ifdef INTRNG
195297539Sskra#define GIC_INTR_ISRC(sc, irq)	(&sc->gic_irqs[irq].gi_isrc)
196297539Sskra#endif
197297539Sskra
198239268Sgonzostatic struct resource_spec arm_gic_spec[] = {
199239268Sgonzo	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },	/* Distributor registers */
200239268Sgonzo	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },	/* CPU Interrupt Intf. registers */
201298068Sandrew#ifdef INTRNG
202289529Sian	{ SYS_RES_IRQ,	  0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */
203289529Sian#endif
204239268Sgonzo	{ -1, 0 }
205239268Sgonzo};
206239268Sgonzo
207297561Sandrewstatic u_int arm_gic_map[MAXCPU];
208297561Sandrew
209289529Sianstatic struct arm_gic_softc *gic_sc = NULL;
210239268Sgonzo
211276015Sandrew#define	gic_c_read_4(_sc, _reg)		\
212276015Sandrew    bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
213276015Sandrew#define	gic_c_write_4(_sc, _reg, _val)		\
214276015Sandrew    bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
215276015Sandrew#define	gic_d_read_4(_sc, _reg)		\
216276015Sandrew    bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
217289529Sian#define	gic_d_write_1(_sc, _reg, _val)		\
218289529Sian    bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
219276015Sandrew#define	gic_d_write_4(_sc, _reg, _val)		\
220276015Sandrew    bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
221239268Sgonzo
222298068Sandrew#ifndef INTRNG
223260161Szbbstatic int gic_config_irq(int irq, enum intr_trigger trig,
224260161Szbb    enum intr_polarity pol);
225239268Sgonzostatic void gic_post_filter(void *);
226289529Sian#endif
227239268Sgonzo
228271595Sianstatic struct ofw_compat_data compat_data[] = {
229271595Sian	{"arm,gic",		true},	/* Non-standard, used in FreeBSD dts. */
230271595Sian	{"arm,gic-400",		true},
231271595Sian	{"arm,cortex-a15-gic",	true},
232271595Sian	{"arm,cortex-a9-gic",	true},
233271595Sian	{"arm,cortex-a7-gic",	true},
234271595Sian	{"arm,arm11mp-gic",	true},
235271595Sian	{"brcm,brahma-b15-gic",	true},
236298051Sandrew	{"qcom,msm-qgic2",	true},
237271595Sian	{NULL,			false}
238271595Sian};
239271595Sian
240239268Sgonzostatic int
241239268Sgonzoarm_gic_probe(device_t dev)
242239268Sgonzo{
243252370Sray
244261410Sian	if (!ofw_bus_status_okay(dev))
245261410Sian		return (ENXIO);
246261410Sian
247271595Sian	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
248239268Sgonzo		return (ENXIO);
249239268Sgonzo	device_set_desc(dev, "ARM Generic Interrupt Controller");
250239268Sgonzo	return (BUS_PROBE_DEFAULT);
251239268Sgonzo}
252239268Sgonzo
253298068Sandrew#ifdef INTRNG
254289529Sianstatic inline void
255289529Siangic_irq_unmask(struct arm_gic_softc *sc, u_int irq)
256289529Sian{
257289529Sian
258289529Sian	gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
259289529Sian}
260289529Sian
261289529Sianstatic inline void
262289529Siangic_irq_mask(struct arm_gic_softc *sc, u_int irq)
263289529Sian{
264289529Sian
265289529Sian	gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
266289529Sian}
267289529Sian#endif
268289529Sian
269297561Sandrewstatic uint8_t
270297561Sandrewgic_cpu_mask(struct arm_gic_softc *sc)
271297561Sandrew{
272297561Sandrew	uint32_t mask;
273297561Sandrew	int i;
274297561Sandrew
275297561Sandrew	/* Read the current cpuid mask by reading ITARGETSR{0..7} */
276297561Sandrew	for (i = 0; i < 8; i++) {
277297561Sandrew		mask = gic_d_read_4(sc, GICD_ITARGETSR(i));
278297561Sandrew		if (mask != 0)
279297561Sandrew			break;
280297561Sandrew	}
281297561Sandrew	/* No mask found, assume we are on CPU interface 0 */
282297561Sandrew	if (mask == 0)
283297561Sandrew		return (1);
284297561Sandrew
285297561Sandrew	/* Collect the mask in the lower byte */
286297561Sandrew	mask |= mask >> 16;
287297561Sandrew	mask |= mask >> 8;
288297561Sandrew
289297561Sandrew	return (mask);
290297561Sandrew}
291297561Sandrew
292289529Sian#ifdef SMP
293298068Sandrew#ifdef INTRNG
294276963Sandrewstatic void
295276963Sandrewarm_gic_init_secondary(device_t dev)
296239268Sgonzo{
297276963Sandrew	struct arm_gic_softc *sc = device_get_softc(dev);
298297674Sskra	u_int irq, cpu;
299289529Sian
300297561Sandrew	/* Set the mask so we can find this CPU to send it IPIs */
301297674Sskra	cpu = PCPU_GET(cpuid);
302297674Sskra	arm_gic_map[cpu] = gic_cpu_mask(sc);
303297561Sandrew
304289529Sian	for (irq = 0; irq < sc->nirqs; irq += 4)
305289529Sian		gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0);
306289529Sian
307289529Sian	/* Set all the interrupts to be in Group 0 (secure) */
308300051Sbz	for (irq = 0; GIC_SUPPORT_SECEXT(sc) && irq < sc->nirqs; irq += 32) {
309289529Sian		gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0);
310289529Sian	}
311289529Sian
312289529Sian	/* Enable CPU interface */
313289529Sian	gic_c_write_4(sc, GICC_CTLR, 1);
314289529Sian
315289529Sian	/* Set priority mask register. */
316289529Sian	gic_c_write_4(sc, GICC_PMR, 0xff);
317289529Sian
318289529Sian	/* Enable interrupt distribution */
319289529Sian	gic_d_write_4(sc, GICD_CTLR, 0x01);
320289529Sian
321289529Sian	/* Unmask attached SGI interrupts. */
322297674Sskra	for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++)
323297674Sskra		if (intr_isrc_init_on_cpu(GIC_INTR_ISRC(sc, irq), cpu))
324289529Sian			gic_irq_unmask(sc, irq);
325289529Sian
326289529Sian	/* Unmask attached PPI interrupts. */
327297674Sskra	for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++)
328297674Sskra		if (intr_isrc_init_on_cpu(GIC_INTR_ISRC(sc, irq), cpu))
329289529Sian			gic_irq_unmask(sc, irq);
330289529Sian}
331289529Sian#else
332289529Sianstatic void
333289529Sianarm_gic_init_secondary(device_t dev)
334289529Sian{
335289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
336276028Sandrew	int i;
337252370Sray
338297561Sandrew	/* Set the mask so we can find this CPU to send it IPIs */
339297561Sandrew	arm_gic_map[PCPU_GET(cpuid)] = gic_cpu_mask(sc);
340297561Sandrew
341276028Sandrew	for (i = 0; i < sc->nirqs; i += 4)
342276015Sandrew		gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
343252370Sray
344252370Sray	/* Set all the interrupts to be in Group 0 (secure) */
345300051Sbz	for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) {
346276015Sandrew		gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
347252370Sray	}
348252370Sray
349239268Sgonzo	/* Enable CPU interface */
350276015Sandrew	gic_c_write_4(sc, GICC_CTLR, 1);
351239268Sgonzo
352249762Sdmarion	/* Set priority mask register. */
353276015Sandrew	gic_c_write_4(sc, GICC_PMR, 0xff);
354249762Sdmarion
355239268Sgonzo	/* Enable interrupt distribution */
356276015Sandrew	gic_d_write_4(sc, GICD_CTLR, 0x01);
357252370Sray
358271181Sandrew	/*
359271181Sandrew	 * Activate the timer interrupts: virtual, secure, and non-secure.
360271181Sandrew	 */
361276015Sandrew	gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F)));
362276015Sandrew	gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
363276015Sandrew	gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
364239268Sgonzo}
365298068Sandrew#endif /* INTRNG */
366289529Sian#endif /* SMP */
367291424Smmel
368298068Sandrew#ifndef INTRNG
369271601Sianint
370289548Siangic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt,
371271601Sian    int *trig, int *pol)
372271601Sian{
373271601Sian	static u_int num_intr_cells;
374289548Sian	static phandle_t self;
375289548Sian	struct ofw_compat_data *ocd;
376271601Sian
377289548Sian	if (self == 0) {
378289548Sian		for (ocd = compat_data; ocd->ocd_str != NULL; ocd++) {
379289548Sian			if (fdt_is_compatible(iparent, ocd->ocd_str)) {
380289548Sian				self = iparent;
381289548Sian				break;
382289548Sian			}
383289548Sian		}
384289548Sian	}
385289548Sian	if (self != iparent)
386289548Sian		return (ENXIO);
387289548Sian
388271601Sian	if (num_intr_cells == 0) {
389283366Sandrew		if (OF_searchencprop(OF_node_from_xref(iparent),
390283366Sandrew		    "#interrupt-cells", &num_intr_cells,
391271601Sian		    sizeof(num_intr_cells)) == -1) {
392271601Sian			num_intr_cells = 1;
393271601Sian		}
394271601Sian	}
395271601Sian
396271601Sian	if (num_intr_cells == 1) {
397271601Sian		*interrupt = fdt32_to_cpu(intr[0]);
398271601Sian		*trig = INTR_TRIGGER_CONFORM;
399271601Sian		*pol = INTR_POLARITY_CONFORM;
400271601Sian	} else {
401279235Szbb		if (fdt32_to_cpu(intr[0]) == 0)
402271630Sian			*interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI;
403271601Sian		else
404271630Sian			*interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI;
405271601Sian		/*
406271601Sian		 * In intr[2], bits[3:0] are trigger type and level flags.
407271601Sian		 *   1 = low-to-high edge triggered
408271601Sian		 *   2 = high-to-low edge triggered
409271601Sian		 *   4 = active high level-sensitive
410271601Sian		 *   8 = active low level-sensitive
411294422Szbb		 * The hardware only supports active-high-level or rising-edge
412294422Szbb		 * for SPIs
413271601Sian		 */
414294422Szbb		if (*interrupt >= GIC_FIRST_SPI &&
415294422Szbb		    fdt32_to_cpu(intr[2]) & 0x0a) {
416271601Sian			printf("unsupported trigger/polarity configuration "
417291424Smmel			    "0x%02x\n", fdt32_to_cpu(intr[2]) & 0x0f);
418271601Sian		}
419271601Sian		*pol  = INTR_POLARITY_CONFORM;
420291424Smmel		if (fdt32_to_cpu(intr[2]) & 0x03)
421271601Sian			*trig = INTR_TRIGGER_EDGE;
422271601Sian		else
423271601Sian			*trig = INTR_TRIGGER_LEVEL;
424271601Sian	}
425271601Sian	return (0);
426271601Sian}
427289529Sian#endif
428271601Sian
429298068Sandrew#ifdef INTRNG
430289529Sianstatic inline intptr_t
431289529Siangic_xref(device_t dev)
432289529Sian{
433289529Sian#ifdef FDT
434289529Sian	return (OF_xref_from_node(ofw_bus_get_node(dev)));
435289529Sian#else
436289529Sian	return (0);
437289529Sian#endif
438289529Sian}
439297539Sskra
440297539Sskrastatic int
441297539Sskraarm_gic_register_isrcs(struct arm_gic_softc *sc, uint32_t num)
442297539Sskra{
443297539Sskra	int error;
444297539Sskra	uint32_t irq;
445297539Sskra	struct gic_irqsrc *irqs;
446297539Sskra	struct intr_irqsrc *isrc;
447297539Sskra	const char *name;
448297539Sskra
449297539Sskra	irqs = malloc(num * sizeof(struct gic_irqsrc), M_DEVBUF,
450297539Sskra	    M_WAITOK | M_ZERO);
451297539Sskra
452297539Sskra	name = device_get_nameunit(sc->gic_dev);
453297539Sskra	for (irq = 0; irq < num; irq++) {
454297539Sskra		irqs[irq].gi_irq = irq;
455297539Sskra		irqs[irq].gi_pol = INTR_POLARITY_CONFORM;
456297539Sskra		irqs[irq].gi_trig = INTR_TRIGGER_CONFORM;
457297539Sskra
458297539Sskra		isrc = &irqs[irq].gi_isrc;
459297539Sskra		if (irq <= GIC_LAST_SGI) {
460297539Sskra			error = intr_isrc_register(isrc, sc->gic_dev,
461297539Sskra			    INTR_ISRCF_IPI, "%s,i%u", name, irq - GIC_FIRST_SGI);
462297539Sskra		} else if (irq <= GIC_LAST_PPI) {
463297539Sskra			error = intr_isrc_register(isrc, sc->gic_dev,
464297539Sskra			    INTR_ISRCF_PPI, "%s,p%u", name, irq - GIC_FIRST_PPI);
465297539Sskra		} else {
466297539Sskra			error = intr_isrc_register(isrc, sc->gic_dev, 0,
467297539Sskra			    "%s,s%u", name, irq - GIC_FIRST_SPI);
468297539Sskra		}
469297539Sskra		if (error != 0) {
470297539Sskra			/* XXX call intr_isrc_deregister() */
471297539Sskra			free(irqs, M_DEVBUF);
472297539Sskra			return (error);
473297539Sskra		}
474297539Sskra	}
475297539Sskra	sc->gic_irqs = irqs;
476297539Sskra	sc->nirqs = num;
477297539Sskra	return (0);
478297539Sskra}
479298051Sandrew
480298051Sandrewstatic int
481298051Sandrewarm_gic_fill_ranges(phandle_t node, struct arm_gic_softc *sc)
482298051Sandrew{
483298051Sandrew	pcell_t host_cells;
484298051Sandrew	cell_t *base_ranges;
485298051Sandrew	ssize_t nbase_ranges;
486298051Sandrew	int i, j, k;
487298051Sandrew
488298051Sandrew	host_cells = 1;
489298051Sandrew	OF_getencprop(OF_parent(node), "#address-cells", &host_cells,
490298051Sandrew	    sizeof(host_cells));
491298051Sandrew	sc->addr_cells = 2;
492298051Sandrew	OF_getencprop(node, "#address-cells", &sc->addr_cells,
493298051Sandrew	    sizeof(sc->addr_cells));
494298051Sandrew	sc->size_cells = 2;
495298051Sandrew	OF_getencprop(node, "#size-cells", &sc->size_cells,
496298051Sandrew	    sizeof(sc->size_cells));
497298051Sandrew
498298051Sandrew	nbase_ranges = OF_getproplen(node, "ranges");
499298051Sandrew	if (nbase_ranges < 0)
500298051Sandrew		return (-1);
501298051Sandrew	sc->nranges = nbase_ranges / sizeof(cell_t) /
502298051Sandrew	    (sc->addr_cells + host_cells + sc->size_cells);
503298051Sandrew	if (sc->nranges == 0)
504298051Sandrew		return (0);
505298051Sandrew
506298051Sandrew	sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]),
507298051Sandrew	    M_DEVBUF, M_WAITOK);
508298051Sandrew	base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
509298051Sandrew	OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
510298051Sandrew
511298051Sandrew	for (i = 0, j = 0; i < sc->nranges; i++) {
512298051Sandrew		sc->ranges[i].bus = 0;
513298051Sandrew		for (k = 0; k < sc->addr_cells; k++) {
514298051Sandrew			sc->ranges[i].bus <<= 32;
515298051Sandrew			sc->ranges[i].bus |= base_ranges[j++];
516298051Sandrew		}
517298051Sandrew		sc->ranges[i].host = 0;
518298051Sandrew		for (k = 0; k < host_cells; k++) {
519298051Sandrew			sc->ranges[i].host <<= 32;
520298051Sandrew			sc->ranges[i].host |= base_ranges[j++];
521298051Sandrew		}
522298051Sandrew		sc->ranges[i].size = 0;
523298051Sandrew		for (k = 0; k < sc->size_cells; k++) {
524298051Sandrew			sc->ranges[i].size <<= 32;
525298051Sandrew			sc->ranges[i].size |= base_ranges[j++];
526298051Sandrew		}
527298051Sandrew	}
528298051Sandrew
529298051Sandrew	free(base_ranges, M_DEVBUF);
530298051Sandrew	return (sc->nranges);
531298051Sandrew}
532298051Sandrew
533298051Sandrewstatic bool
534298051Sandrewarm_gic_add_children(device_t dev)
535298051Sandrew{
536298051Sandrew	struct arm_gic_softc *sc;
537298051Sandrew	struct arm_gic_devinfo *dinfo;
538298051Sandrew	phandle_t child, node;
539298051Sandrew	device_t cdev;
540298051Sandrew
541298051Sandrew	sc = device_get_softc(dev);
542298051Sandrew	node = ofw_bus_get_node(dev);
543298051Sandrew
544298051Sandrew	/* If we have no children don't probe for them */
545298051Sandrew	child = OF_child(node);
546298051Sandrew	if (child == 0)
547298051Sandrew		return (false);
548298051Sandrew
549298051Sandrew	if (arm_gic_fill_ranges(node, sc) < 0) {
550298051Sandrew		device_printf(dev, "Have a child, but no ranges\n");
551298051Sandrew		return (false);
552298051Sandrew	}
553298051Sandrew
554298051Sandrew	for (; child != 0; child = OF_peer(child)) {
555298051Sandrew		dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO);
556298051Sandrew
557298051Sandrew		if (ofw_bus_gen_setup_devinfo(&dinfo->obdinfo, child) != 0) {
558298051Sandrew			free(dinfo, M_DEVBUF);
559298051Sandrew			continue;
560298051Sandrew		}
561298051Sandrew
562298051Sandrew		resource_list_init(&dinfo->rl);
563298051Sandrew		ofw_bus_reg_to_rl(dev, child, sc->addr_cells,
564298051Sandrew		    sc->size_cells, &dinfo->rl);
565298051Sandrew
566298051Sandrew		cdev = device_add_child(dev, NULL, -1);
567298051Sandrew		if (cdev == NULL) {
568298051Sandrew			device_printf(dev, "<%s>: device_add_child failed\n",
569298051Sandrew			    dinfo->obdinfo.obd_name);
570298051Sandrew			resource_list_free(&dinfo->rl);
571298051Sandrew			ofw_bus_gen_destroy_devinfo(&dinfo->obdinfo);
572298051Sandrew			free(dinfo, M_DEVBUF);
573298051Sandrew			continue;
574298051Sandrew		}
575298051Sandrew		device_set_ivars(cdev, dinfo);
576298051Sandrew	}
577298051Sandrew
578298051Sandrew	return (true);
579298051Sandrew}
580299928Sandrew
581299928Sandrewstatic void
582299928Sandrewarm_gic_reserve_msi_range(device_t dev, u_int start, u_int count)
583299928Sandrew{
584299928Sandrew	struct arm_gic_softc *sc;
585299928Sandrew	int i;
586299928Sandrew
587299928Sandrew	sc = device_get_softc(dev);
588299928Sandrew
589299928Sandrew	KASSERT((start + count) < sc->nirqs,
590299928Sandrew	    ("%s: Trying to allocate too many MSI IRQs: %d + %d > %d", __func__,
591299928Sandrew	    start, count, sc->nirqs));
592299928Sandrew	for (i = 0; i < count; i++) {
593299928Sandrew		KASSERT(sc->gic_irqs[start + i].gi_isrc.isrc_handlers == 0,
594299928Sandrew		    ("%s: MSI interrupt %d already has a handler", __func__,
595299928Sandrew		    count + i));
596299928Sandrew		KASSERT(sc->gic_irqs[start + i].gi_pol == INTR_POLARITY_CONFORM,
597299928Sandrew		    ("%s: MSI interrupt %d already has a polarity", __func__,
598299928Sandrew		    count + i));
599299928Sandrew		KASSERT(sc->gic_irqs[start + i].gi_trig == INTR_TRIGGER_CONFORM,
600299928Sandrew		    ("%s: MSI interrupt %d already has a trigger", __func__,
601299928Sandrew		    count + i));
602299928Sandrew		sc->gic_irqs[start + i].gi_pol = INTR_POLARITY_HIGH;
603299928Sandrew		sc->gic_irqs[start + i].gi_trig = INTR_TRIGGER_EDGE;
604299928Sandrew		sc->gic_irqs[start + i].gi_flags |= GI_FLAG_MSI;
605299928Sandrew	}
606299928Sandrew}
607289529Sian#endif
608289529Sian
609239268Sgonzostatic int
610239268Sgonzoarm_gic_attach(device_t dev)
611239268Sgonzo{
612252370Sray	struct		arm_gic_softc *sc;
613239268Sgonzo	int		i;
614297539Sskra	uint32_t	icciidr, mask, nirqs;
615298068Sandrew#ifdef INTRNG
616291424Smmel	phandle_t	pxref;
617289529Sian	intptr_t	xref = gic_xref(dev);
618289529Sian#endif
619239268Sgonzo
620289529Sian	if (gic_sc)
621239268Sgonzo		return (ENXIO);
622239268Sgonzo
623252370Sray	sc = device_get_softc(dev);
624252370Sray
625239268Sgonzo	if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) {
626239268Sgonzo		device_printf(dev, "could not allocate resources\n");
627239268Sgonzo		return (ENXIO);
628239268Sgonzo	}
629239268Sgonzo
630276028Sandrew	sc->gic_dev = dev;
631289529Sian	gic_sc = sc;
632276028Sandrew
633260161Szbb	/* Initialize mutex */
634260161Szbb	mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
635239268Sgonzo
636239268Sgonzo	/* Distributor Interface */
637239268Sgonzo	sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]);
638239268Sgonzo	sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]);
639239268Sgonzo
640239268Sgonzo	/* CPU Interface */
641239268Sgonzo	sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]);
642239268Sgonzo	sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]);
643239268Sgonzo
644239268Sgonzo	/* Disable interrupt forwarding to the CPU interface */
645276015Sandrew	gic_d_write_4(sc, GICD_CTLR, 0x00);
646239268Sgonzo
647239268Sgonzo	/* Get the number of interrupts */
648300051Sbz	sc->typer = gic_d_read_4(sc, GICD_TYPER);
649300051Sbz	nirqs = 32 * ((sc->typer & 0x1f) + 1);
650239268Sgonzo
651298068Sandrew#ifdef INTRNG
652297539Sskra	if (arm_gic_register_isrcs(sc, nirqs)) {
653297539Sskra		device_printf(dev, "could not register irqs\n");
654297539Sskra		goto cleanup;
655297539Sskra	}
656289529Sian#else
657297539Sskra	sc->nirqs = nirqs;
658297539Sskra
659260161Szbb	/* Set up function pointers */
660260161Szbb	arm_post_filter = gic_post_filter;
661260161Szbb	arm_config_irq = gic_config_irq;
662289529Sian#endif
663260161Szbb
664276015Sandrew	icciidr = gic_c_read_4(sc, GICC_IIDR);
665274484Szbb	device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
666239268Sgonzo			icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf,
667260161Szbb			(icciidr & 0xfff), sc->nirqs);
668239268Sgonzo
669239268Sgonzo	/* Set all global interrupts to be level triggered, active low. */
670260161Szbb	for (i = 32; i < sc->nirqs; i += 16) {
671280905Sganbold		gic_d_write_4(sc, GICD_ICFGR(i >> 4), GIC_DEFAULT_ICFGR_INIT);
672239268Sgonzo	}
673239268Sgonzo
674239268Sgonzo	/* Disable all interrupts. */
675260161Szbb	for (i = 32; i < sc->nirqs; i += 32) {
676276015Sandrew		gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF);
677239268Sgonzo	}
678239268Sgonzo
679297561Sandrew	/* Find the current cpu mask */
680297561Sandrew	mask = gic_cpu_mask(sc);
681297561Sandrew	/* Set the mask so we can find this CPU to send it IPIs */
682297561Sandrew	arm_gic_map[PCPU_GET(cpuid)] = mask;
683297561Sandrew	/* Set all four targets to this cpu */
684297390Sandrew	mask |= mask << 8;
685297390Sandrew	mask |= mask << 16;
686297390Sandrew
687260161Szbb	for (i = 0; i < sc->nirqs; i += 4) {
688276015Sandrew		gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0);
689297390Sandrew		if (i > 32) {
690297390Sandrew			gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), mask);
691297390Sandrew		}
692239268Sgonzo	}
693239268Sgonzo
694252370Sray	/* Set all the interrupts to be in Group 0 (secure) */
695300051Sbz	for (i = 0; GIC_SUPPORT_SECEXT(sc) && i < sc->nirqs; i += 32) {
696276015Sandrew		gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0);
697252370Sray	}
698252370Sray
699239268Sgonzo	/* Enable CPU interface */
700276015Sandrew	gic_c_write_4(sc, GICC_CTLR, 1);
701239268Sgonzo
702249762Sdmarion	/* Set priority mask register. */
703276015Sandrew	gic_c_write_4(sc, GICC_PMR, 0xff);
704249762Sdmarion
705239268Sgonzo	/* Enable interrupt distribution */
706276015Sandrew	gic_d_write_4(sc, GICD_CTLR, 0x01);
707298068Sandrew#ifndef INTRNG
708289529Sian	return (0);
709289529Sian#else
710289529Sian	/*
711289529Sian	 * Now, when everything is initialized, it's right time to
712289529Sian	 * register interrupt controller to interrupt framefork.
713289529Sian	 */
714300149Sandrew	if (intr_pic_register(dev, xref) == NULL) {
715289529Sian		device_printf(dev, "could not register PIC\n");
716289529Sian		goto cleanup;
717289529Sian	}
718239268Sgonzo
719291649Smmel	/*
720291649Smmel	 * Controller is root if:
721291649Smmel	 * - doesn't have interrupt parent
722291649Smmel	 * - his interrupt parent is this controller
723291649Smmel	 */
724291649Smmel	pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev));
725291649Smmel	if (pxref == 0 || xref == pxref) {
726292426Sadrian		if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc,
727289529Sian		    GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) {
728289529Sian			device_printf(dev, "could not set PIC as a root\n");
729297539Sskra			intr_pic_deregister(dev, xref);
730289529Sian			goto cleanup;
731289529Sian		}
732289529Sian	} else {
733291649Smmel		if (sc->gic_res[2] == NULL) {
734291649Smmel			device_printf(dev,
735291649Smmel			    "not root PIC must have defined interrupt\n");
736297539Sskra			intr_pic_deregister(dev, xref);
737291649Smmel			goto cleanup;
738291649Smmel		}
739289529Sian		if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK,
740289529Sian		    arm_gic_intr, NULL, sc, &sc->gic_intrhand)) {
741289529Sian			device_printf(dev, "could not setup irq handler\n");
742297539Sskra			intr_pic_deregister(dev, xref);
743289529Sian			goto cleanup;
744289529Sian		}
745289529Sian	}
746289529Sian
747291424Smmel	OF_device_register_xref(xref, dev);
748298051Sandrew
749298051Sandrew	/* If we have children probe and attach them */
750298051Sandrew	if (arm_gic_add_children(dev)) {
751298051Sandrew		bus_generic_probe(dev);
752298051Sandrew		return (bus_generic_attach(dev));
753298051Sandrew	}
754298051Sandrew
755239268Sgonzo	return (0);
756289529Sian
757289529Siancleanup:
758289529Sian	/*
759289529Sian	 * XXX - not implemented arm_gic_detach() should be called !
760289529Sian	 */
761289529Sian	if (sc->gic_irqs != NULL)
762289529Sian		free(sc->gic_irqs, M_DEVBUF);
763289529Sian	bus_release_resources(dev, arm_gic_spec, sc->gic_res);
764289529Sian	return(ENXIO);
765289529Sian#endif
766239268Sgonzo}
767239268Sgonzo
768298068Sandrew#ifdef INTRNG
769298051Sandrewstatic struct resource *
770298051Sandrewarm_gic_alloc_resource(device_t bus, device_t child, int type, int *rid,
771298051Sandrew    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
772298051Sandrew{
773298051Sandrew	struct arm_gic_softc *sc;
774298051Sandrew	struct arm_gic_devinfo *di;
775298051Sandrew	struct resource_list_entry *rle;
776298051Sandrew	int j;
777298051Sandrew
778298051Sandrew	KASSERT(type == SYS_RES_MEMORY, ("Invalid resoure type %x", type));
779298051Sandrew
780298051Sandrew	sc = device_get_softc(bus);
781298051Sandrew
782298051Sandrew	/*
783298051Sandrew	 * Request for the default allocation with a given rid: use resource
784298051Sandrew	 * list stored in the local device info.
785298051Sandrew	 */
786298051Sandrew	if (RMAN_IS_DEFAULT_RANGE(start, end)) {
787298051Sandrew		if ((di = device_get_ivars(child)) == NULL)
788298051Sandrew			return (NULL);
789298051Sandrew
790298051Sandrew		if (type == SYS_RES_IOPORT)
791298051Sandrew			type = SYS_RES_MEMORY;
792298051Sandrew
793298051Sandrew		rle = resource_list_find(&di->rl, type, *rid);
794298051Sandrew		if (rle == NULL) {
795298051Sandrew			if (bootverbose)
796298051Sandrew				device_printf(bus, "no default resources for "
797298051Sandrew				    "rid = %d, type = %d\n", *rid, type);
798298051Sandrew			return (NULL);
799298051Sandrew		}
800298051Sandrew		start = rle->start;
801298051Sandrew		end = rle->end;
802298051Sandrew		count = rle->count;
803298051Sandrew	}
804298051Sandrew
805298051Sandrew	/* Remap through ranges property */
806298051Sandrew	for (j = 0; j < sc->nranges; j++) {
807298051Sandrew		if (start >= sc->ranges[j].bus && end <
808298051Sandrew		    sc->ranges[j].bus + sc->ranges[j].size) {
809298051Sandrew			start -= sc->ranges[j].bus;
810298051Sandrew			start += sc->ranges[j].host;
811298051Sandrew			end -= sc->ranges[j].bus;
812298051Sandrew			end += sc->ranges[j].host;
813298051Sandrew			break;
814298051Sandrew		}
815298051Sandrew	}
816298051Sandrew	if (j == sc->nranges && sc->nranges != 0) {
817298051Sandrew		if (bootverbose)
818298051Sandrew			device_printf(bus, "Could not map resource "
819298051Sandrew			    "%#jx-%#jx\n", (uintmax_t)start, (uintmax_t)end);
820298051Sandrew
821298051Sandrew		return (NULL);
822298051Sandrew	}
823298051Sandrew
824298051Sandrew	return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
825298051Sandrew	    count, flags));
826298051Sandrew}
827298051Sandrew
828298051Sandrewstatic const struct ofw_bus_devinfo *
829298051Sandrewarm_gic_ofw_get_devinfo(device_t bus __unused, device_t child)
830298051Sandrew{
831298051Sandrew	struct arm_gic_devinfo *di;
832298051Sandrew
833298051Sandrew	di = device_get_ivars(child);
834298051Sandrew
835298051Sandrew	return (&di->obdinfo);
836298051Sandrew}
837298051Sandrew
838276963Sandrewstatic int
839289529Sianarm_gic_intr(void *arg)
840289529Sian{
841289529Sian	struct arm_gic_softc *sc = arg;
842297539Sskra	struct gic_irqsrc *gi;
843289529Sian	uint32_t irq_active_reg, irq;
844289529Sian	struct trapframe *tf;
845289529Sian
846289529Sian	irq_active_reg = gic_c_read_4(sc, GICC_IAR);
847289529Sian	irq = irq_active_reg & 0x3FF;
848289529Sian
849289529Sian	/*
850289529Sian	 * 1. We do EOI here because recent read value from active interrupt
851289529Sian	 *    register must be used for it. Another approach is to save this
852289529Sian	 *    value into associated interrupt source.
853289529Sian	 * 2. EOI must be done on same CPU where interrupt has fired. Thus
854289529Sian	 *    we must ensure that interrupted thread does not migrate to
855289529Sian	 *    another CPU.
856289529Sian	 * 3. EOI cannot be delayed by any preemption which could happen on
857289529Sian	 *    critical_exit() used in MI intr code, when interrupt thread is
858289529Sian	 *    scheduled. See next point.
859289529Sian	 * 4. IPI_RENDEZVOUS assumes that no preemption is permitted during
860289529Sian	 *    an action and any use of critical_exit() could break this
861289529Sian	 *    assumption. See comments within smp_rendezvous_action().
862289529Sian	 * 5. We always return FILTER_HANDLED as this is an interrupt
863289529Sian	 *    controller dispatch function. Otherwise, in cascaded interrupt
864289529Sian	 *    case, the whole interrupt subtree would be masked.
865289529Sian	 */
866289529Sian
867289529Sian	if (irq >= sc->nirqs) {
868291424Smmel#ifdef GIC_DEBUG_SPURIOUS
869291424Smmel		device_printf(sc->gic_dev,
870291424Smmel		    "Spurious interrupt detected: last irq: %d on CPU%d\n",
871291424Smmel		    sc->last_irq[PCPU_GET(cpuid)], PCPU_GET(cpuid));
872291424Smmel#endif
873289529Sian		return (FILTER_HANDLED);
874289529Sian	}
875289529Sian
876289529Sian	tf = curthread->td_intr_frame;
877289529Siandispatch_irq:
878297539Sskra	gi = sc->gic_irqs + irq;
879289529Sian	/*
880289529Sian	 * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement
881289529Sian	 * as compiler complains that comparing u_int >= 0 is always true.
882289529Sian	 */
883289529Sian	if (irq <= GIC_LAST_SGI) {
884289529Sian#ifdef SMP
885289529Sian		/* Call EOI for all IPI before dispatch. */
886289529Sian		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
887297539Sskra		intr_ipi_dispatch(sgi_to_ipi[gi->gi_irq], tf);
888289529Sian		goto next_irq;
889289529Sian#else
890291424Smmel		device_printf(sc->gic_dev, "SGI %u on UP system detected\n",
891291424Smmel		    irq - GIC_FIRST_SGI);
892289529Sian		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
893289529Sian		goto next_irq;
894289529Sian#endif
895289529Sian	}
896289529Sian
897291424Smmel#ifdef GIC_DEBUG_SPURIOUS
898291424Smmel	sc->last_irq[PCPU_GET(cpuid)] = irq;
899291424Smmel#endif
900298054Sandrew	if ((gi->gi_flags & GI_FLAG_EARLY_EOI) == GI_FLAG_EARLY_EOI)
901289529Sian		gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
902289529Sian
903297539Sskra	if (intr_isrc_dispatch(&gi->gi_isrc, tf) != 0) {
904297539Sskra		gic_irq_mask(sc, irq);
905298054Sandrew		if ((gi->gi_flags & GI_FLAG_EARLY_EOI) != GI_FLAG_EARLY_EOI)
906297539Sskra			gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
907297539Sskra		device_printf(sc->gic_dev, "Stray irq %u disabled\n", irq);
908297539Sskra	}
909289529Sian
910289529Siannext_irq:
911289631Sian	arm_irq_memory_barrier(irq);
912289631Sian	irq_active_reg = gic_c_read_4(sc, GICC_IAR);
913289631Sian	irq = irq_active_reg & 0x3FF;
914289631Sian	if (irq < sc->nirqs)
915289529Sian		goto dispatch_irq;
916289529Sian
917289529Sian	return (FILTER_HANDLED);
918289529Sian}
919289529Sian
920289529Sianstatic void
921289529Siangic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig,
922289529Sian    enum intr_polarity pol)
923289529Sian{
924289529Sian	uint32_t reg;
925289529Sian	uint32_t mask;
926289529Sian
927289529Sian	if (irq < GIC_FIRST_SPI)
928289529Sian		return;
929289529Sian
930289529Sian	mtx_lock_spin(&sc->mutex);
931289529Sian
932289529Sian	reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
933289529Sian	mask = (reg >> 2*(irq % 16)) & 0x3;
934289529Sian
935289529Sian	if (pol == INTR_POLARITY_LOW) {
936289529Sian		mask &= ~GICD_ICFGR_POL_MASK;
937289529Sian		mask |= GICD_ICFGR_POL_LOW;
938289529Sian	} else if (pol == INTR_POLARITY_HIGH) {
939289529Sian		mask &= ~GICD_ICFGR_POL_MASK;
940289529Sian		mask |= GICD_ICFGR_POL_HIGH;
941289529Sian	}
942289529Sian
943289529Sian	if (trig == INTR_TRIGGER_LEVEL) {
944289529Sian		mask &= ~GICD_ICFGR_TRIG_MASK;
945289529Sian		mask |= GICD_ICFGR_TRIG_LVL;
946289529Sian	} else if (trig == INTR_TRIGGER_EDGE) {
947289529Sian		mask &= ~GICD_ICFGR_TRIG_MASK;
948289529Sian		mask |= GICD_ICFGR_TRIG_EDGE;
949289529Sian	}
950289529Sian
951289529Sian	/* Set mask */
952289529Sian	reg = reg & ~(0x3 << 2*(irq % 16));
953289529Sian	reg = reg | (mask << 2*(irq % 16));
954289529Sian	gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
955289529Sian
956289529Sian	mtx_unlock_spin(&sc->mutex);
957289529Sian}
958289529Sian
959289529Sianstatic int
960289529Siangic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus)
961289529Sian{
962289529Sian	uint32_t cpu, end, mask;
963289529Sian
964289529Sian	end = min(mp_ncpus, 8);
965289529Sian	for (cpu = end; cpu < MAXCPU; cpu++)
966289529Sian		if (CPU_ISSET(cpu, cpus))
967289529Sian			return (EINVAL);
968289529Sian
969289529Sian	for (mask = 0, cpu = 0; cpu < end; cpu++)
970289529Sian		if (CPU_ISSET(cpu, cpus))
971301062Sandrew			mask |= arm_gic_map[cpu];
972289529Sian
973289529Sian	gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask);
974289529Sian	return (0);
975289529Sian}
976289529Sian
977297539Sskra#ifdef FDT
978289529Sianstatic int
979297539Sskragic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp,
980297539Sskra    enum intr_polarity *polp, enum intr_trigger *trigp)
981289529Sian{
982289529Sian
983297539Sskra	if (ncells == 1) {
984297539Sskra		*irqp = cells[0];
985297539Sskra		*polp = INTR_POLARITY_CONFORM;
986297539Sskra		*trigp = INTR_TRIGGER_CONFORM;
987297539Sskra		return (0);
988297539Sskra	}
989297539Sskra	if (ncells == 3) {
990297539Sskra		u_int irq, tripol;
991289529Sian
992297539Sskra		/*
993297539Sskra		 * The 1st cell is the interrupt type:
994297539Sskra		 *	0 = SPI
995297539Sskra		 *	1 = PPI
996297539Sskra		 * The 2nd cell contains the interrupt number:
997297539Sskra		 *	[0 - 987] for SPI
998297539Sskra		 *	[0 -  15] for PPI
999297539Sskra		 * The 3rd cell is the flags, encoded as follows:
1000297539Sskra		 *   bits[3:0] trigger type and level flags
1001297539Sskra		 *	1 = low-to-high edge triggered
1002297539Sskra		 *	2 = high-to-low edge triggered
1003297539Sskra		 *	4 = active high level-sensitive
1004297539Sskra		 *	8 = active low level-sensitive
1005297539Sskra		 *   bits[15:8] PPI interrupt cpu mask
1006297539Sskra		 *	Each bit corresponds to each of the 8 possible cpus
1007297539Sskra		 *	attached to the GIC.  A bit set to '1' indicated
1008297539Sskra		 *	the interrupt is wired to that CPU.
1009297539Sskra		 */
1010297539Sskra		switch (cells[0]) {
1011297539Sskra		case 0:
1012297539Sskra			irq = GIC_FIRST_SPI + cells[1];
1013297539Sskra			/* SPI irq is checked later. */
1014297539Sskra			break;
1015297539Sskra		case 1:
1016297539Sskra			irq = GIC_FIRST_PPI + cells[1];
1017297539Sskra			if (irq > GIC_LAST_PPI) {
1018297539Sskra				device_printf(dev, "unsupported PPI interrupt "
1019297539Sskra				    "number %u\n", cells[1]);
1020297539Sskra				return (EINVAL);
1021297539Sskra			}
1022297539Sskra			break;
1023297539Sskra		default:
1024297539Sskra			device_printf(dev, "unsupported interrupt type "
1025297539Sskra			    "configuration %u\n", cells[0]);
1026297539Sskra			return (EINVAL);
1027297539Sskra		}
1028289529Sian
1029297539Sskra		tripol = cells[2] & 0xff;
1030297539Sskra		if (tripol & 0xf0 || (tripol & 0x0a && cells[0] == 0))
1031297539Sskra			device_printf(dev, "unsupported trigger/polarity "
1032297539Sskra			    "configuration 0x%02x\n", tripol);
1033289529Sian
1034297539Sskra		*irqp = irq;
1035297539Sskra		*polp = INTR_POLARITY_CONFORM;
1036297539Sskra		*trigp = tripol & 0x03 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL;
1037297539Sskra		return (0);
1038289529Sian	}
1039297539Sskra	return (EINVAL);
1040289529Sian}
1041297539Sskra#endif
1042289529Sian
1043289529Sianstatic int
1044297539Sskragic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp,
1045297539Sskra    enum intr_polarity *polp, enum intr_trigger *trigp)
1046289529Sian{
1047297539Sskra	u_int irq;
1048297539Sskra	enum intr_polarity pol;
1049297539Sskra	enum intr_trigger trig;
1050297539Sskra	struct arm_gic_softc *sc;
1051299117Sskra#ifdef FDT
1052299117Sskra	struct intr_map_data_fdt *daf;
1053299117Sskra#endif
1054289529Sian
1055297539Sskra	sc = device_get_softc(dev);
1056297539Sskra	switch (data->type) {
1057289529Sian#ifdef FDT
1058297539Sskra	case INTR_MAP_DATA_FDT:
1059299117Sskra		daf = (struct intr_map_data_fdt *)data;
1060299117Sskra		if (gic_map_fdt(dev, daf->ncells, daf->cells, &irq, &pol,
1061299117Sskra		    &trig) != 0)
1062297539Sskra			return (EINVAL);
1063299928Sandrew		KASSERT(irq >= sc->nirqs ||
1064299928Sandrew		    (sc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) == 0,
1065299928Sandrew		    ("%s: Attempting to map a MSI interrupt from FDT",
1066299928Sandrew		    __func__));
1067297539Sskra		break;
1068297539Sskra#endif
1069297539Sskra	default:
1070299117Sskra		return (ENOTSUP);
1071297539Sskra	}
1072289529Sian
1073289529Sian	if (irq >= sc->nirqs)
1074289529Sian		return (EINVAL);
1075297539Sskra	if (pol != INTR_POLARITY_CONFORM && pol != INTR_POLARITY_LOW &&
1076297539Sskra	    pol != INTR_POLARITY_HIGH)
1077297539Sskra		return (EINVAL);
1078297539Sskra	if (trig != INTR_TRIGGER_CONFORM && trig != INTR_TRIGGER_EDGE &&
1079297539Sskra	    trig != INTR_TRIGGER_LEVEL)
1080297539Sskra		return (EINVAL);
1081289529Sian
1082289529Sian	*irqp = irq;
1083297539Sskra	if (polp != NULL)
1084297539Sskra		*polp = pol;
1085297539Sskra	if (trigp != NULL)
1086297539Sskra		*trigp = trig;
1087289529Sian	return (0);
1088289529Sian}
1089289529Sian
1090289529Sianstatic int
1091297539Sskraarm_gic_map_intr(device_t dev, struct intr_map_data *data,
1092297539Sskra    struct intr_irqsrc **isrcp)
1093289529Sian{
1094297539Sskra	int error;
1095289529Sian	u_int irq;
1096297539Sskra	struct arm_gic_softc *sc;
1097289529Sian
1098297539Sskra	error = gic_map_intr(dev, data, &irq, NULL, NULL);
1099297539Sskra	if (error == 0) {
1100297539Sskra		sc = device_get_softc(dev);
1101297539Sskra		*isrcp = GIC_INTR_ISRC(sc, irq);
1102297539Sskra	}
1103289529Sian	return (error);
1104289529Sian}
1105289529Sian
1106297539Sskrastatic int
1107297539Sskraarm_gic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
1108297539Sskra    struct resource *res, struct intr_map_data *data)
1109289529Sian{
1110289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1111297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1112297539Sskra	enum intr_trigger trig;
1113297539Sskra	enum intr_polarity pol;
1114289529Sian
1115299928Sandrew	if ((gi->gi_flags & GI_FLAG_MSI) == GI_FLAG_MSI) {
1116299928Sandrew		pol = gi->gi_pol;
1117299928Sandrew		trig = gi->gi_trig;
1118299928Sandrew		KASSERT(pol == INTR_POLARITY_HIGH,
1119299928Sandrew		    ("%s: MSI interrupts must be active-high", __func__));
1120299928Sandrew		KASSERT(trig == INTR_TRIGGER_EDGE,
1121299928Sandrew		    ("%s: MSI interrupts must be edge triggered", __func__));
1122299928Sandrew	} else if (data != NULL) {
1123301267Sskra		u_int irq;
1124301267Sskra
1125299928Sandrew		/* Get config for resource. */
1126301267Sskra		if (gic_map_intr(dev, data, &irq, &pol, &trig) ||
1127301267Sskra		    gi->gi_irq != irq)
1128299928Sandrew			return (EINVAL);
1129300951Smmel	} else {
1130300951Smmel		pol = INTR_POLARITY_CONFORM;
1131300951Smmel		trig = INTR_TRIGGER_CONFORM;
1132300951Smmel	}
1133289529Sian
1134297539Sskra	/* Compare config if this is not first setup. */
1135297539Sskra	if (isrc->isrc_handlers != 0) {
1136297539Sskra		if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) ||
1137297539Sskra		    (trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig))
1138297539Sskra			return (EINVAL);
1139297539Sskra		else
1140297539Sskra			return (0);
1141297539Sskra	}
1142297539Sskra
1143299928Sandrew	/* For MSI/MSI-X we should have already configured these */
1144299928Sandrew	if ((gi->gi_flags & GI_FLAG_MSI) == 0) {
1145299928Sandrew		if (pol == INTR_POLARITY_CONFORM)
1146299928Sandrew			pol = INTR_POLARITY_LOW;	/* just pick some */
1147299928Sandrew		if (trig == INTR_TRIGGER_CONFORM)
1148299928Sandrew			trig = INTR_TRIGGER_EDGE;	/* just pick some */
1149297539Sskra
1150299928Sandrew		gi->gi_pol = pol;
1151299928Sandrew		gi->gi_trig = trig;
1152297539Sskra
1153299928Sandrew		/* Edge triggered interrupts need an early EOI sent */
1154299928Sandrew		if (gi->gi_pol == INTR_TRIGGER_EDGE)
1155299928Sandrew			gi->gi_flags |= GI_FLAG_EARLY_EOI;
1156299928Sandrew	}
1157299928Sandrew
1158289529Sian	/*
1159289529Sian	 * XXX - In case that per CPU interrupt is going to be enabled in time
1160289529Sian	 *       when SMP is already started, we need some IPI call which
1161289529Sian	 *       enables it on others CPUs. Further, it's more complicated as
1162289529Sian	 *       pic_enable_source() and pic_disable_source() should act on
1163289529Sian	 *       per CPU basis only. Thus, it should be solved here somehow.
1164289529Sian	 */
1165297539Sskra	if (isrc->isrc_flags & INTR_ISRCF_PPI)
1166289529Sian		CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
1167289529Sian
1168299928Sandrew	gic_config(sc, gi->gi_irq, gi->gi_trig, gi->gi_pol);
1169297539Sskra	arm_gic_bind_intr(dev, isrc);
1170297539Sskra	return (0);
1171289529Sian}
1172289529Sian
1173297539Sskrastatic int
1174297539Sskraarm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
1175297539Sskra    struct resource *res, struct intr_map_data *data)
1176289529Sian{
1177297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1178289529Sian
1179299928Sandrew	if (isrc->isrc_handlers == 0 && (gi->gi_flags & GI_FLAG_MSI) == 0) {
1180297539Sskra		gi->gi_pol = INTR_POLARITY_CONFORM;
1181297539Sskra		gi->gi_trig = INTR_TRIGGER_CONFORM;
1182297539Sskra	}
1183297539Sskra	return (0);
1184289529Sian}
1185289529Sian
1186289529Sianstatic void
1187297539Sskraarm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
1188289529Sian{
1189289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1190297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1191289529Sian
1192297539Sskra	arm_irq_memory_barrier(gi->gi_irq);
1193297539Sskra	gic_irq_unmask(sc, gi->gi_irq);
1194289529Sian}
1195289529Sian
1196297539Sskrastatic void
1197297539Sskraarm_gic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
1198289529Sian{
1199289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1200297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1201289529Sian
1202297539Sskra	gic_irq_mask(sc, gi->gi_irq);
1203289529Sian}
1204289529Sian
1205289529Sianstatic void
1206292426Sadrianarm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
1207289529Sian{
1208289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1209297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1210289529Sian
1211297539Sskra	arm_gic_disable_intr(dev, isrc);
1212297539Sskra	gic_c_write_4(sc, GICC_EOIR, gi->gi_irq);
1213289529Sian}
1214289529Sian
1215289529Sianstatic void
1216292426Sadrianarm_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
1217289529Sian{
1218289529Sian
1219289529Sian	arm_irq_memory_barrier(0);
1220297539Sskra	arm_gic_enable_intr(dev, isrc);
1221289529Sian}
1222289529Sian
1223289529Sianstatic void
1224292426Sadrianarm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc)
1225289529Sian{
1226289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1227297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1228289529Sian
1229289529Sian        /* EOI for edge-triggered done earlier. */
1230298054Sandrew	if ((gi->gi_flags & GI_FLAG_EARLY_EOI) == GI_FLAG_EARLY_EOI)
1231289529Sian		return;
1232289529Sian
1233289529Sian	arm_irq_memory_barrier(0);
1234297539Sskra	gic_c_write_4(sc, GICC_EOIR, gi->gi_irq);
1235289529Sian}
1236289529Sian
1237289529Sianstatic int
1238297539Sskraarm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc)
1239289529Sian{
1240289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1241297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1242289529Sian
1243297539Sskra	if (gi->gi_irq < GIC_FIRST_SPI)
1244289529Sian		return (EINVAL);
1245289529Sian
1246289529Sian	if (CPU_EMPTY(&isrc->isrc_cpu)) {
1247292426Sadrian		gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus);
1248289529Sian		CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu);
1249289529Sian	}
1250297539Sskra	return (gic_bind(sc, gi->gi_irq, &isrc->isrc_cpu));
1251289529Sian}
1252289529Sian
1253289698Sian#ifdef SMP
1254289529Sianstatic void
1255297539Sskraarm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
1256297539Sskra    u_int ipi)
1257289529Sian{
1258289529Sian	struct arm_gic_softc *sc = device_get_softc(dev);
1259297539Sskra	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1260297539Sskra	uint32_t val = 0, i;
1261289529Sian
1262289529Sian	for (i = 0; i < MAXCPU; i++)
1263289529Sian		if (CPU_ISSET(i, &cpus))
1264297561Sandrew			val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
1265289529Sian
1266297539Sskra	gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq);
1267289529Sian}
1268297230Sskra
1269297230Sskrastatic int
1270297539Sskraarm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
1271297230Sskra{
1272297677Sskra	struct intr_irqsrc *isrc;
1273297230Sskra	struct arm_gic_softc *sc = device_get_softc(dev);
1274297230Sskra
1275297539Sskra	if (sgi_first_unused > GIC_LAST_SGI)
1276297539Sskra		return (ENOSPC);
1277297539Sskra
1278297677Sskra	isrc = GIC_INTR_ISRC(sc, sgi_first_unused);
1279297539Sskra	sgi_to_ipi[sgi_first_unused++] = ipi;
1280297677Sskra
1281297677Sskra	CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
1282297677Sskra
1283297677Sskra	*isrcp = isrc;
1284297230Sskra	return (0);
1285297230Sskra}
1286289529Sian#endif
1287289529Sian#else
1288289529Sianstatic int
1289276963Sandrewarm_gic_next_irq(struct arm_gic_softc *sc, int last_irq)
1290239268Sgonzo{
1291239268Sgonzo	uint32_t active_irq;
1292239268Sgonzo
1293276015Sandrew	active_irq = gic_c_read_4(sc, GICC_IAR);
1294239268Sgonzo
1295252370Sray	/*
1296299069Spfg	 * Immediately EOIR the SGIs, because doing so requires the other
1297239268Sgonzo	 * bits (ie CPU number), not just the IRQ number, and we do not
1298239268Sgonzo	 * have this information later.
1299239268Sgonzo	 */
1300289529Sian	if ((active_irq & 0x3ff) <= GIC_LAST_SGI)
1301276015Sandrew		gic_c_write_4(sc, GICC_EOIR, active_irq);
1302239268Sgonzo	active_irq &= 0x3FF;
1303239268Sgonzo
1304239268Sgonzo	if (active_irq == 0x3FF) {
1305239268Sgonzo		if (last_irq == -1)
1306291424Smmel			device_printf(sc->gic_dev,
1307291424Smmel			    "Spurious interrupt detected\n");
1308239268Sgonzo		return -1;
1309239268Sgonzo	}
1310239268Sgonzo
1311239268Sgonzo	return active_irq;
1312239268Sgonzo}
1313239268Sgonzo
1314260161Szbbstatic int
1315276963Sandrewarm_gic_config(device_t dev, int irq, enum intr_trigger trig,
1316260161Szbb    enum intr_polarity pol)
1317260161Szbb{
1318276963Sandrew	struct arm_gic_softc *sc = device_get_softc(dev);
1319260161Szbb	uint32_t reg;
1320260161Szbb	uint32_t mask;
1321260161Szbb
1322260161Szbb	/* Function is public-accessible, so validate input arguments */
1323276015Sandrew	if ((irq < 0) || (irq >= sc->nirqs))
1324260161Szbb		goto invalid_args;
1325260161Szbb	if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) &&
1326260161Szbb	    (trig != INTR_TRIGGER_CONFORM))
1327260161Szbb		goto invalid_args;
1328260161Szbb	if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) &&
1329260161Szbb	    (pol != INTR_POLARITY_CONFORM))
1330260161Szbb		goto invalid_args;
1331260161Szbb
1332276015Sandrew	mtx_lock_spin(&sc->mutex);
1333260161Szbb
1334276015Sandrew	reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
1335260161Szbb	mask = (reg >> 2*(irq % 16)) & 0x3;
1336260161Szbb
1337260161Szbb	if (pol == INTR_POLARITY_LOW) {
1338260161Szbb		mask &= ~GICD_ICFGR_POL_MASK;
1339260161Szbb		mask |= GICD_ICFGR_POL_LOW;
1340260161Szbb	} else if (pol == INTR_POLARITY_HIGH) {
1341260161Szbb		mask &= ~GICD_ICFGR_POL_MASK;
1342260161Szbb		mask |= GICD_ICFGR_POL_HIGH;
1343260161Szbb	}
1344260161Szbb
1345260161Szbb	if (trig == INTR_TRIGGER_LEVEL) {
1346260161Szbb		mask &= ~GICD_ICFGR_TRIG_MASK;
1347260161Szbb		mask |= GICD_ICFGR_TRIG_LVL;
1348260161Szbb	} else if (trig == INTR_TRIGGER_EDGE) {
1349260161Szbb		mask &= ~GICD_ICFGR_TRIG_MASK;
1350260161Szbb		mask |= GICD_ICFGR_TRIG_EDGE;
1351260161Szbb	}
1352260161Szbb
1353260161Szbb	/* Set mask */
1354260161Szbb	reg = reg & ~(0x3 << 2*(irq % 16));
1355260161Szbb	reg = reg | (mask << 2*(irq % 16));
1356276015Sandrew	gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
1357260161Szbb
1358276015Sandrew	mtx_unlock_spin(&sc->mutex);
1359260161Szbb
1360260161Szbb	return (0);
1361260161Szbb
1362260161Szbbinvalid_args:
1363276028Sandrew	device_printf(dev, "gic_config_irg, invalid parameters\n");
1364260161Szbb	return (EINVAL);
1365260161Szbb}
1366260161Szbb
1367276963Sandrew
1368276963Sandrewstatic void
1369276963Sandrewarm_gic_mask(device_t dev, int irq)
1370276963Sandrew{
1371276963Sandrew	struct arm_gic_softc *sc = device_get_softc(dev);
1372276963Sandrew
1373276963Sandrew	gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
1374289529Sian	gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */
1375276963Sandrew}
1376276963Sandrew
1377276963Sandrewstatic void
1378276963Sandrewarm_gic_unmask(device_t dev, int irq)
1379276963Sandrew{
1380276963Sandrew	struct arm_gic_softc *sc = device_get_softc(dev);
1381276963Sandrew
1382289529Sian	if (irq > GIC_LAST_SGI)
1383276963Sandrew		arm_irq_memory_barrier(irq);
1384276963Sandrew
1385276963Sandrew	gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
1386276963Sandrew}
1387276963Sandrew
1388239268Sgonzo#ifdef SMP
1389276963Sandrewstatic void
1390276963Sandrewarm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi)
1391239268Sgonzo{
1392276963Sandrew	struct arm_gic_softc *sc = device_get_softc(dev);
1393239268Sgonzo	uint32_t val = 0, i;
1394239268Sgonzo
1395239268Sgonzo	for (i = 0; i < MAXCPU; i++)
1396239268Sgonzo		if (CPU_ISSET(i, &cpus))
1397297561Sandrew			val |= arm_gic_map[i] << GICD_SGI_TARGET_SHIFT;
1398252370Sray
1399276015Sandrew	gic_d_write_4(sc, GICD_SGIR(0), val | ipi);
1400239268Sgonzo}
1401239268Sgonzo
1402276963Sandrewstatic int
1403276963Sandrewarm_gic_ipi_read(device_t dev, int i)
1404239268Sgonzo{
1405252370Sray
1406239268Sgonzo	if (i != -1) {
1407239268Sgonzo		/*
1408239268Sgonzo		 * The intr code will automagically give the frame pointer
1409239268Sgonzo		 * if the interrupt argument is 0.
1410239268Sgonzo		 */
1411252370Sray		if ((unsigned int)i > 16)
1412239268Sgonzo			return (0);
1413239268Sgonzo		return (i);
1414239268Sgonzo	}
1415276028Sandrew
1416239268Sgonzo	return (0x3ff);
1417239268Sgonzo}
1418239268Sgonzo
1419276963Sandrewstatic void
1420276963Sandrewarm_gic_ipi_clear(device_t dev, int ipi)
1421276963Sandrew{
1422276963Sandrew	/* no-op */
1423276963Sandrew}
1424276963Sandrew#endif
1425276963Sandrew
1426276963Sandrewstatic void
1427276963Sandrewgic_post_filter(void *arg)
1428276963Sandrew{
1429289529Sian	struct arm_gic_softc *sc = gic_sc;
1430276963Sandrew	uintptr_t irq = (uintptr_t) arg;
1431276963Sandrew
1432289529Sian	if (irq > GIC_LAST_SGI)
1433276963Sandrew		arm_irq_memory_barrier(irq);
1434276963Sandrew	gic_c_write_4(sc, GICC_EOIR, irq);
1435276963Sandrew}
1436276963Sandrew
1437276963Sandrewstatic int
1438276963Sandrewgic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol)
1439276963Sandrew{
1440276963Sandrew
1441289529Sian	return (arm_gic_config(gic_sc->gic_dev, irq, trig, pol));
1442276963Sandrew}
1443276963Sandrew
1444239268Sgonzovoid
1445276963Sandrewarm_mask_irq(uintptr_t nb)
1446276963Sandrew{
1447276963Sandrew
1448289529Sian	arm_gic_mask(gic_sc->gic_dev, nb);
1449276963Sandrew}
1450276963Sandrew
1451276963Sandrewvoid
1452276963Sandrewarm_unmask_irq(uintptr_t nb)
1453276963Sandrew{
1454276963Sandrew
1455289529Sian	arm_gic_unmask(gic_sc->gic_dev, nb);
1456276963Sandrew}
1457276963Sandrew
1458276963Sandrewint
1459276963Sandrewarm_get_next_irq(int last_irq)
1460276963Sandrew{
1461276963Sandrew
1462289529Sian	return (arm_gic_next_irq(gic_sc, last_irq));
1463276963Sandrew}
1464276963Sandrew
1465289529Sian#ifdef SMP
1466276963Sandrewvoid
1467292426Sadrianintr_pic_init_secondary(void)
1468276963Sandrew{
1469276963Sandrew
1470289529Sian	arm_gic_init_secondary(gic_sc->gic_dev);
1471276963Sandrew}
1472276963Sandrew
1473276963Sandrewvoid
1474276963Sandrewpic_ipi_send(cpuset_t cpus, u_int ipi)
1475276963Sandrew{
1476276963Sandrew
1477289529Sian	arm_gic_ipi_send(gic_sc->gic_dev, cpus, ipi);
1478276963Sandrew}
1479276963Sandrew
1480276963Sandrewint
1481276963Sandrewpic_ipi_read(int i)
1482276963Sandrew{
1483276963Sandrew
1484289529Sian	return (arm_gic_ipi_read(gic_sc->gic_dev, i));
1485276963Sandrew}
1486276963Sandrew
1487276963Sandrewvoid
1488239268Sgonzopic_ipi_clear(int ipi)
1489239268Sgonzo{
1490276963Sandrew
1491289529Sian	arm_gic_ipi_clear(gic_sc->gic_dev, ipi);
1492239268Sgonzo}
1493239268Sgonzo#endif
1494298068Sandrew#endif /* INTRNG */
1495239268Sgonzo
1496276028Sandrewstatic device_method_t arm_gic_methods[] = {
1497276028Sandrew	/* Device interface */
1498276028Sandrew	DEVMETHOD(device_probe,		arm_gic_probe),
1499276028Sandrew	DEVMETHOD(device_attach,	arm_gic_attach),
1500298051Sandrew
1501298068Sandrew#ifdef INTRNG
1502298051Sandrew	/* Bus interface */
1503298051Sandrew	DEVMETHOD(bus_add_child,	bus_generic_add_child),
1504298051Sandrew	DEVMETHOD(bus_alloc_resource,	arm_gic_alloc_resource),
1505298051Sandrew	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
1506298051Sandrew	DEVMETHOD(bus_activate_resource,bus_generic_activate_resource),
1507298051Sandrew
1508298051Sandrew	/* ofw_bus interface */
1509298051Sandrew	DEVMETHOD(ofw_bus_get_devinfo,	arm_gic_ofw_get_devinfo),
1510298051Sandrew	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
1511298051Sandrew	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
1512298051Sandrew	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
1513298051Sandrew	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
1514298051Sandrew	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
1515298051Sandrew
1516289529Sian	/* Interrupt controller interface */
1517297539Sskra	DEVMETHOD(pic_disable_intr,	arm_gic_disable_intr),
1518289529Sian	DEVMETHOD(pic_enable_intr,	arm_gic_enable_intr),
1519297539Sskra	DEVMETHOD(pic_map_intr,		arm_gic_map_intr),
1520297539Sskra	DEVMETHOD(pic_setup_intr,	arm_gic_setup_intr),
1521297539Sskra	DEVMETHOD(pic_teardown_intr,	arm_gic_teardown_intr),
1522289529Sian	DEVMETHOD(pic_post_filter,	arm_gic_post_filter),
1523289529Sian	DEVMETHOD(pic_post_ithread,	arm_gic_post_ithread),
1524289529Sian	DEVMETHOD(pic_pre_ithread,	arm_gic_pre_ithread),
1525289529Sian#ifdef SMP
1526297539Sskra	DEVMETHOD(pic_bind_intr,	arm_gic_bind_intr),
1527289529Sian	DEVMETHOD(pic_init_secondary,	arm_gic_init_secondary),
1528289529Sian	DEVMETHOD(pic_ipi_send,		arm_gic_ipi_send),
1529297230Sskra	DEVMETHOD(pic_ipi_setup,	arm_gic_ipi_setup),
1530289529Sian#endif
1531289529Sian#endif
1532276028Sandrew	{ 0, 0 }
1533276028Sandrew};
1534276028Sandrew
1535276028Sandrewstatic driver_t arm_gic_driver = {
1536276028Sandrew	"gic",
1537276028Sandrew	arm_gic_methods,
1538276028Sandrew	sizeof(struct arm_gic_softc),
1539276028Sandrew};
1540276028Sandrew
1541276028Sandrewstatic devclass_t arm_gic_devclass;
1542276028Sandrew
1543276028SandrewEARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0,
1544276028Sandrew    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
1545276028SandrewEARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0,
1546276028Sandrew    BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
1547298051Sandrew
1548298068Sandrew#ifdef INTRNG
1549298051Sandrew/*
1550298051Sandrew * GICv2m support -- the GICv2 MSI/MSI-X controller.
1551298051Sandrew */
1552298051Sandrew
1553298051Sandrew#define	GICV2M_MSI_TYPER	0x008
1554298051Sandrew#define	 MSI_TYPER_SPI_BASE(x)	(((x) >> 16) & 0x3ff)
1555298051Sandrew#define	 MSI_TYPER_SPI_COUNT(x)	(((x) >> 0) & 0x3ff)
1556298051Sandrew#define	GICv2M_MSI_SETSPI_NS	0x040
1557298051Sandrew#define	GICV2M_MSI_IIDR		0xFCC
1558298051Sandrew
1559298051Sandrewstruct arm_gicv2m_softc {
1560298051Sandrew	struct resource	*sc_mem;
1561298051Sandrew	struct mtx	sc_mutex;
1562298051Sandrew	u_int		sc_spi_start;
1563299928Sandrew	u_int		sc_spi_end;
1564298051Sandrew	u_int		sc_spi_count;
1565298051Sandrew};
1566298051Sandrew
1567298051Sandrewstatic struct ofw_compat_data gicv2m_compat_data[] = {
1568298051Sandrew	{"arm,gic-v2m-frame",	true},
1569298051Sandrew	{NULL,			false}
1570298051Sandrew};
1571298051Sandrew
1572298051Sandrewstatic int
1573298051Sandrewarm_gicv2m_probe(device_t dev)
1574298051Sandrew{
1575298051Sandrew
1576298051Sandrew	if (!ofw_bus_status_okay(dev))
1577298051Sandrew		return (ENXIO);
1578298051Sandrew
1579298051Sandrew	if (!ofw_bus_search_compatible(dev, gicv2m_compat_data)->ocd_data)
1580298051Sandrew		return (ENXIO);
1581298051Sandrew
1582298051Sandrew	device_set_desc(dev, "ARM Generic Interrupt Controller MSI/MSIX");
1583298051Sandrew	return (BUS_PROBE_DEFAULT);
1584298051Sandrew}
1585298051Sandrew
1586298051Sandrewstatic int
1587298051Sandrewarm_gicv2m_attach(device_t dev)
1588298051Sandrew{
1589298051Sandrew	struct arm_gicv2m_softc *sc;
1590299928Sandrew	struct arm_gic_softc *psc;
1591298051Sandrew	uint32_t typer;
1592298051Sandrew	int rid;
1593298051Sandrew
1594299928Sandrew	psc = device_get_softc(device_get_parent(dev));
1595298051Sandrew	sc = device_get_softc(dev);
1596298051Sandrew
1597298051Sandrew	rid = 0;
1598298051Sandrew	sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1599298051Sandrew	    RF_ACTIVE);
1600298051Sandrew	if (sc->sc_mem == NULL) {
1601298051Sandrew		device_printf(dev, "Unable to allocate resources\n");
1602298051Sandrew		return (ENXIO);
1603298051Sandrew	}
1604298051Sandrew
1605298051Sandrew	typer = bus_read_4(sc->sc_mem, GICV2M_MSI_TYPER);
1606298051Sandrew	sc->sc_spi_start = MSI_TYPER_SPI_BASE(typer);
1607298051Sandrew	sc->sc_spi_count = MSI_TYPER_SPI_COUNT(typer);
1608299928Sandrew	sc->sc_spi_end = sc->sc_spi_start + sc->sc_spi_count;
1609298051Sandrew
1610299928Sandrew	/* Reserve these interrupts for MSI/MSI-X use */
1611299928Sandrew	arm_gic_reserve_msi_range(device_get_parent(dev), sc->sc_spi_start,
1612299928Sandrew	    sc->sc_spi_count);
1613299928Sandrew
1614298051Sandrew	mtx_init(&sc->sc_mutex, "GICv2m lock", "", MTX_DEF);
1615298051Sandrew
1616299928Sandrew	intr_msi_register(dev, gic_xref(dev));
1617299928Sandrew
1618298051Sandrew	if (bootverbose)
1619298051Sandrew		device_printf(dev, "using spi %u to %u\n", sc->sc_spi_start,
1620298051Sandrew		    sc->sc_spi_start + sc->sc_spi_count - 1);
1621298051Sandrew
1622298051Sandrew	return (0);
1623298051Sandrew}
1624298051Sandrew
1625299928Sandrewstatic int
1626299928Sandrewarm_gicv2m_alloc_msi(device_t dev, device_t child, int count, int maxcount,
1627299928Sandrew    device_t *pic, struct intr_irqsrc **srcs)
1628299928Sandrew{
1629299928Sandrew	struct arm_gic_softc *psc;
1630299928Sandrew	struct arm_gicv2m_softc *sc;
1631299928Sandrew	int i, irq, end_irq;
1632299928Sandrew	bool found;
1633299928Sandrew
1634299928Sandrew	KASSERT(powerof2(count), ("%s: bad count", __func__));
1635299928Sandrew	KASSERT(powerof2(maxcount), ("%s: bad maxcount", __func__));
1636299928Sandrew
1637299928Sandrew	psc = device_get_softc(device_get_parent(dev));
1638299928Sandrew	sc = device_get_softc(dev);
1639299928Sandrew
1640299928Sandrew	mtx_lock(&sc->sc_mutex);
1641299928Sandrew
1642299928Sandrew	found = false;
1643319915Semaste	for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) {
1644299928Sandrew		/* Start on an aligned interrupt */
1645299928Sandrew		if ((irq & (maxcount - 1)) != 0)
1646299928Sandrew			continue;
1647299928Sandrew
1648299928Sandrew		/* Assume we found a valid range until shown otherwise */
1649299928Sandrew		found = true;
1650299928Sandrew
1651299928Sandrew		/* Check this range is valid */
1652319915Semaste		for (end_irq = irq; end_irq != irq + count; end_irq++) {
1653299928Sandrew			/* No free interrupts */
1654299928Sandrew			if (end_irq == sc->sc_spi_end) {
1655299928Sandrew				found = false;
1656299928Sandrew				break;
1657299928Sandrew			}
1658299928Sandrew
1659329280Sgonzo			KASSERT((psc->gic_irqs[end_irq].gi_flags & GI_FLAG_MSI)!= 0,
1660299928Sandrew			    ("%s: Non-MSI interrupt found", __func__));
1661299928Sandrew
1662299928Sandrew			/* This is already used */
1663329280Sgonzo			if ((psc->gic_irqs[end_irq].gi_flags & GI_FLAG_MSI_USED) ==
1664299928Sandrew			    GI_FLAG_MSI_USED) {
1665299928Sandrew				found = false;
1666299928Sandrew				break;
1667299928Sandrew			}
1668299928Sandrew		}
1669319915Semaste		if (found)
1670319915Semaste			break;
1671299928Sandrew	}
1672299928Sandrew
1673299928Sandrew	/* Not enough interrupts were found */
1674299928Sandrew	if (!found || irq == sc->sc_spi_end) {
1675299928Sandrew		mtx_unlock(&sc->sc_mutex);
1676299928Sandrew		return (ENXIO);
1677299928Sandrew	}
1678299928Sandrew
1679299928Sandrew	for (i = 0; i < count; i++) {
1680299928Sandrew		/* Mark the interrupt as used */
1681299928Sandrew		psc->gic_irqs[irq + i].gi_flags |= GI_FLAG_MSI_USED;
1682299928Sandrew
1683299928Sandrew	}
1684299928Sandrew	mtx_unlock(&sc->sc_mutex);
1685299928Sandrew
1686299928Sandrew	for (i = 0; i < count; i++)
1687299928Sandrew		srcs[i] = (struct intr_irqsrc *)&psc->gic_irqs[irq + i];
1688299928Sandrew	*pic = device_get_parent(dev);
1689299928Sandrew
1690299928Sandrew	return (0);
1691299928Sandrew}
1692299928Sandrew
1693299928Sandrewstatic int
1694299928Sandrewarm_gicv2m_release_msi(device_t dev, device_t child, int count,
1695299928Sandrew    struct intr_irqsrc **isrc)
1696299928Sandrew{
1697299928Sandrew	struct arm_gicv2m_softc *sc;
1698299928Sandrew	struct gic_irqsrc *gi;
1699299928Sandrew	int i;
1700299928Sandrew
1701299928Sandrew	sc = device_get_softc(dev);
1702299928Sandrew
1703299928Sandrew	mtx_lock(&sc->sc_mutex);
1704299928Sandrew	for (i = 0; i < count; i++) {
1705308382Sgonzo		gi = (struct gic_irqsrc *)isrc[i];
1706299928Sandrew
1707299928Sandrew		KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED,
1708299928Sandrew		    ("%s: Trying to release an unused MSI-X interrupt",
1709299928Sandrew		    __func__));
1710299928Sandrew
1711299928Sandrew		gi->gi_flags &= ~GI_FLAG_MSI_USED;
1712299928Sandrew	}
1713308382Sgonzo	mtx_unlock(&sc->sc_mutex);
1714299928Sandrew
1715299928Sandrew	return (0);
1716299928Sandrew}
1717299928Sandrew
1718299928Sandrewstatic int
1719299928Sandrewarm_gicv2m_alloc_msix(device_t dev, device_t child, device_t *pic,
1720299928Sandrew    struct intr_irqsrc **isrcp)
1721299928Sandrew{
1722299928Sandrew	struct arm_gicv2m_softc *sc;
1723299928Sandrew	struct arm_gic_softc *psc;
1724299928Sandrew	int irq;
1725299928Sandrew
1726299928Sandrew	psc = device_get_softc(device_get_parent(dev));
1727299928Sandrew	sc = device_get_softc(dev);
1728299928Sandrew
1729299928Sandrew	mtx_lock(&sc->sc_mutex);
1730299928Sandrew	/* Find an unused interrupt */
1731299928Sandrew	for (irq = sc->sc_spi_start; irq < sc->sc_spi_end; irq++) {
1732299928Sandrew		KASSERT((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI) != 0,
1733299928Sandrew		    ("%s: Non-MSI interrupt found", __func__));
1734299928Sandrew		if ((psc->gic_irqs[irq].gi_flags & GI_FLAG_MSI_USED) == 0)
1735299928Sandrew			break;
1736299928Sandrew	}
1737299928Sandrew	/* No free interrupt was found */
1738299928Sandrew	if (irq == sc->sc_spi_end) {
1739299928Sandrew		mtx_unlock(&sc->sc_mutex);
1740299928Sandrew		return (ENXIO);
1741299928Sandrew	}
1742299928Sandrew
1743299928Sandrew	/* Mark the interrupt as used */
1744299928Sandrew	psc->gic_irqs[irq].gi_flags |= GI_FLAG_MSI_USED;
1745299928Sandrew	mtx_unlock(&sc->sc_mutex);
1746299928Sandrew
1747299928Sandrew	*isrcp = (struct intr_irqsrc *)&psc->gic_irqs[irq];
1748299928Sandrew	*pic = device_get_parent(dev);
1749299928Sandrew
1750299928Sandrew	return (0);
1751299928Sandrew}
1752299928Sandrew
1753299928Sandrewstatic int
1754299928Sandrewarm_gicv2m_release_msix(device_t dev, device_t child, struct intr_irqsrc *isrc)
1755299928Sandrew{
1756299928Sandrew	struct arm_gicv2m_softc *sc;
1757299928Sandrew	struct gic_irqsrc *gi;
1758299928Sandrew
1759299928Sandrew	sc = device_get_softc(dev);
1760299928Sandrew	gi = (struct gic_irqsrc *)isrc;
1761299928Sandrew
1762299928Sandrew	KASSERT((gi->gi_flags & GI_FLAG_MSI_USED) == GI_FLAG_MSI_USED,
1763299928Sandrew	    ("%s: Trying to release an unused MSI-X interrupt", __func__));
1764299928Sandrew
1765299928Sandrew	mtx_lock(&sc->sc_mutex);
1766299928Sandrew	gi->gi_flags &= ~GI_FLAG_MSI_USED;
1767299928Sandrew	mtx_unlock(&sc->sc_mutex);
1768299928Sandrew
1769299928Sandrew	return (0);
1770299928Sandrew}
1771299928Sandrew
1772299928Sandrewstatic int
1773299928Sandrewarm_gicv2m_map_msi(device_t dev, device_t child, struct intr_irqsrc *isrc,
1774299928Sandrew    uint64_t *addr, uint32_t *data)
1775299928Sandrew{
1776299928Sandrew	struct arm_gicv2m_softc *sc = device_get_softc(dev);
1777299928Sandrew	struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc;
1778299928Sandrew
1779299928Sandrew	*addr = vtophys(rman_get_virtual(sc->sc_mem)) + GICv2M_MSI_SETSPI_NS;
1780299928Sandrew	*data = gi->gi_irq;
1781299928Sandrew
1782299928Sandrew	return (0);
1783299928Sandrew}
1784299928Sandrew
1785298051Sandrewstatic device_method_t arm_gicv2m_methods[] = {
1786298051Sandrew	/* Device interface */
1787298051Sandrew	DEVMETHOD(device_probe,		arm_gicv2m_probe),
1788298051Sandrew	DEVMETHOD(device_attach,	arm_gicv2m_attach),
1789298051Sandrew
1790299928Sandrew	/* MSI/MSI-X */
1791299928Sandrew	DEVMETHOD(msi_alloc_msi,	arm_gicv2m_alloc_msi),
1792299928Sandrew	DEVMETHOD(msi_release_msi,	arm_gicv2m_release_msi),
1793299928Sandrew	DEVMETHOD(msi_alloc_msix,	arm_gicv2m_alloc_msix),
1794299928Sandrew	DEVMETHOD(msi_release_msix,	arm_gicv2m_release_msix),
1795299928Sandrew	DEVMETHOD(msi_map_msi,		arm_gicv2m_map_msi),
1796299928Sandrew
1797298051Sandrew	/* End */
1798298051Sandrew	DEVMETHOD_END
1799298051Sandrew};
1800298051Sandrew
1801298051SandrewDEFINE_CLASS_0(gicv2m, arm_gicv2m_driver, arm_gicv2m_methods,
1802298051Sandrew    sizeof(struct arm_gicv2m_softc));
1803298051Sandrew
1804298051Sandrewstatic devclass_t arm_gicv2m_devclass;
1805298051Sandrew
1806298051SandrewEARLY_DRIVER_MODULE(gicv2m, gic, arm_gicv2m_driver,
1807298051Sandrew    arm_gicv2m_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
1808298051Sandrew#endif
1809