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