xref: /openbsd/sys/arch/arm64/dev/ampintc.c (revision 5dea098c)
1 /* $OpenBSD: ampintc.c,v 1.31 2023/09/22 01:10:43 jsg Exp $ */
2 /*
3  * Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /*
19  * This driver implements the interrupt controller as specified in
20  * DDI0407E_cortex_a9_mpcore_r2p0_trm with the
21  * IHI0048A_gic_architecture_spec_v1_0 underlying specification
22  */
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/queue.h>
26 #include <sys/malloc.h>
27 #include <sys/device.h>
28 #include <sys/evcount.h>
29 
30 #include <uvm/uvm_extern.h>
31 
32 #include <machine/bus.h>
33 #include <machine/fdt.h>
34 
35 #include <dev/ofw/fdt.h>
36 #include <dev/ofw/openfirm.h>
37 
38 #include <machine/simplebusvar.h>
39 
40 /* registers */
41 #define	ICD_DCR			0x000
42 #define		ICD_DCR_ES		0x00000001
43 #define		ICD_DCR_ENS		0x00000002
44 
45 #define ICD_ICTR			0x004
46 #define		ICD_ICTR_LSPI_SH	11
47 #define		ICD_ICTR_LSPI_M		0x1f
48 #define		ICD_ICTR_CPU_SH		5
49 #define		ICD_ICTR_CPU_M		0x07
50 #define		ICD_ICTR_ITL_SH		0
51 #define		ICD_ICTR_ITL_M		0x1f
52 #define ICD_IDIR			0x008
53 #define 	ICD_DIR_PROD_SH		24
54 #define 	ICD_DIR_PROD_M		0xff
55 #define 	ICD_DIR_REV_SH		12
56 #define 	ICD_DIR_REV_M		0xfff
57 #define 	ICD_DIR_IMP_SH		0
58 #define 	ICD_DIR_IMP_M		0xfff
59 
60 #define IRQ_TO_REG32(i)		(((i) >> 5) & 0x1f)
61 #define IRQ_TO_REG32BIT(i)	((i) & 0x1f)
62 #define IRQ_TO_REG4(i)		(((i) >> 2) & 0xff)
63 #define IRQ_TO_REG4BIT(i)	((i) & 0x3)
64 #define IRQ_TO_REG16(i)		(((i) >> 4) & 0x3f)
65 #define IRQ_TO_REG16BIT(i)	((i) & 0xf)
66 #define IRQ_TO_REGBIT_S(i)	8
67 #define IRQ_TO_REG4BIT_M(i)	8
68 
69 #define ICD_ISRn(i)		(0x080 + (IRQ_TO_REG32(i) * 4))
70 #define ICD_ISERn(i)		(0x100 + (IRQ_TO_REG32(i) * 4))
71 #define ICD_ICERn(i)		(0x180 + (IRQ_TO_REG32(i) * 4))
72 #define ICD_ISPRn(i)		(0x200 + (IRQ_TO_REG32(i) * 4))
73 #define ICD_ICPRn(i)		(0x280 + (IRQ_TO_REG32(i) * 4))
74 #define ICD_ABRn(i)		(0x300 + (IRQ_TO_REG32(i) * 4))
75 #define ICD_IPRn(i)		(0x400 + (i))
76 #define ICD_IPTRn(i)		(0x800 + (i))
77 #define ICD_ICRn(i)		(0xC00 + (IRQ_TO_REG16(i) * 4))
78 #define 	ICD_ICR_TRIG_LEVEL(i)	(0x0 << (IRQ_TO_REG16BIT(i) * 2))
79 #define 	ICD_ICR_TRIG_EDGE(i)	(0x2 << (IRQ_TO_REG16BIT(i) * 2))
80 #define 	ICD_ICR_TRIG_MASK(i)	(0x2 << (IRQ_TO_REG16BIT(i) * 2))
81 
82 /*
83  * what about (ppi|spi)_status
84  */
85 #define ICD_PPI			0xD00
86 #define 	ICD_PPI_GTIMER	(1 << 11)
87 #define 	ICD_PPI_FIQ		(1 << 12)
88 #define 	ICD_PPI_PTIMER	(1 << 13)
89 #define 	ICD_PPI_PWDOG	(1 << 14)
90 #define 	ICD_PPI_IRQ		(1 << 15)
91 #define ICD_SPI_BASE		0xD04
92 #define ICD_SPIn(i)			(ICD_SPI_BASE + ((i) * 4))
93 
94 
95 #define ICD_SGIR			0xF00
96 
97 #define ICD_PERIPH_ID_0			0xFD0
98 #define ICD_PERIPH_ID_1			0xFD4
99 #define ICD_PERIPH_ID_2			0xFD8
100 #define ICD_PERIPH_ID_3			0xFDC
101 #define ICD_PERIPH_ID_4			0xFE0
102 #define ICD_PERIPH_ID_5			0xFE4
103 #define ICD_PERIPH_ID_6			0xFE8
104 #define ICD_PERIPH_ID_7			0xFEC
105 
106 #define ICD_COMP_ID_0			0xFEC
107 #define ICD_COMP_ID_1			0xFEC
108 #define ICD_COMP_ID_2			0xFEC
109 #define ICD_COMP_ID_3			0xFEC
110 
111 
112 #define ICPICR				0x00
113 #define ICPIPMR				0x04
114 /* XXX - must left justify bits to  0 - 7  */
115 #define 	ICMIPMR_SH 		4
116 #define ICPBPR				0x08
117 #define ICPIAR				0x0C
118 #define 	ICPIAR_IRQ_SH		0
119 #define 	ICPIAR_IRQ_M		0x3ff
120 #define 	ICPIAR_CPUID_SH		10
121 #define 	ICPIAR_CPUID_M		0x7
122 #define 	ICPIAR_NO_PENDING_IRQ	ICPIAR_IRQ_M
123 #define ICPEOIR				0x10
124 #define ICPPRP				0x14
125 #define ICPHPIR				0x18
126 #define ICPIIR				0xFC
127 
128 /*
129  * what about periph_id and component_id
130  */
131 
132 #define IRQ_ENABLE	1
133 #define IRQ_DISABLE	0
134 
135 struct ampintc_softc {
136 	struct simplebus_softc	 sc_sbus;
137 	struct intrq 		*sc_handler;
138 	int			 sc_nintr;
139 	bus_space_tag_t		 sc_iot;
140 	bus_space_handle_t	 sc_d_ioh, sc_p_ioh;
141 	uint8_t			 sc_cpu_mask[ICD_ICTR_CPU_M + 1];
142 	struct evcount		 sc_spur;
143 	struct interrupt_controller sc_ic;
144 	int			 sc_ipi_reason[ICD_ICTR_CPU_M + 1];
145 	int			 sc_ipi_num[3];
146 };
147 struct ampintc_softc *ampintc;
148 
149 
150 struct intrhand {
151 	TAILQ_ENTRY(intrhand) ih_list;	/* link on intrq list */
152 	int (*ih_func)(void *);		/* handler */
153 	void *ih_arg;			/* arg for handler */
154 	int ih_ipl;			/* IPL_* */
155 	int ih_flags;
156 	int ih_irq;			/* IRQ number */
157 	struct evcount	ih_count;
158 	char *ih_name;
159 	struct cpu_info *ih_ci;		/* CPU the IRQ runs on */
160 };
161 
162 struct intrq {
163 	TAILQ_HEAD(, intrhand) iq_list;	/* handler list */
164 	struct cpu_info *iq_ci;		/* CPU the IRQ runs on */
165 	int iq_irq_max;			/* IRQ to mask while handling */
166 	int iq_irq_min;			/* lowest IRQ when shared */
167 	int iq_ist;			/* share type */
168 };
169 
170 
171 int		 ampintc_match(struct device *, void *, void *);
172 void		 ampintc_attach(struct device *, struct device *, void *);
173 int		 ampintc_activate(struct device *, int);
174 void		 ampintc_init(struct ampintc_softc *);
175 void		 ampintc_cpuinit(void);
176 int		 ampintc_spllower(int);
177 void		 ampintc_splx(int);
178 int		 ampintc_splraise(int);
179 void		 ampintc_setipl(int);
180 void		 ampintc_calc_mask(void);
181 void		 ampintc_calc_irq(struct ampintc_softc *, int);
182 void		*ampintc_intr_establish(int, int, int, struct cpu_info *,
183 		    int (*)(void *), void *, char *);
184 void		*ampintc_intr_establish_fdt(void *, int *, int,
185 		    struct cpu_info *, int (*)(void *), void *, char *);
186 void		 ampintc_intr_disestablish(void *);
187 void		 ampintc_irq_handler(void *);
188 const char	*ampintc_intr_string(void *);
189 uint32_t	 ampintc_iack(void);
190 void		 ampintc_eoi(uint32_t);
191 void		 ampintc_set_priority(int, int);
192 void		 ampintc_intr_enable(int);
193 void		 ampintc_intr_disable(int);
194 void		 ampintc_intr_config(int, int);
195 void		 ampintc_route(int, int, struct cpu_info *);
196 void		 ampintc_route_irq(void *, int, struct cpu_info *);
197 void		 ampintc_intr_barrier(void *);
198 
199 int		 ampintc_ipi_combined(void *);
200 int		 ampintc_ipi_nop(void *);
201 int		 ampintc_ipi_ddb(void *);
202 int		 ampintc_ipi_halt(void *);
203 void		 ampintc_send_ipi(struct cpu_info *, int);
204 
205 const struct cfattach	ampintc_ca = {
206 	sizeof (struct ampintc_softc), ampintc_match, ampintc_attach,
207 	NULL, ampintc_activate
208 };
209 
210 struct cfdriver ampintc_cd = {
211 	NULL, "ampintc", DV_DULL
212 };
213 
214 static char *ampintc_compatibles[] = {
215 	"arm,cortex-a7-gic",
216 	"arm,cortex-a9-gic",
217 	"arm,cortex-a15-gic",
218 	"arm,gic-400",
219 	NULL
220 };
221 
222 int
223 ampintc_match(struct device *parent, void *cfdata, void *aux)
224 {
225 	struct fdt_attach_args *faa = aux;
226 	int i;
227 
228 	for (i = 0; ampintc_compatibles[i]; i++)
229 		if (OF_is_compatible(faa->fa_node, ampintc_compatibles[i]))
230 			return (1);
231 
232 	return (0);
233 }
234 
235 void
236 ampintc_attach(struct device *parent, struct device *self, void *aux)
237 {
238 	struct ampintc_softc *sc = (struct ampintc_softc *)self;
239 	struct fdt_attach_args *faa = aux;
240 	int i, nintr, ncpu;
241 	uint32_t ictr;
242 #ifdef MULTIPROCESSOR
243 	int nipi, ipiirq[3];
244 #endif
245 
246 	ampintc = sc;
247 
248 	arm_init_smask();
249 
250 	sc->sc_iot = faa->fa_iot;
251 
252 	/* First row: ICD */
253 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
254 	    faa->fa_reg[0].size, 0, &sc->sc_d_ioh))
255 		panic("%s: ICD bus_space_map failed!", __func__);
256 
257 	/* Second row: ICP */
258 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
259 	    faa->fa_reg[1].size, 0, &sc->sc_p_ioh))
260 		panic("%s: ICP bus_space_map failed!", __func__);
261 
262 	evcount_attach(&sc->sc_spur, "irq1023/spur", NULL);
263 
264 	ictr = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICTR);
265 	nintr = 32 * ((ictr >> ICD_ICTR_ITL_SH) & ICD_ICTR_ITL_M);
266 	nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */
267 	sc->sc_nintr = nintr;
268 	ncpu = ((ictr >> ICD_ICTR_CPU_SH) & ICD_ICTR_CPU_M) + 1;
269 	printf(" nirq %d, ncpu %d", nintr, ncpu);
270 
271 	KASSERT(curcpu()->ci_cpuid <= ICD_ICTR_CPU_M);
272 	sc->sc_cpu_mask[curcpu()->ci_cpuid] =
273 	    bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(0));
274 
275 	ampintc_init(sc);
276 
277 	/* software reset of the part? */
278 	/* set protection bit (kernel only)? */
279 
280 	/* XXX - check power saving bit */
281 
282 	sc->sc_handler = mallocarray(nintr, sizeof(*sc->sc_handler), M_DEVBUF,
283 	    M_ZERO | M_NOWAIT);
284 	for (i = 0; i < nintr; i++) {
285 		TAILQ_INIT(&sc->sc_handler[i].iq_list);
286 	}
287 
288 	ampintc_setipl(IPL_HIGH);  /* XXX ??? */
289 	ampintc_calc_mask();
290 
291 	/* insert self as interrupt handler */
292 	arm_set_intr_handler(ampintc_splraise, ampintc_spllower, ampintc_splx,
293 	    ampintc_setipl, ampintc_irq_handler, NULL, NULL, NULL);
294 
295 #ifdef MULTIPROCESSOR
296 	/* setup IPI interrupts */
297 
298 	/*
299 	 * Ideally we want three IPI interrupts, one for NOP, one for
300 	 * DDB and one for HALT.  However we can survive if only one
301 	 * is available; it is possible that most are not available to
302 	 * the non-secure OS.
303 	 */
304 	nipi = 0;
305 	for (i = 0; i < 16; i++) {
306 		int reg, oldreg;
307 
308 		oldreg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh,
309 		    ICD_IPRn(i));
310 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i),
311 		    oldreg ^ 0x20);
312 
313 		/* if this interrupt is not usable, route will be zero */
314 		reg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i));
315 		if (reg == oldreg)
316 			continue;
317 
318 		/* return to original value, will be set when used */
319 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i),
320 		    oldreg);
321 
322 		if (nipi == 0)
323 			printf(" ipi: %d", i);
324 		else
325 			printf(", %d", i);
326 		ipiirq[nipi++] = i;
327 		if (nipi == 3)
328 			break;
329 	}
330 
331 	if (nipi == 0)
332 		panic ("no irq available for IPI");
333 
334 	switch (nipi) {
335 	case 1:
336 		ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
337 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_combined, sc, "ipi");
338 		sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
339 		sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0];
340 		sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[0];
341 		break;
342 	case 2:
343 		ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
344 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_nop, sc, "ipinop");
345 		sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
346 		ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING,
347 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_combined, sc, "ipi");
348 		sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
349 		sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[1];
350 		break;
351 	case 3:
352 		ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING,
353 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_nop, sc, "ipinop");
354 		sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0];
355 		ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING,
356 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_ddb, sc, "ipiddb");
357 		sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1];
358 		ampintc_intr_establish(ipiirq[2], IST_EDGE_RISING,
359 		    IPL_IPI|IPL_MPSAFE, NULL, ampintc_ipi_halt, sc, "ipihalt");
360 		sc->sc_ipi_num[ARM_IPI_HALT] = ipiirq[2];
361 		break;
362 	default:
363 		panic("nipi unexpected number %d", nipi);
364 	}
365 
366 	intr_send_ipi_func = ampintc_send_ipi;
367 #endif
368 
369 	/* enable interrupts */
370 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
371 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
372 	intr_enable();
373 
374 	sc->sc_ic.ic_node = faa->fa_node;
375 	sc->sc_ic.ic_cookie = self;
376 	sc->sc_ic.ic_establish = ampintc_intr_establish_fdt;
377 	sc->sc_ic.ic_disestablish = ampintc_intr_disestablish;
378 	sc->sc_ic.ic_route = ampintc_route_irq;
379 	sc->sc_ic.ic_cpu_enable = ampintc_cpuinit;
380 	sc->sc_ic.ic_barrier = ampintc_intr_barrier;
381 	arm_intr_register_fdt(&sc->sc_ic);
382 
383 	/* attach GICv2M frame controller */
384 	simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
385 }
386 
387 int
388 ampintc_activate(struct device *self, int act)
389 {
390 	struct ampintc_softc *sc = (struct ampintc_softc *)self;
391 	struct cpu_info *ci;
392 	int irq, min;
393 
394 	switch (act) {
395 	case DVACT_RESUME:
396 		for (irq = 0; irq < sc->sc_nintr; irq++) {
397 			ci = sc->sc_handler[irq].iq_ci;
398 			min = sc->sc_handler[irq].iq_irq_min;
399 			if (min != IPL_NONE) {
400 				ampintc_set_priority(irq, min);
401 				ampintc_intr_enable(irq);
402 				ampintc_route(irq, IRQ_ENABLE, ci);
403 			} else {
404 				ampintc_intr_disable(irq);
405 			}
406 		}
407 
408 		/* enable interrupts */
409 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3);
410 		bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
411 		break;
412 	}
413 
414 	return 0;
415 }
416 
417 void
418 ampintc_init(struct ampintc_softc *sc)
419 {
420 	int i;
421 
422 	/* Disable all interrupts, clear all pending */
423 	for (i = 0; i < sc->sc_nintr / 32; i++) {
424 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
425 		    ICD_ICERn(i * 32), ~0);
426 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
427 		    ICD_ICPRn(i * 32), ~0);
428 	}
429 	for (i = 0; i < sc->sc_nintr; i++) {
430 		/* lowest priority ?? */
431 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 0xff);
432 		/* target no cpus */
433 		bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(i), 0);
434 	}
435 	for (i = 2; i < sc->sc_nintr / 16; i++) {
436 		/* irq 32 - N */
437 		bus_space_write_4(sc->sc_iot, sc->sc_d_ioh,
438 		    ICD_ICRn(i * 16), 0);
439 	}
440 }
441 
442 void
443 ampintc_set_priority(int irq, int pri)
444 {
445 	struct ampintc_softc	*sc = ampintc;
446 	uint32_t		 prival;
447 
448 	/*
449 	 * We only use 16 (13 really) interrupt priorities,
450 	 * and a CPU is only required to implement bit 4-7 of each field
451 	 * so shift into the top bits.
452 	 * also low values are higher priority thus IPL_HIGH - pri
453 	 */
454 	prival = (IPL_HIGH - pri) << ICMIPMR_SH;
455 	bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(irq), prival);
456 }
457 
458 void
459 ampintc_setipl(int new)
460 {
461 	struct cpu_info		*ci = curcpu();
462 	struct ampintc_softc	*sc = ampintc;
463 	u_long			 psw;
464 
465 	/* disable here is only to keep hardware in sync with ci->ci_cpl */
466 	psw = intr_disable();
467 	ci->ci_cpl = new;
468 
469 	/* low values are higher priority thus IPL_HIGH - pri */
470 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPIPMR,
471 	    (IPL_HIGH - new) << ICMIPMR_SH);
472 	intr_restore(psw);
473 }
474 
475 void
476 ampintc_intr_enable(int irq)
477 {
478 	struct ampintc_softc	*sc = ampintc;
479 
480 #ifdef DEBUG
481 	printf("enable irq %d register %x bitmask %08x\n",
482 	    irq, ICD_ISERn(irq), 1 << IRQ_TO_REG32BIT(irq));
483 #endif
484 
485 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ISERn(irq),
486 	    1 << IRQ_TO_REG32BIT(irq));
487 }
488 
489 void
490 ampintc_intr_disable(int irq)
491 {
492 	struct ampintc_softc	*sc = ampintc;
493 
494 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICERn(irq),
495 	    1 << IRQ_TO_REG32BIT(irq));
496 }
497 
498 void
499 ampintc_intr_config(int irqno, int type)
500 {
501 	struct ampintc_softc	*sc = ampintc;
502 	uint32_t		 ctrl;
503 
504 	ctrl = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(irqno));
505 
506 	ctrl &= ~ICD_ICR_TRIG_MASK(irqno);
507 	if (type == IST_EDGE_RISING)
508 		ctrl |= ICD_ICR_TRIG_EDGE(irqno);
509 	else
510 		ctrl |= ICD_ICR_TRIG_LEVEL(irqno);
511 
512 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(irqno), ctrl);
513 }
514 
515 void
516 ampintc_calc_mask(void)
517 {
518 	struct ampintc_softc	*sc = ampintc;
519 	int			 irq;
520 
521 	for (irq = 0; irq < sc->sc_nintr; irq++)
522 		ampintc_calc_irq(sc, irq);
523 }
524 
525 void
526 ampintc_calc_irq(struct ampintc_softc *sc, int irq)
527 {
528 	struct cpu_info		*ci = sc->sc_handler[irq].iq_ci;
529 	struct intrhand		*ih;
530 	int			max = IPL_NONE;
531 	int			min = IPL_HIGH;
532 
533 	TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
534 		if (ih->ih_ipl > max)
535 			max = ih->ih_ipl;
536 
537 		if (ih->ih_ipl < min)
538 			min = ih->ih_ipl;
539 	}
540 
541 	if (max == IPL_NONE)
542 		min = IPL_NONE;
543 
544 	if (sc->sc_handler[irq].iq_irq_max == max &&
545 	    sc->sc_handler[irq].iq_irq_min == min)
546 		return;
547 
548 	sc->sc_handler[irq].iq_irq_max = max;
549 	sc->sc_handler[irq].iq_irq_min = min;
550 
551 	/* Enable interrupts at lower levels, clear -> enable */
552 	/* Set interrupt priority/enable */
553 	if (min != IPL_NONE) {
554 		ampintc_set_priority(irq, min);
555 		ampintc_intr_enable(irq);
556 		ampintc_route(irq, IRQ_ENABLE, ci);
557 	} else {
558 		ampintc_intr_disable(irq);
559 		ampintc_route(irq, IRQ_DISABLE, ci);
560 	}
561 }
562 
563 void
564 ampintc_splx(int new)
565 {
566 	struct cpu_info *ci = curcpu();
567 
568 	if (ci->ci_ipending & arm_smask[new])
569 		arm_do_pending_intr(new);
570 
571 	ampintc_setipl(new);
572 }
573 
574 int
575 ampintc_spllower(int new)
576 {
577 	struct cpu_info *ci = curcpu();
578 	int old = ci->ci_cpl;
579 	ampintc_splx(new);
580 	return (old);
581 }
582 
583 int
584 ampintc_splraise(int new)
585 {
586 	struct cpu_info *ci = curcpu();
587 	int old;
588 	old = ci->ci_cpl;
589 
590 	/*
591 	 * setipl must always be called because there is a race window
592 	 * where the variable is updated before the mask is set
593 	 * an interrupt occurs in that window without the mask always
594 	 * being set, the hardware might not get updated on the next
595 	 * splraise completely messing up spl protection.
596 	 */
597 	if (old > new)
598 		new = old;
599 
600 	ampintc_setipl(new);
601 
602 	return (old);
603 }
604 
605 
606 uint32_t
607 ampintc_iack(void)
608 {
609 	uint32_t intid;
610 	struct ampintc_softc	*sc = ampintc;
611 
612 	intid = bus_space_read_4(sc->sc_iot, sc->sc_p_ioh, ICPIAR);
613 
614 	return (intid);
615 }
616 
617 void
618 ampintc_eoi(uint32_t eoi)
619 {
620 	struct ampintc_softc	*sc = ampintc;
621 
622 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPEOIR, eoi);
623 }
624 
625 void
626 ampintc_route(int irq, int enable, struct cpu_info *ci)
627 {
628 	struct ampintc_softc	*sc = ampintc;
629 	uint8_t			 mask, val;
630 
631 	KASSERT(ci->ci_cpuid <= ICD_ICTR_CPU_M);
632 	mask = sc->sc_cpu_mask[ci->ci_cpuid];
633 
634 	val = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq));
635 	if (enable == IRQ_ENABLE)
636 		val |= mask;
637 	else
638 		val &= ~mask;
639 	bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), val);
640 }
641 
642 void
643 ampintc_cpuinit(void)
644 {
645 	struct ampintc_softc	*sc = ampintc;
646 	int			 i, irq;
647 
648 	/* XXX - this is the only cpu specific call to set this */
649 	if (sc->sc_cpu_mask[cpu_number()] == 0) {
650 		for (i = 0; i < 32; i++) {
651 			int cpumask =
652 			    bus_space_read_1(sc->sc_iot, sc->sc_d_ioh,
653 			        ICD_IPTRn(i));
654 
655 			if (cpumask != 0) {
656 				sc->sc_cpu_mask[cpu_number()] = cpumask;
657 				break;
658 			}
659 		}
660 	}
661 
662 	if (sc->sc_cpu_mask[cpu_number()] == 0)
663 		panic("could not determine cpu target mask");
664 
665 	for (irq = 0; irq < sc->sc_nintr; irq++) {
666 		if (sc->sc_handler[irq].iq_ci != curcpu())
667 			continue;
668 		if (sc->sc_handler[irq].iq_irq_min != IPL_NONE)
669 			ampintc_route(irq, IRQ_ENABLE, curcpu());
670 		else
671 			ampintc_route(irq, IRQ_DISABLE, curcpu());
672 	}
673 
674 	/*
675 	 * If a secondary CPU is turned off from an IPI handler and
676 	 * the GIC did not go through a full reset (for example when
677 	 * we fail to suspend) the IPI might still be active.  So
678 	 * signal EOI here to make sure new interrupts will be
679 	 * serviced.
680 	 */
681 	ampintc_eoi(sc->sc_ipi_num[ARM_IPI_HALT]);
682 }
683 
684 void
685 ampintc_route_irq(void *v, int enable, struct cpu_info *ci)
686 {
687 	struct ampintc_softc    *sc = ampintc;
688 	struct intrhand         *ih = v;
689 
690 	bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1);
691 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(ih->ih_irq), 0);
692 	if (enable) {
693 		ampintc_set_priority(ih->ih_irq,
694 		    sc->sc_handler[ih->ih_irq].iq_irq_min);
695 		ampintc_intr_enable(ih->ih_irq);
696 	}
697 
698 	ampintc_route(ih->ih_irq, enable, ci);
699 }
700 
701 void
702 ampintc_intr_barrier(void *cookie)
703 {
704 	struct intrhand		*ih = cookie;
705 
706 	sched_barrier(ih->ih_ci);
707 }
708 
709 void
710 ampintc_run_handler(struct intrhand *ih, void *frame, int s)
711 {
712 	void *arg;
713 	int handled;
714 
715 #ifdef MULTIPROCESSOR
716 	int need_lock;
717 
718 	if (ih->ih_flags & IPL_MPSAFE)
719 		need_lock = 0;
720 	else
721 		need_lock = s < IPL_SCHED;
722 
723 	if (need_lock)
724 		KERNEL_LOCK();
725 #endif
726 
727 	if (ih->ih_arg)
728 		arg = ih->ih_arg;
729 	else
730 		arg = frame;
731 
732 	handled = ih->ih_func(arg);
733 	if (handled)
734 		ih->ih_count.ec_count++;
735 
736 #ifdef MULTIPROCESSOR
737 	if (need_lock)
738 		KERNEL_UNLOCK();
739 #endif
740 }
741 
742 void
743 ampintc_irq_handler(void *frame)
744 {
745 	struct ampintc_softc	*sc = ampintc;
746 	struct intrhand		*ih;
747 	uint32_t		 iack_val;
748 	int			 irq, pri, s;
749 
750 	iack_val = ampintc_iack();
751 #ifdef DEBUG_INTC
752 	if (iack_val != 27)
753 		printf("irq  %d fired\n", iack_val);
754 	else {
755 		static int cnt = 0;
756 		if ((cnt++ % 100) == 0) {
757 			printf("irq  %d fired * _100\n", iack_val);
758 #ifdef DDB
759 			db_enter();
760 #endif
761 		}
762 
763 	}
764 #endif
765 
766 	irq = iack_val & ICPIAR_IRQ_M;
767 
768 	if (irq == 1023) {
769 		sc->sc_spur.ec_count++;
770 		return;
771 	}
772 
773 	if (irq >= sc->sc_nintr)
774 		return;
775 
776 	pri = sc->sc_handler[irq].iq_irq_max;
777 	s = ampintc_splraise(pri);
778 	intr_enable();
779 	TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) {
780 		ampintc_run_handler(ih, frame, s);
781 	}
782 	intr_disable();
783 	ampintc_eoi(iack_val);
784 
785 	ampintc_splx(s);
786 }
787 
788 void *
789 ampintc_intr_establish_fdt(void *cookie, int *cell, int level,
790     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
791 {
792 	struct ampintc_softc	*sc = (struct ampintc_softc *)cookie;
793 	int			 irq;
794 	int			 type;
795 
796 	/* 2nd cell contains the interrupt number */
797 	irq = cell[1];
798 
799 	/* 1st cell contains type: 0 SPI (32-X), 1 PPI (16-31) */
800 	if (cell[0] == 0)
801 		irq += 32;
802 	else if (cell[0] == 1)
803 		irq += 16;
804 	else
805 		panic("%s: bogus interrupt type", sc->sc_sbus.sc_dev.dv_xname);
806 
807 	/* SPIs are only active-high level or low-to-high edge */
808 	if (cell[2] & 0x3)
809 		type = IST_EDGE_RISING;
810 	else
811 		type = IST_LEVEL_HIGH;
812 
813 	return ampintc_intr_establish(irq, type, level, ci, func, arg, name);
814 }
815 
816 void *
817 ampintc_intr_establish(int irqno, int type, int level, struct cpu_info *ci,
818     int (*func)(void *), void *arg, char *name)
819 {
820 	struct ampintc_softc	*sc = ampintc;
821 	struct intrhand		*ih;
822 	u_long			 psw;
823 
824 	if (irqno < 0 || irqno >= sc->sc_nintr)
825 		panic("ampintc_intr_establish: bogus irqnumber %d: %s",
826 		     irqno, name);
827 
828 	if (ci == NULL)
829 		ci = &cpu_info_primary;
830 
831 	if (irqno < 16) {
832 		/* SGI are only EDGE */
833 		type = IST_EDGE_RISING;
834 	} else if (irqno < 32) {
835 		/* PPI are only LEVEL */
836 		type = IST_LEVEL_HIGH;
837 	}
838 
839 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
840 	ih->ih_func = func;
841 	ih->ih_arg = arg;
842 	ih->ih_ipl = level & IPL_IRQMASK;
843 	ih->ih_flags = level & IPL_FLAGMASK;
844 	ih->ih_irq = irqno;
845 	ih->ih_name = name;
846 	ih->ih_ci = ci;
847 
848 	psw = intr_disable();
849 
850 	if (!TAILQ_EMPTY(&sc->sc_handler[irqno].iq_list) &&
851 	    sc->sc_handler[irqno].iq_ci != ci) {
852 		free(ih, M_DEVBUF, sizeof(*ih));
853 		intr_restore(psw);
854 		return NULL;
855 	}
856 
857 	TAILQ_INSERT_TAIL(&sc->sc_handler[irqno].iq_list, ih, ih_list);
858 	sc->sc_handler[irqno].iq_ci = ci;
859 
860 	if (name != NULL)
861 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
862 
863 #ifdef DEBUG_INTC
864 	printf("ampintc_intr_establish irq %d level %d [%s]\n", irqno, level,
865 	    name);
866 #endif
867 
868 	ampintc_intr_config(irqno, type);
869 	ampintc_calc_mask();
870 
871 	intr_restore(psw);
872 	return (ih);
873 }
874 
875 void
876 ampintc_intr_disestablish(void *cookie)
877 {
878 	struct ampintc_softc	*sc = ampintc;
879 	struct intrhand		*ih = cookie;
880 	u_long			 psw;
881 
882 #ifdef DEBUG_INTC
883 	printf("ampintc_intr_disestablish irq %d level %d [%s]\n",
884 	    ih->ih_irq, ih->ih_ipl, ih->ih_name);
885 #endif
886 
887 	psw = intr_disable();
888 
889 	TAILQ_REMOVE(&sc->sc_handler[ih->ih_irq].iq_list, ih, ih_list);
890 	if (ih->ih_name != NULL)
891 		evcount_detach(&ih->ih_count);
892 
893 	ampintc_calc_mask();
894 
895 	intr_restore(psw);
896 
897 	free(ih, M_DEVBUF, sizeof(*ih));
898 }
899 
900 const char *
901 ampintc_intr_string(void *cookie)
902 {
903 	struct intrhand *ih = (struct intrhand *)cookie;
904 	static char irqstr[1 + sizeof("ampintc irq ") + 4];
905 
906 	snprintf(irqstr, sizeof irqstr, "ampintc irq %d", ih->ih_irq);
907 	return irqstr;
908 }
909 
910 /*
911  * GICv2m frame controller for MSI interrupts.
912  */
913 #define GICV2M_TYPER		0x008
914 #define  GICV2M_TYPER_SPI_BASE(x)	(((x) >> 16) & 0x3ff)
915 #define  GICV2M_TYPER_SPI_COUNT(x)	(((x) >> 0) & 0x3ff)
916 #define GICV2M_SETSPI_NS	0x040
917 
918 int	 ampintc_msi_match(struct device *, void *, void *);
919 void	 ampintc_msi_attach(struct device *, struct device *, void *);
920 void	*ampintc_intr_establish_msi(void *, uint64_t *, uint64_t *,
921 	    int , struct cpu_info *, int (*)(void *), void *, char *);
922 void	 ampintc_intr_disestablish_msi(void *);
923 void	 ampintc_intr_barrier_msi(void *);
924 
925 struct ampintc_msi_softc {
926 	struct device			 sc_dev;
927 	bus_space_tag_t			 sc_iot;
928 	bus_space_handle_t		 sc_ioh;
929 	int				 sc_node;
930 	paddr_t				 sc_addr;
931 	int				 sc_bspi;
932 	int				 sc_nspi;
933 	void				**sc_spi;
934 	struct interrupt_controller	 sc_ic;
935 };
936 
937 const struct cfattach	ampintcmsi_ca = {
938 	sizeof (struct ampintc_msi_softc), ampintc_msi_match, ampintc_msi_attach
939 };
940 
941 struct cfdriver ampintcmsi_cd = {
942 	NULL, "ampintcmsi", DV_DULL
943 };
944 
945 int
946 ampintc_msi_match(struct device *parent, void *cfdata, void *aux)
947 {
948 	struct fdt_attach_args *faa = aux;
949 
950 	return OF_is_compatible(faa->fa_node, "arm,gic-v2m-frame");
951 }
952 
953 void
954 ampintc_msi_attach(struct device *parent, struct device *self, void *aux)
955 {
956 	struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
957 	struct fdt_attach_args *faa = aux;
958 	uint32_t typer;
959 
960 	sc->sc_node = faa->fa_node;
961 	sc->sc_iot = faa->fa_iot;
962 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
963 	    faa->fa_reg[0].size, 0, &sc->sc_ioh))
964 		panic("%s: bus_space_map failed!", __func__);
965 
966 	/* XXX: Hack to retrieve the physical address (from a CPU PoV). */
967 	if (!pmap_extract(pmap_kernel(), sc->sc_ioh, &sc->sc_addr)) {
968 		printf(": cannot retrieve msi addr\n");
969 		return;
970 	}
971 
972 	typer = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GICV2M_TYPER);
973 	sc->sc_bspi = GICV2M_TYPER_SPI_BASE(typer);
974 	sc->sc_nspi = GICV2M_TYPER_SPI_COUNT(typer);
975 
976 	sc->sc_bspi = OF_getpropint(faa->fa_node,
977 	    "arm,msi-base-spi", sc->sc_bspi);
978 	sc->sc_nspi = OF_getpropint(faa->fa_node,
979 	    "arm,msi-num-spis", sc->sc_nspi);
980 
981 	printf(": nspi %d\n", sc->sc_nspi);
982 
983 	sc->sc_spi = mallocarray(sc->sc_nspi, sizeof(void *), M_DEVBUF,
984 	    M_WAITOK|M_ZERO);
985 
986 	sc->sc_ic.ic_node = faa->fa_node;
987 	sc->sc_ic.ic_cookie = sc;
988 	sc->sc_ic.ic_establish_msi = ampintc_intr_establish_msi;
989 	sc->sc_ic.ic_disestablish = ampintc_intr_disestablish_msi;
990 	sc->sc_ic.ic_barrier = ampintc_intr_barrier_msi;
991 	arm_intr_register_fdt(&sc->sc_ic);
992 }
993 
994 void *
995 ampintc_intr_establish_msi(void *self, uint64_t *addr, uint64_t *data,
996     int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
997 {
998 	struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
999 	extern LIST_HEAD(, interrupt_controller) interrupt_controllers;
1000 	struct interrupt_controller *ic;
1001 	struct machine_intr_handle *ih;
1002 	void *cookie;
1003 	int cells[3];
1004 	int i;
1005 
1006 	LIST_FOREACH(ic, &interrupt_controllers, ic_list) {
1007 		if (ic->ic_node == OF_parent(sc->sc_node))
1008 			break;
1009 	}
1010 	if (ic == NULL)
1011 		return NULL;
1012 
1013 	cells[0] = 0; /* SPI */
1014 	cells[2] = 1; /* Edge-Rising */
1015 
1016 	for (i = 0; i < sc->sc_nspi; i++) {
1017 		if (sc->sc_spi[i] != NULL)
1018 			continue;
1019 
1020 		cells[1] = sc->sc_bspi + i - 32;
1021 		cookie = ic->ic_establish(ic->ic_cookie, cells,
1022 		    level, ci, func, arg, name);
1023 		if (cookie == NULL)
1024 			return NULL;
1025 
1026 		ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
1027 		ih->ih_ic = ic;
1028 		ih->ih_ih = cookie;
1029 
1030 		*addr = sc->sc_addr + GICV2M_SETSPI_NS;
1031 		*data = sc->sc_bspi + i;
1032 		sc->sc_spi[i] = ih;
1033 		return &sc->sc_spi[i];
1034 	}
1035 
1036 	return NULL;
1037 }
1038 
1039 void
1040 ampintc_intr_disestablish_msi(void *cookie)
1041 {
1042 	fdt_intr_disestablish(*(void **)cookie);
1043 	*(void **)cookie = NULL;
1044 }
1045 
1046 void
1047 ampintc_intr_barrier_msi(void *cookie)
1048 {
1049 	intr_barrier(*(void **)cookie);
1050 }
1051 
1052 #ifdef MULTIPROCESSOR
1053 int
1054 ampintc_ipi_ddb(void *v)
1055 {
1056 	/* XXX */
1057 #ifdef DDB
1058 	db_enter();
1059 #endif
1060 	return 1;
1061 }
1062 
1063 int
1064 ampintc_ipi_halt(void *v)
1065 {
1066 	cpu_halt();
1067 	return 1;
1068 }
1069 
1070 int
1071 ampintc_ipi_nop(void *v)
1072 {
1073 	/* Nothing to do here, just enough to wake up from WFI */
1074 	return 1;
1075 }
1076 
1077 int
1078 ampintc_ipi_combined(void *v)
1079 {
1080 	struct ampintc_softc *sc = (struct ampintc_softc *)v;
1081 
1082 	if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) {
1083 		sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
1084 		return ampintc_ipi_ddb(v);
1085 	} else if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_HALT) {
1086 		sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP;
1087 		return ampintc_ipi_halt(v);
1088 	} else {
1089 		return ampintc_ipi_nop(v);
1090 	}
1091 }
1092 
1093 void
1094 ampintc_send_ipi(struct cpu_info *ci, int id)
1095 {
1096 	struct ampintc_softc	*sc = ampintc;
1097 	int sendmask;
1098 
1099 	if (ci == curcpu() && id == ARM_IPI_NOP)
1100 		return;
1101 
1102 	/* never overwrite IPI_DDB or IPI_HALT with IPI_NOP */
1103 	if (id == ARM_IPI_DDB || id == ARM_IPI_HALT)
1104 		sc->sc_ipi_reason[ci->ci_cpuid] = id;
1105 
1106 	/* currently will only send to one cpu */
1107 	sendmask = sc->sc_cpu_mask[ci->ci_cpuid] << 16;
1108 	sendmask |= sc->sc_ipi_num[id];
1109 
1110 	bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_SGIR, sendmask);
1111 }
1112 #endif
1113