bcm2835_intr.c revision 1.15.4.2 1 1.15.4.2 martin /* $NetBSD: bcm2835_intr.c,v 1.15.4.2 2020/04/08 14:07:28 martin Exp $ */
2 1.1 skrll
3 1.1 skrll /*-
4 1.15.4.2 martin * Copyright (c) 2012, 2015, 2019 The NetBSD Foundation, Inc.
5 1.1 skrll * All rights reserved.
6 1.1 skrll *
7 1.1 skrll * This code is derived from software contributed to The NetBSD Foundation
8 1.1 skrll * by Nick Hudson
9 1.1 skrll *
10 1.1 skrll * Redistribution and use in source and binary forms, with or without
11 1.1 skrll * modification, are permitted provided that the following conditions
12 1.1 skrll * are met:
13 1.1 skrll * 1. Redistributions of source code must retain the above copyright
14 1.1 skrll * notice, this list of conditions and the following disclaimer.
15 1.1 skrll * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 skrll * notice, this list of conditions and the following disclaimer in the
17 1.1 skrll * documentation and/or other materials provided with the distribution.
18 1.1 skrll *
19 1.1 skrll * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 skrll * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 skrll * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 skrll * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 skrll * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 skrll * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 skrll * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 skrll * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 skrll * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 skrll * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 skrll * POSSIBILITY OF SUCH DAMAGE.
30 1.1 skrll */
31 1.1 skrll
32 1.1 skrll #include <sys/cdefs.h>
33 1.15.4.2 martin __KERNEL_RCSID(0, "$NetBSD: bcm2835_intr.c,v 1.15.4.2 2020/04/08 14:07:28 martin Exp $");
34 1.1 skrll
35 1.1 skrll #define _INTR_PRIVATE
36 1.1 skrll
37 1.5 skrll #include "opt_bcm283x.h"
38 1.5 skrll
39 1.1 skrll #include <sys/param.h>
40 1.5 skrll #include <sys/bus.h>
41 1.5 skrll #include <sys/cpu.h>
42 1.5 skrll #include <sys/device.h>
43 1.15.4.1 christos #include <sys/kernel.h>
44 1.15.4.1 christos #include <sys/kmem.h>
45 1.1 skrll #include <sys/proc.h>
46 1.1 skrll
47 1.15 skrll #include <dev/fdt/fdtvar.h>
48 1.15 skrll
49 1.1 skrll #include <machine/intr.h>
50 1.5 skrll
51 1.5 skrll #include <arm/locore.h>
52 1.1 skrll
53 1.1 skrll #include <arm/pic/picvar.h>
54 1.5 skrll #include <arm/cortex/gtmr_var.h>
55 1.1 skrll
56 1.15 skrll #include <arm/broadcom/bcm2835_intr.h>
57 1.1 skrll #include <arm/broadcom/bcm2835reg.h>
58 1.5 skrll #include <arm/broadcom/bcm2835var.h>
59 1.1 skrll
60 1.15 skrll #include <arm/fdt/arm_fdtvar.h>
61 1.15 skrll
62 1.15 skrll static void bcm2835_irq_handler(void *);
63 1.15 skrll static void bcm2836mp_intr_init(void *, struct cpu_info *);
64 1.15 skrll
65 1.1 skrll static void bcm2835_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
66 1.1 skrll static void bcm2835_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
67 1.1 skrll static int bcm2835_pic_find_pending_irqs(struct pic_softc *);
68 1.1 skrll static void bcm2835_pic_establish_irq(struct pic_softc *, struct intrsource *);
69 1.1 skrll static void bcm2835_pic_source_name(struct pic_softc *, int, char *,
70 1.1 skrll size_t);
71 1.1 skrll
72 1.5 skrll static void bcm2836mp_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
73 1.5 skrll static void bcm2836mp_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
74 1.5 skrll static int bcm2836mp_pic_find_pending_irqs(struct pic_softc *);
75 1.5 skrll static void bcm2836mp_pic_establish_irq(struct pic_softc *, struct intrsource *);
76 1.5 skrll static void bcm2836mp_pic_source_name(struct pic_softc *, int, char *,
77 1.5 skrll size_t);
78 1.5 skrll #ifdef MULTIPROCESSOR
79 1.5 skrll int bcm2836mp_ipi_handler(void *);
80 1.5 skrll static void bcm2836mp_cpu_init(struct pic_softc *, struct cpu_info *);
81 1.5 skrll static void bcm2836mp_send_ipi(struct pic_softc *, const kcpuset_t *, u_long);
82 1.5 skrll #endif
83 1.15 skrll
84 1.15 skrll static int bcm2835_icu_fdt_decode_irq(u_int *);
85 1.15 skrll static void *bcm2835_icu_fdt_establish(device_t, u_int *, int, int,
86 1.15 skrll int (*)(void *), void *);
87 1.15 skrll static void bcm2835_icu_fdt_disestablish(device_t, void *);
88 1.15 skrll static bool bcm2835_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
89 1.15 skrll
90 1.15.4.2 martin static int bcm2835_icu_intr(void *);
91 1.15.4.2 martin
92 1.15 skrll static int bcm2836mp_icu_fdt_decode_irq(u_int *);
93 1.15 skrll static void *bcm2836mp_icu_fdt_establish(device_t, u_int *, int, int,
94 1.15 skrll int (*)(void *), void *);
95 1.15 skrll static void bcm2836mp_icu_fdt_disestablish(device_t, void *);
96 1.15 skrll static bool bcm2836mp_icu_fdt_intrstr(device_t, u_int *, char *, size_t);
97 1.5 skrll
98 1.1 skrll static int bcm2835_icu_match(device_t, cfdata_t, void *);
99 1.1 skrll static void bcm2835_icu_attach(device_t, device_t, void *);
100 1.1 skrll
101 1.15.4.2 martin static int bcm2835_int_base;
102 1.15.4.2 martin static int bcm2836mp_int_base[BCM2836_NCPUS];
103 1.15.4.2 martin
104 1.15.4.2 martin #define BCM2835_INT_BASE bcm2835_int_base
105 1.15.4.2 martin #define BCM2836_INT_BASECPUN(n) bcm2836mp_int_base[(n)]
106 1.15.4.2 martin
107 1.15 skrll static void
108 1.15 skrll bcm2835_set_priority(struct pic_softc *pic, int ipl)
109 1.15 skrll {
110 1.15 skrll }
111 1.15 skrll
112 1.1 skrll static struct pic_ops bcm2835_picops = {
113 1.1 skrll .pic_unblock_irqs = bcm2835_pic_unblock_irqs,
114 1.1 skrll .pic_block_irqs = bcm2835_pic_block_irqs,
115 1.1 skrll .pic_find_pending_irqs = bcm2835_pic_find_pending_irqs,
116 1.1 skrll .pic_establish_irq = bcm2835_pic_establish_irq,
117 1.1 skrll .pic_source_name = bcm2835_pic_source_name,
118 1.15 skrll .pic_set_priority = bcm2835_set_priority,
119 1.1 skrll };
120 1.1 skrll
121 1.15.4.1 christos static struct pic_softc bcm2835_pic = {
122 1.1 skrll .pic_ops = &bcm2835_picops,
123 1.1 skrll .pic_maxsources = BCM2835_NIRQ,
124 1.1 skrll .pic_name = "bcm2835 pic",
125 1.1 skrll };
126 1.1 skrll
127 1.5 skrll static struct pic_ops bcm2836mp_picops = {
128 1.5 skrll .pic_unblock_irqs = bcm2836mp_pic_unblock_irqs,
129 1.5 skrll .pic_block_irqs = bcm2836mp_pic_block_irqs,
130 1.5 skrll .pic_find_pending_irqs = bcm2836mp_pic_find_pending_irqs,
131 1.5 skrll .pic_establish_irq = bcm2836mp_pic_establish_irq,
132 1.5 skrll .pic_source_name = bcm2836mp_pic_source_name,
133 1.8 skrll #if defined(MULTIPROCESSOR)
134 1.5 skrll .pic_cpu_init = bcm2836mp_cpu_init,
135 1.5 skrll .pic_ipi_send = bcm2836mp_send_ipi,
136 1.5 skrll #endif
137 1.5 skrll };
138 1.5 skrll
139 1.15.4.1 christos static struct pic_softc bcm2836mp_pic[BCM2836_NCPUS] = {
140 1.13 skrll [0 ... BCM2836_NCPUS - 1] = {
141 1.8 skrll .pic_ops = &bcm2836mp_picops,
142 1.8 skrll .pic_maxsources = BCM2836_NIRQPERCPU,
143 1.8 skrll .pic_name = "bcm2836 pic",
144 1.13 skrll }
145 1.5 skrll };
146 1.15 skrll
147 1.15 skrll static struct fdtbus_interrupt_controller_func bcm2835icu_fdt_funcs = {
148 1.15 skrll .establish = bcm2835_icu_fdt_establish,
149 1.15 skrll .disestablish = bcm2835_icu_fdt_disestablish,
150 1.15 skrll .intrstr = bcm2835_icu_fdt_intrstr
151 1.15 skrll };
152 1.15 skrll
153 1.15 skrll static struct fdtbus_interrupt_controller_func bcm2836mpicu_fdt_funcs = {
154 1.15 skrll .establish = bcm2836mp_icu_fdt_establish,
155 1.15 skrll .disestablish = bcm2836mp_icu_fdt_disestablish,
156 1.15 skrll .intrstr = bcm2836mp_icu_fdt_intrstr
157 1.15 skrll };
158 1.5 skrll
159 1.15.4.1 christos struct bcm2836mp_interrupt {
160 1.15.4.1 christos bool bi_done;
161 1.15.4.1 christos TAILQ_ENTRY(bcm2836mp_interrupt) bi_next;
162 1.15.4.1 christos int bi_irq;
163 1.15.4.1 christos int bi_ipl;
164 1.15.4.1 christos int bi_flags;
165 1.15.4.1 christos int (*bi_func)(void *);
166 1.15.4.1 christos void *bi_arg;
167 1.15.4.1 christos void *bi_ihs[BCM2836_NCPUS];
168 1.15.4.1 christos };
169 1.15.4.1 christos
170 1.15.4.1 christos static TAILQ_HEAD(, bcm2836mp_interrupt) bcm2836mp_interrupts =
171 1.15.4.1 christos TAILQ_HEAD_INITIALIZER(bcm2836mp_interrupts);
172 1.15.4.1 christos
173 1.15.4.2 martin struct bcm2835icu_irqhandler;
174 1.15.4.2 martin struct bcm2835icu_irq;
175 1.15.4.2 martin struct bcm2835icu_softc;
176 1.15.4.2 martin
177 1.15.4.2 martin struct bcm2835icu_irqhandler {
178 1.15.4.2 martin struct bcm2835icu_irq *ih_irq;
179 1.15.4.2 martin int (*ih_fn)(void *);
180 1.15.4.2 martin void *ih_arg;
181 1.15.4.2 martin TAILQ_ENTRY(bcm2835icu_irqhandler) ih_next;
182 1.15.4.2 martin };
183 1.15.4.2 martin
184 1.15.4.2 martin struct bcm2835icu_irq {
185 1.15.4.2 martin struct bcm2835icu_softc *intr_sc;
186 1.15.4.2 martin void *intr_ih;
187 1.15.4.2 martin void *intr_arg;
188 1.15.4.2 martin int intr_refcnt;
189 1.15.4.2 martin int intr_ipl;
190 1.15.4.2 martin int intr_irq;
191 1.15.4.2 martin int intr_mpsafe;
192 1.15.4.2 martin TAILQ_HEAD(, bcm2835icu_irqhandler) intr_handlers;
193 1.15.4.2 martin };
194 1.15.4.2 martin
195 1.1 skrll struct bcm2835icu_softc {
196 1.1 skrll device_t sc_dev;
197 1.1 skrll bus_space_tag_t sc_iot;
198 1.1 skrll bus_space_handle_t sc_ioh;
199 1.15 skrll
200 1.15.4.2 martin struct bcm2835icu_irq *sc_irq[BCM2835_NIRQ];
201 1.15.4.2 martin
202 1.15 skrll int sc_phandle;
203 1.1 skrll };
204 1.1 skrll
205 1.15 skrll struct bcm2835icu_softc *bcml1icu_sc;
206 1.1 skrll struct bcm2835icu_softc *bcmicu_sc;
207 1.3 skrll
208 1.1 skrll #define read_bcm2835reg(o) \
209 1.1 skrll bus_space_read_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o))
210 1.3 skrll
211 1.1 skrll #define write_bcm2835reg(o, v) \
212 1.1 skrll bus_space_write_4(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, (o), (v))
213 1.1 skrll
214 1.1 skrll
215 1.1 skrll #define bcm2835_barrier() \
216 1.1 skrll bus_space_barrier(bcmicu_sc->sc_iot, bcmicu_sc->sc_ioh, 0, \
217 1.1 skrll BCM2835_ARMICU_SIZE, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE)
218 1.3 skrll
219 1.1 skrll static const char * const bcm2835_sources[BCM2835_NIRQ] = {
220 1.1 skrll "(unused 0)", "(unused 1)", "(unused 2)", "timer3",
221 1.1 skrll "(unused 4)", "(unused 5)", "(unused 6)", "jpeg",
222 1.2 jakllsch "(unused 8)", "usb", "(unused 10)", "(unused 11)",
223 1.2 jakllsch "(unused 12)", "(unused 13)", "(unused 14)", "(unused 15)",
224 1.4 skrll "dma0", "dma1", "dma2", "dma3",
225 1.4 skrll "dma4", "dma5", "dma6", "dma7",
226 1.4 skrll "dma8", "dma9", "dma10", "dma11",
227 1.4 skrll "dma12", "aux", "(unused 30)", "(unused 31)",
228 1.1 skrll "(unused 32)", "(unused 33)", "(unused 34)", "(unused 35)",
229 1.1 skrll "(unused 36)", "(unused 37)", "(unused 38)", "(unused 39)",
230 1.1 skrll "(unused 40)", "(unused 41)", "(unused 42)", "i2c spl slv",
231 1.1 skrll "(unused 44)", "pwa0", "pwa1", "(unused 47)",
232 1.1 skrll "smi", "gpio[0]", "gpio[1]", "gpio[2]",
233 1.1 skrll "gpio[3]", "i2c", "spi", "pcm",
234 1.12 jmcneill "sdhost", "uart", "(unused 58)", "(unused 59)",
235 1.1 skrll "(unused 60)", "(unused 61)", "emmc", "(unused 63)",
236 1.1 skrll "Timer", "Mailbox", "Doorbell0", "Doorbell1",
237 1.1 skrll "GPU0 Halted", "GPU1 Halted", "Illegal #1", "Illegal #0"
238 1.1 skrll };
239 1.1 skrll
240 1.8 skrll static const char * const bcm2836mp_sources[BCM2836_NIRQPERCPU] = {
241 1.5 skrll "cntpsirq", "cntpnsirq", "cnthpirq", "cntvirq",
242 1.5 skrll "mailbox0", "mailbox1", "mailbox2", "mailbox3",
243 1.15.4.1 christos "gpu", "pmu"
244 1.5 skrll };
245 1.5 skrll
246 1.5 skrll #define BCM2836_INTBIT_GPUPENDING __BIT(8)
247 1.5 skrll
248 1.1 skrll #define BCM2835_INTBIT_PENDING1 __BIT(8)
249 1.1 skrll #define BCM2835_INTBIT_PENDING2 __BIT(9)
250 1.1 skrll #define BCM2835_INTBIT_ARM __BITS(0,7)
251 1.1 skrll #define BCM2835_INTBIT_GPU0 __BITS(10,14)
252 1.1 skrll #define BCM2835_INTBIT_GPU1 __BITS(15,20)
253 1.1 skrll
254 1.1 skrll CFATTACH_DECL_NEW(bcmicu, sizeof(struct bcm2835icu_softc),
255 1.1 skrll bcm2835_icu_match, bcm2835_icu_attach, NULL, NULL);
256 1.1 skrll
257 1.1 skrll static int
258 1.1 skrll bcm2835_icu_match(device_t parent, cfdata_t cf, void *aux)
259 1.1 skrll {
260 1.15 skrll const char * const compatible[] = {
261 1.15 skrll "brcm,bcm2708-armctrl-ic",
262 1.15 skrll "brcm,bcm2709-armctrl-ic",
263 1.15 skrll "brcm,bcm2835-armctrl-ic",
264 1.15 skrll "brcm,bcm2836-armctrl-ic",
265 1.15 skrll "brcm,bcm2836-l1-intc",
266 1.15 skrll NULL
267 1.15 skrll };
268 1.15 skrll struct fdt_attach_args * const faa = aux;
269 1.1 skrll
270 1.15 skrll return of_match_compatible(faa->faa_phandle, compatible);
271 1.1 skrll }
272 1.1 skrll
273 1.1 skrll static void
274 1.1 skrll bcm2835_icu_attach(device_t parent, device_t self, void *aux)
275 1.1 skrll {
276 1.15 skrll struct bcm2835icu_softc * const sc = device_private(self);
277 1.15 skrll struct fdt_attach_args * const faa = aux;
278 1.15 skrll struct fdtbus_interrupt_controller_func *ifuncs;
279 1.15 skrll const int phandle = faa->faa_phandle;
280 1.15 skrll bus_addr_t addr;
281 1.15 skrll bus_size_t size;
282 1.15 skrll bus_space_handle_t ioh;
283 1.15 skrll int error;
284 1.15 skrll
285 1.15 skrll if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
286 1.15 skrll aprint_error(": couldn't get registers\n");
287 1.15 skrll return;
288 1.15 skrll }
289 1.1 skrll
290 1.1 skrll sc->sc_dev = self;
291 1.15 skrll sc->sc_iot = faa->faa_bst;
292 1.1 skrll
293 1.15 skrll if (bus_space_map(sc->sc_iot, addr, size, 0, &ioh) != 0) {
294 1.15 skrll aprint_error(": couldn't map device\n");
295 1.1 skrll return;
296 1.1 skrll }
297 1.1 skrll
298 1.15 skrll sc->sc_ioh = ioh;
299 1.15 skrll sc->sc_phandle = phandle;
300 1.5 skrll
301 1.15 skrll const char * const local_intc[] = { "brcm,bcm2836-l1-intc", NULL };
302 1.15 skrll if (of_match_compatible(faa->faa_phandle, local_intc)) {
303 1.8 skrll #if defined(MULTIPROCESSOR)
304 1.15 skrll aprint_normal(": Multiprocessor");
305 1.5 skrll #endif
306 1.15 skrll bcml1icu_sc = sc;
307 1.5 skrll
308 1.15 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh,
309 1.15 skrll BCM2836_LOCAL_CONTROL, 0);
310 1.15 skrll bus_space_write_4(sc->sc_iot, sc->sc_ioh,
311 1.15 skrll BCM2836_LOCAL_PRESCALER, 0x80000000);
312 1.15 skrll
313 1.15 skrll ifuncs = &bcm2836mpicu_fdt_funcs;
314 1.15 skrll
315 1.15 skrll bcm2836mp_intr_init(self, curcpu());
316 1.15 skrll arm_fdt_cpu_hatch_register(self, bcm2836mp_intr_init);
317 1.15 skrll } else {
318 1.15 skrll if (bcml1icu_sc == NULL)
319 1.15 skrll arm_fdt_irq_set_handler(bcm2835_irq_handler);
320 1.15 skrll bcmicu_sc = sc;
321 1.15 skrll sc->sc_ioh = ioh;
322 1.15 skrll sc->sc_phandle = phandle;
323 1.15.4.2 martin bcm2835_int_base = pic_add(&bcm2835_pic, PIC_IRQBASE_ALLOC);
324 1.15 skrll ifuncs = &bcm2835icu_fdt_funcs;
325 1.15 skrll }
326 1.15 skrll
327 1.15 skrll error = fdtbus_register_interrupt_controller(self, phandle, ifuncs);
328 1.15 skrll if (error != 0) {
329 1.15 skrll aprint_error(": couldn't register with fdtbus: %d\n", error);
330 1.15 skrll return;
331 1.15 skrll }
332 1.1 skrll aprint_normal("\n");
333 1.1 skrll }
334 1.1 skrll
335 1.15 skrll static void
336 1.1 skrll bcm2835_irq_handler(void *frame)
337 1.1 skrll {
338 1.1 skrll struct cpu_info * const ci = curcpu();
339 1.1 skrll const int oldipl = ci->ci_cpl;
340 1.15.4.1 christos const cpuid_t cpuid = ci->ci_core_id;
341 1.1 skrll const uint32_t oldipl_mask = __BIT(oldipl);
342 1.1 skrll int ipl_mask = 0;
343 1.1 skrll
344 1.1 skrll ci->ci_data.cpu_nintr++;
345 1.1 skrll
346 1.1 skrll bcm2835_barrier();
347 1.8 skrll if (cpuid == 0) {
348 1.8 skrll ipl_mask = bcm2835_pic_find_pending_irqs(&bcm2835_pic);
349 1.8 skrll }
350 1.15 skrll #if defined(SOC_BCM2836)
351 1.8 skrll ipl_mask |= bcm2836mp_pic_find_pending_irqs(&bcm2836mp_pic[cpuid]);
352 1.5 skrll #endif
353 1.1 skrll
354 1.1 skrll /*
355 1.1 skrll * Record the pending_ipls and deliver them if we can.
356 1.1 skrll */
357 1.1 skrll if ((ipl_mask & ~oldipl_mask) > oldipl_mask)
358 1.1 skrll pic_do_pending_ints(I32_bit, oldipl, frame);
359 1.1 skrll }
360 1.1 skrll
361 1.1 skrll static void
362 1.1 skrll bcm2835_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
363 1.1 skrll uint32_t irq_mask)
364 1.1 skrll {
365 1.1 skrll
366 1.1 skrll write_bcm2835reg(BCM2835_INTC_ENABLEBASE + (irqbase >> 3), irq_mask);
367 1.1 skrll bcm2835_barrier();
368 1.1 skrll }
369 1.1 skrll
370 1.1 skrll static void
371 1.1 skrll bcm2835_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
372 1.1 skrll uint32_t irq_mask)
373 1.1 skrll {
374 1.1 skrll
375 1.1 skrll write_bcm2835reg(BCM2835_INTC_DISABLEBASE + (irqbase >> 3), irq_mask);
376 1.1 skrll bcm2835_barrier();
377 1.1 skrll }
378 1.1 skrll
379 1.1 skrll /*
380 1.1 skrll * Called with interrupts disabled
381 1.1 skrll */
382 1.1 skrll static int
383 1.1 skrll bcm2835_pic_find_pending_irqs(struct pic_softc *pic)
384 1.1 skrll {
385 1.1 skrll int ipl = 0;
386 1.1 skrll uint32_t bpending, gpu0irq, gpu1irq, armirq;
387 1.1 skrll
388 1.1 skrll bcm2835_barrier();
389 1.1 skrll bpending = read_bcm2835reg(BCM2835_INTC_IRQBPENDING);
390 1.1 skrll if (bpending == 0)
391 1.1 skrll return 0;
392 1.1 skrll
393 1.1 skrll armirq = bpending & BCM2835_INTBIT_ARM;
394 1.1 skrll gpu0irq = bpending & BCM2835_INTBIT_GPU0;
395 1.1 skrll gpu1irq = bpending & BCM2835_INTBIT_GPU1;
396 1.1 skrll
397 1.1 skrll if (armirq) {
398 1.8 skrll ipl |= pic_mark_pending_sources(pic,
399 1.8 skrll BCM2835_INT_BASICBASE - BCM2835_INT_BASE, armirq);
400 1.1 skrll }
401 1.1 skrll
402 1.1 skrll if (gpu0irq || (bpending & BCM2835_INTBIT_PENDING1)) {
403 1.1 skrll uint32_t pending1;
404 1.3 skrll
405 1.1 skrll pending1 = read_bcm2835reg(BCM2835_INTC_IRQ1PENDING);
406 1.8 skrll ipl |= pic_mark_pending_sources(pic,
407 1.8 skrll BCM2835_INT_GPU0BASE - BCM2835_INT_BASE, pending1);
408 1.1 skrll }
409 1.1 skrll if (gpu1irq || (bpending & BCM2835_INTBIT_PENDING2)) {
410 1.1 skrll uint32_t pending2;
411 1.3 skrll
412 1.1 skrll pending2 = read_bcm2835reg(BCM2835_INTC_IRQ2PENDING);
413 1.8 skrll ipl |= pic_mark_pending_sources(pic,
414 1.8 skrll BCM2835_INT_GPU1BASE - BCM2835_INT_BASE, pending2);
415 1.1 skrll }
416 1.3 skrll
417 1.1 skrll return ipl;
418 1.1 skrll }
419 1.1 skrll
420 1.1 skrll static void
421 1.1 skrll bcm2835_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
422 1.1 skrll {
423 1.1 skrll
424 1.1 skrll /* Nothing really*/
425 1.1 skrll KASSERT(is->is_irq < BCM2835_NIRQ);
426 1.1 skrll KASSERT(is->is_type == IST_LEVEL);
427 1.1 skrll }
428 1.1 skrll
429 1.1 skrll static void
430 1.1 skrll bcm2835_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
431 1.1 skrll {
432 1.1 skrll
433 1.1 skrll strlcpy(buf, bcm2835_sources[irq], len);
434 1.1 skrll }
435 1.5 skrll
436 1.15 skrll static int
437 1.15 skrll bcm2835_icu_fdt_decode_irq(u_int *specifier)
438 1.15 skrll {
439 1.15 skrll u_int base;
440 1.15 skrll
441 1.15 skrll if (!specifier)
442 1.15 skrll return -1;
443 1.15 skrll
444 1.15 skrll /* 1st cell is the bank number. 0 = ARM, 1 = GPU0, 2 = GPU1 */
445 1.15 skrll /* 2nd cell is the irq relative to that bank */
446 1.15 skrll
447 1.15 skrll const u_int bank = be32toh(specifier[0]);
448 1.15 skrll switch (bank) {
449 1.15 skrll case 0:
450 1.15 skrll base = BCM2835_INT_BASICBASE;
451 1.15 skrll break;
452 1.15 skrll case 1:
453 1.15 skrll base = BCM2835_INT_GPU0BASE;
454 1.15 skrll break;
455 1.15 skrll case 2:
456 1.15 skrll base = BCM2835_INT_GPU1BASE;
457 1.15 skrll break;
458 1.15 skrll default:
459 1.15 skrll return -1;
460 1.15 skrll }
461 1.15 skrll const u_int off = be32toh(specifier[1]);
462 1.15 skrll
463 1.15 skrll return base + off;
464 1.15 skrll }
465 1.15 skrll
466 1.15 skrll static void *
467 1.15 skrll bcm2835_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
468 1.15 skrll int (*func)(void *), void *arg)
469 1.15 skrll {
470 1.15.4.2 martin struct bcm2835icu_softc * const sc = device_private(dev);
471 1.15.4.2 martin struct bcm2835icu_irq *firq;
472 1.15.4.2 martin struct bcm2835icu_irqhandler *firqh;
473 1.15 skrll int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
474 1.15.4.2 martin int irq, irqidx;
475 1.15 skrll
476 1.15 skrll irq = bcm2835_icu_fdt_decode_irq(specifier);
477 1.15 skrll if (irq == -1)
478 1.15 skrll return NULL;
479 1.15.4.2 martin irqidx = irq - BCM2835_INT_BASE;
480 1.15.4.2 martin
481 1.15.4.2 martin KASSERT(irqidx < BCM2835_NIRQ);
482 1.15.4.2 martin
483 1.15.4.2 martin firq = sc->sc_irq[irqidx];
484 1.15.4.2 martin if (firq == NULL) {
485 1.15.4.2 martin firq = kmem_alloc(sizeof(*firq), KM_SLEEP);
486 1.15.4.2 martin firq->intr_sc = sc;
487 1.15.4.2 martin firq->intr_refcnt = 0;
488 1.15.4.2 martin firq->intr_arg = arg;
489 1.15.4.2 martin firq->intr_ipl = ipl;
490 1.15.4.2 martin firq->intr_mpsafe = iflags;
491 1.15.4.2 martin firq->intr_irq = irq;
492 1.15.4.2 martin TAILQ_INIT(&firq->intr_handlers);
493 1.15.4.2 martin if (arg == NULL) {
494 1.15.4.2 martin firq->intr_ih = intr_establish(irq, ipl,
495 1.15.4.2 martin IST_LEVEL | iflags, func, NULL);
496 1.15.4.2 martin } else {
497 1.15.4.2 martin firq->intr_ih = intr_establish(irq, ipl,
498 1.15.4.2 martin IST_LEVEL | iflags, bcm2835_icu_intr, firq);
499 1.15.4.2 martin }
500 1.15.4.2 martin if (firq->intr_ih == NULL) {
501 1.15.4.2 martin kmem_free(firq, sizeof(*firq));
502 1.15.4.2 martin return NULL;
503 1.15.4.2 martin }
504 1.15.4.2 martin sc->sc_irq[irqidx] = firq;
505 1.15.4.2 martin } else {
506 1.15.4.2 martin if (firq->intr_arg == NULL || arg == NULL) {
507 1.15.4.2 martin device_printf(dev,
508 1.15.4.2 martin "cannot share irq with NULL-arg handler\n");
509 1.15.4.2 martin return NULL;
510 1.15.4.2 martin }
511 1.15.4.2 martin if (firq->intr_ipl != ipl) {
512 1.15.4.2 martin device_printf(dev,
513 1.15.4.2 martin "cannot share irq with different ipl\n");
514 1.15.4.2 martin return NULL;
515 1.15.4.2 martin }
516 1.15.4.2 martin if (firq->intr_mpsafe != iflags) {
517 1.15.4.2 martin device_printf(dev,
518 1.15.4.2 martin "cannot share irq between mpsafe/non-mpsafe\n");
519 1.15.4.2 martin return NULL;
520 1.15.4.2 martin }
521 1.15.4.2 martin }
522 1.5 skrll
523 1.15.4.2 martin firqh = kmem_alloc(sizeof(*firqh), KM_SLEEP);
524 1.15.4.2 martin firqh->ih_irq = firq;
525 1.15.4.2 martin firqh->ih_fn = func;
526 1.15.4.2 martin firqh->ih_arg = arg;
527 1.15.4.2 martin
528 1.15.4.2 martin firq->intr_refcnt++;
529 1.15.4.2 martin TAILQ_INSERT_TAIL(&firq->intr_handlers, firqh, ih_next);
530 1.15.4.2 martin
531 1.15.4.2 martin /*
532 1.15.4.2 martin * XXX interrupt_distribute(9) assumes that any interrupt
533 1.15.4.2 martin * handle can be used as an input to the MD interrupt_distribute
534 1.15.4.2 martin * implementationm, so we are forced to return the handle
535 1.15.4.2 martin * we got back from intr_establish(). Upshot is that the
536 1.15.4.2 martin * input to bcm2835_icu_fdt_disestablish() is ambiguous for
537 1.15.4.2 martin * shared IRQs, rendering them un-disestablishable.
538 1.15.4.2 martin */
539 1.15.4.2 martin
540 1.15.4.2 martin return firq->intr_ih;
541 1.15 skrll }
542 1.15 skrll
543 1.15 skrll static void
544 1.15 skrll bcm2835_icu_fdt_disestablish(device_t dev, void *ih)
545 1.15 skrll {
546 1.15.4.2 martin struct bcm2835icu_softc * const sc = device_private(dev);
547 1.15.4.2 martin struct bcm2835icu_irqhandler *firqh;
548 1.15.4.2 martin struct bcm2835icu_irq *firq;
549 1.15.4.2 martin u_int n;
550 1.15.4.2 martin
551 1.15.4.2 martin for (n = 0; n < BCM2835_NIRQ; n++) {
552 1.15.4.2 martin firq = sc->sc_irq[n];
553 1.15.4.2 martin if (firq == NULL || firq->intr_ih != ih)
554 1.15.4.2 martin continue;
555 1.15.4.2 martin
556 1.15.4.2 martin KASSERT(firq->intr_refcnt > 0);
557 1.15.4.2 martin KASSERT(n == (firq->intr_irq - BCM2835_INT_BASE));
558 1.15.4.2 martin
559 1.15.4.2 martin /* XXX see above */
560 1.15.4.2 martin if (firq->intr_refcnt > 1)
561 1.15.4.2 martin panic("%s: cannot disestablish shared irq", __func__);
562 1.15.4.2 martin
563 1.15.4.2 martin intr_disestablish(firq->intr_ih);
564 1.15.4.2 martin
565 1.15.4.2 martin firqh = TAILQ_FIRST(&firq->intr_handlers);
566 1.15.4.2 martin TAILQ_REMOVE(&firq->intr_handlers, firqh, ih_next);
567 1.15.4.2 martin kmem_free(firqh, sizeof(*firqh));
568 1.15.4.2 martin
569 1.15.4.2 martin sc->sc_irq[n] = NULL;
570 1.15.4.2 martin kmem_free(firq, sizeof(*firq));
571 1.15.4.2 martin
572 1.15.4.2 martin return;
573 1.15.4.2 martin }
574 1.15.4.2 martin
575 1.15.4.2 martin panic("%s: interrupt not established", __func__);
576 1.15.4.2 martin }
577 1.15.4.2 martin
578 1.15.4.2 martin static int
579 1.15.4.2 martin bcm2835_icu_intr(void *priv)
580 1.15.4.2 martin {
581 1.15.4.2 martin struct bcm2835icu_irq *firq = priv;
582 1.15.4.2 martin struct bcm2835icu_irqhandler *firqh;
583 1.15.4.2 martin int handled = 0;
584 1.15.4.2 martin
585 1.15.4.2 martin TAILQ_FOREACH(firqh, &firq->intr_handlers, ih_next) {
586 1.15.4.2 martin handled |= firqh->ih_fn(firqh->ih_arg);
587 1.15.4.2 martin }
588 1.15.4.2 martin
589 1.15.4.2 martin return handled;
590 1.15 skrll }
591 1.15 skrll
592 1.15 skrll static bool
593 1.15 skrll bcm2835_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen)
594 1.15 skrll {
595 1.15 skrll int irq;
596 1.15 skrll
597 1.15 skrll irq = bcm2835_icu_fdt_decode_irq(specifier);
598 1.15 skrll if (irq == -1)
599 1.15 skrll return false;
600 1.15 skrll
601 1.15 skrll snprintf(buf, buflen, "icu irq %d", irq);
602 1.15 skrll
603 1.15 skrll return true;
604 1.15 skrll }
605 1.5 skrll
606 1.5 skrll #define BCM2836MP_TIMER_IRQS __BITS(3,0)
607 1.15.4.1 christos #define BCM2836MP_MAILBOX_IRQS __BITS(4,7)
608 1.15.4.1 christos #define BCM2836MP_GPU_IRQ __BIT(8)
609 1.15.4.1 christos #define BCM2836MP_PMU_IRQ __BIT(9)
610 1.15.4.1 christos #define BCM2836MP_ALL_IRQS (BCM2836MP_TIMER_IRQS | BCM2836MP_MAILBOX_IRQS | BCM2836MP_GPU_IRQ | BCM2836MP_PMU_IRQ)
611 1.5 skrll
612 1.5 skrll static void
613 1.5 skrll bcm2836mp_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
614 1.5 skrll uint32_t irq_mask)
615 1.5 skrll {
616 1.15 skrll const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
617 1.15 skrll const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
618 1.15.4.1 christos const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
619 1.5 skrll
620 1.8 skrll KASSERT(irqbase == 0);
621 1.5 skrll
622 1.5 skrll if (irq_mask & BCM2836MP_TIMER_IRQS) {
623 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
624 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
625 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
626 1.5 skrll val |= mask;
627 1.15 skrll bus_space_write_4(iot, ioh,
628 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
629 1.5 skrll val);
630 1.15 skrll bus_space_barrier(iot, ioh,
631 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROL_BASE,
632 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROL_SIZE,
633 1.5 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
634 1.10 skrll }
635 1.10 skrll if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
636 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
637 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
638 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
639 1.5 skrll val |= mask;
640 1.15 skrll bus_space_write_4(iot, ioh,
641 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
642 1.5 skrll val);
643 1.15 skrll bus_space_barrier(iot, ioh,
644 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_BASE,
645 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROL_SIZE,
646 1.5 skrll BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
647 1.5 skrll }
648 1.15.4.1 christos if (irq_mask & BCM2836MP_PMU_IRQ) {
649 1.15.4.1 christos bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET,
650 1.15.4.1 christos __BIT(cpuid));
651 1.15.4.1 christos bus_space_barrier(iot, ioh, BCM2836_LOCAL_PM_ROUTING_SET, 4,
652 1.15.4.1 christos BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
653 1.15.4.1 christos }
654 1.5 skrll
655 1.5 skrll return;
656 1.5 skrll }
657 1.5 skrll
658 1.5 skrll static void
659 1.5 skrll bcm2836mp_pic_block_irqs(struct pic_softc *pic, size_t irqbase,
660 1.5 skrll uint32_t irq_mask)
661 1.5 skrll {
662 1.15 skrll const bus_space_tag_t iot = bcml1icu_sc->sc_iot;
663 1.15 skrll const bus_space_handle_t ioh = bcml1icu_sc->sc_ioh;
664 1.15.4.1 christos const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
665 1.8 skrll
666 1.8 skrll KASSERT(irqbase == 0);
667 1.5 skrll
668 1.5 skrll if (irq_mask & BCM2836MP_TIMER_IRQS) {
669 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_TIMER_IRQS);
670 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
671 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid));
672 1.5 skrll val &= ~mask;
673 1.15 skrll bus_space_write_4(iot, ioh,
674 1.5 skrll BCM2836_LOCAL_TIMER_IRQ_CONTROLN(cpuid),
675 1.5 skrll val);
676 1.10 skrll }
677 1.10 skrll if (irq_mask & BCM2836MP_MAILBOX_IRQS) {
678 1.5 skrll uint32_t mask = __SHIFTOUT(irq_mask, BCM2836MP_MAILBOX_IRQS);
679 1.15 skrll uint32_t val = bus_space_read_4(iot, ioh,
680 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid));
681 1.5 skrll val &= ~mask;
682 1.15 skrll bus_space_write_4(iot, ioh,
683 1.5 skrll BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(cpuid),
684 1.5 skrll val);
685 1.5 skrll }
686 1.15.4.1 christos if (irq_mask & BCM2836MP_PMU_IRQ) {
687 1.15.4.1 christos bus_space_write_4(iot, ioh, BCM2836_LOCAL_PM_ROUTING_CLR,
688 1.15.4.1 christos __BIT(cpuid));
689 1.15.4.1 christos }
690 1.5 skrll
691 1.5 skrll bcm2835_barrier();
692 1.5 skrll return;
693 1.5 skrll }
694 1.5 skrll
695 1.5 skrll static int
696 1.5 skrll bcm2836mp_pic_find_pending_irqs(struct pic_softc *pic)
697 1.5 skrll {
698 1.8 skrll struct cpu_info * const ci = curcpu();
699 1.15.4.1 christos const cpuid_t cpuid = ci->ci_core_id;
700 1.5 skrll uint32_t lpending;
701 1.5 skrll int ipl = 0;
702 1.5 skrll
703 1.8 skrll KASSERT(pic == &bcm2836mp_pic[cpuid]);
704 1.8 skrll
705 1.5 skrll bcm2835_barrier();
706 1.5 skrll
707 1.15 skrll lpending = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
708 1.5 skrll BCM2836_LOCAL_INTC_IRQPENDINGN(cpuid));
709 1.5 skrll
710 1.5 skrll lpending &= ~BCM2836_INTBIT_GPUPENDING;
711 1.15.4.2 martin const uint32_t allirqs = lpending & BCM2836MP_ALL_IRQS;
712 1.15.4.2 martin if (allirqs) {
713 1.15.4.2 martin ipl |= pic_mark_pending_sources(pic, 0, allirqs);
714 1.5 skrll }
715 1.5 skrll
716 1.5 skrll return ipl;
717 1.5 skrll }
718 1.5 skrll
719 1.5 skrll static void
720 1.5 skrll bcm2836mp_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
721 1.5 skrll {
722 1.5 skrll /* Nothing really*/
723 1.5 skrll KASSERT(is->is_irq >= 0);
724 1.8 skrll KASSERT(is->is_irq < BCM2836_NIRQPERCPU);
725 1.8 skrll }
726 1.8 skrll
727 1.8 skrll static void
728 1.8 skrll bcm2836mp_pic_source_name(struct pic_softc *pic, int irq, char *buf, size_t len)
729 1.8 skrll {
730 1.8 skrll
731 1.8 skrll irq %= BCM2836_NIRQPERCPU;
732 1.8 skrll strlcpy(buf, bcm2836mp_sources[irq], len);
733 1.8 skrll }
734 1.5 skrll
735 1.5 skrll
736 1.15 skrll #if defined(MULTIPROCESSOR)
737 1.8 skrll static void bcm2836mp_cpu_init(struct pic_softc *pic, struct cpu_info *ci)
738 1.8 skrll {
739 1.8 skrll
740 1.8 skrll /* Enable IRQ and not FIQ */
741 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
742 1.15.4.1 christos BCM2836_LOCAL_MAILBOX_IRQ_CONTROLN(ci->ci_core_id), 1);
743 1.5 skrll }
744 1.5 skrll
745 1.5 skrll static void
746 1.8 skrll bcm2836mp_send_ipi(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi)
747 1.8 skrll {
748 1.10 skrll KASSERT(pic != NULL);
749 1.10 skrll KASSERT(pic != &bcm2835_pic);
750 1.10 skrll KASSERT(pic->pic_cpus != NULL);
751 1.10 skrll
752 1.8 skrll const cpuid_t cpuid = pic - &bcm2836mp_pic[0];
753 1.8 skrll
754 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
755 1.9 jmcneill BCM2836_LOCAL_MAILBOX0_SETN(cpuid), __BIT(ipi));
756 1.8 skrll }
757 1.8 skrll
758 1.8 skrll int
759 1.8 skrll bcm2836mp_ipi_handler(void *priv)
760 1.8 skrll {
761 1.8 skrll const struct cpu_info *ci = curcpu();
762 1.15.4.1 christos const cpuid_t cpuid = ci->ci_core_id;
763 1.9 jmcneill uint32_t ipimask, bit;
764 1.9 jmcneill
765 1.15 skrll ipimask = bus_space_read_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
766 1.8 skrll BCM2836_LOCAL_MAILBOX0_CLRN(cpuid));
767 1.15 skrll bus_space_write_4(bcml1icu_sc->sc_iot, bcml1icu_sc->sc_ioh,
768 1.15 skrll BCM2836_LOCAL_MAILBOX0_CLRN(cpuid), ipimask);
769 1.8 skrll
770 1.9 jmcneill while ((bit = ffs(ipimask)) > 0) {
771 1.9 jmcneill const u_int ipi = bit - 1;
772 1.9 jmcneill switch (ipi) {
773 1.9 jmcneill case IPI_AST:
774 1.11 skrll pic_ipi_ast(priv);
775 1.11 skrll break;
776 1.9 jmcneill case IPI_NOP:
777 1.11 skrll pic_ipi_nop(priv);
778 1.11 skrll break;
779 1.9 jmcneill #ifdef __HAVE_PREEMPTION
780 1.9 jmcneill case IPI_KPREEMPT:
781 1.11 skrll pic_ipi_kpreempt(priv);
782 1.11 skrll break;
783 1.9 jmcneill #endif
784 1.9 jmcneill case IPI_XCALL:
785 1.9 jmcneill pic_ipi_xcall(priv);
786 1.9 jmcneill break;
787 1.9 jmcneill case IPI_GENERIC:
788 1.9 jmcneill pic_ipi_generic(priv);
789 1.9 jmcneill break;
790 1.9 jmcneill case IPI_SHOOTDOWN:
791 1.9 jmcneill pic_ipi_shootdown(priv);
792 1.9 jmcneill break;
793 1.8 skrll #ifdef DDB
794 1.9 jmcneill case IPI_DDB:
795 1.9 jmcneill pic_ipi_ddb(priv);
796 1.9 jmcneill break;
797 1.8 skrll #endif
798 1.9 jmcneill }
799 1.9 jmcneill ipimask &= ~__BIT(ipi);
800 1.8 skrll }
801 1.8 skrll
802 1.8 skrll return 1;
803 1.8 skrll }
804 1.15 skrll #endif
805 1.8 skrll
806 1.15 skrll static void
807 1.15 skrll bcm2836mp_intr_init(void *priv, struct cpu_info *ci)
808 1.5 skrll {
809 1.15.4.1 christos const cpuid_t cpuid = ci->ci_core_id;
810 1.8 skrll struct pic_softc * const pic = &bcm2836mp_pic[cpuid];
811 1.8 skrll
812 1.15 skrll #if defined(MULTIPROCESSOR)
813 1.8 skrll pic->pic_cpus = ci->ci_kcpuset;
814 1.15.4.1 christos
815 1.15.4.1 christos /*
816 1.15.4.1 christos * Append "#n" to avoid duplication of .pic_name[]
817 1.15.4.1 christos * It should be a unique id for intr_get_source()
818 1.15.4.1 christos */
819 1.15.4.1 christos char suffix[sizeof("#00000")];
820 1.15.4.1 christos snprintf(suffix, sizeof(suffix), "#%lu", cpuid);
821 1.15.4.1 christos strlcat(pic->pic_name, suffix, sizeof(pic->pic_name));
822 1.15 skrll #endif
823 1.15.4.2 martin bcm2836mp_int_base[cpuid] = pic_add(pic, PIC_IRQBASE_ALLOC);
824 1.8 skrll
825 1.15 skrll #if defined(MULTIPROCESSOR)
826 1.10 skrll intr_establish(BCM2836_INT_MAILBOX0_CPUN(cpuid), IPL_HIGH,
827 1.8 skrll IST_LEVEL | IST_MPSAFE, bcm2836mp_ipi_handler, NULL);
828 1.8 skrll
829 1.15.4.1 christos struct bcm2836mp_interrupt *bip;
830 1.15.4.1 christos TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
831 1.15.4.1 christos if (bip->bi_done)
832 1.15.4.1 christos continue;
833 1.15.4.1 christos
834 1.15.4.1 christos const int irq = BCM2836_INT_BASECPUN(cpuid) + bip->bi_irq;
835 1.15.4.1 christos void *ih = intr_establish(irq, bip->bi_ipl,
836 1.15.4.1 christos IST_LEVEL | bip->bi_flags, bip->bi_func, bip->bi_arg);
837 1.15.4.1 christos
838 1.15.4.1 christos bip->bi_ihs[cpuid] = ih;
839 1.15.4.1 christos }
840 1.15 skrll #endif
841 1.5 skrll }
842 1.8 skrll
843 1.15 skrll static int
844 1.15 skrll bcm2836mp_icu_fdt_decode_irq(u_int *specifier)
845 1.15 skrll {
846 1.15 skrll if (!specifier)
847 1.15 skrll return -1;
848 1.15.4.1 christos return be32toh(specifier[0]);
849 1.15 skrll }
850 1.15 skrll
851 1.15 skrll static void *
852 1.15 skrll bcm2836mp_icu_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags,
853 1.15 skrll int (*func)(void *), void *arg)
854 1.15 skrll {
855 1.15 skrll int iflags = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0;
856 1.15.4.1 christos struct bcm2836mp_interrupt *bip;
857 1.15.4.1 christos void *ih;
858 1.15 skrll
859 1.15.4.1 christos int irq = bcm2836mp_icu_fdt_decode_irq(specifier);
860 1.15 skrll if (irq == -1)
861 1.15 skrll return NULL;
862 1.15 skrll
863 1.15.4.1 christos TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
864 1.15.4.1 christos if (irq == bip->bi_irq)
865 1.15.4.1 christos return NULL;
866 1.15.4.1 christos }
867 1.15.4.1 christos
868 1.15.4.1 christos bip = kmem_alloc(sizeof(*bip), KM_SLEEP);
869 1.15.4.1 christos if (bip == NULL)
870 1.15.4.1 christos return NULL;
871 1.15.4.1 christos
872 1.15.4.1 christos bip->bi_done = false;
873 1.15.4.1 christos bip->bi_irq = irq;
874 1.15.4.1 christos bip->bi_ipl = ipl;
875 1.15.4.1 christos bip->bi_flags = IST_LEVEL | iflags;
876 1.15.4.1 christos bip->bi_func = func;
877 1.15.4.1 christos bip->bi_arg = arg;
878 1.15.4.1 christos
879 1.15.4.1 christos /*
880 1.15.4.1 christos * If we're not cold and the BPs have been started then we can register the
881 1.15.4.1 christos * interupt for all CPUs now, e.g. PMU
882 1.15.4.1 christos */
883 1.15.4.1 christos if (!cold) {
884 1.15.4.1 christos for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++) {
885 1.15.4.1 christos ih = intr_establish(BCM2836_INT_BASECPUN(cpuid) + irq, ipl,
886 1.15.4.1 christos IST_LEVEL | iflags, func, arg);
887 1.15.4.1 christos if (!ih) {
888 1.15.4.1 christos kmem_free(bip, sizeof(*bip));
889 1.15.4.1 christos return NULL;
890 1.15.4.1 christos }
891 1.15.4.1 christos bip->bi_ihs[cpuid] = ih;
892 1.15.4.1 christos
893 1.15.4.1 christos }
894 1.15.4.1 christos bip->bi_done = true;
895 1.15.4.1 christos ih = bip->bi_ihs[0];
896 1.15.4.1 christos goto done;
897 1.15.4.1 christos }
898 1.15.4.1 christos
899 1.15.4.1 christos /*
900 1.15.4.1 christos * Otherwise we can only establish the interrupt for the BP and
901 1.15.4.1 christos * delay until bcm2836mp_intr_init is called for each AP, e.g.
902 1.15.4.1 christos * gtmr
903 1.15.4.1 christos */
904 1.15.4.1 christos ih = intr_establish(BCM2836_INT_BASECPUN(0) + irq, ipl,
905 1.15.4.1 christos IST_LEVEL | iflags, func, arg);
906 1.15.4.1 christos if (!ih) {
907 1.15.4.1 christos kmem_free(bip, sizeof(*bip));
908 1.15.4.1 christos return NULL;
909 1.15.4.1 christos }
910 1.15.4.1 christos
911 1.15.4.1 christos bip->bi_ihs[0] = ih;
912 1.15.4.1 christos for (cpuid_t cpuid = 1; cpuid < BCM2836_NCPUS; cpuid++)
913 1.15.4.1 christos bip->bi_ihs[cpuid] = NULL;
914 1.15.4.1 christos
915 1.15.4.1 christos done:
916 1.15.4.1 christos TAILQ_INSERT_TAIL(&bcm2836mp_interrupts, bip, bi_next);
917 1.15.4.1 christos
918 1.15.4.1 christos /*
919 1.15.4.1 christos * Return the intr_establish handle for cpu 0 for API compatibility.
920 1.15.4.1 christos * Any cpu would do here as these sources don't support set_affinity
921 1.15.4.1 christos * when the handle is used in interrupt_distribute(9)
922 1.15.4.1 christos */
923 1.15.4.1 christos return ih;
924 1.15 skrll }
925 1.15 skrll
926 1.15 skrll static void
927 1.15 skrll bcm2836mp_icu_fdt_disestablish(device_t dev, void *ih)
928 1.15 skrll {
929 1.15.4.1 christos struct bcm2836mp_interrupt *bip;
930 1.15.4.1 christos
931 1.15.4.1 christos TAILQ_FOREACH(bip, &bcm2836mp_interrupts, bi_next) {
932 1.15.4.1 christos if (bip->bi_ihs[0] == ih)
933 1.15.4.1 christos break;
934 1.15.4.1 christos }
935 1.15.4.1 christos
936 1.15.4.1 christos if (bip == NULL)
937 1.15.4.1 christos return;
938 1.15.4.1 christos
939 1.15.4.1 christos for (cpuid_t cpuid = 0; cpuid < BCM2836_NCPUS; cpuid++)
940 1.15.4.1 christos intr_disestablish(bip->bi_ihs[cpuid]);
941 1.15.4.1 christos
942 1.15.4.1 christos TAILQ_REMOVE(&bcm2836mp_interrupts, bip, bi_next);
943 1.15.4.1 christos
944 1.15.4.1 christos kmem_free(bip, sizeof(*bip));
945 1.15 skrll }
946 1.15 skrll
947 1.15 skrll static bool
948 1.15 skrll bcm2836mp_icu_fdt_intrstr(device_t dev, u_int *specifier, char *buf,
949 1.15 skrll size_t buflen)
950 1.15 skrll {
951 1.15 skrll int irq;
952 1.15 skrll
953 1.15 skrll irq = bcm2836mp_icu_fdt_decode_irq(specifier);
954 1.15 skrll if (irq == -1)
955 1.15 skrll return false;
956 1.15 skrll
957 1.15 skrll snprintf(buf, buflen, "local_intc irq %d", irq);
958 1.15 skrll
959 1.15 skrll return true;
960 1.15 skrll }
961