xref: /openbsd/sys/arch/arm64/dev/ampintc.c (revision 94673892)
1*94673892Sjsg /* $OpenBSD: ampintc.c,v 1.31 2023/09/22 01:10:43 jsg Exp $ */
2f24071e5Spatrick /*
3f24071e5Spatrick  * Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org>
4f24071e5Spatrick  *
5f24071e5Spatrick  * Permission to use, copy, modify, and distribute this software for any
6f24071e5Spatrick  * purpose with or without fee is hereby granted, provided that the above
7f24071e5Spatrick  * copyright notice and this permission notice appear in all copies.
8f24071e5Spatrick  *
9f24071e5Spatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10f24071e5Spatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11f24071e5Spatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12f24071e5Spatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13f24071e5Spatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14f24071e5Spatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15f24071e5Spatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16f24071e5Spatrick  */
17f24071e5Spatrick 
18f24071e5Spatrick /*
19f24071e5Spatrick  * This driver implements the interrupt controller as specified in
20f24071e5Spatrick  * DDI0407E_cortex_a9_mpcore_r2p0_trm with the
21f24071e5Spatrick  * IHI0048A_gic_architecture_spec_v1_0 underlying specification
22f24071e5Spatrick  */
23f24071e5Spatrick #include <sys/param.h>
24f24071e5Spatrick #include <sys/systm.h>
25f24071e5Spatrick #include <sys/queue.h>
26f24071e5Spatrick #include <sys/malloc.h>
27f24071e5Spatrick #include <sys/device.h>
28f24071e5Spatrick #include <sys/evcount.h>
29f24071e5Spatrick 
30c17c7ba4Spatrick #include <uvm/uvm_extern.h>
31c17c7ba4Spatrick 
32f24071e5Spatrick #include <machine/bus.h>
33f24071e5Spatrick #include <machine/fdt.h>
34f24071e5Spatrick 
35f24071e5Spatrick #include <dev/ofw/fdt.h>
36f24071e5Spatrick #include <dev/ofw/openfirm.h>
37f24071e5Spatrick 
38*94673892Sjsg #include <machine/simplebusvar.h>
39c17c7ba4Spatrick 
40f24071e5Spatrick /* registers */
41f24071e5Spatrick #define	ICD_DCR			0x000
42f24071e5Spatrick #define		ICD_DCR_ES		0x00000001
43f24071e5Spatrick #define		ICD_DCR_ENS		0x00000002
44f24071e5Spatrick 
45f24071e5Spatrick #define ICD_ICTR			0x004
46f24071e5Spatrick #define		ICD_ICTR_LSPI_SH	11
47f24071e5Spatrick #define		ICD_ICTR_LSPI_M		0x1f
48f24071e5Spatrick #define		ICD_ICTR_CPU_SH		5
49f24071e5Spatrick #define		ICD_ICTR_CPU_M		0x07
50f24071e5Spatrick #define		ICD_ICTR_ITL_SH		0
51f24071e5Spatrick #define		ICD_ICTR_ITL_M		0x1f
52f24071e5Spatrick #define ICD_IDIR			0x008
53f24071e5Spatrick #define 	ICD_DIR_PROD_SH		24
54f24071e5Spatrick #define 	ICD_DIR_PROD_M		0xff
55f24071e5Spatrick #define 	ICD_DIR_REV_SH		12
56f24071e5Spatrick #define 	ICD_DIR_REV_M		0xfff
57f24071e5Spatrick #define 	ICD_DIR_IMP_SH		0
58f24071e5Spatrick #define 	ICD_DIR_IMP_M		0xfff
59f24071e5Spatrick 
6018a1c566Spatrick #define IRQ_TO_REG32(i)		(((i) >> 5) & 0x1f)
61f24071e5Spatrick #define IRQ_TO_REG32BIT(i)	((i) & 0x1f)
6218a1c566Spatrick #define IRQ_TO_REG4(i)		(((i) >> 2) & 0xff)
63f24071e5Spatrick #define IRQ_TO_REG4BIT(i)	((i) & 0x3)
6418a1c566Spatrick #define IRQ_TO_REG16(i)		(((i) >> 4) & 0x3f)
65edffca28Spatrick #define IRQ_TO_REG16BIT(i)	((i) & 0xf)
66f24071e5Spatrick #define IRQ_TO_REGBIT_S(i)	8
67f24071e5Spatrick #define IRQ_TO_REG4BIT_M(i)	8
68f24071e5Spatrick 
69f24071e5Spatrick #define ICD_ISRn(i)		(0x080 + (IRQ_TO_REG32(i) * 4))
70f24071e5Spatrick #define ICD_ISERn(i)		(0x100 + (IRQ_TO_REG32(i) * 4))
71f24071e5Spatrick #define ICD_ICERn(i)		(0x180 + (IRQ_TO_REG32(i) * 4))
72f24071e5Spatrick #define ICD_ISPRn(i)		(0x200 + (IRQ_TO_REG32(i) * 4))
73f24071e5Spatrick #define ICD_ICPRn(i)		(0x280 + (IRQ_TO_REG32(i) * 4))
74f24071e5Spatrick #define ICD_ABRn(i)		(0x300 + (IRQ_TO_REG32(i) * 4))
75f24071e5Spatrick #define ICD_IPRn(i)		(0x400 + (i))
76f24071e5Spatrick #define ICD_IPTRn(i)		(0x800 + (i))
77f24071e5Spatrick #define ICD_ICRn(i)		(0xC00 + (IRQ_TO_REG16(i) * 4))
78edffca28Spatrick #define 	ICD_ICR_TRIG_LEVEL(i)	(0x0 << (IRQ_TO_REG16BIT(i) * 2))
79edffca28Spatrick #define 	ICD_ICR_TRIG_EDGE(i)	(0x2 << (IRQ_TO_REG16BIT(i) * 2))
80edffca28Spatrick #define 	ICD_ICR_TRIG_MASK(i)	(0x2 << (IRQ_TO_REG16BIT(i) * 2))
81edffca28Spatrick 
82f24071e5Spatrick /*
83f24071e5Spatrick  * what about (ppi|spi)_status
84f24071e5Spatrick  */
85f24071e5Spatrick #define ICD_PPI			0xD00
86f24071e5Spatrick #define 	ICD_PPI_GTIMER	(1 << 11)
87f24071e5Spatrick #define 	ICD_PPI_FIQ		(1 << 12)
88f24071e5Spatrick #define 	ICD_PPI_PTIMER	(1 << 13)
89f24071e5Spatrick #define 	ICD_PPI_PWDOG	(1 << 14)
90f24071e5Spatrick #define 	ICD_PPI_IRQ		(1 << 15)
91f24071e5Spatrick #define ICD_SPI_BASE		0xD04
92f24071e5Spatrick #define ICD_SPIn(i)			(ICD_SPI_BASE + ((i) * 4))
93f24071e5Spatrick 
94f24071e5Spatrick 
95f24071e5Spatrick #define ICD_SGIR			0xF00
96f24071e5Spatrick 
97f24071e5Spatrick #define ICD_PERIPH_ID_0			0xFD0
98f24071e5Spatrick #define ICD_PERIPH_ID_1			0xFD4
99f24071e5Spatrick #define ICD_PERIPH_ID_2			0xFD8
100f24071e5Spatrick #define ICD_PERIPH_ID_3			0xFDC
101f24071e5Spatrick #define ICD_PERIPH_ID_4			0xFE0
102f24071e5Spatrick #define ICD_PERIPH_ID_5			0xFE4
103f24071e5Spatrick #define ICD_PERIPH_ID_6			0xFE8
104f24071e5Spatrick #define ICD_PERIPH_ID_7			0xFEC
105f24071e5Spatrick 
106f24071e5Spatrick #define ICD_COMP_ID_0			0xFEC
107f24071e5Spatrick #define ICD_COMP_ID_1			0xFEC
108f24071e5Spatrick #define ICD_COMP_ID_2			0xFEC
109f24071e5Spatrick #define ICD_COMP_ID_3			0xFEC
110f24071e5Spatrick 
111f24071e5Spatrick 
112f24071e5Spatrick #define ICPICR				0x00
113f24071e5Spatrick #define ICPIPMR				0x04
114f24071e5Spatrick /* XXX - must left justify bits to  0 - 7  */
115f24071e5Spatrick #define 	ICMIPMR_SH 		4
116f24071e5Spatrick #define ICPBPR				0x08
117f24071e5Spatrick #define ICPIAR				0x0C
118f24071e5Spatrick #define 	ICPIAR_IRQ_SH		0
119f24071e5Spatrick #define 	ICPIAR_IRQ_M		0x3ff
120f24071e5Spatrick #define 	ICPIAR_CPUID_SH		10
121f24071e5Spatrick #define 	ICPIAR_CPUID_M		0x7
122f24071e5Spatrick #define 	ICPIAR_NO_PENDING_IRQ	ICPIAR_IRQ_M
123f24071e5Spatrick #define ICPEOIR				0x10
124f24071e5Spatrick #define ICPPRP				0x14
125f24071e5Spatrick #define ICPHPIR				0x18
126f24071e5Spatrick #define ICPIIR				0xFC
127f24071e5Spatrick 
128f24071e5Spatrick /*
129f24071e5Spatrick  * what about periph_id and component_id
130f24071e5Spatrick  */
131f24071e5Spatrick 
132f24071e5Spatrick #define IRQ_ENABLE	1
133f24071e5Spatrick #define IRQ_DISABLE	0
134f24071e5Spatrick 
135f24071e5Spatrick struct ampintc_softc {
136c17c7ba4Spatrick 	struct simplebus_softc	 sc_sbus;
137d7e3db9cSkettenis 	struct intrq 		*sc_handler;
138f24071e5Spatrick 	int			 sc_nintr;
139f24071e5Spatrick 	bus_space_tag_t		 sc_iot;
140f24071e5Spatrick 	bus_space_handle_t	 sc_d_ioh, sc_p_ioh;
1410d4f5be1Skettenis 	uint8_t			 sc_cpu_mask[ICD_ICTR_CPU_M + 1];
142f24071e5Spatrick 	struct evcount		 sc_spur;
143f24071e5Spatrick 	struct interrupt_controller sc_ic;
144d7e3db9cSkettenis 	int			 sc_ipi_reason[ICD_ICTR_CPU_M + 1];
1454002e08dSkettenis 	int			 sc_ipi_num[3];
146f24071e5Spatrick };
147f24071e5Spatrick struct ampintc_softc *ampintc;
148f24071e5Spatrick 
149f24071e5Spatrick 
150f24071e5Spatrick struct intrhand {
151f24071e5Spatrick 	TAILQ_ENTRY(intrhand) ih_list;	/* link on intrq list */
152f24071e5Spatrick 	int (*ih_func)(void *);		/* handler */
153f24071e5Spatrick 	void *ih_arg;			/* arg for handler */
154f24071e5Spatrick 	int ih_ipl;			/* IPL_* */
1557a7b3facSkettenis 	int ih_flags;
156f24071e5Spatrick 	int ih_irq;			/* IRQ number */
157f24071e5Spatrick 	struct evcount	ih_count;
158f24071e5Spatrick 	char *ih_name;
159452daaedSpatrick 	struct cpu_info *ih_ci;		/* CPU the IRQ runs on */
160f24071e5Spatrick };
161f24071e5Spatrick 
162f24071e5Spatrick struct intrq {
163f24071e5Spatrick 	TAILQ_HEAD(, intrhand) iq_list;	/* handler list */
164de70244eSpatrick 	struct cpu_info *iq_ci;		/* CPU the IRQ runs on */
165eb0c9b3cSpatrick 	int iq_irq_max;			/* IRQ to mask while handling */
166eb0c9b3cSpatrick 	int iq_irq_min;			/* lowest IRQ when shared */
167f24071e5Spatrick 	int iq_ist;			/* share type */
168f24071e5Spatrick };
169f24071e5Spatrick 
170f24071e5Spatrick 
171f24071e5Spatrick int		 ampintc_match(struct device *, void *, void *);
172f24071e5Spatrick void		 ampintc_attach(struct device *, struct device *, void *);
1734002e08dSkettenis int		 ampintc_activate(struct device *, int);
1744002e08dSkettenis void		 ampintc_init(struct ampintc_softc *);
175d7e3db9cSkettenis void		 ampintc_cpuinit(void);
176f24071e5Spatrick int		 ampintc_spllower(int);
177f24071e5Spatrick void		 ampintc_splx(int);
178f24071e5Spatrick int		 ampintc_splraise(int);
179f24071e5Spatrick void		 ampintc_setipl(int);
180f24071e5Spatrick void		 ampintc_calc_mask(void);
181de70244eSpatrick void		 ampintc_calc_irq(struct ampintc_softc *, int);
182789e88a4Spatrick void		*ampintc_intr_establish(int, int, int, struct cpu_info *,
183f24071e5Spatrick 		    int (*)(void *), void *, char *);
184789e88a4Spatrick void		*ampintc_intr_establish_fdt(void *, int *, int,
185789e88a4Spatrick 		    struct cpu_info *, int (*)(void *), void *, char *);
186f24071e5Spatrick void		 ampintc_intr_disestablish(void *);
187f24071e5Spatrick void		 ampintc_irq_handler(void *);
188f24071e5Spatrick const char	*ampintc_intr_string(void *);
189f24071e5Spatrick uint32_t	 ampintc_iack(void);
190f24071e5Spatrick void		 ampintc_eoi(uint32_t);
191f24071e5Spatrick void		 ampintc_set_priority(int, int);
192f24071e5Spatrick void		 ampintc_intr_enable(int);
193f24071e5Spatrick void		 ampintc_intr_disable(int);
194edffca28Spatrick void		 ampintc_intr_config(int, int);
1950d4f5be1Skettenis void		 ampintc_route(int, int, struct cpu_info *);
196d7e3db9cSkettenis void		 ampintc_route_irq(void *, int, struct cpu_info *);
197452daaedSpatrick void		 ampintc_intr_barrier(void *);
198d7e3db9cSkettenis 
199d7e3db9cSkettenis int		 ampintc_ipi_combined(void *);
200d7e3db9cSkettenis int		 ampintc_ipi_nop(void *);
201d7e3db9cSkettenis int		 ampintc_ipi_ddb(void *);
2024002e08dSkettenis int		 ampintc_ipi_halt(void *);
203d7e3db9cSkettenis void		 ampintc_send_ipi(struct cpu_info *, int);
204f24071e5Spatrick 
2059fdf0c62Smpi const struct cfattach	ampintc_ca = {
2064002e08dSkettenis 	sizeof (struct ampintc_softc), ampintc_match, ampintc_attach,
2074002e08dSkettenis 	NULL, ampintc_activate
208f24071e5Spatrick };
209f24071e5Spatrick 
210f24071e5Spatrick struct cfdriver ampintc_cd = {
211f24071e5Spatrick 	NULL, "ampintc", DV_DULL
212f24071e5Spatrick };
213f24071e5Spatrick 
214f24071e5Spatrick static char *ampintc_compatibles[] = {
215f24071e5Spatrick 	"arm,cortex-a7-gic",
216f24071e5Spatrick 	"arm,cortex-a9-gic",
217f24071e5Spatrick 	"arm,cortex-a15-gic",
218b78d0bc7Sjsg 	"arm,gic-400",
219f24071e5Spatrick 	NULL
220f24071e5Spatrick };
221f24071e5Spatrick 
222f24071e5Spatrick int
ampintc_match(struct device * parent,void * cfdata,void * aux)223f24071e5Spatrick ampintc_match(struct device *parent, void *cfdata, void *aux)
224f24071e5Spatrick {
225f24071e5Spatrick 	struct fdt_attach_args *faa = aux;
226f24071e5Spatrick 	int i;
227f24071e5Spatrick 
228f24071e5Spatrick 	for (i = 0; ampintc_compatibles[i]; i++)
229f24071e5Spatrick 		if (OF_is_compatible(faa->fa_node, ampintc_compatibles[i]))
230f24071e5Spatrick 			return (1);
231f24071e5Spatrick 
232f24071e5Spatrick 	return (0);
233f24071e5Spatrick }
234f24071e5Spatrick 
235f24071e5Spatrick void
ampintc_attach(struct device * parent,struct device * self,void * aux)236f24071e5Spatrick ampintc_attach(struct device *parent, struct device *self, void *aux)
237f24071e5Spatrick {
238f24071e5Spatrick 	struct ampintc_softc *sc = (struct ampintc_softc *)self;
239f24071e5Spatrick 	struct fdt_attach_args *faa = aux;
2400d4f5be1Skettenis 	int i, nintr, ncpu;
2410d4f5be1Skettenis 	uint32_t ictr;
242d7e3db9cSkettenis #ifdef MULTIPROCESSOR
2434002e08dSkettenis 	int nipi, ipiirq[3];
244d7e3db9cSkettenis #endif
245f24071e5Spatrick 
246f24071e5Spatrick 	ampintc = sc;
247f24071e5Spatrick 
248f24071e5Spatrick 	arm_init_smask();
249f24071e5Spatrick 
250f24071e5Spatrick 	sc->sc_iot = faa->fa_iot;
251f24071e5Spatrick 
252f24071e5Spatrick 	/* First row: ICD */
253f24071e5Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
254f24071e5Spatrick 	    faa->fa_reg[0].size, 0, &sc->sc_d_ioh))
255f24071e5Spatrick 		panic("%s: ICD bus_space_map failed!", __func__);
256f24071e5Spatrick 
257f24071e5Spatrick 	/* Second row: ICP */
258f24071e5Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
259f24071e5Spatrick 	    faa->fa_reg[1].size, 0, &sc->sc_p_ioh))
260f24071e5Spatrick 		panic("%s: ICP bus_space_map failed!", __func__);
261f24071e5Spatrick 
262f24071e5Spatrick 	evcount_attach(&sc->sc_spur, "irq1023/spur", NULL);
263f24071e5Spatrick 
2640d4f5be1Skettenis 	ictr = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICTR);
2650d4f5be1Skettenis 	nintr = 32 * ((ictr >> ICD_ICTR_ITL_SH) & ICD_ICTR_ITL_M);
266f24071e5Spatrick 	nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */
267f24071e5Spatrick 	sc->sc_nintr = nintr;
2680d4f5be1Skettenis 	ncpu = ((ictr >> ICD_ICTR_CPU_SH) & ICD_ICTR_CPU_M) + 1;
2690d4f5be1Skettenis 	printf(" nirq %d, ncpu %d", nintr, ncpu);
2700d4f5be1Skettenis 
2710d4f5be1Skettenis 	KASSERT(curcpu()->ci_cpuid <= ICD_ICTR_CPU_M);
2720d4f5be1Skettenis 	sc->sc_cpu_mask[curcpu()->ci_cpuid] =
2730d4f5be1Skettenis 	    bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(0));
274f24071e5Spatrick 
2754002e08dSkettenis 	ampintc_init(sc);
276f24071e5Spatrick 
277f24071e5Spatrick 	/* software reset of the part? */
278f24071e5Spatrick 	/* set protection bit (kernel only)? */
279f24071e5Spatrick 
280f24071e5Spatrick 	/* XXX - check power saving bit */
281f24071e5Spatrick 
282d7e3db9cSkettenis 	sc->sc_handler = mallocarray(nintr, sizeof(*sc->sc_handler), M_DEVBUF,
283d7e3db9cSkettenis 	    M_ZERO | M_NOWAIT);
284f24071e5Spatrick 	for (i = 0; i < nintr; i++) {
285d7e3db9cSkettenis 		TAILQ_INIT(&sc->sc_handler[i].iq_list);
286f24071e5Spatrick 	}
287f24071e5Spatrick 
288f24071e5Spatrick 	ampintc_setipl(IPL_HIGH);  /* XXX ??? */
289f24071e5Spatrick 	ampintc_calc_mask();
290f24071e5Spatrick 
291f24071e5Spatrick 	/* insert self as interrupt handler */
292f24071e5Spatrick 	arm_set_intr_handler(ampintc_splraise, ampintc_spllower, ampintc_splx,
2935dee5702Skettenis 	    ampintc_setipl, ampintc_irq_handler, NULL, NULL, NULL);
294f24071e5Spatrick 
295d7e3db9cSkettenis #ifdef MULTIPROCESSOR
296d7e3db9cSkettenis 	/* setup IPI interrupts */
297d7e3db9cSkettenis 
298d7e3db9cSkettenis 	/*
2994002e08dSkettenis 	 * Ideally we want three IPI interrupts, one for NOP, one for
3004002e08dSkettenis 	 * DDB and one for HALT.  However we can survive if only one
3014002e08dSkettenis 	 * is available; it is possible that most are not available to
3024002e08dSkettenis 	 * the non-secure OS.
303d7e3db9cSkettenis 	 */
304d7e3db9cSkettenis 	nipi = 0;
305d7e3db9cSkettenis 	for (i = 0; i < 16; i++) {
306d7e3db9cSkettenis 		int reg, oldreg;
307d7e3db9cSkettenis 
308d7e3db9cSkettenis 		oldreg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh,
309d7e3db9cSkettenis 		    ICD_IPRn(i));
310d7e3db9cSkettenis 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i),
311d7e3db9cSkettenis 		    oldreg ^ 0x20);
312d7e3db9cSkettenis 
313d7e3db9cSkettenis 		/* if this interrupt is not usable, route will be zero */
314d7e3db9cSkettenis 		reg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i));
315d7e3db9cSkettenis 		if (reg == oldreg)
316d7e3db9cSkettenis 			continue;
317d7e3db9cSkettenis 
318d7e3db9cSkettenis 		/* return to original value, will be set when used */
319d7e3db9cSkettenis 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i),
320d7e3db9cSkettenis 		    oldreg);
321d7e3db9cSkettenis 
322d7e3db9cSkettenis 		if (nipi == 0)
323d7e3db9cSkettenis 			printf(" ipi: %d", i);
324d7e3db9cSkettenis 		else
325d7e3db9cSkettenis 			printf(", %d", i);
326d7e3db9cSkettenis 		ipiirq[nipi++] = i;
3274002e08dSkettenis 		if (nipi == 3)
328d7e3db9cSkettenis 			break;
329d7e3db9cSkettenis 	}
330d7e3db9cSkettenis 
331d7e3db9cSkettenis 	if (nipi == 0)
332d7e3db9cSkettenis 		panic ("no irq available for IPI");
333d7e3db9cSkettenis 
334d7e3db9cSkettenis 	switch (nipi) {
335d7e3db9cSkettenis 	case 1:
336d7e3db9cSkettenis 		ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
337789e88a4Spatrick 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_combined, sc, "ipi");
338d7e3db9cSkettenis 		sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
339d7e3db9cSkettenis 		sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0];
3404002e08dSkettenis 		sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[0];
341d7e3db9cSkettenis 		break;
342d7e3db9cSkettenis 	case 2:
343d7e3db9cSkettenis 		ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
344789e88a4Spatrick 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_nop, sc, "ipinop");
345d7e3db9cSkettenis 		sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
346d7e3db9cSkettenis 		ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING,
3474002e08dSkettenis 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_combined, sc, "ipi");
3484002e08dSkettenis 		sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
3494002e08dSkettenis 		sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[1];
3504002e08dSkettenis 		break;
3514002e08dSkettenis 	case 3:
3524002e08dSkettenis 		ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
3534002e08dSkettenis 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_nop, sc, "ipinop");
3544002e08dSkettenis 		sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
3554002e08dSkettenis 		ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING,
356789e88a4Spatrick 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_ddb, sc, "ipiddb");
357d7e3db9cSkettenis 		sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
3584002e08dSkettenis 		ampintc_intr_establish(ipiirq[2], IST_EDGE_RISING,
3594002e08dSkettenis 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_halt, sc, "ipihalt");
3604002e08dSkettenis 		sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[2];
361d7e3db9cSkettenis 		break;
362d7e3db9cSkettenis 	default:
363d7e3db9cSkettenis 		panic("nipi unexpected number %d", nipi);
364d7e3db9cSkettenis 	}
365d7e3db9cSkettenis 
366d7e3db9cSkettenis 	intr_send_ipi_func = ampintc_send_ipi;
367d7e3db9cSkettenis #endif
368d7e3db9cSkettenis 
369f24071e5Spatrick 	/* enable interrupts */
370f24071e5Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
371f24071e5Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
372daf2e6ccSkettenis 	intr_enable();
373f24071e5Spatrick 
374f24071e5Spatrick 	sc->sc_ic.ic_node = faa->fa_node;
375f24071e5Spatrick 	sc->sc_ic.ic_cookie = self;
376f24071e5Spatrick 	sc->sc_ic.ic_establish = ampintc_intr_establish_fdt;
377f24071e5Spatrick 	sc->sc_ic.ic_disestablish = ampintc_intr_disestablish;
378d7e3db9cSkettenis 	sc->sc_ic.ic_route = ampintc_route_irq;
379d7e3db9cSkettenis 	sc->sc_ic.ic_cpu_enable = ampintc_cpuinit;
380452daaedSpatrick 	sc->sc_ic.ic_barrier = ampintc_intr_barrier;
381f24071e5Spatrick 	arm_intr_register_fdt(&sc->sc_ic);
382c17c7ba4Spatrick 
383c17c7ba4Spatrick 	/* attach GICv2M frame controller */
384c17c7ba4Spatrick 	simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
385f24071e5Spatrick }
386f24071e5Spatrick 
3874002e08dSkettenis int
ampintc_activate(struct device * self,int act)3884002e08dSkettenis ampintc_activate(struct device *self, int act)
3894002e08dSkettenis {
3904002e08dSkettenis 	struct ampintc_softc *sc = (struct ampintc_softc *)self;
3914002e08dSkettenis 	struct cpu_info *ci;
3924002e08dSkettenis 	int irq, min;
3934002e08dSkettenis 
3944002e08dSkettenis 	switch (act) {
3954002e08dSkettenis 	case DVACT_RESUME:
3964002e08dSkettenis 		for (irq = 0; irq < sc->sc_nintr; irq++) {
3974002e08dSkettenis 			ci = sc->sc_handler[irq].iq_ci;
3984002e08dSkettenis 			min = sc->sc_handler[irq].iq_irq_min;
3994002e08dSkettenis 			if (min != IPL_NONE) {
4004002e08dSkettenis 				ampintc_set_priority(irq, min);
4014002e08dSkettenis 				ampintc_intr_enable(irq);
4024002e08dSkettenis 				ampintc_route(irq, IRQ_ENABLE, ci);
4034002e08dSkettenis 			} else {
4044002e08dSkettenis 				ampintc_intr_disable(irq);
4054002e08dSkettenis 			}
4064002e08dSkettenis 		}
4074002e08dSkettenis 
4084002e08dSkettenis 		/* enable interrupts */
4094002e08dSkettenis 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
4104002e08dSkettenis 		bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
4114002e08dSkettenis 		break;
4124002e08dSkettenis 	}
4134002e08dSkettenis 
4144002e08dSkettenis 	return 0;
4154002e08dSkettenis }
4164002e08dSkettenis 
4174002e08dSkettenis void
ampintc_init(struct ampintc_softc * sc)4184002e08dSkettenis ampintc_init(struct ampintc_softc *sc)
4194002e08dSkettenis {
4204002e08dSkettenis 	int i;
4214002e08dSkettenis 
4224002e08dSkettenis 	/* Disable all interrupts, clear all pending */
4234002e08dSkettenis 	for (i = 0; i < sc->sc_nintr / 32; i++) {
4244002e08dSkettenis 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
4254002e08dSkettenis 		    ICD_ICERn(i * 32), ~0);
4264002e08dSkettenis 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
4274002e08dSkettenis 		    ICD_ICPRn(i * 32), ~0);
4284002e08dSkettenis 	}
4294002e08dSkettenis 	for (i = 0; i < sc->sc_nintr; i++) {
4304002e08dSkettenis 		/* lowest priority ?? */
4314002e08dSkettenis 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 0xff);
4324002e08dSkettenis 		/* target no cpus */
4334002e08dSkettenis 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(i), 0);
4344002e08dSkettenis 	}
4354002e08dSkettenis 	for (i = 2; i < sc->sc_nintr / 16; i++) {
4364002e08dSkettenis 		/* irq 32 - N */
4374002e08dSkettenis 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
4384002e08dSkettenis 		    ICD_ICRn(i * 16), 0);
4394002e08dSkettenis 	}
4404002e08dSkettenis }
4414002e08dSkettenis 
442f24071e5Spatrick void
ampintc_set_priority(int irq,int pri)443f24071e5Spatrick ampintc_set_priority(int irq, int pri)
444f24071e5Spatrick {
445f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
446f24071e5Spatrick 	uint32_t		 prival;
447f24071e5Spatrick 
448f24071e5Spatrick 	/*
449f24071e5Spatrick 	 * We only use 16 (13 really) interrupt priorities,
450f24071e5Spatrick 	 * and a CPU is only required to implement bit 4-7 of each field
451f24071e5Spatrick 	 * so shift into the top bits.
452f24071e5Spatrick 	 * also low values are higher priority thus IPL_HIGH - pri
453f24071e5Spatrick 	 */
454f24071e5Spatrick 	prival = (IPL_HIGH - pri) << ICMIPMR_SH;
455f24071e5Spatrick 	bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(irq), prival);
456f24071e5Spatrick }
457f24071e5Spatrick 
458f24071e5Spatrick void
ampintc_setipl(int new)459f24071e5Spatrick ampintc_setipl(int new)
460f24071e5Spatrick {
461f24071e5Spatrick 	struct cpu_info		*ci = curcpu();
462f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
463daf2e6ccSkettenis 	u_long			 psw;
464f24071e5Spatrick 
465f24071e5Spatrick 	/* disable here is only to keep hardware in sync with ci->ci_cpl */
466daf2e6ccSkettenis 	psw = intr_disable();
467f24071e5Spatrick 	ci->ci_cpl = new;
468f24071e5Spatrick 
469f24071e5Spatrick 	/* low values are higher priority thus IPL_HIGH - pri */
470f24071e5Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPIPMR,
471f24071e5Spatrick 	    (IPL_HIGH - new) << ICMIPMR_SH);
472daf2e6ccSkettenis 	intr_restore(psw);
473f24071e5Spatrick }
474f24071e5Spatrick 
475f24071e5Spatrick void
ampintc_intr_enable(int irq)476f24071e5Spatrick ampintc_intr_enable(int irq)
477f24071e5Spatrick {
478f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
479f24071e5Spatrick 
480f24071e5Spatrick #ifdef DEBUG
481f24071e5Spatrick 	printf("enable irq %d register %x bitmask %08x\n",
482f24071e5Spatrick 	    irq, ICD_ISERn(irq), 1 << IRQ_TO_REG32BIT(irq));
483f24071e5Spatrick #endif
484f24071e5Spatrick 
485f24071e5Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ISERn(irq),
486f24071e5Spatrick 	    1 << IRQ_TO_REG32BIT(irq));
487f24071e5Spatrick }
488f24071e5Spatrick 
489f24071e5Spatrick void
ampintc_intr_disable(int irq)490f24071e5Spatrick ampintc_intr_disable(int irq)
491f24071e5Spatrick {
492f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
493f24071e5Spatrick 
494f24071e5Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICERn(irq),
495f24071e5Spatrick 	    1 << IRQ_TO_REG32BIT(irq));
496f24071e5Spatrick }
497f24071e5Spatrick 
498edffca28Spatrick void
ampintc_intr_config(int irqno,int type)499edffca28Spatrick ampintc_intr_config(int irqno, int type)
500edffca28Spatrick {
501edffca28Spatrick 	struct ampintc_softc	*sc = ampintc;
502edffca28Spatrick 	uint32_t		 ctrl;
503edffca28Spatrick 
504edffca28Spatrick 	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(irqno));
505edffca28Spatrick 
506edffca28Spatrick 	ctrl &= ~ICD_ICR_TRIG_MASK(irqno);
507edffca28Spatrick 	if (type == IST_EDGE_RISING)
508edffca28Spatrick 		ctrl |= ICD_ICR_TRIG_EDGE(irqno);
509edffca28Spatrick 	else
510edffca28Spatrick 		ctrl |= ICD_ICR_TRIG_LEVEL(irqno);
511edffca28Spatrick 
512edffca28Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(irqno), ctrl);
513edffca28Spatrick }
514f24071e5Spatrick 
515f24071e5Spatrick void
ampintc_calc_mask(void)516f24071e5Spatrick ampintc_calc_mask(void)
517f24071e5Spatrick {
518f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
519f24071e5Spatrick 	int			 irq;
520f24071e5Spatrick 
521de70244eSpatrick 	for (irq = 0; irq < sc->sc_nintr; irq++)
522de70244eSpatrick 		ampintc_calc_irq(sc, irq);
523de70244eSpatrick }
524de70244eSpatrick 
525de70244eSpatrick void
ampintc_calc_irq(struct ampintc_softc * sc,int irq)526de70244eSpatrick ampintc_calc_irq(struct ampintc_softc *sc, int irq)
527de70244eSpatrick {
528de70244eSpatrick 	struct cpu_info		*ci = sc->sc_handler[irq].iq_ci;
529de70244eSpatrick 	struct intrhand		*ih;
530f24071e5Spatrick 	int			max = IPL_NONE;
531f24071e5Spatrick 	int			min = IPL_HIGH;
532de70244eSpatrick 
533d7e3db9cSkettenis 	TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
534f24071e5Spatrick 		if (ih->ih_ipl > max)
535f24071e5Spatrick 			max = ih->ih_ipl;
536f24071e5Spatrick 
537f24071e5Spatrick 		if (ih->ih_ipl < min)
538f24071e5Spatrick 			min = ih->ih_ipl;
539f24071e5Spatrick 	}
540f24071e5Spatrick 
541f24071e5Spatrick 	if (max == IPL_NONE)
542f24071e5Spatrick 		min = IPL_NONE;
543f24071e5Spatrick 
544eb0c9b3cSpatrick 	if (sc->sc_handler[irq].iq_irq_max == max &&
545eb0c9b3cSpatrick 	    sc->sc_handler[irq].iq_irq_min == min)
546de70244eSpatrick 		return;
547eb0c9b3cSpatrick 
548eb0c9b3cSpatrick 	sc->sc_handler[irq].iq_irq_max = max;
549eb0c9b3cSpatrick 	sc->sc_handler[irq].iq_irq_min = min;
550eb0c9b3cSpatrick 
551f24071e5Spatrick 	/* Enable interrupts at lower levels, clear -> enable */
552f24071e5Spatrick 	/* Set interrupt priority/enable */
553f24071e5Spatrick 	if (min != IPL_NONE) {
554f24071e5Spatrick 		ampintc_set_priority(irq, min);
555f24071e5Spatrick 		ampintc_intr_enable(irq);
5560d4f5be1Skettenis 		ampintc_route(irq, IRQ_ENABLE, ci);
557f24071e5Spatrick 	} else {
558f24071e5Spatrick 		ampintc_intr_disable(irq);
5590d4f5be1Skettenis 		ampintc_route(irq, IRQ_DISABLE, ci);
560f24071e5Spatrick 	}
561f24071e5Spatrick }
562f24071e5Spatrick 
563f24071e5Spatrick void
ampintc_splx(int new)564f24071e5Spatrick ampintc_splx(int new)
565f24071e5Spatrick {
566f24071e5Spatrick 	struct cpu_info *ci = curcpu();
567f24071e5Spatrick 
568f24071e5Spatrick 	if (ci->ci_ipending & arm_smask[new])
569f24071e5Spatrick 		arm_do_pending_intr(new);
570f24071e5Spatrick 
571f24071e5Spatrick 	ampintc_setipl(new);
572f24071e5Spatrick }
573f24071e5Spatrick 
574f24071e5Spatrick int
ampintc_spllower(int new)575f24071e5Spatrick ampintc_spllower(int new)
576f24071e5Spatrick {
577f24071e5Spatrick 	struct cpu_info *ci = curcpu();
578f24071e5Spatrick 	int old = ci->ci_cpl;
579f24071e5Spatrick 	ampintc_splx(new);
580f24071e5Spatrick 	return (old);
581f24071e5Spatrick }
582f24071e5Spatrick 
583f24071e5Spatrick int
ampintc_splraise(int new)584f24071e5Spatrick ampintc_splraise(int new)
585f24071e5Spatrick {
586f24071e5Spatrick 	struct cpu_info *ci = curcpu();
587f24071e5Spatrick 	int old;
588f24071e5Spatrick 	old = ci->ci_cpl;
589f24071e5Spatrick 
590f24071e5Spatrick 	/*
591f24071e5Spatrick 	 * setipl must always be called because there is a race window
592f24071e5Spatrick 	 * where the variable is updated before the mask is set
593f24071e5Spatrick 	 * an interrupt occurs in that window without the mask always
594f24071e5Spatrick 	 * being set, the hardware might not get updated on the next
595f24071e5Spatrick 	 * splraise completely messing up spl protection.
596f24071e5Spatrick 	 */
597f24071e5Spatrick 	if (old > new)
598f24071e5Spatrick 		new = old;
599f24071e5Spatrick 
600f24071e5Spatrick 	ampintc_setipl(new);
601f24071e5Spatrick 
602f24071e5Spatrick 	return (old);
603f24071e5Spatrick }
604f24071e5Spatrick 
605f24071e5Spatrick 
606f24071e5Spatrick uint32_t
ampintc_iack(void)607f24071e5Spatrick ampintc_iack(void)
608f24071e5Spatrick {
609f24071e5Spatrick 	uint32_t intid;
610f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
611f24071e5Spatrick 
612f24071e5Spatrick 	intid = bus_space_read_4(sc->sc_iot, sc->sc_p_ioh, ICPIAR);
613f24071e5Spatrick 
614f24071e5Spatrick 	return (intid);
615f24071e5Spatrick }
616f24071e5Spatrick 
617f24071e5Spatrick void
ampintc_eoi(uint32_t eoi)618f24071e5Spatrick ampintc_eoi(uint32_t eoi)
619f24071e5Spatrick {
620f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
621f24071e5Spatrick 
622f24071e5Spatrick 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPEOIR, eoi);
623f24071e5Spatrick }
624f24071e5Spatrick 
625f24071e5Spatrick void
ampintc_route(int irq,int enable,struct cpu_info * ci)6260d4f5be1Skettenis ampintc_route(int irq, int enable, struct cpu_info *ci)
627f24071e5Spatrick {
628f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
6290d4f5be1Skettenis 	uint8_t			 mask, val;
6300d4f5be1Skettenis 
6310d4f5be1Skettenis 	KASSERT(ci->ci_cpuid <= ICD_ICTR_CPU_M);
6320d4f5be1Skettenis 	mask = sc->sc_cpu_mask[ci->ci_cpuid];
633f24071e5Spatrick 
634f24071e5Spatrick 	val = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq));
635f24071e5Spatrick 	if (enable == IRQ_ENABLE)
6360d4f5be1Skettenis 		val |= mask;
637f24071e5Spatrick 	else
6380d4f5be1Skettenis 		val &= ~mask;
639f24071e5Spatrick 	bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), val);
640f24071e5Spatrick }
641f24071e5Spatrick 
642f24071e5Spatrick void
ampintc_cpuinit(void)6432f346d2bSkettenis ampintc_cpuinit(void)
644d7e3db9cSkettenis {
645d7e3db9cSkettenis 	struct ampintc_softc	*sc = ampintc;
646de70244eSpatrick 	int			 i, irq;
647d7e3db9cSkettenis 
648d7e3db9cSkettenis 	/* XXX - this is the only cpu specific call to set this */
649d7e3db9cSkettenis 	if (sc->sc_cpu_mask[cpu_number()] == 0) {
650d7e3db9cSkettenis 		for (i = 0; i < 32; i++) {
651d7e3db9cSkettenis 			int cpumask =
652d7e3db9cSkettenis 			    bus_space_read_1(sc->sc_iot, sc->sc_d_ioh,
653d7e3db9cSkettenis 			        ICD_IPTRn(i));
654d7e3db9cSkettenis 
655d7e3db9cSkettenis 			if (cpumask != 0) {
656d7e3db9cSkettenis 				sc->sc_cpu_mask[cpu_number()] = cpumask;
657d7e3db9cSkettenis 				break;
658d7e3db9cSkettenis 			}
659d7e3db9cSkettenis 		}
660d7e3db9cSkettenis 	}
661d7e3db9cSkettenis 
662d7e3db9cSkettenis 	if (sc->sc_cpu_mask[cpu_number()] == 0)
663d7e3db9cSkettenis 		panic("could not determine cpu target mask");
664de70244eSpatrick 
665de70244eSpatrick 	for (irq = 0; irq < sc->sc_nintr; irq++) {
666de70244eSpatrick 		if (sc->sc_handler[irq].iq_ci != curcpu())
667de70244eSpatrick 			continue;
668de70244eSpatrick 		if (sc->sc_handler[irq].iq_irq_min != IPL_NONE)
669de70244eSpatrick 			ampintc_route(irq, IRQ_ENABLE, curcpu());
670de70244eSpatrick 		else
671de70244eSpatrick 			ampintc_route(irq, IRQ_DISABLE, curcpu());
672de70244eSpatrick 	}
6734002e08dSkettenis 
6744002e08dSkettenis 	/*
6754002e08dSkettenis 	 * If a secondary CPU is turned off from an IPI handler and
6764002e08dSkettenis 	 * the GIC did not go through a full reset (for example when
6774002e08dSkettenis 	 * we fail to suspend) the IPI might still be active.  So
6784002e08dSkettenis 	 * signal EOI here to make sure new interrupts will be
6794002e08dSkettenis 	 * serviced.
6804002e08dSkettenis 	 */
6814002e08dSkettenis 	ampintc_eoi(sc->sc_ipi_num[ARM_IPI_HALT]);
682d7e3db9cSkettenis }
683d7e3db9cSkettenis 
684d7e3db9cSkettenis void
ampintc_route_irq(void * v,int enable,struct cpu_info * ci)685d7e3db9cSkettenis ampintc_route_irq(void *v, int enable, struct cpu_info *ci)
686d7e3db9cSkettenis {
687d7e3db9cSkettenis 	struct ampintc_softc    *sc = ampintc;
688d7e3db9cSkettenis 	struct intrhand         *ih = v;
689d7e3db9cSkettenis 
690d7e3db9cSkettenis 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
691d7e3db9cSkettenis 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(ih->ih_irq), 0);
692d7e3db9cSkettenis 	if (enable) {
693d7e3db9cSkettenis 		ampintc_set_priority(ih->ih_irq,
694eb0c9b3cSpatrick 		    sc->sc_handler[ih->ih_irq].iq_irq_min);
695d7e3db9cSkettenis 		ampintc_intr_enable(ih->ih_irq);
696d7e3db9cSkettenis 	}
697d7e3db9cSkettenis 
698d7e3db9cSkettenis 	ampintc_route(ih->ih_irq, enable, ci);
699d7e3db9cSkettenis }
700d7e3db9cSkettenis 
701d7e3db9cSkettenis void
ampintc_intr_barrier(void * cookie)702452daaedSpatrick ampintc_intr_barrier(void *cookie)
703452daaedSpatrick {
704452daaedSpatrick 	struct intrhand		*ih = cookie;
705452daaedSpatrick 
706452daaedSpatrick 	sched_barrier(ih->ih_ci);
707452daaedSpatrick }
708452daaedSpatrick 
709452daaedSpatrick void
ampintc_run_handler(struct intrhand * ih,void * frame,int s)7107b137141Skettenis ampintc_run_handler(struct intrhand *ih, void *frame, int s)
7117b137141Skettenis {
7127b137141Skettenis 	void *arg;
7137b137141Skettenis 	int handled;
7147b137141Skettenis 
7157b137141Skettenis #ifdef MULTIPROCESSOR
7167b137141Skettenis 	int need_lock;
7177b137141Skettenis 
7187b137141Skettenis 	if (ih->ih_flags & IPL_MPSAFE)
7197b137141Skettenis 		need_lock = 0;
7207b137141Skettenis 	else
7217b137141Skettenis 		need_lock = s < IPL_SCHED;
7227b137141Skettenis 
7237b137141Skettenis 	if (need_lock)
7247b137141Skettenis 		KERNEL_LOCK();
7257b137141Skettenis #endif
7267b137141Skettenis 
727f9b35d7eSkettenis 	if (ih->ih_arg)
7287b137141Skettenis 		arg = ih->ih_arg;
7297b137141Skettenis 	else
7307b137141Skettenis 		arg = frame;
7317b137141Skettenis 
7327b137141Skettenis 	handled = ih->ih_func(arg);
7337b137141Skettenis 	if (handled)
7347b137141Skettenis 		ih->ih_count.ec_count++;
7357b137141Skettenis 
7367b137141Skettenis #ifdef MULTIPROCESSOR
7377b137141Skettenis 	if (need_lock)
7387b137141Skettenis 		KERNEL_UNLOCK();
7397b137141Skettenis #endif
7407b137141Skettenis }
7417b137141Skettenis 
7427b137141Skettenis void
ampintc_irq_handler(void * frame)743f24071e5Spatrick ampintc_irq_handler(void *frame)
744f24071e5Spatrick {
745f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
746f24071e5Spatrick 	struct intrhand		*ih;
747f24071e5Spatrick 	uint32_t		 iack_val;
7487b137141Skettenis 	int			 irq, pri, s;
749f24071e5Spatrick 
750f24071e5Spatrick 	iack_val = ampintc_iack();
751f24071e5Spatrick #ifdef DEBUG_INTC
752f24071e5Spatrick 	if (iack_val != 27)
753f24071e5Spatrick 		printf("irq  %d fired\n", iack_val);
754f24071e5Spatrick 	else {
755f24071e5Spatrick 		static int cnt = 0;
756f24071e5Spatrick 		if ((cnt++ % 100) == 0) {
757f24071e5Spatrick 			printf("irq  %d fired * _100\n", iack_val);
758f24071e5Spatrick #ifdef DDB
759e97088d6Smpi 			db_enter();
760f24071e5Spatrick #endif
761f24071e5Spatrick 		}
762f24071e5Spatrick 
763f24071e5Spatrick 	}
764f24071e5Spatrick #endif
765f24071e5Spatrick 
7668daa750dSpatrick 	irq = iack_val & ICPIAR_IRQ_M;
7678daa750dSpatrick 
7688daa750dSpatrick 	if (irq == 1023) {
769f24071e5Spatrick 		sc->sc_spur.ec_count++;
770f24071e5Spatrick 		return;
771f24071e5Spatrick 	}
7728daa750dSpatrick 
7738daa750dSpatrick 	if (irq >= sc->sc_nintr)
7748daa750dSpatrick 		return;
775f24071e5Spatrick 
776eb0c9b3cSpatrick 	pri = sc->sc_handler[irq].iq_irq_max;
777f24071e5Spatrick 	s = ampintc_splraise(pri);
778daf2e6ccSkettenis 	intr_enable();
7797b137141Skettenis 	TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
7807b137141Skettenis 		ampintc_run_handler(ih, frame, s);
781f24071e5Spatrick 	}
7827b137141Skettenis 	intr_disable();
783f24071e5Spatrick 	ampintc_eoi(iack_val);
784f24071e5Spatrick 
785f24071e5Spatrick 	ampintc_splx(s);
786f24071e5Spatrick }
787f24071e5Spatrick 
788f24071e5Spatrick void *
ampintc_intr_establish_fdt(void * cookie,int * cell,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)789f24071e5Spatrick ampintc_intr_establish_fdt(void *cookie, int *cell, int level,
790789e88a4Spatrick     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
791f24071e5Spatrick {
792f24071e5Spatrick 	struct ampintc_softc	*sc = (struct ampintc_softc *)cookie;
793f24071e5Spatrick 	int			 irq;
794edffca28Spatrick 	int			 type;
795f24071e5Spatrick 
796f24071e5Spatrick 	/* 2nd cell contains the interrupt number */
797f24071e5Spatrick 	irq = cell[1];
798f24071e5Spatrick 
799f24071e5Spatrick 	/* 1st cell contains type: 0 SPI (32-X), 1 PPI (16-31) */
800f24071e5Spatrick 	if (cell[0] == 0)
801f24071e5Spatrick 		irq += 32;
802f24071e5Spatrick 	else if (cell[0] == 1)
803f24071e5Spatrick 		irq += 16;
804f24071e5Spatrick 	else
805c17c7ba4Spatrick 		panic("%s: bogus interrupt type", sc->sc_sbus.sc_dev.dv_xname);
806f24071e5Spatrick 
807edffca28Spatrick 	/* SPIs are only active-high level or low-to-high edge */
808edffca28Spatrick 	if (cell[2] & 0x3)
809edffca28Spatrick 		type = IST_EDGE_RISING;
810edffca28Spatrick 	else
811edffca28Spatrick 		type = IST_LEVEL_HIGH;
812edffca28Spatrick 
813789e88a4Spatrick 	return ampintc_intr_establish(irq, type, level, ci, func, arg, name);
814f24071e5Spatrick }
815f24071e5Spatrick 
816f24071e5Spatrick void *
ampintc_intr_establish(int irqno,int type,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)817789e88a4Spatrick ampintc_intr_establish(int irqno, int type, int level, struct cpu_info *ci,
818789e88a4Spatrick     int (*func)(void *), void *arg, char *name)
819f24071e5Spatrick {
820f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
821f24071e5Spatrick 	struct intrhand		*ih;
822daf2e6ccSkettenis 	u_long			 psw;
823f24071e5Spatrick 
824f24071e5Spatrick 	if (irqno < 0 || irqno >= sc->sc_nintr)
825f24071e5Spatrick 		panic("ampintc_intr_establish: bogus irqnumber %d: %s",
826f24071e5Spatrick 		     irqno, name);
827f24071e5Spatrick 
828789e88a4Spatrick 	if (ci == NULL)
829789e88a4Spatrick 		ci = &cpu_info_primary;
830789e88a4Spatrick 
831d7e3db9cSkettenis 	if (irqno < 16) {
832d7e3db9cSkettenis 		/* SGI are only EDGE */
833d7e3db9cSkettenis 		type = IST_EDGE_RISING;
834d7e3db9cSkettenis 	} else if (irqno < 32) {
835d7e3db9cSkettenis 		/* PPI are only LEVEL */
836d7e3db9cSkettenis 		type = IST_LEVEL_HIGH;
837d7e3db9cSkettenis 	}
838d7e3db9cSkettenis 
839f24071e5Spatrick 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
840f24071e5Spatrick 	ih->ih_func = func;
841f24071e5Spatrick 	ih->ih_arg = arg;
842d7e3db9cSkettenis 	ih->ih_ipl = level & IPL_IRQMASK;
843d7e3db9cSkettenis 	ih->ih_flags = level & IPL_FLAGMASK;
844f24071e5Spatrick 	ih->ih_irq = irqno;
845f24071e5Spatrick 	ih->ih_name = name;
846452daaedSpatrick 	ih->ih_ci = ci;
847f24071e5Spatrick 
848daf2e6ccSkettenis 	psw = intr_disable();
849f24071e5Spatrick 
850de70244eSpatrick 	if (!TAILQ_EMPTY(&sc->sc_handler[irqno].iq_list) &&
851de70244eSpatrick 	    sc->sc_handler[irqno].iq_ci != ci) {
852de70244eSpatrick 		free(ih, M_DEVBUF, sizeof(*ih));
853daf2e6ccSkettenis 		intr_restore(psw);
854de70244eSpatrick 		return NULL;
855de70244eSpatrick 	}
856de70244eSpatrick 
857d7e3db9cSkettenis 	TAILQ_INSERT_TAIL(&sc->sc_handler[irqno].iq_list, ih, ih_list);
858de70244eSpatrick 	sc->sc_handler[irqno].iq_ci = ci;
859f24071e5Spatrick 
860f24071e5Spatrick 	if (name != NULL)
861f24071e5Spatrick 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
862f24071e5Spatrick 
863f24071e5Spatrick #ifdef DEBUG_INTC
864f24071e5Spatrick 	printf("ampintc_intr_establish irq %d level %d [%s]\n", irqno, level,
865f24071e5Spatrick 	    name);
866f24071e5Spatrick #endif
867edffca28Spatrick 
868edffca28Spatrick 	ampintc_intr_config(irqno, type);
869f24071e5Spatrick 	ampintc_calc_mask();
870f24071e5Spatrick 
871daf2e6ccSkettenis 	intr_restore(psw);
872f24071e5Spatrick 	return (ih);
873f24071e5Spatrick }
874f24071e5Spatrick 
875f24071e5Spatrick void
ampintc_intr_disestablish(void * cookie)876f24071e5Spatrick ampintc_intr_disestablish(void *cookie)
877f24071e5Spatrick {
878f24071e5Spatrick 	struct ampintc_softc	*sc = ampintc;
879f24071e5Spatrick 	struct intrhand		*ih = cookie;
880daf2e6ccSkettenis 	u_long			 psw;
881f24071e5Spatrick 
882f24071e5Spatrick #ifdef DEBUG_INTC
883f24071e5Spatrick 	printf("ampintc_intr_disestablish irq %d level %d [%s]\n",
884f24071e5Spatrick 	    ih->ih_irq, ih->ih_ipl, ih->ih_name);
885f24071e5Spatrick #endif
886f24071e5Spatrick 
887daf2e6ccSkettenis 	psw = intr_disable();
888f24071e5Spatrick 
889d7e3db9cSkettenis 	TAILQ_REMOVE(&sc->sc_handler[ih->ih_irq].iq_list, ih, ih_list);
890f24071e5Spatrick 	if (ih->ih_name != NULL)
891f24071e5Spatrick 		evcount_detach(&ih->ih_count);
892f24071e5Spatrick 
893f24071e5Spatrick 	ampintc_calc_mask();
894f24071e5Spatrick 
895daf2e6ccSkettenis 	intr_restore(psw);
896daf2e6ccSkettenis 
897daf2e6ccSkettenis 	free(ih, M_DEVBUF, sizeof(*ih));
898f24071e5Spatrick }
899f24071e5Spatrick 
900f24071e5Spatrick const char *
ampintc_intr_string(void * cookie)901f24071e5Spatrick ampintc_intr_string(void *cookie)
902f24071e5Spatrick {
903f24071e5Spatrick 	struct intrhand *ih = (struct intrhand *)cookie;
904f24071e5Spatrick 	static char irqstr[1 + sizeof("ampintc irq ") + 4];
905f24071e5Spatrick 
906f24071e5Spatrick 	snprintf(irqstr, sizeof irqstr, "ampintc irq %d", ih->ih_irq);
907f24071e5Spatrick 	return irqstr;
908f24071e5Spatrick }
909c17c7ba4Spatrick 
910c17c7ba4Spatrick /*
911c17c7ba4Spatrick  * GICv2m frame controller for MSI interrupts.
912c17c7ba4Spatrick  */
913c17c7ba4Spatrick #define GICV2M_TYPER		0x008
914c17c7ba4Spatrick #define  GICV2M_TYPER_SPI_BASE(x)	(((x) >> 16) & 0x3ff)
915c17c7ba4Spatrick #define  GICV2M_TYPER_SPI_COUNT(x)	(((x) >> 0) & 0x3ff)
916c17c7ba4Spatrick #define GICV2M_SETSPI_NS	0x040
917c17c7ba4Spatrick 
918c17c7ba4Spatrick int	 ampintc_msi_match(struct device *, void *, void *);
919c17c7ba4Spatrick void	 ampintc_msi_attach(struct device *, struct device *, void *);
920c17c7ba4Spatrick void	*ampintc_intr_establish_msi(void *, uint64_t *, uint64_t *,
921789e88a4Spatrick 	    int , struct cpu_info *, int (*)(void *), void *, char *);
922c17c7ba4Spatrick void	 ampintc_intr_disestablish_msi(void *);
923452daaedSpatrick void	 ampintc_intr_barrier_msi(void *);
924c17c7ba4Spatrick 
925c17c7ba4Spatrick struct ampintc_msi_softc {
926c17c7ba4Spatrick 	struct device			 sc_dev;
927c17c7ba4Spatrick 	bus_space_tag_t			 sc_iot;
928c17c7ba4Spatrick 	bus_space_handle_t		 sc_ioh;
929c50a818aSpatrick 	int				 sc_node;
930c17c7ba4Spatrick 	paddr_t				 sc_addr;
931c17c7ba4Spatrick 	int				 sc_bspi;
932c17c7ba4Spatrick 	int				 sc_nspi;
933c17c7ba4Spatrick 	void				**sc_spi;
934c17c7ba4Spatrick 	struct interrupt_controller	 sc_ic;
935c17c7ba4Spatrick };
936c17c7ba4Spatrick 
9379fdf0c62Smpi const struct cfattach	ampintcmsi_ca = {
938c17c7ba4Spatrick 	sizeof (struct ampintc_msi_softc), ampintc_msi_match, ampintc_msi_attach
939c17c7ba4Spatrick };
940c17c7ba4Spatrick 
941c17c7ba4Spatrick struct cfdriver ampintcmsi_cd = {
942c17c7ba4Spatrick 	NULL, "ampintcmsi", DV_DULL
943c17c7ba4Spatrick };
944c17c7ba4Spatrick 
945c17c7ba4Spatrick int
ampintc_msi_match(struct device * parent,void * cfdata,void * aux)946c17c7ba4Spatrick ampintc_msi_match(struct device *parent, void *cfdata, void *aux)
947c17c7ba4Spatrick {
948c17c7ba4Spatrick 	struct fdt_attach_args *faa = aux;
949c17c7ba4Spatrick 
950c17c7ba4Spatrick 	return OF_is_compatible(faa->fa_node, "arm,gic-v2m-frame");
951c17c7ba4Spatrick }
952c17c7ba4Spatrick 
953c17c7ba4Spatrick void
ampintc_msi_attach(struct device * parent,struct device * self,void * aux)954c17c7ba4Spatrick ampintc_msi_attach(struct device *parent, struct device *self, void *aux)
955c17c7ba4Spatrick {
956c17c7ba4Spatrick 	struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
957c17c7ba4Spatrick 	struct fdt_attach_args *faa = aux;
958c17c7ba4Spatrick 	uint32_t typer;
959c17c7ba4Spatrick 
960c50a818aSpatrick 	sc->sc_node = faa->fa_node;
961c17c7ba4Spatrick 	sc->sc_iot = faa->fa_iot;
962c17c7ba4Spatrick 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
963c17c7ba4Spatrick 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
964c17c7ba4Spatrick 		panic("%s: bus_space_map failed!", __func__);
965c17c7ba4Spatrick 
966c17c7ba4Spatrick 	/* XXX: Hack to retrieve the physical address (from a CPU PoV). */
967c17c7ba4Spatrick 	if (!pmap_extract(pmap_kernel(), sc->sc_ioh, &sc->sc_addr)) {
968c17c7ba4Spatrick 		printf(": cannot retrieve msi addr\n");
969c17c7ba4Spatrick 		return;
970c17c7ba4Spatrick 	}
971c17c7ba4Spatrick 
972c17c7ba4Spatrick 	typer = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GICV2M_TYPER);
973c17c7ba4Spatrick 	sc->sc_bspi = GICV2M_TYPER_SPI_BASE(typer);
974c17c7ba4Spatrick 	sc->sc_nspi = GICV2M_TYPER_SPI_COUNT(typer);
975c17c7ba4Spatrick 
976c17c7ba4Spatrick 	sc->sc_bspi = OF_getpropint(faa->fa_node,
977c17c7ba4Spatrick 	    "arm,msi-base-spi", sc->sc_bspi);
978c17c7ba4Spatrick 	sc->sc_nspi = OF_getpropint(faa->fa_node,
979c17c7ba4Spatrick 	    "arm,msi-num-spis", sc->sc_nspi);
980c17c7ba4Spatrick 
981c17c7ba4Spatrick 	printf(": nspi %d\n", sc->sc_nspi);
982c17c7ba4Spatrick 
98375baf936Skettenis 	sc->sc_spi = mallocarray(sc->sc_nspi, sizeof(void *), M_DEVBUF,
984c17c7ba4Spatrick 	    M_WAITOK|M_ZERO);
985c17c7ba4Spatrick 
986c17c7ba4Spatrick 	sc->sc_ic.ic_node = faa->fa_node;
987c17c7ba4Spatrick 	sc->sc_ic.ic_cookie = sc;
988c17c7ba4Spatrick 	sc->sc_ic.ic_establish_msi = ampintc_intr_establish_msi;
989c17c7ba4Spatrick 	sc->sc_ic.ic_disestablish = ampintc_intr_disestablish_msi;
990452daaedSpatrick 	sc->sc_ic.ic_barrier = ampintc_intr_barrier_msi;
991c17c7ba4Spatrick 	arm_intr_register_fdt(&sc->sc_ic);
992c17c7ba4Spatrick }
993c17c7ba4Spatrick 
994c17c7ba4Spatrick void *
ampintc_intr_establish_msi(void * self,uint64_t * addr,uint64_t * data,int level,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)995c17c7ba4Spatrick ampintc_intr_establish_msi(void *self, uint64_t *addr, uint64_t *data,
996789e88a4Spatrick     int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
997c17c7ba4Spatrick {
998c17c7ba4Spatrick 	struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
999c50a818aSpatrick 	extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
1000c50a818aSpatrick 	struct interrupt_controller *ic;
1001c50a818aSpatrick 	struct machine_intr_handle *ih;
1002c17c7ba4Spatrick 	void *cookie;
1003c50a818aSpatrick 	int cells[3];
1004c17c7ba4Spatrick 	int i;
1005c17c7ba4Spatrick 
1006c50a818aSpatrick 	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
1007c50a818aSpatrick 		if (ic->ic_node == OF_parent(sc->sc_node))
1008c50a818aSpatrick 			break;
1009c50a818aSpatrick 	}
1010c50a818aSpatrick 	if (ic == NULL)
1011c50a818aSpatrick 		return NULL;
1012c50a818aSpatrick 
1013c50a818aSpatrick 	cells[0] = 0; /* SPI */
1014c50a818aSpatrick 	cells[2] = 1; /* Edge-Rising */
1015c50a818aSpatrick 
1016c17c7ba4Spatrick 	for (i = 0; i < sc->sc_nspi; i++) {
1017c17c7ba4Spatrick 		if (sc->sc_spi[i] != NULL)
1018c17c7ba4Spatrick 			continue;
1019c17c7ba4Spatrick 
1020c50a818aSpatrick 		cells[1] = sc->sc_bspi + i - 32;
1021c50a818aSpatrick 		cookie = ic->ic_establish(ic->ic_cookie, cells,
1022c50a818aSpatrick 		    level, ci, func, arg, name);
1023c17c7ba4Spatrick 		if (cookie == NULL)
1024c17c7ba4Spatrick 			return NULL;
1025c17c7ba4Spatrick 
1026c50a818aSpatrick 		ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
1027c50a818aSpatrick 		ih->ih_ic = ic;
1028c50a818aSpatrick 		ih->ih_ih = cookie;
1029c50a818aSpatrick 
1030c17c7ba4Spatrick 		*addr = sc->sc_addr + GICV2M_SETSPI_NS;
1031895dad33Skettenis 		*data = sc->sc_bspi + i;
1032c50a818aSpatrick 		sc->sc_spi[i] = ih;
1033c17c7ba4Spatrick 		return &sc->sc_spi[i];
1034c17c7ba4Spatrick 	}
1035c17c7ba4Spatrick 
1036c17c7ba4Spatrick 	return NULL;
1037c17c7ba4Spatrick }
1038c17c7ba4Spatrick 
1039c17c7ba4Spatrick void
ampintc_intr_disestablish_msi(void * cookie)1040c17c7ba4Spatrick ampintc_intr_disestablish_msi(void *cookie)
1041c17c7ba4Spatrick {
1042c50a818aSpatrick 	fdt_intr_disestablish(*(void **)cookie);
1043c17c7ba4Spatrick 	*(void **)cookie = NULL;
1044c17c7ba4Spatrick }
1045d7e3db9cSkettenis 
1046452daaedSpatrick void
ampintc_intr_barrier_msi(void * cookie)1047452daaedSpatrick ampintc_intr_barrier_msi(void *cookie)
1048452daaedSpatrick {
1049beae6a4fSpatrick 	intr_barrier(*(void **)cookie);
1050452daaedSpatrick }
1051452daaedSpatrick 
1052d7e3db9cSkettenis #ifdef MULTIPROCESSOR
1053d7e3db9cSkettenis int
ampintc_ipi_ddb(void * v)1054d7e3db9cSkettenis ampintc_ipi_ddb(void *v)
1055d7e3db9cSkettenis {
1056d7e3db9cSkettenis 	/* XXX */
1057a9a6a9f2Sderaadt #ifdef DDB
1058d7e3db9cSkettenis 	db_enter();
1059a9a6a9f2Sderaadt #endif
1060d7e3db9cSkettenis 	return 1;
1061d7e3db9cSkettenis }
1062d7e3db9cSkettenis 
1063d7e3db9cSkettenis int
ampintc_ipi_halt(void * v)10644002e08dSkettenis ampintc_ipi_halt(void *v)
10654002e08dSkettenis {
10664002e08dSkettenis 	cpu_halt();
10674002e08dSkettenis 	return 1;
10684002e08dSkettenis }
10694002e08dSkettenis 
10704002e08dSkettenis int
ampintc_ipi_nop(void * v)1071d7e3db9cSkettenis ampintc_ipi_nop(void *v)
1072d7e3db9cSkettenis {
1073d7e3db9cSkettenis 	/* Nothing to do here, just enough to wake up from WFI */
1074d7e3db9cSkettenis 	return 1;
1075d7e3db9cSkettenis }
1076d7e3db9cSkettenis 
1077d7e3db9cSkettenis int
ampintc_ipi_combined(void * v)1078d7e3db9cSkettenis ampintc_ipi_combined(void *v)
1079d7e3db9cSkettenis {
1080d7e3db9cSkettenis 	struct ampintc_softc *sc = (struct ampintc_softc *)v;
1081d7e3db9cSkettenis 
1082d7e3db9cSkettenis 	if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) {
1083d7e3db9cSkettenis 		sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
1084d7e3db9cSkettenis 		return ampintc_ipi_ddb(v);
10854002e08dSkettenis 	} else if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_HALT) {
10864002e08dSkettenis 		sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
10874002e08dSkettenis 		return ampintc_ipi_halt(v);
1088d7e3db9cSkettenis 	} else {
1089d7e3db9cSkettenis 		return ampintc_ipi_nop(v);
1090d7e3db9cSkettenis 	}
1091d7e3db9cSkettenis }
1092d7e3db9cSkettenis 
1093d7e3db9cSkettenis void
ampintc_send_ipi(struct cpu_info * ci,int id)1094d7e3db9cSkettenis ampintc_send_ipi(struct cpu_info *ci, int id)
1095d7e3db9cSkettenis {
1096d7e3db9cSkettenis 	struct ampintc_softc	*sc = ampintc;
1097d7e3db9cSkettenis 	int sendmask;
1098d7e3db9cSkettenis 
1099d7e3db9cSkettenis 	if (ci == curcpu() && id == ARM_IPI_NOP)
1100d7e3db9cSkettenis 		return;
1101d7e3db9cSkettenis 
11024002e08dSkettenis 	/* never overwrite IPI_DDB or IPI_HALT with IPI_NOP */
11034002e08dSkettenis 	if (id == ARM_IPI_DDB || id == ARM_IPI_HALT)
1104d7e3db9cSkettenis 		sc->sc_ipi_reason[ci->ci_cpuid] = id;
1105d7e3db9cSkettenis 
1106d7e3db9cSkettenis 	/* currently will only send to one cpu */
1107cb3eb802Skettenis 	sendmask = sc->sc_cpu_mask[ci->ci_cpuid] << 16;
1108d7e3db9cSkettenis 	sendmask |= sc->sc_ipi_num[id];
1109d7e3db9cSkettenis 
1110d7e3db9cSkettenis 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_SGIR, sendmask);
1111d7e3db9cSkettenis }
1112d7e3db9cSkettenis #endif
1113