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