104160e00SKyle Evans /*-
292e237e1SKyle Evans * SPDX-License-Identifier: BSD-2-Clause
392e237e1SKyle Evans *
404160e00SKyle Evans * Copyright (c) 2021 Andrew Turner
504160e00SKyle Evans * Copyright (c) 2022 Michael J. Karels <karels@freebsd.org>
604160e00SKyle Evans * Copyright (c) 2022 Kyle Evans <kevans@FreeBSD.org>
704160e00SKyle Evans *
804160e00SKyle Evans * Redistribution and use in source and binary forms, with or without
904160e00SKyle Evans * modification, are permitted provided that the following conditions
1004160e00SKyle Evans * are met:
1104160e00SKyle Evans * 1. Redistributions of source code must retain the above copyright
1204160e00SKyle Evans * notice, this list of conditions and the following disclaimer.
1304160e00SKyle Evans * 2. Redistributions in binary form must reproduce the above copyright
1404160e00SKyle Evans * notice, this list of conditions and the following disclaimer in the
1504160e00SKyle Evans * documentation and/or other materials provided with the distribution.
1604160e00SKyle Evans *
1704160e00SKyle Evans * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1804160e00SKyle Evans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1904160e00SKyle Evans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2004160e00SKyle Evans * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2104160e00SKyle Evans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2204160e00SKyle Evans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2304160e00SKyle Evans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2404160e00SKyle Evans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2504160e00SKyle Evans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2604160e00SKyle Evans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2704160e00SKyle Evans * SUCH DAMAGE.
2804160e00SKyle Evans */
2904160e00SKyle Evans
3004160e00SKyle Evans #include "opt_platform.h"
3104160e00SKyle Evans
3204160e00SKyle Evans #include <sys/param.h>
3304160e00SKyle Evans #include <sys/systm.h>
3404160e00SKyle Evans #include <sys/bus.h>
3504160e00SKyle Evans #include <sys/kernel.h>
3604160e00SKyle Evans #include <sys/module.h>
3704160e00SKyle Evans #include <sys/proc.h>
3804160e00SKyle Evans #include <sys/rman.h>
3904160e00SKyle Evans #include <sys/smp.h>
4004160e00SKyle Evans
4104160e00SKyle Evans #include <machine/bus.h>
4204160e00SKyle Evans #include <machine/machdep.h>
4304160e00SKyle Evans #ifdef SMP
4404160e00SKyle Evans #include <machine/intr.h>
4504160e00SKyle Evans #include <machine/smp.h>
4604160e00SKyle Evans #endif
4704160e00SKyle Evans
4804160e00SKyle Evans #include <dev/fdt/fdt_intr.h>
4904160e00SKyle Evans
5004160e00SKyle Evans #include <dev/ofw/openfirm.h>
5104160e00SKyle Evans #include <dev/ofw/ofw_bus.h>
5204160e00SKyle Evans #include <dev/ofw/ofw_bus_subr.h>
5304160e00SKyle Evans
5404160e00SKyle Evans #include <dt-bindings/interrupt-controller/apple-aic.h>
5504160e00SKyle Evans
5604160e00SKyle Evans #include "pic_if.h"
5704160e00SKyle Evans
5804160e00SKyle Evans #define AIC_INFO 0x0004
5904160e00SKyle Evans #define AIC_INFO_NDIE(val) (((val) >> 24) & 0xf)
6004160e00SKyle Evans #define AIC_INFO_NIRQS(val) ((val) & 0x0000ffff)
6104160e00SKyle Evans
6204160e00SKyle Evans #define AIC_WHOAMI 0x2000
6304160e00SKyle Evans #define AIC_EVENT 0x2004
6404160e00SKyle Evans #define AIC_EVENT_DIE(val) (((val) >> 24) & 0xff)
6504160e00SKyle Evans #define AIC_EVENT_TYPE(val) (((val) >> 16) & 0xff)
6604160e00SKyle Evans #define AIC_EVENT_TYPE_NONE 0
6704160e00SKyle Evans #define AIC_EVENT_TYPE_IRQ 1
6804160e00SKyle Evans #define AIC_EVENT_TYPE_IPI 4
6904160e00SKyle Evans #define AIC_EVENT_IRQ(val) ((val) & 0xffff)
7004160e00SKyle Evans #define AIC_EVENT_IPI_OTHER 1
7104160e00SKyle Evans #define AIC_EVENT_IPI_SELF 2
7204160e00SKyle Evans #define AIC_IPI_SEND 0x2008
7304160e00SKyle Evans #define AIC_IPI_ACK 0x200c
7404160e00SKyle Evans #define AIC_IPI_MASK_SET 0x2024
7504160e00SKyle Evans #define AIC_IPI_MASK_CLR 0x2028
7604160e00SKyle Evans #define AIC_IPI_OTHER 0x00000001
7704160e00SKyle Evans #define AIC_IPI_SELF 0x80000000
7804160e00SKyle Evans #define AIC_TARGET_CPU(irq) (0x3000 + (irq) * 4)
7904160e00SKyle Evans #define AIC_SW_SET(irq) (0x4000 + (((irq) >> 5) * 4))
8004160e00SKyle Evans #define AIC_SW_CLEAR(irq) (0x4080 + (((irq) >> 5) * 4))
8104160e00SKyle Evans #define AIC_MASK_SET(irq) (0x4100 + (((irq) >> 5) * 4))
8204160e00SKyle Evans #define AIC_MASK_CLEAR(irq) (0x4180 + (((irq) >> 5) * 4))
8304160e00SKyle Evans #define AIC_IRQ_MASK(irq) (1u << ((irq) & 0x1f))
8404160e00SKyle Evans
8504160e00SKyle Evans #define AIC_IPI_LOCAL_RR_EL1 s3_5_c15_c0_0
8604160e00SKyle Evans #define AIC_IPI_GLOBAL_RR_EL1 s3_5_c15_c0_1
8704160e00SKyle Evans
8804160e00SKyle Evans #define AIC_IPI_SR_EL1 s3_5_c15_c1_1
8904160e00SKyle Evans #define AIC_IPI_SR_EL1_PENDING (1 << 0)
9004160e00SKyle Evans
9104160e00SKyle Evans #define AIC_FIQ_VM_TIMER s3_5_c15_c1_3
9204160e00SKyle Evans #define AIC_FIQ_VM_TIMER_VEN (1 << 0)
9304160e00SKyle Evans #define AIC_FIQ_VM_TIMER_PEN (1 << 1)
9404160e00SKyle Evans #define AIC_FIQ_VM_TIMER_BITS (AIC_FIQ_VM_TIMER_VEN | AIC_FIQ_VM_TIMER_PEN)
9504160e00SKyle Evans
9604160e00SKyle Evans #define CNTV_CTL_ENABLE (1 << 0)
9704160e00SKyle Evans #define CNTV_CTL_IMASK (1 << 1)
9804160e00SKyle Evans #define CNTV_CTL_ISTATUS (1 << 2)
9904160e00SKyle Evans #define CNTV_CTL_BITS \
10004160e00SKyle Evans (CNTV_CTL_ENABLE | CNTV_CTL_IMASK | CNTV_CTL_ISTATUS)
10104160e00SKyle Evans
10204160e00SKyle Evans #define AIC_MAXCPUS 32
10304160e00SKyle Evans #define AIC_MAXDIES 4
10404160e00SKyle Evans
10504160e00SKyle Evans static struct ofw_compat_data compat_data[] = {
10604160e00SKyle Evans { "apple,aic", 1 },
10704160e00SKyle Evans { NULL, 0 }
10804160e00SKyle Evans };
10904160e00SKyle Evans
11004160e00SKyle Evans enum apple_aic_irq_type {
11104160e00SKyle Evans AIC_TYPE_INVAL,
11204160e00SKyle Evans AIC_TYPE_IRQ,
11304160e00SKyle Evans AIC_TYPE_FIQ,
11404160e00SKyle Evans AIC_TYPE_IPI,
11504160e00SKyle Evans };
11604160e00SKyle Evans
11704160e00SKyle Evans struct apple_aic_irqsrc {
11804160e00SKyle Evans struct intr_irqsrc ai_isrc;
11904160e00SKyle Evans enum apple_aic_irq_type ai_type;
12004160e00SKyle Evans struct {
12104160e00SKyle Evans /* AIC_TYPE_IRQ */
12204160e00SKyle Evans enum intr_polarity ai_pol;
12304160e00SKyle Evans enum intr_trigger ai_trig;
12404160e00SKyle Evans u_int ai_irq;
12504160e00SKyle Evans };
12604160e00SKyle Evans };
12704160e00SKyle Evans
12804160e00SKyle Evans #ifdef SMP
12904160e00SKyle Evans #define AIC_NIPIS INTR_IPI_COUNT
13004160e00SKyle Evans #endif
13104160e00SKyle Evans
13204160e00SKyle Evans struct apple_aic_softc {
13304160e00SKyle Evans device_t sc_dev;
13404160e00SKyle Evans struct resource *sc_mem;
13504160e00SKyle Evans struct apple_aic_irqsrc *sc_isrcs[AIC_MAXDIES];
13604160e00SKyle Evans u_int sc_nirqs;
13704160e00SKyle Evans u_int sc_ndie;
13804160e00SKyle Evans #ifdef SMP
13904160e00SKyle Evans struct apple_aic_irqsrc sc_ipi_srcs[AIC_NIPIS];
14004160e00SKyle Evans uint32_t *sc_ipimasks;
14104160e00SKyle Evans #endif
142*16f0d01fSKyle Evans u_int *sc_cpuids; /* cpu index to AIC CPU ID */
14304160e00SKyle Evans };
14404160e00SKyle Evans
14504160e00SKyle Evans static u_int aic_next_cpu;
14604160e00SKyle Evans
14704160e00SKyle Evans static device_probe_t apple_aic_probe;
14804160e00SKyle Evans static device_attach_t apple_aic_attach;
14904160e00SKyle Evans
15004160e00SKyle Evans static pic_disable_intr_t apple_aic_disable_intr;
15104160e00SKyle Evans static pic_enable_intr_t apple_aic_enable_intr;
15204160e00SKyle Evans static pic_map_intr_t apple_aic_map_intr;
15304160e00SKyle Evans static pic_setup_intr_t apple_aic_setup_intr;
15404160e00SKyle Evans static pic_teardown_intr_t apple_aic_teardown_intr;
15504160e00SKyle Evans static pic_post_filter_t apple_aic_post_filter;
15604160e00SKyle Evans static pic_post_ithread_t apple_aic_post_ithread;
15704160e00SKyle Evans static pic_pre_ithread_t apple_aic_pre_ithread;
15804160e00SKyle Evans #ifdef SMP
15904160e00SKyle Evans static pic_bind_intr_t apple_aic_bind_intr;
16004160e00SKyle Evans static pic_init_secondary_t apple_aic_init_secondary;
16104160e00SKyle Evans static pic_ipi_send_t apple_aic_ipi_send;
16204160e00SKyle Evans static pic_ipi_setup_t apple_aic_ipi_setup;
16304160e00SKyle Evans #endif
16404160e00SKyle Evans
16504160e00SKyle Evans static int apple_aic_irq(void *);
16604160e00SKyle Evans static int apple_aic_fiq(void *);
16704160e00SKyle Evans
16804160e00SKyle Evans static int
apple_aic_probe(device_t dev)16904160e00SKyle Evans apple_aic_probe(device_t dev)
17004160e00SKyle Evans {
17104160e00SKyle Evans
17204160e00SKyle Evans if (!ofw_bus_status_okay(dev))
17304160e00SKyle Evans return (ENXIO);
17404160e00SKyle Evans
17504160e00SKyle Evans if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
17604160e00SKyle Evans return (ENXIO);
17704160e00SKyle Evans
17804160e00SKyle Evans device_set_desc(dev, "Apple Interrupt Controller");
17904160e00SKyle Evans return (BUS_PROBE_DEFAULT);
18004160e00SKyle Evans }
18104160e00SKyle Evans
18204160e00SKyle Evans static int
apple_aic_attach(device_t dev)18304160e00SKyle Evans apple_aic_attach(device_t dev)
18404160e00SKyle Evans {
18504160e00SKyle Evans struct apple_aic_softc *sc;
18604160e00SKyle Evans struct intr_irqsrc *isrc;
18704160e00SKyle Evans const char *name;
18804160e00SKyle Evans intptr_t xref;
18904160e00SKyle Evans int error, rid;
19004160e00SKyle Evans u_int i, cpu, j, info;
19104160e00SKyle Evans
19204160e00SKyle Evans sc = device_get_softc(dev);
19304160e00SKyle Evans sc->sc_dev = dev;
19404160e00SKyle Evans
19504160e00SKyle Evans rid = 0;
19604160e00SKyle Evans sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
19704160e00SKyle Evans RF_ACTIVE);
19804160e00SKyle Evans if (sc->sc_mem == NULL) {
19904160e00SKyle Evans device_printf(dev, "Unable to allocate memory\n");
20004160e00SKyle Evans return (ENXIO);
20104160e00SKyle Evans }
20204160e00SKyle Evans
20304160e00SKyle Evans info = bus_read_4(sc->sc_mem, AIC_INFO);
20404160e00SKyle Evans sc->sc_nirqs = AIC_INFO_NIRQS(info);
20504160e00SKyle Evans sc->sc_ndie = AIC_INFO_NDIE(info) + 1;
20604160e00SKyle Evans if (bootverbose)
20704160e00SKyle Evans device_printf(dev, "Found %d interrupts, %d die\n",
20804160e00SKyle Evans sc->sc_nirqs, sc->sc_ndie);
20904160e00SKyle Evans
21004160e00SKyle Evans for (i = 0; i < sc->sc_ndie; i++) {
21104160e00SKyle Evans sc->sc_isrcs[i] = mallocarray(sc->sc_nirqs,
21204160e00SKyle Evans sizeof(**sc->sc_isrcs), M_DEVBUF, M_WAITOK | M_ZERO);
21304160e00SKyle Evans }
21404160e00SKyle Evans
21504160e00SKyle Evans #ifdef SMP
21604160e00SKyle Evans sc->sc_ipimasks = malloc(sizeof(*sc->sc_ipimasks) * mp_maxid + 1,
21704160e00SKyle Evans M_DEVBUF, M_WAITOK | M_ZERO);
218*16f0d01fSKyle Evans #endif
21904160e00SKyle Evans sc->sc_cpuids = malloc(sizeof(*sc->sc_cpuids) * mp_maxid + 1,
22004160e00SKyle Evans M_DEVBUF, M_WAITOK | M_ZERO);
22104160e00SKyle Evans
22204160e00SKyle Evans cpu = PCPU_GET(cpuid);
22304160e00SKyle Evans sc->sc_cpuids[cpu] = bus_read_4(sc->sc_mem, AIC_WHOAMI);
22404160e00SKyle Evans if (bootverbose)
22504160e00SKyle Evans device_printf(dev, "BSP CPU %d: whoami %x\n", cpu,
22604160e00SKyle Evans sc->sc_cpuids[cpu]);
22704160e00SKyle Evans
22804160e00SKyle Evans name = device_get_nameunit(dev);
22904160e00SKyle Evans for (i = 0; i < sc->sc_ndie; i++) {
23004160e00SKyle Evans struct apple_aic_irqsrc *die_isrcs;
23104160e00SKyle Evans
23204160e00SKyle Evans die_isrcs = sc->sc_isrcs[i];
23304160e00SKyle Evans for (j = 0; j < sc->sc_nirqs; j++) {
23404160e00SKyle Evans isrc = &die_isrcs[j].ai_isrc;
23504160e00SKyle Evans die_isrcs[j].ai_pol = INTR_POLARITY_CONFORM;
23604160e00SKyle Evans die_isrcs[j].ai_trig = INTR_TRIGGER_CONFORM;
23704160e00SKyle Evans die_isrcs[j].ai_type = AIC_TYPE_INVAL;
23804160e00SKyle Evans die_isrcs[j].ai_irq = j;
23904160e00SKyle Evans
24004160e00SKyle Evans error = intr_isrc_register(isrc, dev, 0, "%s,d%us%u", name,
24104160e00SKyle Evans i, j);
24204160e00SKyle Evans if (error != 0) {
24304160e00SKyle Evans device_printf(dev, "Unable to register irq %u:%u\n",
24404160e00SKyle Evans i, j);
24504160e00SKyle Evans return (error);
24604160e00SKyle Evans }
24704160e00SKyle Evans }
24804160e00SKyle Evans }
24904160e00SKyle Evans
25004160e00SKyle Evans xref = OF_xref_from_node(ofw_bus_get_node(dev));
25104160e00SKyle Evans if (intr_pic_register(dev, xref) == NULL) {
25204160e00SKyle Evans device_printf(dev, "Unable to register interrupt handler\n");
25304160e00SKyle Evans return (ENXIO);
25404160e00SKyle Evans }
25504160e00SKyle Evans
25604160e00SKyle Evans if (intr_pic_claim_root(dev, xref, apple_aic_irq, sc,
25704160e00SKyle Evans INTR_ROOT_IRQ) != 0) {
25804160e00SKyle Evans device_printf(dev,
25904160e00SKyle Evans "Unable to set root interrupt controller\n");
26004160e00SKyle Evans intr_pic_deregister(dev, xref);
26104160e00SKyle Evans return (ENXIO);
26204160e00SKyle Evans }
26304160e00SKyle Evans
26404160e00SKyle Evans if (intr_pic_claim_root(dev, xref, apple_aic_fiq, sc,
26504160e00SKyle Evans INTR_ROOT_FIQ) != 0) {
26604160e00SKyle Evans device_printf(dev,
26704160e00SKyle Evans "Unable to set root fiq controller\n");
26804160e00SKyle Evans intr_pic_deregister(dev, xref);
26904160e00SKyle Evans return (ENXIO);
27004160e00SKyle Evans }
27104160e00SKyle Evans
27204160e00SKyle Evans #ifdef SMP
27304160e00SKyle Evans if (intr_ipi_pic_register(dev, 0) != 0) {
27404160e00SKyle Evans device_printf(dev, "could not register for IPIs\n");
27504160e00SKyle Evans return (ENXIO);
27604160e00SKyle Evans }
27704160e00SKyle Evans #endif
27804160e00SKyle Evans
27904160e00SKyle Evans OF_device_register_xref(xref, dev);
28004160e00SKyle Evans
28104160e00SKyle Evans return (0);
28204160e00SKyle Evans }
28304160e00SKyle Evans
28404160e00SKyle Evans static int
apple_aic_map_intr_fdt(struct apple_aic_softc * sc,struct intr_map_data_fdt * data,u_int * irq,enum apple_aic_irq_type * typep,enum intr_polarity * polp,enum intr_trigger * trigp,u_int * die)28504160e00SKyle Evans apple_aic_map_intr_fdt(struct apple_aic_softc *sc,
28604160e00SKyle Evans struct intr_map_data_fdt *data, u_int *irq, enum apple_aic_irq_type *typep,
28704160e00SKyle Evans enum intr_polarity *polp, enum intr_trigger *trigp, u_int *die)
28804160e00SKyle Evans {
28904160e00SKyle Evans if (data->ncells != 3)
29004160e00SKyle Evans return (EINVAL);
29104160e00SKyle Evans
29204160e00SKyle Evans /* XXX AIC2 */
29304160e00SKyle Evans *die = 0;
29404160e00SKyle Evans
29504160e00SKyle Evans /*
29604160e00SKyle Evans * The first cell is the interrupt type:
29704160e00SKyle Evans * 0 = IRQ
29804160e00SKyle Evans * 1 = FIQ
29904160e00SKyle Evans * The second cell is the interrupt number
30004160e00SKyle Evans * The third cell is the flags
30104160e00SKyle Evans */
30204160e00SKyle Evans switch(data->cells[0]) {
30304160e00SKyle Evans case 0:
30404160e00SKyle Evans if (typep != NULL)
30504160e00SKyle Evans *typep = AIC_TYPE_IRQ;
30604160e00SKyle Evans break;
30704160e00SKyle Evans case 1:
30804160e00SKyle Evans if (typep != NULL)
30904160e00SKyle Evans *typep = AIC_TYPE_FIQ;
31004160e00SKyle Evans break;
31104160e00SKyle Evans default:
31204160e00SKyle Evans return (EINVAL);
31304160e00SKyle Evans }
31404160e00SKyle Evans
31504160e00SKyle Evans *irq = data->cells[1];
31604160e00SKyle Evans if (*irq > sc->sc_nirqs)
31704160e00SKyle Evans return (EINVAL);
31804160e00SKyle Evans
31904160e00SKyle Evans if (trigp != NULL) {
32004160e00SKyle Evans if ((data->cells[2] & FDT_INTR_EDGE_MASK) != 0)
32104160e00SKyle Evans *trigp = INTR_TRIGGER_EDGE;
32204160e00SKyle Evans else
32304160e00SKyle Evans *trigp = INTR_TRIGGER_LEVEL;
32404160e00SKyle Evans }
32504160e00SKyle Evans if (polp != NULL) {
32604160e00SKyle Evans if ((data->cells[2] & FDT_INTR_LEVEL_HIGH) != 0)
32704160e00SKyle Evans *polp = INTR_POLARITY_HIGH;
32804160e00SKyle Evans else
32904160e00SKyle Evans *polp = INTR_POLARITY_LOW;
33004160e00SKyle Evans }
33104160e00SKyle Evans
33204160e00SKyle Evans return (0);
33304160e00SKyle Evans }
33404160e00SKyle Evans
33504160e00SKyle Evans static int
apple_aic_map_intr(device_t dev,struct intr_map_data * data,struct intr_irqsrc ** isrcp)33604160e00SKyle Evans apple_aic_map_intr(device_t dev, struct intr_map_data *data,
33704160e00SKyle Evans struct intr_irqsrc **isrcp)
33804160e00SKyle Evans {
33904160e00SKyle Evans struct apple_aic_softc *sc;
34004160e00SKyle Evans int error;
34104160e00SKyle Evans u_int irq;
34204160e00SKyle Evans u_int die;
34304160e00SKyle Evans
34404160e00SKyle Evans sc = device_get_softc(dev);
34504160e00SKyle Evans
34604160e00SKyle Evans error = 0;
34704160e00SKyle Evans switch(data->type) {
34804160e00SKyle Evans case INTR_MAP_DATA_FDT:
34904160e00SKyle Evans error = apple_aic_map_intr_fdt(sc,
35004160e00SKyle Evans (struct intr_map_data_fdt *)data, &irq, NULL, NULL, NULL,
35104160e00SKyle Evans &die);
35204160e00SKyle Evans if (error == 0)
35304160e00SKyle Evans *isrcp = &sc->sc_isrcs[0 /* XXX */][irq].ai_isrc;
35404160e00SKyle Evans break;
35504160e00SKyle Evans default:
35604160e00SKyle Evans return (ENOTSUP);
35704160e00SKyle Evans }
35804160e00SKyle Evans
35904160e00SKyle Evans return (error);
36004160e00SKyle Evans }
36104160e00SKyle Evans
36204160e00SKyle Evans static int
apple_aic_setup_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)36304160e00SKyle Evans apple_aic_setup_intr(device_t dev, struct intr_irqsrc *isrc,
36404160e00SKyle Evans struct resource *res, struct intr_map_data *data)
36504160e00SKyle Evans {
36604160e00SKyle Evans struct apple_aic_softc *sc;
36704160e00SKyle Evans enum apple_aic_irq_type type;
36804160e00SKyle Evans struct apple_aic_irqsrc *ai;
36904160e00SKyle Evans enum intr_trigger trig;
37004160e00SKyle Evans enum intr_polarity pol;
37104160e00SKyle Evans int error;
37204160e00SKyle Evans u_int die, irq;
37304160e00SKyle Evans
37404160e00SKyle Evans sc = device_get_softc(dev);
37504160e00SKyle Evans ai = (struct apple_aic_irqsrc *)isrc;
37604160e00SKyle Evans
37704160e00SKyle Evans if (data != NULL) {
37804160e00SKyle Evans KASSERT(data->type == INTR_MAP_DATA_FDT,
37904160e00SKyle Evans ("%s: Only FDT data is supported (got %#x)", __func__,
38004160e00SKyle Evans data->type));
38104160e00SKyle Evans error = apple_aic_map_intr_fdt(sc,
38204160e00SKyle Evans (struct intr_map_data_fdt *)data, &irq, &type, &pol, &trig,
38304160e00SKyle Evans &die);
38404160e00SKyle Evans if (error != 0)
38504160e00SKyle Evans return (error);
38604160e00SKyle Evans } else {
38704160e00SKyle Evans pol = INTR_POLARITY_CONFORM;
38804160e00SKyle Evans trig = INTR_TRIGGER_CONFORM;
38904160e00SKyle Evans }
39004160e00SKyle Evans
39104160e00SKyle Evans if (isrc->isrc_handlers != 0) {
39204160e00SKyle Evans /* TODO */
39304160e00SKyle Evans return (0);
39404160e00SKyle Evans }
39504160e00SKyle Evans
39604160e00SKyle Evans if (pol == INTR_POLARITY_CONFORM)
39704160e00SKyle Evans pol = INTR_POLARITY_LOW;
39804160e00SKyle Evans if (trig == INTR_TRIGGER_CONFORM)
39904160e00SKyle Evans trig = INTR_TRIGGER_EDGE;
40004160e00SKyle Evans
40104160e00SKyle Evans ai->ai_pol = pol;
40204160e00SKyle Evans ai->ai_trig = trig;
40304160e00SKyle Evans ai->ai_type = type;
40404160e00SKyle Evans
40504160e00SKyle Evans /*
40604160e00SKyle Evans * Only the timer uses FIQs. These could be sent to any CPU.
40704160e00SKyle Evans */
40804160e00SKyle Evans switch (type) {
40904160e00SKyle Evans case AIC_TYPE_IRQ:
41004160e00SKyle Evans /* XXX die sensitive? */
41104160e00SKyle Evans aic_next_cpu = intr_irq_next_cpu(aic_next_cpu, &all_cpus);
41204160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_TARGET_CPU(irq),
41304160e00SKyle Evans 1 << sc->sc_cpuids[aic_next_cpu]);
41404160e00SKyle Evans break;
41504160e00SKyle Evans case AIC_TYPE_FIQ:
41604160e00SKyle Evans isrc->isrc_flags |= INTR_ISRCF_PPI;
41704160e00SKyle Evans break;
41804160e00SKyle Evans default:
41904160e00SKyle Evans return (EINVAL);
42004160e00SKyle Evans }
42104160e00SKyle Evans
42204160e00SKyle Evans return (0);
42304160e00SKyle Evans }
42404160e00SKyle Evans
42504160e00SKyle Evans static int
apple_aic_teardown_intr(device_t dev,struct intr_irqsrc * isrc,struct resource * res,struct intr_map_data * data)42604160e00SKyle Evans apple_aic_teardown_intr(device_t dev, struct intr_irqsrc *isrc,
42704160e00SKyle Evans struct resource *res, struct intr_map_data *data)
42804160e00SKyle Evans {
42904160e00SKyle Evans panic("%s\n", __func__);
43004160e00SKyle Evans }
43104160e00SKyle Evans
43204160e00SKyle Evans static void
apple_aic_enable_intr(device_t dev,struct intr_irqsrc * isrc)43304160e00SKyle Evans apple_aic_enable_intr(device_t dev, struct intr_irqsrc *isrc)
43404160e00SKyle Evans {
43504160e00SKyle Evans struct apple_aic_irqsrc *ai;
43604160e00SKyle Evans struct apple_aic_softc *sc;
43704160e00SKyle Evans u_int irq;
43804160e00SKyle Evans
43904160e00SKyle Evans ai = (struct apple_aic_irqsrc *)isrc;
44004160e00SKyle Evans irq = ai->ai_irq;
44104160e00SKyle Evans switch(ai->ai_type) {
44204160e00SKyle Evans case AIC_TYPE_IRQ:
44304160e00SKyle Evans sc = device_get_softc(dev);
44404160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_MASK_CLEAR(irq), AIC_IRQ_MASK(irq));
44504160e00SKyle Evans break;
44604160e00SKyle Evans case AIC_TYPE_IPI:
44704160e00SKyle Evans /* Nothing needed here. */
44804160e00SKyle Evans break;
44904160e00SKyle Evans case AIC_TYPE_FIQ:
45004160e00SKyle Evans /* TODO */
45104160e00SKyle Evans break;
45204160e00SKyle Evans default:
45304160e00SKyle Evans panic("%s: %x\n", __func__, ai->ai_type);
45404160e00SKyle Evans }
45504160e00SKyle Evans }
45604160e00SKyle Evans
45704160e00SKyle Evans static void
apple_aic_disable_intr(device_t dev,struct intr_irqsrc * isrc)45804160e00SKyle Evans apple_aic_disable_intr(device_t dev, struct intr_irqsrc *isrc)
45904160e00SKyle Evans {
46004160e00SKyle Evans struct apple_aic_irqsrc *ai;
46104160e00SKyle Evans struct apple_aic_softc *sc;
46204160e00SKyle Evans u_int irq;
46304160e00SKyle Evans
46404160e00SKyle Evans ai = (struct apple_aic_irqsrc *)isrc;
46504160e00SKyle Evans irq = ai->ai_irq;
46604160e00SKyle Evans switch(ai->ai_type) {
46704160e00SKyle Evans case AIC_TYPE_IRQ:
46804160e00SKyle Evans sc = device_get_softc(dev);
46904160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_MASK_SET(irq), AIC_IRQ_MASK(irq));
47004160e00SKyle Evans break;
47104160e00SKyle Evans case AIC_TYPE_IPI:
47204160e00SKyle Evans /* Nothing needed here. */
47304160e00SKyle Evans break;
47404160e00SKyle Evans case AIC_TYPE_FIQ:
47504160e00SKyle Evans /* TODO */
47604160e00SKyle Evans break;
47704160e00SKyle Evans default:
47804160e00SKyle Evans panic("%s: %x\n", __func__, ai->ai_type);
47904160e00SKyle Evans }
48004160e00SKyle Evans }
48104160e00SKyle Evans
48204160e00SKyle Evans static void
apple_aic_post_filter(device_t dev,struct intr_irqsrc * isrc)48304160e00SKyle Evans apple_aic_post_filter(device_t dev, struct intr_irqsrc *isrc)
48404160e00SKyle Evans {
48504160e00SKyle Evans struct apple_aic_softc *sc;
48604160e00SKyle Evans struct apple_aic_irqsrc *ai;
48704160e00SKyle Evans int irq;
48804160e00SKyle Evans
48904160e00SKyle Evans ai = (struct apple_aic_irqsrc *)isrc;
49004160e00SKyle Evans irq = ai->ai_irq;
49104160e00SKyle Evans switch(ai->ai_type) {
49204160e00SKyle Evans case AIC_TYPE_IRQ:
49304160e00SKyle Evans sc = device_get_softc(dev);
49404160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_SW_CLEAR(irq), AIC_IRQ_MASK(irq));
49504160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_MASK_CLEAR(irq), AIC_IRQ_MASK(irq));
49604160e00SKyle Evans break;
49704160e00SKyle Evans case AIC_TYPE_FIQ:
49804160e00SKyle Evans /* TODO */
49904160e00SKyle Evans break;
50004160e00SKyle Evans default:
50104160e00SKyle Evans panic("%s: %x\n", __func__, ai->ai_type);
50204160e00SKyle Evans }
50304160e00SKyle Evans }
50404160e00SKyle Evans
50504160e00SKyle Evans static void
apple_aic_pre_ithread(device_t dev,struct intr_irqsrc * isrc)50604160e00SKyle Evans apple_aic_pre_ithread(device_t dev, struct intr_irqsrc *isrc)
50704160e00SKyle Evans {
50804160e00SKyle Evans struct apple_aic_softc *sc;
50904160e00SKyle Evans struct apple_aic_irqsrc *ai;
51004160e00SKyle Evans int irq;
51104160e00SKyle Evans
51204160e00SKyle Evans ai = (struct apple_aic_irqsrc *)isrc;
51304160e00SKyle Evans sc = device_get_softc(dev);
51404160e00SKyle Evans irq = ai->ai_irq;
51504160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_SW_CLEAR(irq), AIC_IRQ_MASK(irq));
51604160e00SKyle Evans apple_aic_disable_intr(dev, isrc);
51704160e00SKyle Evans /* ACK IT */
51804160e00SKyle Evans }
51904160e00SKyle Evans
52004160e00SKyle Evans static void
apple_aic_post_ithread(device_t dev,struct intr_irqsrc * isrc)52104160e00SKyle Evans apple_aic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
52204160e00SKyle Evans {
52304160e00SKyle Evans struct apple_aic_softc *sc;
52404160e00SKyle Evans struct apple_aic_irqsrc *ai;
52504160e00SKyle Evans int irq;
52604160e00SKyle Evans
52704160e00SKyle Evans ai = (struct apple_aic_irqsrc *)isrc;
52804160e00SKyle Evans sc = device_get_softc(dev);
52904160e00SKyle Evans irq = ai->ai_irq;
53004160e00SKyle Evans
53104160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_MASK_CLEAR(irq), AIC_IRQ_MASK(irq));
53204160e00SKyle Evans apple_aic_enable_intr(dev, isrc);
53304160e00SKyle Evans }
53404160e00SKyle Evans
53504160e00SKyle Evans #ifdef SMP
53604160e00SKyle Evans static void
apple_aic_ipi_received(struct apple_aic_softc * sc,struct trapframe * tf)53704160e00SKyle Evans apple_aic_ipi_received(struct apple_aic_softc *sc, struct trapframe *tf)
53804160e00SKyle Evans {
53904160e00SKyle Evans uint32_t mask;
54004160e00SKyle Evans uint32_t ipi;
54104160e00SKyle Evans int cpu;
54204160e00SKyle Evans
54304160e00SKyle Evans cpu = PCPU_GET(cpuid);
54404160e00SKyle Evans
54504160e00SKyle Evans mask = atomic_readandclear_32(&sc->sc_ipimasks[cpu]);
54604160e00SKyle Evans
54704160e00SKyle Evans while (mask != 0) {
54804160e00SKyle Evans ipi = ffs(mask) - 1;
54904160e00SKyle Evans mask &= ~(1 << ipi);
55004160e00SKyle Evans
55104160e00SKyle Evans intr_ipi_dispatch(ipi);
55204160e00SKyle Evans }
55304160e00SKyle Evans }
55404160e00SKyle Evans #endif
55504160e00SKyle Evans
55604160e00SKyle Evans static int
apple_aic_irq(void * arg)55704160e00SKyle Evans apple_aic_irq(void *arg)
55804160e00SKyle Evans {
55904160e00SKyle Evans struct apple_aic_softc *sc;
56004160e00SKyle Evans uint32_t die, event, irq, type;
56104160e00SKyle Evans struct apple_aic_irqsrc *aisrc;
56204160e00SKyle Evans struct trapframe *tf;
56304160e00SKyle Evans
56404160e00SKyle Evans sc = arg;
56504160e00SKyle Evans tf = curthread->td_intr_frame;
56604160e00SKyle Evans
56704160e00SKyle Evans event = bus_read_4(sc->sc_mem, AIC_EVENT);
56804160e00SKyle Evans type = AIC_EVENT_TYPE(event);
56904160e00SKyle Evans
57004160e00SKyle Evans /* If we get an IPI here, we really goofed. */
57104160e00SKyle Evans MPASS(type != AIC_EVENT_TYPE_IPI);
57204160e00SKyle Evans
57304160e00SKyle Evans if (type != AIC_EVENT_TYPE_IRQ) {
57404160e00SKyle Evans if (type != AIC_EVENT_TYPE_NONE)
57504160e00SKyle Evans device_printf(sc->sc_dev, "unexpected event type %d\n",
57604160e00SKyle Evans type);
57704160e00SKyle Evans return (FILTER_STRAY);
57804160e00SKyle Evans }
57904160e00SKyle Evans
58004160e00SKyle Evans die = AIC_EVENT_DIE(event);
58104160e00SKyle Evans irq = AIC_EVENT_IRQ(event);
58204160e00SKyle Evans
58304160e00SKyle Evans if (die >= sc->sc_ndie)
58404160e00SKyle Evans panic("%s: unexpected die %d", __func__, die);
58504160e00SKyle Evans if (irq >= sc->sc_nirqs)
58604160e00SKyle Evans panic("%s: unexpected irq %d", __func__, irq);
58704160e00SKyle Evans
58804160e00SKyle Evans aisrc = &sc->sc_isrcs[die][irq];
58904160e00SKyle Evans if (intr_isrc_dispatch(&aisrc->ai_isrc, tf) != 0) {
59004160e00SKyle Evans device_printf(sc->sc_dev, "Stray irq %u:%u disabled\n",
59104160e00SKyle Evans die, irq);
59204160e00SKyle Evans return (FILTER_STRAY);
59304160e00SKyle Evans }
59404160e00SKyle Evans
59504160e00SKyle Evans return (FILTER_HANDLED);
59604160e00SKyle Evans }
59704160e00SKyle Evans
59804160e00SKyle Evans static int
apple_aic_fiq(void * arg)59904160e00SKyle Evans apple_aic_fiq(void *arg)
60004160e00SKyle Evans {
60104160e00SKyle Evans struct apple_aic_softc *sc;
60204160e00SKyle Evans struct apple_aic_irqsrc *isrcs;
60304160e00SKyle Evans struct trapframe *tf;
60404160e00SKyle Evans
60504160e00SKyle Evans sc = arg;
60604160e00SKyle Evans tf = curthread->td_intr_frame;
60704160e00SKyle Evans
60804160e00SKyle Evans #ifdef SMP
60904160e00SKyle Evans /* Handle IPIs. */
61004160e00SKyle Evans if ((READ_SPECIALREG(AIC_IPI_SR_EL1) & AIC_IPI_SR_EL1_PENDING) != 0) {
61104160e00SKyle Evans WRITE_SPECIALREG(AIC_IPI_SR_EL1, AIC_IPI_SR_EL1_PENDING);
61204160e00SKyle Evans apple_aic_ipi_received(sc, tf);
61304160e00SKyle Evans }
61404160e00SKyle Evans #endif
61504160e00SKyle Evans
61604160e00SKyle Evans /*
61704160e00SKyle Evans * FIQs don't store any state in the interrupt controller at all outside
61804160e00SKyle Evans * of IPI handling, so we have to probe around outside of AIC to
61904160e00SKyle Evans * determine if we might have been fired off due to a timer.
62004160e00SKyle Evans */
62104160e00SKyle Evans isrcs = sc->sc_isrcs[0];
62204160e00SKyle Evans if ((READ_SPECIALREG(cntv_ctl_el0) & CNTV_CTL_BITS) ==
62304160e00SKyle Evans (CNTV_CTL_ENABLE | CNTV_CTL_ISTATUS)) {
62404160e00SKyle Evans intr_isrc_dispatch(&isrcs[AIC_TMR_GUEST_VIRT].ai_isrc, tf);
62504160e00SKyle Evans }
62604160e00SKyle Evans
62704160e00SKyle Evans if (has_hyp()) {
62804160e00SKyle Evans uint64_t reg;
62904160e00SKyle Evans
63004160e00SKyle Evans if ((READ_SPECIALREG(cntp_ctl_el0) & CNTV_CTL_ISTATUS) != 0) {
63104160e00SKyle Evans intr_isrc_dispatch(&isrcs[AIC_TMR_GUEST_PHYS].ai_isrc,
63204160e00SKyle Evans tf);
63304160e00SKyle Evans }
63404160e00SKyle Evans
63504160e00SKyle Evans reg = READ_SPECIALREG(AIC_FIQ_VM_TIMER);
63604160e00SKyle Evans if ((reg & AIC_FIQ_VM_TIMER_PEN) != 0) {
63704160e00SKyle Evans intr_isrc_dispatch(&isrcs[AIC_TMR_HV_PHYS].ai_isrc, tf);
63804160e00SKyle Evans }
63904160e00SKyle Evans
64004160e00SKyle Evans if ((reg & AIC_FIQ_VM_TIMER_VEN) != 0) {
64104160e00SKyle Evans intr_isrc_dispatch(&isrcs[AIC_TMR_HV_VIRT].ai_isrc, tf);
64204160e00SKyle Evans }
64304160e00SKyle Evans }
64404160e00SKyle Evans
64504160e00SKyle Evans return (FILTER_HANDLED);
64604160e00SKyle Evans }
64704160e00SKyle Evans
64804160e00SKyle Evans #ifdef SMP
64904160e00SKyle Evans static int
apple_aic_bind_intr(device_t dev,struct intr_irqsrc * isrc)65004160e00SKyle Evans apple_aic_bind_intr(device_t dev, struct intr_irqsrc *isrc)
65104160e00SKyle Evans {
65204160e00SKyle Evans struct apple_aic_softc *sc = device_get_softc(dev);
65304160e00SKyle Evans static int aic_next_cpu;
65404160e00SKyle Evans uint32_t targets = 0;
65504160e00SKyle Evans u_int irq, cpu;
65604160e00SKyle Evans
65704160e00SKyle Evans MPASS(((struct apple_aic_irqsrc *)isrc)->ai_type == AIC_TYPE_IRQ);
65804160e00SKyle Evans irq = ((struct apple_aic_irqsrc *)isrc)->ai_irq;
65904160e00SKyle Evans if (CPU_EMPTY(&isrc->isrc_cpu)) {
66004160e00SKyle Evans aic_next_cpu = intr_irq_next_cpu(aic_next_cpu, &all_cpus);
66104160e00SKyle Evans CPU_SETOF(aic_next_cpu, &isrc->isrc_cpu);
66204160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_TARGET_CPU(irq),
66304160e00SKyle Evans sc->sc_cpuids[aic_next_cpu] << 1);
66404160e00SKyle Evans } else {
66504160e00SKyle Evans CPU_FOREACH_ISSET(cpu, &isrc->isrc_cpu) {
66604160e00SKyle Evans targets |= sc->sc_cpuids[cpu] << 1;
66704160e00SKyle Evans }
66804160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_TARGET_CPU(irq), targets);
66904160e00SKyle Evans }
67004160e00SKyle Evans return (0);
67104160e00SKyle Evans }
67204160e00SKyle Evans
67304160e00SKyle Evans static void
apple_aic_ipi_send(device_t dev,struct intr_irqsrc * isrc,cpuset_t cpus,u_int ipi)67404160e00SKyle Evans apple_aic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus,
67504160e00SKyle Evans u_int ipi)
67604160e00SKyle Evans {
67704160e00SKyle Evans struct apple_aic_softc *sc;
67804160e00SKyle Evans uint64_t aff, localgrp, sendmask;
67904160e00SKyle Evans u_int cpu;
68004160e00SKyle Evans
68104160e00SKyle Evans sc = device_get_softc(dev);
68204160e00SKyle Evans sendmask = 0;
68304160e00SKyle Evans localgrp = CPU_AFF1(CPU_AFFINITY(PCPU_GET(cpuid)));
68404160e00SKyle Evans
68504160e00SKyle Evans KASSERT(isrc == &sc->sc_ipi_srcs[ipi].ai_isrc,
68604160e00SKyle Evans ("%s: bad ISRC %p argument", __func__, isrc));
68704160e00SKyle Evans for (cpu = 0; cpu <= mp_maxid; cpu++) {
68804160e00SKyle Evans if (CPU_ISSET(cpu, &cpus)) {
68904160e00SKyle Evans aff = CPU_AFFINITY(cpu);
69004160e00SKyle Evans sendmask = CPU_AFF0(aff);
69104160e00SKyle Evans atomic_set_32(&sc->sc_ipimasks[cpu], 1 << ipi);
69204160e00SKyle Evans
69304160e00SKyle Evans /*
69404160e00SKyle Evans * The above write to sc_ipimasks needs to be visible
69504160e00SKyle Evans * before we write to the ipi register to avoid the
69604160e00SKyle Evans * targetted CPU missing the dispatch in
69704160e00SKyle Evans * apple_aic_ipi_received(). Note that WRITE_SPECIALREG
69804160e00SKyle Evans * isn't a memory operation, so we can't relax this to a
69904160e00SKyle Evans * a dmb.
70004160e00SKyle Evans */
70104160e00SKyle Evans dsb(ishst);
70204160e00SKyle Evans
70304160e00SKyle Evans if (CPU_AFF1(aff) == localgrp) {
70404160e00SKyle Evans WRITE_SPECIALREG(AIC_IPI_LOCAL_RR_EL1,
70504160e00SKyle Evans sendmask);
70604160e00SKyle Evans } else {
70704160e00SKyle Evans sendmask |= CPU_AFF1(aff) << 16;
70804160e00SKyle Evans WRITE_SPECIALREG(AIC_IPI_GLOBAL_RR_EL1,
70904160e00SKyle Evans sendmask);
71004160e00SKyle Evans }
71104160e00SKyle Evans
71204160e00SKyle Evans isb();
71304160e00SKyle Evans }
71404160e00SKyle Evans }
71504160e00SKyle Evans }
71604160e00SKyle Evans
71704160e00SKyle Evans static int
apple_aic_ipi_setup(device_t dev,u_int ipi,struct intr_irqsrc ** isrcp)71804160e00SKyle Evans apple_aic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp)
71904160e00SKyle Evans {
72004160e00SKyle Evans struct apple_aic_softc *sc = device_get_softc(dev);
72104160e00SKyle Evans struct apple_aic_irqsrc *ai;
72204160e00SKyle Evans
72304160e00SKyle Evans KASSERT(ipi < AIC_NIPIS, ("%s: ipi %u too high", __func__, ipi));
72404160e00SKyle Evans
72504160e00SKyle Evans ai = &sc->sc_ipi_srcs[ipi];
72604160e00SKyle Evans ai->ai_type = AIC_TYPE_IPI;
72704160e00SKyle Evans
72804160e00SKyle Evans *isrcp = &ai->ai_isrc;
72904160e00SKyle Evans return (0);
73004160e00SKyle Evans }
73104160e00SKyle Evans
73204160e00SKyle Evans static void
apple_aic_init_secondary(device_t dev,uint32_t rootnum)73304160e00SKyle Evans apple_aic_init_secondary(device_t dev, uint32_t rootnum)
73404160e00SKyle Evans {
73504160e00SKyle Evans struct apple_aic_softc *sc = device_get_softc(dev);
73604160e00SKyle Evans u_int cpu = PCPU_GET(cpuid);
73704160e00SKyle Evans
73804160e00SKyle Evans /* We don't need to re-initialize for the FIQ root. */
73904160e00SKyle Evans if (rootnum != INTR_ROOT_IRQ)
74004160e00SKyle Evans return;
74104160e00SKyle Evans
74204160e00SKyle Evans sc->sc_cpuids[cpu] = bus_read_4(sc->sc_mem, AIC_WHOAMI);
74304160e00SKyle Evans if (bootverbose)
74404160e00SKyle Evans device_printf(dev, "CPU %d: whoami %x\n", cpu,
74504160e00SKyle Evans sc->sc_cpuids[cpu]);
74604160e00SKyle Evans
74704160e00SKyle Evans bus_write_4(sc->sc_mem, AIC_IPI_MASK_SET, AIC_IPI_SELF | AIC_IPI_OTHER);
74804160e00SKyle Evans }
74904160e00SKyle Evans #endif
75004160e00SKyle Evans
75104160e00SKyle Evans static device_method_t apple_aic_methods[] = {
75204160e00SKyle Evans /* Device interface */
75304160e00SKyle Evans DEVMETHOD(device_probe, apple_aic_probe),
75404160e00SKyle Evans DEVMETHOD(device_attach, apple_aic_attach),
75504160e00SKyle Evans
75604160e00SKyle Evans /* Interrupt controller interface */
75704160e00SKyle Evans DEVMETHOD(pic_disable_intr, apple_aic_disable_intr),
75804160e00SKyle Evans DEVMETHOD(pic_enable_intr, apple_aic_enable_intr),
75904160e00SKyle Evans DEVMETHOD(pic_map_intr, apple_aic_map_intr),
76004160e00SKyle Evans DEVMETHOD(pic_setup_intr, apple_aic_setup_intr),
76104160e00SKyle Evans DEVMETHOD(pic_teardown_intr, apple_aic_teardown_intr),
76204160e00SKyle Evans DEVMETHOD(pic_post_filter, apple_aic_post_filter),
76304160e00SKyle Evans DEVMETHOD(pic_post_ithread, apple_aic_post_ithread),
76404160e00SKyle Evans DEVMETHOD(pic_pre_ithread, apple_aic_pre_ithread),
76504160e00SKyle Evans #ifdef SMP
76604160e00SKyle Evans DEVMETHOD(pic_bind_intr, apple_aic_bind_intr),
76704160e00SKyle Evans DEVMETHOD(pic_init_secondary, apple_aic_init_secondary),
76804160e00SKyle Evans DEVMETHOD(pic_ipi_send, apple_aic_ipi_send),
76904160e00SKyle Evans DEVMETHOD(pic_ipi_setup, apple_aic_ipi_setup),
77004160e00SKyle Evans #endif
77104160e00SKyle Evans
77204160e00SKyle Evans /* End */
77304160e00SKyle Evans DEVMETHOD_END
77404160e00SKyle Evans };
77504160e00SKyle Evans
77604160e00SKyle Evans static DEFINE_CLASS_0(aic, apple_aic_driver, apple_aic_methods,
77704160e00SKyle Evans sizeof(struct apple_aic_softc));
77804160e00SKyle Evans
77904160e00SKyle Evans EARLY_DRIVER_MODULE(aic, simplebus, apple_aic_driver, 0, 0,
78004160e00SKyle Evans BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
781