1 1.9 jmcneill /* $NetBSD: apple_intc.c,v 1.9 2022/06/28 10:42:22 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.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.9 jmcneill __KERNEL_RCSID(0, "$NetBSD: apple_intc.c,v 1.9 2022/06/28 10:42:22 jmcneill 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.7 riastrad #define PICTOSOFTC(pic) container_of(pic, struct apple_intc_softc, sc_pic) 116 1.7 riastrad #define PICTOPERCPU(pic) container_of(pic, struct apple_intc_percpu, pc_pic) 117 1.1 jmcneill 118 1.1 jmcneill #define AIC_READ(sc, reg) \ 119 1.1 jmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 120 1.1 jmcneill #define AIC_WRITE(sc, reg, val) \ 121 1.1 jmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 122 1.1 jmcneill 123 1.1 jmcneill static void 124 1.1 jmcneill apple_intc_unblock_irqs(struct pic_softc *pic, size_t irqbase, uint32_t mask) 125 1.1 jmcneill { 126 1.1 jmcneill struct apple_intc_softc * const sc = PICTOSOFTC(pic); 127 1.1 jmcneill 128 1.1 jmcneill AIC_WRITE(sc, AIC_SW_SET(irqbase), mask); 129 1.1 jmcneill AIC_WRITE(sc, AIC_MASK_CLR(irqbase), mask); 130 1.1 jmcneill } 131 1.1 jmcneill 132 1.1 jmcneill static void 133 1.1 jmcneill apple_intc_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t mask) 134 1.1 jmcneill { 135 1.1 jmcneill } 136 1.1 jmcneill 137 1.1 jmcneill static void 138 1.1 jmcneill apple_intc_establish_irq(struct pic_softc *pic, struct intrsource *is) 139 1.1 jmcneill { 140 1.1 jmcneill struct apple_intc_softc * const sc = PICTOSOFTC(pic); 141 1.1 jmcneill 142 1.1 jmcneill KASSERT(is->is_type == IST_LEVEL); 143 1.1 jmcneill 144 1.1 jmcneill /* Route to primary PE by default */ 145 1.1 jmcneill AIC_WRITE(sc, AIC_AFFINITY(is->is_irq), __BIT(0)); 146 1.1 jmcneill AIC_WRITE(sc, AIC_MASK_CLR(is->is_irq), 147 1.1 jmcneill AIC_MASK_BIT(is->is_irq)); 148 1.1 jmcneill } 149 1.1 jmcneill 150 1.1 jmcneill static void 151 1.1 jmcneill apple_intc_set_priority(struct pic_softc *pic, int ipl) 152 1.1 jmcneill { 153 1.9 jmcneill curcpu()->ci_cpl = ipl; 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.3 ryo #ifdef MULTIPROCESSOR 171 1.1 jmcneill .pic_cpu_init = apple_intc_cpu_init, 172 1.3 ryo #endif 173 1.1 jmcneill }; 174 1.1 jmcneill 175 1.1 jmcneill static void 176 1.1 jmcneill apple_intc_local_unblock_irqs(struct pic_softc *pic, size_t irqbase, 177 1.1 jmcneill uint32_t mask) 178 1.1 jmcneill { 179 1.1 jmcneill KASSERT(irqbase == 0); 180 1.1 jmcneill 181 1.1 jmcneill if ((mask & __BIT(LOCALPIC_SOURCE_TIMER)) != 0) { 182 1.1 jmcneill gtmr_cntv_ctl_write(gtmr_cntv_ctl_read() & ~CNTCTL_IMASK); 183 1.1 jmcneill isb(); 184 1.1 jmcneill } 185 1.1 jmcneill } 186 1.1 jmcneill 187 1.1 jmcneill static void 188 1.1 jmcneill apple_intc_local_block_irqs(struct pic_softc *pic, size_t irqbase, 189 1.1 jmcneill uint32_t mask) 190 1.1 jmcneill { 191 1.1 jmcneill KASSERT(irqbase == 0); 192 1.1 jmcneill 193 1.1 jmcneill if ((mask & __BIT(LOCALPIC_SOURCE_TIMER)) != 0) { 194 1.1 jmcneill gtmr_cntv_ctl_write(gtmr_cntv_ctl_read() | CNTCTL_IMASK); 195 1.1 jmcneill isb(); 196 1.1 jmcneill } 197 1.1 jmcneill } 198 1.1 jmcneill 199 1.1 jmcneill static void 200 1.1 jmcneill apple_intc_local_establish_irq(struct pic_softc *pic, struct intrsource *is) 201 1.1 jmcneill { 202 1.1 jmcneill } 203 1.1 jmcneill 204 1.3 ryo #ifdef MULTIPROCESSOR 205 1.1 jmcneill static void 206 1.1 jmcneill apple_intc_local_ipi_send(struct pic_softc *pic, const kcpuset_t *kcp, u_long ipi) 207 1.1 jmcneill { 208 1.1 jmcneill struct apple_intc_percpu * const pc = PICTOPERCPU(pic); 209 1.1 jmcneill struct apple_intc_softc * const sc = pc->pc_sc; 210 1.1 jmcneill const u_int target = sc->sc_cpuid[pc->pc_cpuid]; 211 1.1 jmcneill 212 1.1 jmcneill atomic_or_32(&pc->pc_ipimask, __BIT(ipi)); 213 1.1 jmcneill AIC_WRITE(sc, AIC_IPI_SEND, __BIT(target)); 214 1.1 jmcneill } 215 1.3 ryo #endif /* MULTIPROCESSOR */ 216 1.1 jmcneill 217 1.1 jmcneill static const struct pic_ops apple_intc_localpicops = { 218 1.1 jmcneill .pic_unblock_irqs = apple_intc_local_unblock_irqs, 219 1.1 jmcneill .pic_block_irqs = apple_intc_local_block_irqs, 220 1.1 jmcneill .pic_establish_irq = apple_intc_local_establish_irq, 221 1.3 ryo #ifdef MULTIPROCESSOR 222 1.1 jmcneill .pic_ipi_send = apple_intc_local_ipi_send, 223 1.3 ryo #endif 224 1.1 jmcneill }; 225 1.1 jmcneill 226 1.1 jmcneill static void * 227 1.1 jmcneill apple_intc_fdt_establish(device_t dev, u_int *specifier, int ipl, int flags, 228 1.1 jmcneill int (*func)(void *), void *arg, const char *xname) 229 1.1 jmcneill { 230 1.1 jmcneill struct apple_intc_softc * const sc = device_private(dev); 231 1.1 jmcneill 232 1.1 jmcneill /* 1st cell is the interrupt type (0=IRQ, 1=FIQ) */ 233 1.1 jmcneill const u_int type = be32toh(specifier[0]); 234 1.1 jmcneill /* 2nd cell is the interrupt number */ 235 1.1 jmcneill const u_int intno = be32toh(specifier[1]); 236 1.1 jmcneill /* 3rd cell is the interrupt flags */ 237 1.1 jmcneill 238 1.1 jmcneill const u_int mpsafe = (flags & FDT_INTR_MPSAFE) ? IST_MPSAFE : 0; 239 1.4 skrll 240 1.4 skrll if (type == 0) 241 1.4 skrll return intr_establish_xname(intno, ipl, IST_LEVEL | mpsafe, 242 1.4 skrll func, arg, xname); 243 1.4 skrll 244 1.4 skrll /* interate over CPUs for LOCALPIC_SOURCE_TIMER */ 245 1.4 skrll CPU_INFO_ITERATOR cii; 246 1.4 skrll struct cpu_info *ci; 247 1.4 skrll void *ih = NULL; 248 1.4 skrll for (CPU_INFO_FOREACH(cii, ci)) { 249 1.4 skrll const cpuid_t cpuno = cpu_index(ci); 250 1.4 skrll struct apple_intc_percpu * const pc = &sc->sc_pc[cpuno]; 251 1.4 skrll struct pic_softc * const pic = &pc->pc_pic; 252 1.4 skrll const int irq = pic->pic_irqbase + LOCALPIC_SOURCE_TIMER; 253 1.4 skrll 254 1.4 skrll void *ihn = intr_establish_xname(irq, ipl, IST_LEVEL | mpsafe, 255 1.4 skrll func, arg, xname); 256 1.4 skrll if (cpuno == 0) 257 1.4 skrll ih = ihn; 258 1.4 skrll } 259 1.4 skrll return ih; 260 1.1 jmcneill } 261 1.1 jmcneill 262 1.1 jmcneill static void 263 1.1 jmcneill apple_intc_fdt_disestablish(device_t dev, void *ih) 264 1.1 jmcneill { 265 1.1 jmcneill intr_disestablish(ih); 266 1.1 jmcneill } 267 1.1 jmcneill 268 1.1 jmcneill static bool 269 1.1 jmcneill apple_intc_fdt_intrstr(device_t dev, u_int *specifier, char *buf, size_t buflen) 270 1.1 jmcneill { 271 1.1 jmcneill if (!specifier) 272 1.1 jmcneill return false; 273 1.1 jmcneill 274 1.1 jmcneill /* 1st cell is the interrupt type (0=IRQ, 1=FIQ) */ 275 1.1 jmcneill const u_int type = be32toh(specifier[0]); 276 1.1 jmcneill /* 2nd cell is the interrupt number */ 277 1.1 jmcneill const u_int intno = be32toh(specifier[1]); 278 1.1 jmcneill 279 1.5 skrll snprintf(buf, buflen, "%s %u", type == 0 ? "irq" : "fiq", intno); 280 1.1 jmcneill 281 1.1 jmcneill return true; 282 1.1 jmcneill } 283 1.1 jmcneill 284 1.1 jmcneill static const struct fdtbus_interrupt_controller_func apple_intc_fdt_funcs = { 285 1.1 jmcneill .establish = apple_intc_fdt_establish, 286 1.1 jmcneill .disestablish = apple_intc_fdt_disestablish, 287 1.1 jmcneill .intrstr = apple_intc_fdt_intrstr, 288 1.1 jmcneill }; 289 1.1 jmcneill 290 1.1 jmcneill static void 291 1.1 jmcneill apple_intc_mark_pending(struct pic_softc *pic, u_int intno) 292 1.1 jmcneill { 293 1.6 skrll const int base = intno & ~0x1f; 294 1.1 jmcneill const uint32_t pending = __BIT(intno & 0x1f); 295 1.6 skrll pic_mark_pending_sources(pic, base, pending); 296 1.1 jmcneill } 297 1.1 jmcneill 298 1.1 jmcneill static void 299 1.1 jmcneill apple_intc_irq_handler(void *frame) 300 1.1 jmcneill { 301 1.1 jmcneill struct cpu_info * const ci = curcpu(); 302 1.1 jmcneill struct apple_intc_softc * const sc = intc_softc; 303 1.1 jmcneill struct pic_softc *pic; 304 1.1 jmcneill struct intrsource *is; 305 1.1 jmcneill const int oldipl = ci->ci_cpl; 306 1.1 jmcneill uint16_t evtype, evdata; 307 1.1 jmcneill bus_size_t clr_reg; 308 1.1 jmcneill uint32_t clr_val; 309 1.1 jmcneill 310 1.1 jmcneill ci->ci_data.cpu_nintr++; 311 1.1 jmcneill 312 1.1 jmcneill for (;;) { 313 1.1 jmcneill const uint32_t ev = AIC_READ(sc, AIC_EVENT); 314 1.1 jmcneill evtype = __SHIFTOUT(ev, AIC_EVENT_TYPE); 315 1.1 jmcneill evdata = __SHIFTOUT(ev, AIC_EVENT_DATA); 316 1.1 jmcneill 317 1.1 jmcneill dsb(sy); 318 1.1 jmcneill isb(); 319 1.1 jmcneill 320 1.1 jmcneill if (evtype == AIC_EVENT_TYPE_IRQ) { 321 1.1 jmcneill KASSERT(evdata < sc->sc_nirq); 322 1.1 jmcneill pic = &sc->sc_pic; 323 1.1 jmcneill is = pic->pic_sources[evdata]; 324 1.1 jmcneill KASSERT(is != NULL); 325 1.1 jmcneill 326 1.1 jmcneill AIC_WRITE(sc, AIC_SW_CLR(evdata), 327 1.1 jmcneill __BIT(evdata & 0x1f)); 328 1.1 jmcneill 329 1.1 jmcneill clr_reg = AIC_MASK_CLR(evdata); 330 1.1 jmcneill clr_val = AIC_MASK_BIT(evdata); 331 1.1 jmcneill } else if (evtype == AIC_EVENT_TYPE_IPI) { 332 1.1 jmcneill KASSERT(evdata == AIC_EVENT_IPI_OTHER); 333 1.1 jmcneill pic = &sc->sc_pc[cpu_index(ci)].pc_pic; 334 1.1 jmcneill is = pic->pic_sources[LOCALPIC_SOURCE_IPI]; 335 1.1 jmcneill KASSERT(is != NULL); 336 1.1 jmcneill 337 1.1 jmcneill AIC_WRITE(sc, AIC_IPI_ACK, AIC_IPI_OTHER); 338 1.1 jmcneill 339 1.1 jmcneill clr_reg = 0; 340 1.1 jmcneill clr_val = 0; 341 1.1 jmcneill } else { 342 1.1 jmcneill break; 343 1.1 jmcneill } 344 1.1 jmcneill 345 1.1 jmcneill if (ci->ci_cpl >= is->is_ipl) { 346 1.1 jmcneill apple_intc_mark_pending(pic, is->is_irq); 347 1.1 jmcneill } else { 348 1.1 jmcneill pic_set_priority(ci, is->is_ipl); 349 1.1 jmcneill ENABLE_INTERRUPT(); 350 1.1 jmcneill pic_dispatch(is, frame); 351 1.1 jmcneill DISABLE_INTERRUPT(); 352 1.1 jmcneill 353 1.1 jmcneill if (clr_val != 0) { 354 1.1 jmcneill AIC_WRITE(sc, clr_reg, clr_val); 355 1.1 jmcneill } 356 1.1 jmcneill } 357 1.1 jmcneill } 358 1.1 jmcneill 359 1.1 jmcneill if (oldipl != IPL_HIGH) { 360 1.1 jmcneill pic_do_pending_ints(DAIF_I|DAIF_F, oldipl, frame); 361 1.1 jmcneill } 362 1.1 jmcneill } 363 1.1 jmcneill 364 1.1 jmcneill static void 365 1.1 jmcneill apple_intc_fiq_handler(void *frame) 366 1.1 jmcneill { 367 1.1 jmcneill struct cpu_info * const ci = curcpu(); 368 1.1 jmcneill struct apple_intc_softc * const sc = intc_softc; 369 1.1 jmcneill struct pic_softc * const pic = &sc->sc_pc[cpu_index(ci)].pc_pic; 370 1.1 jmcneill const int oldipl = ci->ci_cpl; 371 1.1 jmcneill 372 1.1 jmcneill ci->ci_data.cpu_nintr++; 373 1.1 jmcneill 374 1.1 jmcneill struct intrsource * const is = pic->pic_sources[LOCALPIC_SOURCE_TIMER]; 375 1.1 jmcneill 376 1.1 jmcneill dsb(sy); 377 1.1 jmcneill isb(); 378 1.1 jmcneill 379 1.1 jmcneill if (oldipl >= is->is_ipl) { 380 1.1 jmcneill apple_intc_mark_pending(pic, LOCALPIC_SOURCE_TIMER); 381 1.1 jmcneill } else { 382 1.1 jmcneill pic_set_priority(ci, is->is_ipl); 383 1.1 jmcneill pic_dispatch(is, frame); 384 1.1 jmcneill } 385 1.1 jmcneill 386 1.1 jmcneill if (oldipl != IPL_HIGH) { 387 1.1 jmcneill pic_do_pending_ints(DAIF_I|DAIF_F, oldipl, frame); 388 1.1 jmcneill } 389 1.1 jmcneill } 390 1.1 jmcneill 391 1.3 ryo #ifdef MULTIPROCESSOR 392 1.1 jmcneill static int 393 1.1 jmcneill apple_intc_ipi_handler(void *priv) 394 1.1 jmcneill { 395 1.1 jmcneill struct apple_intc_percpu * const pc = priv; 396 1.1 jmcneill struct apple_intc_softc * const sc = pc->pc_sc; 397 1.1 jmcneill uint32_t ipimask, bit; 398 1.1 jmcneill 399 1.1 jmcneill AIC_WRITE(sc, AIC_IPI_MASK_CLR, AIC_IPI_OTHER); 400 1.1 jmcneill ipimask = atomic_swap_32(&pc->pc_ipimask, 0); 401 1.1 jmcneill 402 1.1 jmcneill while ((bit = ffs(ipimask)) > 0) { 403 1.1 jmcneill const u_int ipi = bit - 1; 404 1.1 jmcneill 405 1.1 jmcneill switch (ipi) { 406 1.1 jmcneill case IPI_AST: 407 1.1 jmcneill pic_ipi_ast(priv); 408 1.1 jmcneill break; 409 1.1 jmcneill case IPI_NOP: 410 1.1 jmcneill pic_ipi_nop(priv); 411 1.1 jmcneill break; 412 1.1 jmcneill #ifdef __HAVE_PREEMPTION 413 1.1 jmcneill case IPI_KPREEMPT: 414 1.1 jmcneill pic_ipi_kpreempt(priv); 415 1.1 jmcneill break; 416 1.1 jmcneill #endif 417 1.1 jmcneill case IPI_XCALL: 418 1.1 jmcneill pic_ipi_xcall(priv); 419 1.1 jmcneill break; 420 1.1 jmcneill case IPI_GENERIC: 421 1.1 jmcneill pic_ipi_generic(priv); 422 1.1 jmcneill break; 423 1.1 jmcneill case IPI_SHOOTDOWN: 424 1.1 jmcneill pic_ipi_shootdown(priv); 425 1.1 jmcneill break; 426 1.1 jmcneill #ifdef DDB 427 1.1 jmcneill case IPI_DDB: 428 1.1 jmcneill pic_ipi_ddb(priv); 429 1.1 jmcneill break; 430 1.1 jmcneill #endif 431 1.1 jmcneill } 432 1.1 jmcneill ipimask &= ~__BIT(ipi); 433 1.1 jmcneill } 434 1.1 jmcneill 435 1.1 jmcneill return 1; 436 1.1 jmcneill } 437 1.3 ryo #endif /* MULTIPROCESSOR */ 438 1.1 jmcneill 439 1.1 jmcneill static int 440 1.1 jmcneill apple_intc_match(device_t parent, cfdata_t cf, void *aux) 441 1.1 jmcneill { 442 1.1 jmcneill struct fdt_attach_args * const faa = aux; 443 1.1 jmcneill 444 1.1 jmcneill return of_compatible_match(faa->faa_phandle, compat_data); 445 1.1 jmcneill } 446 1.1 jmcneill 447 1.1 jmcneill static void 448 1.1 jmcneill apple_intc_attach(device_t parent, device_t self, void *aux) 449 1.1 jmcneill { 450 1.1 jmcneill struct apple_intc_softc * const sc = device_private(self); 451 1.1 jmcneill struct fdt_attach_args * const faa = aux; 452 1.1 jmcneill const int phandle = faa->faa_phandle; 453 1.1 jmcneill bus_addr_t addr; 454 1.1 jmcneill bus_size_t size; 455 1.1 jmcneill int error; 456 1.1 jmcneill 457 1.1 jmcneill if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 458 1.1 jmcneill aprint_error(": couldn't get registers\n"); 459 1.1 jmcneill return; 460 1.1 jmcneill } 461 1.1 jmcneill 462 1.1 jmcneill sc->sc_dev = self; 463 1.1 jmcneill sc->sc_bst = faa->faa_bst; 464 1.2 jmcneill if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 465 1.1 jmcneill aprint_error(": couldn't map registers\n"); 466 1.1 jmcneill return; 467 1.1 jmcneill } 468 1.1 jmcneill 469 1.1 jmcneill sc->sc_nirq = AIC_READ(sc, AIC_INFO) & AIC_INFO_NIRQ; 470 1.1 jmcneill 471 1.1 jmcneill aprint_naive("\n"); 472 1.1 jmcneill aprint_normal(": Apple AIC (%u IRQs, 1 FIQ)\n", sc->sc_nirq); 473 1.1 jmcneill KASSERT(sc->sc_nirq % 32 == 0); 474 1.1 jmcneill 475 1.1 jmcneill sc->sc_pic.pic_ops = &apple_intc_picops; 476 1.1 jmcneill sc->sc_pic.pic_maxsources = sc->sc_nirq; 477 1.1 jmcneill snprintf(sc->sc_pic.pic_name, sizeof(sc->sc_pic.pic_name), "AIC"); 478 1.1 jmcneill pic_add(&sc->sc_pic, 0); 479 1.1 jmcneill 480 1.1 jmcneill error = fdtbus_register_interrupt_controller(self, phandle, 481 1.1 jmcneill &apple_intc_fdt_funcs); 482 1.1 jmcneill if (error) { 483 1.1 jmcneill aprint_error_dev(self, "couldn't register with fdtbus: %d\n", 484 1.1 jmcneill error); 485 1.1 jmcneill return; 486 1.1 jmcneill } 487 1.1 jmcneill 488 1.1 jmcneill KASSERT(intc_softc == NULL); 489 1.1 jmcneill intc_softc = sc; 490 1.1 jmcneill arm_fdt_irq_set_handler(apple_intc_irq_handler); 491 1.1 jmcneill arm_fdt_fiq_set_handler(apple_intc_fiq_handler); 492 1.1 jmcneill 493 1.1 jmcneill KASSERT(ncpu != 0); 494 1.1 jmcneill sc->sc_cpuid = kmem_zalloc(sizeof(*sc->sc_cpuid) * ncpu, KM_SLEEP); 495 1.1 jmcneill sc->sc_pc = kmem_zalloc(sizeof(*sc->sc_pc) * ncpu, KM_SLEEP); 496 1.4 skrll 497 1.4 skrll CPU_INFO_ITERATOR cii; 498 1.4 skrll struct cpu_info *ci; 499 1.4 skrll for (CPU_INFO_FOREACH(cii, ci)) { 500 1.4 skrll const cpuid_t cpuno = cpu_index(ci); 501 1.4 skrll struct apple_intc_percpu * const pc = &sc->sc_pc[cpuno]; 502 1.4 skrll struct pic_softc * const pic = &pc->pc_pic; 503 1.4 skrll 504 1.4 skrll pc->pc_sc = sc; 505 1.4 skrll pc->pc_cpuid = cpuno; 506 1.4 skrll 507 1.8 ryo #ifdef MULTIPROCESSOR 508 1.4 skrll pic->pic_cpus = ci->ci_kcpuset; 509 1.8 ryo #endif 510 1.4 skrll pic->pic_ops = &apple_intc_localpicops; 511 1.4 skrll pic->pic_maxsources = 2; 512 1.4 skrll snprintf(pic->pic_name, sizeof(pic->pic_name), "AIC/%lu", cpuno); 513 1.4 skrll 514 1.4 skrll pic_add(pic, PIC_IRQBASE_ALLOC); 515 1.4 skrll 516 1.8 ryo #ifdef MULTIPROCESSOR 517 1.4 skrll intr_establish_xname(pic->pic_irqbase + LOCALPIC_SOURCE_IPI, 518 1.4 skrll IPL_HIGH, IST_LEVEL | IST_MPSAFE, apple_intc_ipi_handler, 519 1.4 skrll pc, "ipi"); 520 1.8 ryo #endif 521 1.1 jmcneill } 522 1.1 jmcneill 523 1.1 jmcneill apple_intc_cpu_init(&sc->sc_pic, curcpu()); 524 1.1 jmcneill } 525 1.1 jmcneill 526 1.1 jmcneill CFATTACH_DECL_NEW(apple_intc, sizeof(struct apple_intc_softc), 527 1.1 jmcneill apple_intc_match, apple_intc_attach, NULL, NULL); 528