Home | History | Annotate | Line # | Download | only in apple
      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