xref: /netbsd-src/sys/arch/arm/apple/apple_intc.c (revision 3280674b8a2e2664b83b29a722df697c18018f20)
1*3280674bSjmcneill /* $NetBSD: apple_intc.c,v 1.9 2022/06/28 10:42:22 jmcneill Exp $ */
2db7e12daSjmcneill 
3db7e12daSjmcneill /*-
4db7e12daSjmcneill  * Copyright (c) 2021 Jared McNeill <jmcneill@invisible.ca>
5db7e12daSjmcneill  * All rights reserved.
6db7e12daSjmcneill  *
7db7e12daSjmcneill  * Redistribution and use in source and binary forms, with or without
8db7e12daSjmcneill  * modification, are permitted provided that the following conditions
9db7e12daSjmcneill  * are met:
10db7e12daSjmcneill  * 1. Redistributions of source code must retain the above copyright
11db7e12daSjmcneill  *    notice, this list of conditions and the following disclaimer.
12db7e12daSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
13db7e12daSjmcneill  *    notice, this list of conditions and the following disclaimer in the
14db7e12daSjmcneill  *    documentation and/or other materials provided with the distribution.
15db7e12daSjmcneill  *
16db7e12daSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17db7e12daSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18db7e12daSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19db7e12daSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20db7e12daSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21db7e12daSjmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22db7e12daSjmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23db7e12daSjmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24db7e12daSjmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25db7e12daSjmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26db7e12daSjmcneill  * SUCH DAMAGE.
27db7e12daSjmcneill  */
28db7e12daSjmcneill 
29db7e12daSjmcneill #include "opt_ddb.h"
30112de833Sryo #include "opt_multiprocessor.h"
31db7e12daSjmcneill 
32db7e12daSjmcneill #define	_INTR_PRIVATE
33db7e12daSjmcneill 
34db7e12daSjmcneill #include <sys/cdefs.h>
35*3280674bSjmcneill __KERNEL_RCSID(0, "$NetBSD: apple_intc.c,v 1.9 2022/06/28 10:42:22 jmcneill Exp $");
36db7e12daSjmcneill 
37db7e12daSjmcneill #include <sys/param.h>
38db7e12daSjmcneill #include <sys/bus.h>
39db7e12daSjmcneill #include <sys/device.h>
40db7e12daSjmcneill #include <sys/intr.h>
41db7e12daSjmcneill #include <sys/kernel.h>
42db7e12daSjmcneill #include <sys/lwp.h>
43db7e12daSjmcneill #include <sys/systm.h>
44db7e12daSjmcneill #include <sys/cpu.h>
45db7e12daSjmcneill #include <sys/kmem.h>
46db7e12daSjmcneill #include <sys/atomic.h>
47db7e12daSjmcneill 
48db7e12daSjmcneill #include <dev/fdt/fdtvar.h>
49db7e12daSjmcneill 
50db7e12daSjmcneill #include <dev/pci/pcireg.h>
51db7e12daSjmcneill #include <dev/pci/pcivar.h>
52db7e12daSjmcneill 
53db7e12daSjmcneill #include <arm/cpu.h>
54db7e12daSjmcneill #include <arm/cpufunc.h>
55db7e12daSjmcneill #include <arm/armreg.h>
56db7e12daSjmcneill #include <arm/locore.h>
57db7e12daSjmcneill #include <arm/pic/picvar.h>
58db7e12daSjmcneill #include <arm/fdt/arm_fdtvar.h>
59db7e12daSjmcneill 
60db7e12daSjmcneill /*
61db7e12daSjmcneill  * AIC registers
62db7e12daSjmcneill  */
63db7e12daSjmcneill #define	AIC_INFO		0x0004
64db7e12daSjmcneill #define	 AIC_INFO_NIRQ		__BITS(15,0)
65db7e12daSjmcneill #define	AIC_WHOAMI		0x2000
66db7e12daSjmcneill #define	AIC_EVENT		0x2004
67db7e12daSjmcneill #define	 AIC_EVENT_TYPE		__BITS(31,16)
68db7e12daSjmcneill #define	  AIC_EVENT_TYPE_NONE	0
69db7e12daSjmcneill #define	  AIC_EVENT_TYPE_IRQ	1
70db7e12daSjmcneill #define	  AIC_EVENT_TYPE_IPI	4
71db7e12daSjmcneill #define	 AIC_EVENT_DATA		__BITS(15,0)
72db7e12daSjmcneill #define	 AIC_EVENT_IPI_OTHER	1
73db7e12daSjmcneill #define	AIC_IPI_SEND		0x2008
74db7e12daSjmcneill #define	AIC_IPI_ACK		0x200c
75db7e12daSjmcneill #define	AIC_IPI_MASK_CLR	0x2028
76db7e12daSjmcneill #define	AIC_IPI_OTHER		__BIT(0)
77db7e12daSjmcneill #define	AIC_AFFINITY(irqno)	(0x3000 + (irqno) * 4)
78db7e12daSjmcneill #define	AIC_SW_SET(irqno)	(0x4000 + (irqno) / 32 * 4)
79db7e12daSjmcneill #define	AIC_SW_CLR(irqno)	(0x4080 + (irqno) / 32 * 4)
80db7e12daSjmcneill #define	AIC_MASK_SET(irqno)	(0x4100 + (irqno) / 32 * 4)
81db7e12daSjmcneill #define	AIC_MASK_CLR(irqno)	(0x4180 + (irqno) / 32 * 4)
82db7e12daSjmcneill #define	 AIC_MASK_BIT(irqno)	__BIT((irqno) & 0x1f)
83db7e12daSjmcneill 
84db7e12daSjmcneill static const struct device_compatible_entry compat_data[] = {
85db7e12daSjmcneill 	{ .compat = "apple,aic" },
86db7e12daSjmcneill 	DEVICE_COMPAT_EOL
87db7e12daSjmcneill };
88db7e12daSjmcneill 
89db7e12daSjmcneill struct apple_intc_softc;
90db7e12daSjmcneill 
91db7e12daSjmcneill struct apple_intc_percpu {
92db7e12daSjmcneill 	struct apple_intc_softc *pc_sc;
93db7e12daSjmcneill 	u_int pc_cpuid;
94db7e12daSjmcneill 	u_int pc_ipimask;
95db7e12daSjmcneill 
96db7e12daSjmcneill 	struct pic_softc pc_pic;
97db7e12daSjmcneill };
98db7e12daSjmcneill 
99db7e12daSjmcneill #define	LOCALPIC_SOURCE_TIMER	0
100db7e12daSjmcneill #define	LOCALPIC_SOURCE_IPI	1
101db7e12daSjmcneill 
102db7e12daSjmcneill struct apple_intc_softc {
103db7e12daSjmcneill 	device_t sc_dev;		/* device handle */
104db7e12daSjmcneill 	bus_space_tag_t sc_bst;		/* mmio tag */
105db7e12daSjmcneill 	bus_space_handle_t sc_bsh;	/* mmio handle */
106db7e12daSjmcneill 	u_int sc_nirq;			/* number of supported IRQs */
107db7e12daSjmcneill 	u_int *sc_cpuid;		/* map of cpu index to AIC CPU ID */
108db7e12daSjmcneill 	struct apple_intc_percpu *sc_pc; /* per-CPU data for timer and IPIs */
109db7e12daSjmcneill 
110db7e12daSjmcneill 	struct pic_softc sc_pic;
111db7e12daSjmcneill };
112db7e12daSjmcneill 
113db7e12daSjmcneill static struct apple_intc_softc *intc_softc;
114db7e12daSjmcneill 
115f017eb2aSriastradh #define	PICTOSOFTC(pic) container_of(pic, struct apple_intc_softc, sc_pic)
116f017eb2aSriastradh #define	PICTOPERCPU(pic) container_of(pic, struct apple_intc_percpu, pc_pic)
117db7e12daSjmcneill 
118db7e12daSjmcneill #define AIC_READ(sc, reg) \
119db7e12daSjmcneill 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
120db7e12daSjmcneill #define	AIC_WRITE(sc, reg, val) \
121db7e12daSjmcneill 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
122db7e12daSjmcneill 
123db7e12daSjmcneill static void
apple_intc_unblock_irqs(struct pic_softc * pic,size_t irqbase,uint32_t mask)124db7e12daSjmcneill apple_intc_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t mask)
125db7e12daSjmcneill {
126db7e12daSjmcneill 	struct apple_intc_softc * const sc = PICTOSOFTC(pic);
127db7e12daSjmcneill 
128db7e12daSjmcneill 	AIC_WRITE(sc, AIC_SW_SET(irqbase), mask);
129db7e12daSjmcneill 	AIC_WRITE(sc, AIC_MASK_CLR(irqbase), mask);
130db7e12daSjmcneill }
131db7e12daSjmcneill 
132db7e12daSjmcneill static void
apple_intc_block_irqs(struct pic_softc * pic,size_t irqbase,uint32_t mask)133db7e12daSjmcneill apple_intc_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t mask)
134db7e12daSjmcneill {
135db7e12daSjmcneill }
136db7e12daSjmcneill 
137db7e12daSjmcneill static void
apple_intc_establish_irq(struct pic_softc * pic,struct intrsource * is)138db7e12daSjmcneill apple_intc_establish_irq(struct pic_softc *pic, struct intrsource *is)
139db7e12daSjmcneill {
140db7e12daSjmcneill 	struct apple_intc_softc * const sc = PICTOSOFTC(pic);
141db7e12daSjmcneill 
142db7e12daSjmcneill 	KASSERT(is->is_type == IST_LEVEL);
143db7e12daSjmcneill 
144db7e12daSjmcneill 	/* Route to primary PE by default */
145db7e12daSjmcneill 	AIC_WRITE(sc, AIC_AFFINITY(is->is_irq), __BIT(0));
146db7e12daSjmcneill 	AIC_WRITE(sc, AIC_MASK_CLR(is->is_irq),
147db7e12daSjmcneill 	    AIC_MASK_BIT(is->is_irq));
148db7e12daSjmcneill }
149db7e12daSjmcneill 
150db7e12daSjmcneill static void
apple_intc_set_priority(struct pic_softc * pic,int ipl)151db7e12daSjmcneill apple_intc_set_priority(struct pic_softc *pic, int ipl)
152db7e12daSjmcneill {
153*3280674bSjmcneill 	curcpu()->ci_cpl = ipl;
154db7e12daSjmcneill }
155db7e12daSjmcneill 
156db7e12daSjmcneill static void
apple_intc_cpu_init(struct pic_softc * pic,struct cpu_info * ci)157db7e12daSjmcneill apple_intc_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
158db7e12daSjmcneill {
159db7e12daSjmcneill 	struct apple_intc_softc * const sc = PICTOSOFTC(pic);
160db7e12daSjmcneill 	const u_int cpuno = cpu_index(ci);
161db7e12daSjmcneill 
162db7e12daSjmcneill 	sc->sc_cpuid[cpuno] = AIC_READ(sc, AIC_WHOAMI);
163db7e12daSjmcneill }
164db7e12daSjmcneill 
165db7e12daSjmcneill static const struct pic_ops apple_intc_picops = {
166db7e12daSjmcneill 	.pic_unblock_irqs = apple_intc_unblock_irqs,
167db7e12daSjmcneill 	.pic_block_irqs = apple_intc_block_irqs,
168db7e12daSjmcneill 	.pic_establish_irq = apple_intc_establish_irq,
169db7e12daSjmcneill 	.pic_set_priority = apple_intc_set_priority,
170112de833Sryo #ifdef MULTIPROCESSOR
171db7e12daSjmcneill 	.pic_cpu_init = apple_intc_cpu_init,
172112de833Sryo #endif
173db7e12daSjmcneill };
174db7e12daSjmcneill 
175db7e12daSjmcneill static void
apple_intc_local_unblock_irqs(struct pic_softc * pic,size_t irqbase,uint32_t mask)176db7e12daSjmcneill apple_intc_local_unblock_irqs(struct pic_softc *pic, size_t irqbase,
177db7e12daSjmcneill     uint32_t mask)
178db7e12daSjmcneill {
179db7e12daSjmcneill 	KASSERT(irqbase == 0);
180db7e12daSjmcneill 
181db7e12daSjmcneill 	if ((mask & __BIT(LOCALPIC_SOURCE_TIMER)) != 0) {
182db7e12daSjmcneill 		gtmr_cntv_ctl_write(gtmr_cntv_ctl_read() & ~CNTCTL_IMASK);
183db7e12daSjmcneill 		isb();
184db7e12daSjmcneill 	}
185db7e12daSjmcneill }
186db7e12daSjmcneill 
187db7e12daSjmcneill static void
apple_intc_local_block_irqs(struct pic_softc * pic,size_t irqbase,uint32_t mask)188db7e12daSjmcneill apple_intc_local_block_irqs(struct pic_softc *pic, size_t irqbase,
189db7e12daSjmcneill     uint32_t mask)
190db7e12daSjmcneill {
191db7e12daSjmcneill 	KASSERT(irqbase == 0);
192db7e12daSjmcneill 
193db7e12daSjmcneill 	if ((mask & __BIT(LOCALPIC_SOURCE_TIMER)) != 0) {
194db7e12daSjmcneill 		gtmr_cntv_ctl_write(gtmr_cntv_ctl_read() | CNTCTL_IMASK);
195db7e12daSjmcneill 		isb();
196db7e12daSjmcneill 	}
197db7e12daSjmcneill }
198db7e12daSjmcneill 
199db7e12daSjmcneill static void
apple_intc_local_establish_irq(struct pic_softc * pic,struct intrsource * is)200db7e12daSjmcneill apple_intc_local_establish_irq(struct pic_softc *pic, struct intrsource *is)
201db7e12daSjmcneill {
202db7e12daSjmcneill }
203db7e12daSjmcneill 
204112de833Sryo #ifdef MULTIPROCESSOR
205db7e12daSjmcneill static void
apple_intc_local_ipi_send(struct pic_softc * pic,const kcpuset_t * kcp,u_long ipi)206db7e12daSjmcneill apple_intc_local_ipi_send(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
207db7e12daSjmcneill {
208db7e12daSjmcneill 	struct apple_intc_percpu * const pc = PICTOPERCPU(pic);
209db7e12daSjmcneill 	struct apple_intc_softc * const sc = pc->pc_sc;
210db7e12daSjmcneill 	const u_int target = sc->sc_cpuid[pc->pc_cpuid];
211db7e12daSjmcneill 
212db7e12daSjmcneill 	atomic_or_32(&pc->pc_ipimask, __BIT(ipi));
213db7e12daSjmcneill 	AIC_WRITE(sc, AIC_IPI_SEND, __BIT(target));
214db7e12daSjmcneill }
215112de833Sryo #endif /* MULTIPROCESSOR */
216db7e12daSjmcneill 
217db7e12daSjmcneill static const struct pic_ops apple_intc_localpicops = {
218db7e12daSjmcneill 	.pic_unblock_irqs = apple_intc_local_unblock_irqs,
219db7e12daSjmcneill 	.pic_block_irqs = apple_intc_local_block_irqs,
220db7e12daSjmcneill 	.pic_establish_irq = apple_intc_local_establish_irq,
221112de833Sryo #ifdef MULTIPROCESSOR
222db7e12daSjmcneill 	.pic_ipi_send = apple_intc_local_ipi_send,
223112de833Sryo #endif
224db7e12daSjmcneill };
225db7e12daSjmcneill 
226db7e12daSjmcneill static void *
apple_intc_fdt_establish(device_t dev,u_int * specifier,int ipl,int flags,int (* func)(void *),void * arg,const char * xname)227db7e12daSjmcneill apple_intc_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
228db7e12daSjmcneill     int (*func)(void *), void *arg, const char *xname)
229db7e12daSjmcneill {
230db7e12daSjmcneill 	struct apple_intc_softc * const sc = device_private(dev);
231db7e12daSjmcneill 
232db7e12daSjmcneill 	/* 1st cell is the interrupt type (0=IRQ, 1=FIQ) */
233db7e12daSjmcneill 	const u_int type = be32toh(specifier[0]);
234db7e12daSjmcneill 	/* 2nd cell is the interrupt number */
235db7e12daSjmcneill 	const u_int intno = be32toh(specifier[1]);
236db7e12daSjmcneill 	/* 3rd cell is the interrupt flags */
237db7e12daSjmcneill 
238db7e12daSjmcneill 	const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
239e677f16fSskrll 
240e677f16fSskrll 	if (type == 0)
241e677f16fSskrll 		return intr_establish_xname(intno, ipl, IST_LEVEL | mpsafe,
242e677f16fSskrll 		    func, arg, xname);
243e677f16fSskrll 
244e677f16fSskrll 	/* interate over CPUs for LOCALPIC_SOURCE_TIMER */
245e677f16fSskrll 	CPU_INFO_ITERATOR cii;
246e677f16fSskrll 	struct cpu_info *ci;
247e677f16fSskrll 	void *ih = NULL;
248e677f16fSskrll 	for (CPU_INFO_FOREACH(cii, ci)) {
249e677f16fSskrll 		const cpuid_t cpuno = cpu_index(ci);
250e677f16fSskrll 		struct apple_intc_percpu * const pc = &sc->sc_pc[cpuno];
251e677f16fSskrll 		struct pic_softc * const pic = &pc->pc_pic;
252e677f16fSskrll 		const int irq = pic->pic_irqbase + LOCALPIC_SOURCE_TIMER;
253e677f16fSskrll 
254e677f16fSskrll 		void *ihn = intr_establish_xname(irq, ipl, IST_LEVEL | mpsafe,
255e677f16fSskrll 		    func, arg, xname);
256e677f16fSskrll 		if (cpuno == 0)
257e677f16fSskrll 			ih = ihn;
258e677f16fSskrll 	}
259e677f16fSskrll 	return ih;
260db7e12daSjmcneill }
261db7e12daSjmcneill 
262db7e12daSjmcneill static void
apple_intc_fdt_disestablish(device_t dev,void * ih)263db7e12daSjmcneill apple_intc_fdt_disestablish(device_t dev, void *ih)
264db7e12daSjmcneill {
265db7e12daSjmcneill 	intr_disestablish(ih);
266db7e12daSjmcneill }
267db7e12daSjmcneill 
268db7e12daSjmcneill static bool
apple_intc_fdt_intrstr(device_t dev,u_int * specifier,char * buf,size_t buflen)269db7e12daSjmcneill apple_intc_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
270db7e12daSjmcneill {
271db7e12daSjmcneill 	if (!specifier)
272db7e12daSjmcneill 		return false;
273db7e12daSjmcneill 
274db7e12daSjmcneill 	/* 1st cell is the interrupt type (0=IRQ, 1=FIQ) */
275db7e12daSjmcneill 	const u_int type = be32toh(specifier[0]);
276db7e12daSjmcneill 	/* 2nd cell is the interrupt number */
277db7e12daSjmcneill 	const u_int intno = be32toh(specifier[1]);
278db7e12daSjmcneill 
279f0ed8c9cSskrll 	snprintf(buf, buflen, "%s %u", type == 0 ? "irq" : "fiq", intno);
280db7e12daSjmcneill 
281db7e12daSjmcneill 	return true;
282db7e12daSjmcneill }
283db7e12daSjmcneill 
284db7e12daSjmcneill static const struct fdtbus_interrupt_controller_func apple_intc_fdt_funcs = {
285db7e12daSjmcneill 	.establish = apple_intc_fdt_establish,
286db7e12daSjmcneill 	.disestablish = apple_intc_fdt_disestablish,
287db7e12daSjmcneill 	.intrstr = apple_intc_fdt_intrstr,
288db7e12daSjmcneill };
289db7e12daSjmcneill 
290db7e12daSjmcneill static void
apple_intc_mark_pending(struct pic_softc * pic,u_int intno)291db7e12daSjmcneill apple_intc_mark_pending(struct pic_softc *pic, u_int intno)
292db7e12daSjmcneill {
293f801d2dcSskrll 	const int base = intno & ~0x1f;
294db7e12daSjmcneill 	const uint32_t pending = __BIT(intno & 0x1f);
295f801d2dcSskrll 	pic_mark_pending_sources(pic, base, pending);
296db7e12daSjmcneill }
297db7e12daSjmcneill 
298db7e12daSjmcneill static void
apple_intc_irq_handler(void * frame)299db7e12daSjmcneill apple_intc_irq_handler(void *frame)
300db7e12daSjmcneill {
301db7e12daSjmcneill 	struct cpu_info * const ci = curcpu();
302db7e12daSjmcneill 	struct apple_intc_softc * const sc = intc_softc;
303db7e12daSjmcneill 	struct pic_softc *pic;
304db7e12daSjmcneill 	struct intrsource *is;
305db7e12daSjmcneill 	const int oldipl = ci->ci_cpl;
306db7e12daSjmcneill 	uint16_t evtype, evdata;
307db7e12daSjmcneill 	bus_size_t clr_reg;
308db7e12daSjmcneill 	uint32_t clr_val;
309db7e12daSjmcneill 
310db7e12daSjmcneill 	ci->ci_data.cpu_nintr++;
311db7e12daSjmcneill 
312db7e12daSjmcneill 	for (;;) {
313db7e12daSjmcneill 		const uint32_t ev = AIC_READ(sc, AIC_EVENT);
314db7e12daSjmcneill 		evtype = __SHIFTOUT(ev, AIC_EVENT_TYPE);
315db7e12daSjmcneill 		evdata = __SHIFTOUT(ev, AIC_EVENT_DATA);
316db7e12daSjmcneill 
317db7e12daSjmcneill 		dsb(sy);
318db7e12daSjmcneill 		isb();
319db7e12daSjmcneill 
320db7e12daSjmcneill 		if (evtype == AIC_EVENT_TYPE_IRQ) {
321db7e12daSjmcneill 			KASSERT(evdata < sc->sc_nirq);
322db7e12daSjmcneill 			pic = &sc->sc_pic;
323db7e12daSjmcneill 			is = pic->pic_sources[evdata];
324db7e12daSjmcneill 			KASSERT(is != NULL);
325db7e12daSjmcneill 
326db7e12daSjmcneill 			AIC_WRITE(sc, AIC_SW_CLR(evdata),
327db7e12daSjmcneill 			    __BIT(evdata & 0x1f));
328db7e12daSjmcneill 
329db7e12daSjmcneill 			clr_reg = AIC_MASK_CLR(evdata);
330db7e12daSjmcneill 			clr_val = AIC_MASK_BIT(evdata);
331db7e12daSjmcneill 		} else if (evtype == AIC_EVENT_TYPE_IPI) {
332db7e12daSjmcneill 			KASSERT(evdata == AIC_EVENT_IPI_OTHER);
333db7e12daSjmcneill 			pic = &sc->sc_pc[cpu_index(ci)].pc_pic;
334db7e12daSjmcneill 			is = pic->pic_sources[LOCALPIC_SOURCE_IPI];
335db7e12daSjmcneill 			KASSERT(is != NULL);
336db7e12daSjmcneill 
337db7e12daSjmcneill 			AIC_WRITE(sc, AIC_IPI_ACK, AIC_IPI_OTHER);
338db7e12daSjmcneill 
339db7e12daSjmcneill 			clr_reg = 0;
340db7e12daSjmcneill 			clr_val = 0;
341db7e12daSjmcneill 		} else {
342db7e12daSjmcneill 			break;
343db7e12daSjmcneill 		}
344db7e12daSjmcneill 
345db7e12daSjmcneill 		if (ci->ci_cpl >= is->is_ipl) {
346db7e12daSjmcneill 			apple_intc_mark_pending(pic, is->is_irq);
347db7e12daSjmcneill 		} else {
348db7e12daSjmcneill 			pic_set_priority(ci, is->is_ipl);
349db7e12daSjmcneill 			ENABLE_INTERRUPT();
350db7e12daSjmcneill 			pic_dispatch(is, frame);
351db7e12daSjmcneill 			DISABLE_INTERRUPT();
352db7e12daSjmcneill 
353db7e12daSjmcneill 			if (clr_val != 0) {
354db7e12daSjmcneill 				AIC_WRITE(sc, clr_reg, clr_val);
355db7e12daSjmcneill 			}
356db7e12daSjmcneill 		}
357db7e12daSjmcneill 	}
358db7e12daSjmcneill 
359db7e12daSjmcneill 	if (oldipl != IPL_HIGH) {
360db7e12daSjmcneill 		pic_do_pending_ints(DAIF_I|DAIF_F, oldipl, frame);
361db7e12daSjmcneill 	}
362db7e12daSjmcneill }
363db7e12daSjmcneill 
364db7e12daSjmcneill static void
apple_intc_fiq_handler(void * frame)365db7e12daSjmcneill apple_intc_fiq_handler(void *frame)
366db7e12daSjmcneill {
367db7e12daSjmcneill 	struct cpu_info * const ci = curcpu();
368db7e12daSjmcneill 	struct apple_intc_softc * const sc = intc_softc;
369db7e12daSjmcneill 	struct pic_softc * const pic = &sc->sc_pc[cpu_index(ci)].pc_pic;
370db7e12daSjmcneill 	const int oldipl = ci->ci_cpl;
371db7e12daSjmcneill 
372db7e12daSjmcneill 	ci->ci_data.cpu_nintr++;
373db7e12daSjmcneill 
374db7e12daSjmcneill 	struct intrsource * const is = pic->pic_sources[LOCALPIC_SOURCE_TIMER];
375db7e12daSjmcneill 
376db7e12daSjmcneill 	dsb(sy);
377db7e12daSjmcneill 	isb();
378db7e12daSjmcneill 
379db7e12daSjmcneill 	if (oldipl >= is->is_ipl) {
380db7e12daSjmcneill 		apple_intc_mark_pending(pic, LOCALPIC_SOURCE_TIMER);
381db7e12daSjmcneill 	} else {
382db7e12daSjmcneill 		pic_set_priority(ci, is->is_ipl);
383db7e12daSjmcneill 		pic_dispatch(is, frame);
384db7e12daSjmcneill 	}
385db7e12daSjmcneill 
386db7e12daSjmcneill 	if (oldipl != IPL_HIGH) {
387db7e12daSjmcneill 		pic_do_pending_ints(DAIF_I|DAIF_F, oldipl, frame);
388db7e12daSjmcneill 	}
389db7e12daSjmcneill }
390db7e12daSjmcneill 
391112de833Sryo #ifdef MULTIPROCESSOR
392db7e12daSjmcneill static int
apple_intc_ipi_handler(void * priv)393db7e12daSjmcneill apple_intc_ipi_handler(void *priv)
394db7e12daSjmcneill {
395db7e12daSjmcneill 	struct apple_intc_percpu * const pc = priv;
396db7e12daSjmcneill 	struct apple_intc_softc * const sc = pc->pc_sc;
397db7e12daSjmcneill 	uint32_t ipimask, bit;
398db7e12daSjmcneill 
399db7e12daSjmcneill 	AIC_WRITE(sc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER);
400db7e12daSjmcneill 	ipimask = atomic_swap_32(&pc->pc_ipimask, 0);
401db7e12daSjmcneill 
402db7e12daSjmcneill 	while ((bit = ffs(ipimask)) > 0) {
403db7e12daSjmcneill 		const u_int ipi = bit - 1;
404db7e12daSjmcneill 
405db7e12daSjmcneill 		switch (ipi) {
406db7e12daSjmcneill 		case IPI_AST:
407db7e12daSjmcneill 			pic_ipi_ast(priv);
408db7e12daSjmcneill 			break;
409db7e12daSjmcneill 		case IPI_NOP:
410db7e12daSjmcneill 			pic_ipi_nop(priv);
411db7e12daSjmcneill 			break;
412db7e12daSjmcneill #ifdef __HAVE_PREEMPTION
413db7e12daSjmcneill 		case IPI_KPREEMPT:
414db7e12daSjmcneill 			pic_ipi_kpreempt(priv);
415db7e12daSjmcneill 			break;
416db7e12daSjmcneill #endif
417db7e12daSjmcneill 		case IPI_XCALL:
418db7e12daSjmcneill 			pic_ipi_xcall(priv);
419db7e12daSjmcneill 			break;
420db7e12daSjmcneill 		case IPI_GENERIC:
421db7e12daSjmcneill 			pic_ipi_generic(priv);
422db7e12daSjmcneill 			break;
423db7e12daSjmcneill 		case IPI_SHOOTDOWN:
424db7e12daSjmcneill 			pic_ipi_shootdown(priv);
425db7e12daSjmcneill 			break;
426db7e12daSjmcneill #ifdef DDB
427db7e12daSjmcneill 		case IPI_DDB:
428db7e12daSjmcneill 			pic_ipi_ddb(priv);
429db7e12daSjmcneill 			break;
430db7e12daSjmcneill #endif
431db7e12daSjmcneill 		}
432db7e12daSjmcneill 		ipimask &= ~__BIT(ipi);
433db7e12daSjmcneill 	}
434db7e12daSjmcneill 
435db7e12daSjmcneill 	return 1;
436db7e12daSjmcneill }
437112de833Sryo #endif /* MULTIPROCESSOR */
438db7e12daSjmcneill 
439db7e12daSjmcneill static int
apple_intc_match(device_t parent,cfdata_t cf,void * aux)440db7e12daSjmcneill apple_intc_match(device_t parent, cfdata_t cf, void *aux)
441db7e12daSjmcneill {
442db7e12daSjmcneill 	struct fdt_attach_args * const faa = aux;
443db7e12daSjmcneill 
444db7e12daSjmcneill 	return of_compatible_match(faa->faa_phandle, compat_data);
445db7e12daSjmcneill }
446db7e12daSjmcneill 
447db7e12daSjmcneill static void
apple_intc_attach(device_t parent,device_t self,void * aux)448db7e12daSjmcneill apple_intc_attach(device_t parent, device_t self, void *aux)
449db7e12daSjmcneill {
450db7e12daSjmcneill 	struct apple_intc_softc * const sc = device_private(self);
451db7e12daSjmcneill 	struct fdt_attach_args * const faa = aux;
452db7e12daSjmcneill 	const int phandle = faa->faa_phandle;
453db7e12daSjmcneill 	bus_addr_t addr;
454db7e12daSjmcneill 	bus_size_t size;
455db7e12daSjmcneill 	int error;
456db7e12daSjmcneill 
457db7e12daSjmcneill 	if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
458db7e12daSjmcneill 		aprint_error(": couldn't get registers\n");
459db7e12daSjmcneill 		return;
460db7e12daSjmcneill 	}
461db7e12daSjmcneill 
462db7e12daSjmcneill 	sc->sc_dev = self;
463db7e12daSjmcneill 	sc->sc_bst = faa->faa_bst;
46477a7b674Sjmcneill 	if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) {
465db7e12daSjmcneill 		aprint_error(": couldn't map registers\n");
466db7e12daSjmcneill 		return;
467db7e12daSjmcneill 	}
468db7e12daSjmcneill 
469db7e12daSjmcneill 	sc->sc_nirq = AIC_READ(sc, AIC_INFO) & AIC_INFO_NIRQ;
470db7e12daSjmcneill 
471db7e12daSjmcneill 	aprint_naive("\n");
472db7e12daSjmcneill 	aprint_normal(": Apple AIC (%u IRQs, 1 FIQ)\n", sc->sc_nirq);
473db7e12daSjmcneill 	KASSERT(sc->sc_nirq % 32 == 0);
474db7e12daSjmcneill 
475db7e12daSjmcneill 	sc->sc_pic.pic_ops = &apple_intc_picops;
476db7e12daSjmcneill 	sc->sc_pic.pic_maxsources = sc->sc_nirq;
477db7e12daSjmcneill 	snprintf(sc->sc_pic.pic_name, sizeof(sc->sc_pic.pic_name), "AIC");
478db7e12daSjmcneill 	pic_add(&sc->sc_pic, 0);
479db7e12daSjmcneill 
480db7e12daSjmcneill 	error = fdtbus_register_interrupt_controller(self, phandle,
481db7e12daSjmcneill 	    &apple_intc_fdt_funcs);
482db7e12daSjmcneill 	if (error) {
483db7e12daSjmcneill 		aprint_error_dev(self, "couldn't register with fdtbus: %d\n",
484db7e12daSjmcneill 		    error);
485db7e12daSjmcneill 		return;
486db7e12daSjmcneill 	}
487db7e12daSjmcneill 
488db7e12daSjmcneill 	KASSERT(intc_softc == NULL);
489db7e12daSjmcneill 	intc_softc = sc;
490db7e12daSjmcneill 	arm_fdt_irq_set_handler(apple_intc_irq_handler);
491db7e12daSjmcneill 	arm_fdt_fiq_set_handler(apple_intc_fiq_handler);
492db7e12daSjmcneill 
493db7e12daSjmcneill 	KASSERT(ncpu != 0);
494db7e12daSjmcneill 	sc->sc_cpuid = kmem_zalloc(sizeof(*sc->sc_cpuid) * ncpu, KM_SLEEP);
495db7e12daSjmcneill 	sc->sc_pc = kmem_zalloc(sizeof(*sc->sc_pc) * ncpu, KM_SLEEP);
496e677f16fSskrll 
497e677f16fSskrll 	CPU_INFO_ITERATOR cii;
498e677f16fSskrll 	struct cpu_info *ci;
499e677f16fSskrll 	for (CPU_INFO_FOREACH(cii, ci)) {
500e677f16fSskrll 		const cpuid_t cpuno = cpu_index(ci);
501e677f16fSskrll 		struct apple_intc_percpu * const pc = &sc->sc_pc[cpuno];
502e677f16fSskrll 		struct pic_softc * const pic = &pc->pc_pic;
503e677f16fSskrll 
504e677f16fSskrll 		pc->pc_sc = sc;
505e677f16fSskrll 		pc->pc_cpuid = cpuno;
506e677f16fSskrll 
50762432df5Sryo #ifdef MULTIPROCESSOR
508e677f16fSskrll 		pic->pic_cpus = ci->ci_kcpuset;
50962432df5Sryo #endif
510e677f16fSskrll 		pic->pic_ops = &apple_intc_localpicops;
511e677f16fSskrll 		pic->pic_maxsources = 2;
512e677f16fSskrll 		snprintf(pic->pic_name, sizeof(pic->pic_name), "AIC/%lu", cpuno);
513e677f16fSskrll 
514e677f16fSskrll 		pic_add(pic, PIC_IRQBASE_ALLOC);
515e677f16fSskrll 
51662432df5Sryo #ifdef MULTIPROCESSOR
517e677f16fSskrll 		intr_establish_xname(pic->pic_irqbase + LOCALPIC_SOURCE_IPI,
518e677f16fSskrll 		    IPL_HIGH, IST_LEVEL | IST_MPSAFE, apple_intc_ipi_handler,
519e677f16fSskrll 		    pc, "ipi");
52062432df5Sryo #endif
521db7e12daSjmcneill 	}
522db7e12daSjmcneill 
523db7e12daSjmcneill 	apple_intc_cpu_init(&sc->sc_pic, curcpu());
524db7e12daSjmcneill }
525db7e12daSjmcneill 
526db7e12daSjmcneill CFATTACH_DECL_NEW(apple_intc, sizeof(struct apple_intc_softc),
527db7e12daSjmcneill 	apple_intc_match, apple_intc_attach, NULL, NULL);
528