diff --git a/sys/arm/arm/gic.c b/sys/arm/arm/gic.c index 9472edb..5fe15e7 100644 --- a/sys/arm/arm/gic.c +++ b/sys/arm/arm/gic.c @@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "pic_if.h" + /* We are using GICv2 register naming */ /* Distributor Registers */ @@ -93,13 +95,14 @@ __FBSDID("$FreeBSD$"); #define GICD_ICFGR_TRIG_MASK 0x2 struct arm_gic_softc { + device_t gic_dev; struct resource * gic_res[3]; bus_space_tag_t gic_c_bst; bus_space_tag_t gic_d_bst; bus_space_handle_t gic_c_bsh; bus_space_handle_t gic_d_bsh; + void * gic_intrhand; uint8_t ver; - device_t dev; struct mtx mutex; uint32_t nirqs; }; @@ -107,85 +110,74 @@ struct arm_gic_softc { static struct resource_spec arm_gic_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ + { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Parent interrupt */ { -1, 0 } }; static struct arm_gic_softc *arm_gic_sc = NULL; -#define gic_c_read_4(reg) \ - bus_space_read_4(arm_gic_sc->gic_c_bst, arm_gic_sc->gic_c_bsh, reg) -#define gic_c_write_4(reg, val) \ - bus_space_write_4(arm_gic_sc->gic_c_bst, arm_gic_sc->gic_c_bsh, reg, val) -#define gic_d_read_4(reg) \ - bus_space_read_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg) -#define gic_d_write_4(reg, val) \ - bus_space_write_4(arm_gic_sc->gic_d_bst, arm_gic_sc->gic_d_bsh, reg, val) - -static int gic_config_irq(int irq, enum intr_trigger trig, - enum intr_polarity pol); -static void gic_post_filter(void *); +static int arm_gic_probe(device_t); +static int arm_gic_attach(device_t); +static void arm_gic_init_secondary(device_t); +static int arm_gic_intr(void *); +static int arm_gic_config(device_t, int, enum intr_trigger, enum intr_polarity); +static void arm_gic_eoi(device_t, int); +static void arm_gic_mask(device_t, int); +static void arm_gic_unmask(device_t, int); +static void arm_gic_ipi_send(device_t, cpuset_t, int); +static void arm_gic_ipi_clear(device_t, int); + +#define gic_c_read_4(_sc, _reg) \ + bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) +#define gic_c_write_4(_sc, _reg, _val) \ + bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) +#define gic_d_read_4(_sc, _reg) \ + bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) +#define gic_d_write_4(_sc, _reg, _val) \ + bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) static int arm_gic_probe(device_t dev) { - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - if (!ofw_bus_is_compatible(dev, "arm,gic")) return (ENXIO); device_set_desc(dev, "ARM Generic Interrupt Controller"); return (BUS_PROBE_DEFAULT); } -void -gic_init_secondary(void) +static void +arm_gic_init_secondary(device_t dev) { - int i, nirqs; - - /* Get the number of interrupts */ - nirqs = gic_d_read_4(GICD_TYPER); - nirqs = 32 * ((nirqs & 0x1f) + 1); - - for (i = 0; i < nirqs; i += 4) - gic_d_write_4(GICD_IPRIORITYR(i >> 2), 0); - - /* Set all the interrupts to be in Group 0 (secure) */ - for (i = 0; i < nirqs; i += 32) { - gic_d_write_4(GICD_IGROUPR(i >> 5), 0); - } + struct arm_gic_softc *sc = device_get_softc(dev); + + for (int i = 0; i < sc->nirqs; i += 4) + gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); /* Enable CPU interface */ - gic_c_write_4(GICC_CTLR, 1); - - /* Set priority mask register. */ - gic_c_write_4(GICC_PMR, 0xff); + gic_c_write_4(sc, GICC_CTLR, 1); /* Enable interrupt distribution */ - gic_d_write_4(GICD_CTLR, 0x01); - + gic_d_write_4(sc, GICD_CTLR, 0x01); + /* Activate IRQ 29, ie private timer IRQ*/ - gic_d_write_4(GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); + gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); } static int arm_gic_attach(device_t dev) { - struct arm_gic_softc *sc; + struct arm_gic_softc *sc = device_get_softc(dev); int i; uint32_t icciidr; - if (arm_gic_sc) - return (ENXIO); - - sc = device_get_softc(dev); - sc->dev = dev; - if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } + sc->gic_dev = dev; + arm_gic_sc = sc; + /* Initialize mutex */ mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); @@ -197,130 +189,99 @@ arm_gic_attach(device_t dev) sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); - arm_gic_sc = sc; + arm_register_pic(dev, PIC_FEATURE_IPI); + + if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_MISC | INTR_CONTROLLER, + arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { + device_printf(dev, "could not setup interrupt handler\n"); + bus_release_resources(dev, arm_gic_spec, sc->gic_res); + return (ENXIO); + } /* Disable interrupt forwarding to the CPU interface */ - gic_d_write_4(GICD_CTLR, 0x00); + gic_d_write_4(sc, GICD_CTLR, 0x00); /* Get the number of interrupts */ - sc->nirqs = gic_d_read_4(GICD_TYPER); + sc->nirqs = gic_d_read_4(sc, GICD_TYPER); sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); - /* Set up function pointers */ - arm_post_filter = gic_post_filter; - arm_config_irq = gic_config_irq; - - icciidr = gic_c_read_4(GICC_IIDR); - device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x sc->nirqs %u\n", + icciidr = gic_c_read_4(sc, GICC_IIDR); + device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x nirqs %u\n", icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, (icciidr & 0xfff), sc->nirqs); /* Set all global interrupts to be level triggered, active low. */ - for (i = 32; i < sc->nirqs; i += 16) { - gic_d_write_4(GICD_ICFGR(i >> 4), 0x00000000); + for (i = 32; i < sc->nirqs; i += 32) { + gic_d_write_4(sc, GICD_ICFGR(i >> 5), 0x00000000); } /* Disable all interrupts. */ for (i = 32; i < sc->nirqs; i += 32) { - gic_d_write_4(GICD_ICENABLER(i >> 5), 0xFFFFFFFF); + gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF); } for (i = 0; i < sc->nirqs; i += 4) { - gic_d_write_4(GICD_IPRIORITYR(i >> 2), 0); - gic_d_write_4(GICD_ITARGETSR(i >> 2), 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24); + gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); + gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), 0xffffffff); } /* Set all the interrupts to be in Group 0 (secure) */ for (i = 0; i < sc->nirqs; i += 32) { - gic_d_write_4(GICD_IGROUPR(i >> 5), 0); + gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); } /* Enable CPU interface */ - gic_c_write_4(GICC_CTLR, 1); + gic_c_write_4(sc, GICC_CTLR, 1); /* Set priority mask register. */ - gic_c_write_4(GICC_PMR, 0xff); + gic_c_write_4(sc, GICC_PMR, 0xff); /* Enable interrupt distribution */ - gic_d_write_4(GICD_CTLR, 0x01); + gic_d_write_4(sc, GICD_CTLR, 0x01); return (0); } -static device_method_t arm_gic_methods[] = { - DEVMETHOD(device_probe, arm_gic_probe), - DEVMETHOD(device_attach, arm_gic_attach), - { 0, 0 } -}; - -static driver_t arm_gic_driver = { - "gic", - arm_gic_methods, - sizeof(struct arm_gic_softc), -}; - -static devclass_t arm_gic_devclass; - -DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0); - -static void -gic_post_filter(void *arg) -{ - uintptr_t irq = (uintptr_t) arg; - - gic_c_write_4(GICC_EOIR, irq); -} - -int -arm_get_next_irq(int last_irq) +static int +arm_gic_intr(void *arg) { - uint32_t active_irq; + struct arm_gic_softc *sc = (struct arm_gic_softc *)arg; + uint32_t active_irq, last_irq = 0; - active_irq = gic_c_read_4(GICC_IAR); + active_irq = gic_c_read_4(sc, GICC_IAR); - /* + /* * Immediatly EOIR the SGIs, because doing so requires the other * bits (ie CPU number), not just the IRQ number, and we do not * have this information later. */ - + if ((active_irq & 0x3ff) < 16) - gic_c_write_4(GICC_EOIR, active_irq); + gic_c_write_4(sc, GICC_EOIR, active_irq); active_irq &= 0x3FF; if (active_irq == 0x3FF) { if (last_irq == -1) printf("Spurious interrupt detected [0x%08x]\n", active_irq); - return -1; + return (FILTER_HANDLED); } + + gic_c_write_4(sc, GICC_EOIR, active_irq); + arm_dispatch_irq(sc->gic_dev, NULL, active_irq); - return active_irq; -} - -void -arm_mask_irq(uintptr_t nb) -{ - - gic_d_write_4(GICD_ICENABLER(nb >> 5), (1UL << (nb & 0x1F))); - gic_c_write_4(GICC_EOIR, nb); -} - -void -arm_unmask_irq(uintptr_t nb) -{ - - gic_d_write_4(GICD_ISENABLER(nb >> 5), (1UL << (nb & 0x1F))); + return (FILTER_HANDLED); } static int -gic_config_irq(int irq, enum intr_trigger trig, +arm_gic_config(device_t dev, int irq, enum intr_trigger trig, enum intr_polarity pol) { + struct arm_gic_softc *sc = device_get_softc(dev); uint32_t reg; uint32_t mask; /* Function is public-accessible, so validate input arguments */ - if ((irq < 0) || (irq >= arm_gic_sc->nirqs)) + if ((irq < 0) || (irq >= sc->nirqs)) goto invalid_args; if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) && (trig != INTR_TRIGGER_CONFORM)) @@ -329,9 +290,9 @@ gic_config_irq(int irq, enum intr_trigger trig, (pol != INTR_POLARITY_CONFORM)) goto invalid_args; - mtx_lock_spin(&arm_gic_sc->mutex); + mtx_lock_spin(&sc->mutex); - reg = gic_d_read_4(GICD_ICFGR(irq >> 4)); + reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); mask = (reg >> 2*(irq % 16)) & 0x3; if (pol == INTR_POLARITY_LOW) { @@ -353,32 +314,58 @@ gic_config_irq(int irq, enum intr_trigger trig, /* Set mask */ reg = reg & ~(0x3 << 2*(irq % 16)); reg = reg | (mask << 2*(irq % 16)); - gic_d_write_4(GICD_ICFGR(irq >> 4), reg); + gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); - mtx_unlock_spin(&arm_gic_sc->mutex); + mtx_unlock_spin(&sc->mutex); return (0); invalid_args: - device_printf(arm_gic_sc->dev, "gic_config_irg, invalid parameters\n"); + device_printf(dev, "gic_config_irg, invalid parameters\n"); return (EINVAL); } -#ifdef SMP -void -pic_ipi_send(cpuset_t cpus, u_int ipi) +static void +arm_gic_eoi(device_t dev, int irq) +{ + struct arm_gic_softc *sc = device_get_softc(dev); + + gic_c_write_4(sc, GICC_EOIR, irq); +} + + +static void +arm_gic_mask(device_t dev, int irq) +{ + struct arm_gic_softc *sc = device_get_softc(dev); + + gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); +} + +static void +arm_gic_unmask(device_t dev, int irq) +{ + struct arm_gic_softc *sc = device_get_softc(dev); + + gic_c_write_4(sc, GICC_EOIR, irq); + gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); +} + +static void +arm_gic_ipi_send(device_t dev, cpuset_t cpus, int ipi) { + struct arm_gic_softc *sc = device_get_softc(dev); uint32_t val = 0, i; for (i = 0; i < MAXCPU; i++) if (CPU_ISSET(i, &cpus)) val |= 1 << (16 + i); - gic_d_write_4(GICD_SGIR(0), val | ipi); + gic_d_write_4(sc, GICD_SGIR(0), val | ipi); } -int -pic_ipi_get(int i) +static int +arm_gic_ipi_read(device_t dev, int i) { if (i != -1) { @@ -386,16 +373,44 @@ pic_ipi_get(int i) * The intr code will automagically give the frame pointer * if the interrupt argument is 0. */ - if ((unsigned int)i > 16) + if ((unsigned int)i > 16) return (0); return (i); } + return (0x3ff); } -void -pic_ipi_clear(int ipi) +static void +arm_gic_ipi_clear(device_t dev, int ipi) { + /* no-op */ } -#endif + +static device_method_t arm_gic_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, arm_gic_probe), + DEVMETHOD(device_attach, arm_gic_attach), + + /* Interrupt controller interface */ + DEVMETHOD(pic_config, arm_gic_config), + DEVMETHOD(pic_mask, arm_gic_mask), + DEVMETHOD(pic_unmask, arm_gic_unmask), + DEVMETHOD(pic_eoi, arm_gic_eoi), + DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), + DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), + DEVMETHOD(pic_ipi_clear, arm_gic_ipi_clear), + DEVMETHOD(pic_ipi_read, arm_gic_ipi_read), + { 0, 0 } +}; + +static driver_t arm_gic_driver = { + "gic", + arm_gic_methods, + sizeof(struct arm_gic_softc), +}; + +static devclass_t arm_gic_devclass; + +DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0); diff --git a/sys/arm/arm/intr.c b/sys/arm/arm/intr.c index ac93cbd..b1333d7 100644 --- a/sys/arm/arm/intr.c +++ b/sys/arm/arm/intr.c @@ -86,6 +86,15 @@ arm_intrnames_init(void) } } +const char * +arm_describe_irq(int irq) +{ + static char buffer[8]; + + sprintf(buffer, "%d", irq); + return (buffer); +} + void arm_setup_irqhandler(const char *name, driver_filter_t *filt, void (*hand)(void*), void *arg, int irq, int flags, void **cookiep) diff --git a/sys/arm/arm/intrng.c b/sys/arm/arm/intrng.c new file mode 100644 index 0000000..40db6f4 --- /dev/null +++ b/sys/arm/arm/intrng.c @@ -0,0 +1,422 @@ +/*- + * Copyright (c) 2012-2014 Jakub Wojciech Klama . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Mark Brinicombe + * for the NetBSD Project. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "pic_if.h" + +#define IRQ_PIC_IDX(_irq) ((_irq >> 8) & 0xff) +#define IRQ_VECTOR_IDX(_irq) ((_irq) & 0xff) +#define IRQ_GEN(_pic, _irq) (((_pic) << 8) | ((_irq) & 0xff)) + +#ifdef DEBUG +#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ + printf(fmt,##args); } while (0) +#else +#define debugf(fmt, args...) +#endif + +typedef void (*mask_fn)(void *); + +struct arm_intr_controller { + device_t ic_dev; + phandle_t ic_node; +}; + +struct arm_intr_handler { + device_t ih_dev; + const char * ih_ipi_name; + int ih_intrcnt_idx; + int ih_irq; + struct intr_event * ih_event; + struct arm_intr_controller *ih_pic; +}; + +static void arm_mask_irq(void *); +static void arm_unmask_irq(void *); +static void arm_eoi(void *); + +static struct arm_intr_handler arm_intrs[NIRQ]; +static struct arm_intr_controller arm_pics[NPIC]; +static struct arm_intr_controller *arm_ipi_pic; + +static int intrcnt_index = 0; +static int last_printed = 0; + +/* Data for statistics reporting. */ +#define INTRNAME_LEN (MAXCOMLEN + 1) +u_long intrcnt[NIRQ]; +char intrnames[NIRQ * INTRNAME_LEN]; +size_t sintrcnt = sizeof(intrcnt); +size_t sintrnames = sizeof(intrnames); +int (*arm_config_irq)(int irq, enum intr_trigger trig, + enum intr_polarity pol) = NULL; + +void +arm_intrnames_init(void) +{ + /* nothing... */ +} + +void +arm_dispatch_irq(device_t dev, struct trapframe *tf, int irq) +{ + struct arm_intr_handler *ih = NULL; + int i; + + debugf("pic %s, tf %p, irq %d\n", device_get_nameunit(dev), tf, irq); + + for (i = 0; arm_intrs[i].ih_dev != NULL; i++) { + if (arm_intrs[i].ih_pic->ic_dev == dev && + arm_intrs[i].ih_irq == irq) { + ih = &arm_intrs[i]; + break; + } + } + + if (ih == NULL) + panic("arm_dispatch_irq: unknown irq"); + + debugf("requested by %s\n", ih->ih_ipi_name != NULL + ? ih->ih_ipi_name + : device_get_nameunit(ih->ih_dev)); + + intrcnt[ih->ih_intrcnt_idx]++; + if (intr_event_handle(ih->ih_event, tf) != 0) { + /* Stray IRQ */ + arm_mask_irq(ih); + } + + debugf("done\n"); +} + +static struct arm_intr_handler * +arm_lookup_intr_handler(device_t pic, int irq) +{ + int i; + + for (i = 0; i < NIRQ; i++) { + if (arm_intrs[i].ih_pic != NULL && + arm_intrs[i].ih_pic->ic_dev == pic && + arm_intrs[i].ih_irq == irq) + return (&arm_intrs[i]); + + if (arm_intrs[i].ih_dev == NULL) + return (&arm_intrs[i]); + } + + return NULL; +} + +int +arm_fdt_map_irq(phandle_t ic, int irq) +{ + int i; + + ic = OF_xref_phandle(ic); + + debugf("ic %08x irq %d\n", ic, irq); + + if (ic == CORE_PIC_NODE) + return (IRQ_GEN(CORE_PIC_IDX, irq)); + + for (i = 0; arm_pics[i].ic_node != 0; i++) { + if (arm_pics[i].ic_node == ic) + return (IRQ_GEN(i, irq)); + } + + /* + * Interrupt controller is not registered yet, so + * we map a stub for it. 'i' is pointing to free + * first slot in arm_pics table. + */ + arm_pics[i].ic_node = ic; + return (IRQ_GEN(i, irq)); +} + +const char * +arm_describe_irq(int irq) +{ + struct arm_intr_controller *pic; + static char buffer[32]; + + pic = &arm_pics[IRQ_PIC_IDX(irq)]; + sprintf(buffer, "%s:%d", device_get_nameunit(pic->ic_dev), + IRQ_VECTOR_IDX(irq)); + + return (buffer); +} + +void +arm_register_pic(device_t dev, int flags) +{ + struct arm_intr_controller *ic = NULL; + phandle_t node; + int i; + + node = ofw_bus_get_node(dev); + + /* Find room for IC */ + for (i = 0; i < NPIC; i++) { + if (arm_pics[i].ic_dev != NULL) + continue; + + if (arm_pics[i].ic_node == node) { + ic = &arm_pics[i]; + break; + } + + if (arm_pics[i].ic_node == 0) { + ic = &arm_pics[i]; + break; + } + } + + if (ic == NULL) + panic("not enough room to register interrupt controller"); + + ic->ic_dev = dev; + ic->ic_node = node; + + debugf("device %s node %08x slot %d\n", device_get_nameunit(dev), ic->ic_node, i); + + if (flags & PIC_FEATURE_IPI) { + if (arm_ipi_pic != NULL) + panic("there's already registered interrupt controller for serving IPIs"); + + arm_ipi_pic = ic; + } + + device_printf(dev, "registered as interrupt controller\n"); +} + +void +arm_setup_irqhandler(device_t dev, driver_filter_t *filt, + void (*hand)(void*), void *arg, int irq, int flags, void **cookiep) +{ + struct arm_intr_controller *pic; + struct arm_intr_handler *ih; + const char *name; + int error; + int ipi; + + if (irq < 0) + return; + + ipi = (flags & INTR_IPI) != 0; + pic = ipi ? arm_ipi_pic : &arm_pics[IRQ_PIC_IDX(irq)]; + ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq)); + + if (ipi) { + name = (const char *)dev; + debugf("setup ipi %d\n", irq); + } else { + name = device_get_nameunit(dev); + debugf("setup irq %d on %s\n", IRQ_VECTOR_IDX(irq), + device_get_nameunit(pic->ic_dev)); + } + + debugf("pic %p, ih %p\n", pic, ih); + + if (ih->ih_event == NULL) { + error = intr_event_create(&ih->ih_event, (void *)ih, 0, irq, + (mask_fn)arm_mask_irq, (mask_fn)arm_unmask_irq, + arm_eoi, NULL, "intr%d:", irq); + + if (error) + return; + + ih->ih_dev = dev; + ih->ih_ipi_name = ipi ? name : NULL; + ih->ih_irq = IRQ_VECTOR_IDX(irq); + ih->ih_pic = pic; + + arm_unmask_irq(ih); + + last_printed += + snprintf(intrnames + last_printed, + MAXCOMLEN + 1, "%s:%d: %s", + device_get_nameunit(pic->ic_dev), + ih->ih_irq, name); + + last_printed++; + ih->ih_intrcnt_idx = intrcnt_index; + intrcnt_index++; + + } + + intr_event_add_handler(ih->ih_event, name, filt, hand, arg, + intr_priority(flags), flags, cookiep); + + /* Unmask IPIs immediately */ + if (ipi) + arm_unmask_irq(ih); +} + +int +arm_remove_irqhandler(int irq, void *cookie) +{ + struct arm_intr_controller *pic; + struct arm_intr_handler *ih; + int error; + + if (irq < 0) + return (ENXIO); + + pic = &arm_pics[IRQ_PIC_IDX(irq)]; + ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq)); + + if (ih->ih_event == NULL) + return (ENXIO); + + arm_mask_irq(ih); + error = intr_event_remove_handler(cookie); + + if (!TAILQ_EMPTY(&ih->ih_event->ie_handlers)) + arm_unmask_irq(ih); + + return (error); +} + +static void +arm_mask_irq(void *arg) +{ + struct arm_intr_handler *ih = (struct arm_intr_handler *)arg; + + PIC_MASK(ih->ih_pic->ic_dev, ih->ih_irq); +} + +static void +arm_unmask_irq(void *arg) +{ + struct arm_intr_handler *ih = (struct arm_intr_handler *)arg; + + PIC_UNMASK(ih->ih_pic->ic_dev, ih->ih_irq); +} + +static void +arm_eoi(void *arg) +{ + struct arm_intr_handler *ih = (struct arm_intr_handler *)arg; + + PIC_EOI(ih->ih_pic->ic_dev, ih->ih_irq); +} + +int +arm_intrng_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol) +{ + struct arm_intr_controller *pic; + struct arm_intr_handler *ih; + + pic = &arm_pics[IRQ_PIC_IDX(irq)]; + ih = arm_lookup_intr_handler(pic->ic_dev, IRQ_VECTOR_IDX(irq)); + + if (ih == NULL) + return (ENXIO); + + return PIC_CONFIG(pic->ic_dev, ih->ih_irq, trig, pol); +} + +#ifdef SMP +void +arm_init_secondary_ic(void) +{ + + KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached")); + PIC_INIT_SECONDARY(arm_ipi_pic->ic_dev); +} + +void +pic_ipi_send(cpuset_t cpus, u_int ipi) +{ + + KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached")); + PIC_IPI_SEND(arm_ipi_pic->ic_dev, cpus, ipi); +} + +void +pic_ipi_clear(int ipi) +{ + + KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached")); + PIC_IPI_CLEAR(arm_ipi_pic->ic_dev, ipi); +} + +int +pic_ipi_read(int ipi) +{ + + KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached")); + return (PIC_IPI_READ(arm_ipi_pic->ic_dev, ipi)); +} + +void +arm_unmask_ipi(int ipi) +{ + + KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached")); + PIC_UNMASK(arm_ipi_pic->ic_dev, ipi); +} + +void +arm_mask_ipi(int ipi) +{ + + KASSERT(arm_ipi_pic != NULL, ("no IPI PIC attached")); + PIC_MASK(arm_ipi_pic->ic_dev, ipi); +} +#endif + +void dosoftints(void); +void +dosoftints(void) +{ +} + diff --git a/sys/arm/arm/mp_machdep.c b/sys/arm/arm/mp_machdep.c index 0d6a0fc..6c79557 100644 --- a/sys/arm/arm/mp_machdep.c +++ b/sys/arm/arm/mp_machdep.c @@ -235,7 +235,7 @@ init_secondary(int cpu) #endif for (int i = start; i <= end; i++) - arm_unmask_irq(i); + arm_unmask_ipi(i); enable_interrupts(I32_bit); loop_counter = 0; @@ -265,7 +265,7 @@ ipi_handler(void *arg) cpu = PCPU_GET(cpuid); - ipi = pic_ipi_get((int)arg); + ipi = pic_ipi_read((int)arg); while ((ipi != 0x3ff)) { switch (ipi) { @@ -316,7 +316,7 @@ ipi_handler(void *arg) } pic_ipi_clear(ipi); - ipi = pic_ipi_get(-1); + ipi = pic_ipi_read(-1); } return (FILTER_HANDLED); @@ -348,11 +348,10 @@ release_aps(void *dummy __unused) * if we used 0, the intr code will give the trap frame * pointer instead. */ - arm_setup_irqhandler("ipi", ipi_handler, NULL, (void *)i, i, - INTR_TYPE_MISC | INTR_EXCL, NULL); - - /* Enable ipi */ - arm_unmask_irq(i); + arm_setup_irqhandler((device_t)"ipi", ipi_handler, NULL, (void *)i, i, + INTR_TYPE_MISC | INTR_EXCL | INTR_IPI, NULL); + + arm_unmask_ipi(i); } atomic_store_rel_int(&aps_ready, 1); diff --git a/sys/arm/arm/nexus.c b/sys/arm/arm/nexus.c index fe1261f..25c16dc 100644 --- a/sys/arm/arm/nexus.c +++ b/sys/arm/arm/nexus.c @@ -68,6 +68,8 @@ __FBSDID("$FreeBSD$"); #include "ofw_bus_if.h" #endif +#include "pic_if.h" + static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device"); struct nexus_device { @@ -77,6 +79,9 @@ struct nexus_device { #define DEVTONX(dev) ((struct nexus_device *)device_get_ivars(dev)) static struct rman mem_rman; +#if defined(ARM_INTRNG) +static device_t nexus_dev; +#endif static int nexus_probe(device_t); static int nexus_attach(device_t); @@ -94,6 +99,13 @@ static int nexus_deactivate_resource(device_t, device_t, int, int, static int nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep); static int nexus_teardown_intr(device_t, device_t, struct resource *, void *); +#if defined(ARM_INTRNG) +static int nexus_pic_config(device_t, int, enum intr_trigger, enum intr_polarity); +static void nexus_pic_mask(device_t, int); +static void nexus_pic_unmask(device_t, int); +static void nexus_pic_eoi(device_t, int); +void arm_irq_handler(struct trapframe *tf, int irqnb); +#endif #ifdef FDT static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, @@ -104,6 +116,7 @@ static device_method_t nexus_methods[] = { /* Device interface */ DEVMETHOD(device_probe, nexus_probe), DEVMETHOD(device_attach, nexus_attach), + /* Bus interface */ DEVMETHOD(bus_print_child, nexus_print_child), DEVMETHOD(bus_add_child, nexus_add_child), @@ -116,6 +129,13 @@ static device_method_t nexus_methods[] = { #ifdef FDT DEVMETHOD(ofw_bus_map_intr, nexus_ofw_map_intr), #endif +#ifdef ARM_INTRNG + /* PIC interface */ + DEVMETHOD(pic_config, nexus_pic_config), + DEVMETHOD(pic_mask, nexus_pic_mask), + DEVMETHOD(pic_unmask, nexus_pic_unmask), + DEVMETHOD(pic_eoi, nexus_pic_eoi), +#endif { 0, 0 } }; @@ -147,6 +167,12 @@ nexus_attach(device_t dev) if (rman_init(&mem_rman) || rman_manage_region(&mem_rman, 0, ~0)) panic("nexus_probe mem_rman"); +#if defined(ARM_INTRNG) + /* Register core interrupt controller */ + nexus_dev = dev; + arm_register_pic(dev, 0); +#endif + /* * First, deal with the children we know about already */ @@ -233,9 +259,12 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig, { int ret = ENODEV; +#ifdef ARM_INTRNG + ret = arm_intrng_config_irq(irq, trig, pol); +#else if (arm_config_irq) ret = (*arm_config_irq)(irq, trig, pol); - +#endif return (ret); } @@ -249,10 +278,16 @@ nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, flags |= INTR_EXCL; for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) { +#if defined(ARM_INTRNG) + arm_setup_irqhandler(child, + filt, intr, arg, irq, flags, cookiep); +#else arm_setup_irqhandler(device_get_nameunit(child), filt, intr, arg, irq, flags, cookiep); arm_unmask_irq(irq); +#endif } + return (0); } @@ -327,6 +362,41 @@ nexus_deactivate_resource(device_t bus, device_t child, int type, int rid, return (rman_deactivate_resource(r)); } +#if defined(ARM_INTRNG) +static int +nexus_pic_config(device_t bus, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + /* unused */ + return (0); +} + +static void +nexus_pic_mask(device_t bus, int irq) +{ + /* unused */ +} + +static void +nexus_pic_unmask(device_t bus, int irq) +{ + /* unused */ +} + +static void +nexus_pic_eoi(device_t bus, int irq) +{ + /* unused */ +} + +void +arm_irq_handler(struct trapframe *tf, int irqnb) +{ + /* Dispatch root interrupt from core */ + arm_dispatch_irq(nexus_dev, tf, 0); +} +#endif + #ifdef FDT static int nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, @@ -337,6 +407,7 @@ nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, int i, rv, interrupt, trig, pol; intr_offset = OF_xref_phandle(iparent); + for (i = 0; i < icells; i++) intr[i] = cpu_to_fdt32(intr[i]); @@ -346,13 +417,13 @@ nexus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells, if (rv == 0) { /* This was recognized as our PIC and decoded. */ - interrupt = FDT_MAP_IRQ(intr_parent, interrupt); + interrupt = FDT_MAP_IRQ(iparent, interrupt); return (interrupt); } } /* Not in table, so guess */ - interrupt = FDT_MAP_IRQ(intr_parent, fdt32_to_cpu(intr[0])); + interrupt = FDT_MAP_IRQ(iparent, fdt32_to_cpu(intr[0])); return (interrupt); } diff --git a/sys/arm/arm/pic_if.m b/sys/arm/arm/pic_if.m new file mode 100644 index 0000000..b2081ca --- /dev/null +++ b/sys/arm/arm/pic_if.m @@ -0,0 +1,96 @@ +#- +# Copyright (c) 2012 Jakub Wojciech Klama +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include +#include + +INTERFACE pic; + +CODE { + static void null_pic_ipi_send(device_t dev, cpuset_t cpus, int ipi) + { + return; + } + + static void null_pic_ipi_clear(device_t dev, int ipi) + { + return; + } + + static int null_pic_ipi_read(device_t dev, int ipi) + { + return (ipi); + } + + static void null_pic_init_secondary(device_t dev) + { + return; + } +}; + +METHOD int config { + device_t dev; + int irq; + enum intr_trigger trig; + enum intr_polarity pol; +}; + +METHOD void eoi { + device_t dev; + int irq; +}; + +METHOD void mask { + device_t dev; + int irq; +}; + +METHOD void unmask { + device_t dev; + int irq; +}; + +METHOD void init_secondary { + device_t dev; +} DEFAULT null_pic_init_secondary; + +METHOD void ipi_send { + device_t dev; + cpuset_t cpus; + int ipi; +} DEFAULT null_pic_ipi_send; + +METHOD void ipi_clear { + device_t dev; + int ipi; +} DEFAULT null_pic_ipi_clear; + +METHOD int ipi_read { + device_t dev; + int ipi; +} DEFAULT null_pic_ipi_read; diff --git a/sys/arm/broadcom/bcm2835/files.bcm2835 b/sys/arm/broadcom/bcm2835/files.bcm2835 index 1bb1cf6..2f76c33 100644 --- a/sys/arm/broadcom/bcm2835/files.bcm2835 +++ b/sys/arm/broadcom/bcm2835/files.bcm2835 @@ -22,6 +22,7 @@ arm/arm/cpufunc_asm_arm11.S standard arm/arm/cpufunc_asm_arm11x6.S standard arm/arm/cpufunc_asm_armv5.S standard arm/arm/cpufunc_asm_armv6.S standard +arm/arm/intr.c standard kern/kern_clocksource.c standard diff --git a/sys/arm/conf/EA3250 b/sys/arm/conf/EA3250 index f2f809e..660728f 100644 --- a/sys/arm/conf/EA3250 +++ b/sys/arm/conf/EA3250 @@ -10,7 +10,7 @@ hints "EA3250.hints" makeoptions MODULES_OVERRIDE="" -#makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols +makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols makeoptions WERROR="-Werror" options SCHED_4BSD # 4BSD scheduler @@ -52,6 +52,8 @@ options WITNESS # Enable checks to detect deadlocks and cycles options WITNESS_SKIPSPIN # Don't run witness on spinlocks for speed #options WITNESS_KDB +options ARM_INTRNG + # Pseudo devices device loop device md @@ -76,9 +78,9 @@ device scbus device pass device da -device mmc -device mmcsd -device lpcmmc +#device mmc +#device mmcsd +#device lpcmmc device gpio device gpioled diff --git a/sys/arm/conf/PANDABOARD b/sys/arm/conf/PANDABOARD index 2a35b48..db0b1aa 100644 --- a/sys/arm/conf/PANDABOARD +++ b/sys/arm/conf/PANDABOARD @@ -49,11 +49,11 @@ options BREAK_TO_DEBUGGER options NFSCL options NFS_ROOT # NFS usable as /, requires NFSCLIENT -#options BOOTP_NFSROOT -#options BOOTP_COMPAT -#options BOOTP -#options BOOTP_NFSV3 -#options BOOTP_WIRED_TO=ue0 +options BOOTP_NFSROOT +options BOOTP_COMPAT +options BOOTP +options BOOTP_NFSV3 +options BOOTP_WIRED_TO=ue0 options GEOM_PART_BSD # BSD partition scheme options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem @@ -70,6 +70,8 @@ options SYSVSEM # SYSV-style semaphores options _KPOSIX_PRIORITY_SCHEDULING # Posix P1003_1B real-time extensions options KBD_INSTALL_CDEV # install a CDEV entry in /dev options FREEBSD_BOOT_LOADER +options ARM_INTRNG +options SMP options PREEMPTION diff --git a/sys/arm/include/fdt.h b/sys/arm/include/fdt.h index 9bd9332..fad6ef9 100644 --- a/sys/arm/include/fdt.h +++ b/sys/arm/include/fdt.h @@ -40,11 +40,25 @@ #include #include +#if defined(ARM_INTRNG) + +/* Max interrupt number */ +#define FDT_INTR_MAX (0xffff) + +/* Map phandle/intpin pair to global IRQ number */ +#define FDT_MAP_IRQ(node, pin) (arm_fdt_map_irq(node, pin)) +#define FDT_DESCRIBE_IRQ(irq) (arm_describe_irq(irq)) + +#else + /* Max interrupt number */ #define FDT_INTR_MAX NIRQ /* Map phandle/intpin pair to global IRQ number */ #define FDT_MAP_IRQ(node, pin) (pin) +#define FDT_DESCRIBE_IRQ(irq) (arm_describe_irq(irq)) + +#endif /* ARM_INTRNG */ /* * Bus space tag. XXX endianess info needs to be derived from the blob. @@ -56,3 +70,4 @@ struct arm_devmap_entry; int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *); #endif /* _MACHINE_FDT_H_ */ + diff --git a/sys/arm/include/intr.h b/sys/arm/include/intr.h index 49d6c05..09b9812 100644 --- a/sys/arm/include/intr.h +++ b/sys/arm/include/intr.h @@ -39,6 +39,41 @@ #ifndef _MACHINE_INTR_H_ #define _MACHINE_INTR_H_ +#include +#include +#include + +#include "opt_global.h" + +#if defined(ARM_INTRNG) + +#define NIRQ 255 +#define NPIC 16 +#define INTR_CONTROLLER INTR_MD1 +#define INTR_IPI INTR_MD2 +#define CORE_PIC_IDX (0) +#define CORE_PIC_NODE (0xffffffff) + +/* Interrupt controller features used in arm_register_pic(): */ +#define PIC_FEATURE_IPI 0x1 + +int arm_fdt_map_irq(phandle_t ic, int irq); +void arm_register_pic(device_t dev, int features); +void arm_unregister_pic(device_t dev); +void arm_dispatch_irq(device_t dev, struct trapframe *tf, int irq); +void arm_setup_irqhandler(device_t dev, int (*)(void*), void (*)(void*), + void *, int, int, void **); +int arm_remove_irqhandler(int, void *); +int arm_intrng_config_irq(int, enum intr_trigger, enum intr_polarity); + +#ifdef SMP +void arm_init_secondary_ic(void); +void arm_unmask_ipi(int); +void arm_mask_ipi(int); +#endif + +#else + /* XXX move to std.* files? */ #ifdef CPU_XSCALE_81342 #define NIRQ 128 @@ -71,14 +106,17 @@ int arm_get_next_irq(int); void arm_mask_irq(uintptr_t); void arm_unmask_irq(uintptr_t); -void arm_intrnames_init(void); void arm_setup_irqhandler(const char *, int (*)(void*), void (*)(void*), void *, int, int, void **); int arm_remove_irqhandler(int, void *); extern void (*arm_post_filter)(void *); +void gic_init_secondary(void); + +#endif /* !ARM_INTRNG */ + extern int (*arm_config_irq)(int irq, enum intr_trigger trig, enum intr_polarity pol); - -void gic_init_secondary(void); +const char *arm_describe_irq(int irq); +void arm_intrnames_init(void); #endif /* _MACHINE_INTR_H */ diff --git a/sys/arm/include/smp.h b/sys/arm/include/smp.h index 179882d..1c61ec9 100644 --- a/sys/arm/include/smp.h +++ b/sys/arm/include/smp.h @@ -24,7 +24,7 @@ void ipi_selected(cpuset_t cpus, u_int ipi); /* PIC interface */ void pic_ipi_send(cpuset_t cpus, u_int ipi); void pic_ipi_clear(int ipi); -int pic_ipi_get(int arg); +int pic_ipi_read(int arg); /* Platform interface */ void platform_mp_setmaxid(void); diff --git a/sys/arm/lpc/lpc_intc.c b/sys/arm/lpc/lpc_intc.c index 3137e89..cf425674 100644 --- a/sys/arm/lpc/lpc_intc.c +++ b/sys/arm/lpc/lpc_intc.c @@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -47,22 +48,29 @@ __FBSDID("$FreeBSD$"); #include +#include "pic_if.h" + struct lpc_intc_softc { - struct resource * li_res; + device_t li_dev; + struct resource * li_mem_res; + struct resource * li_irq_res; bus_space_tag_t li_bst; bus_space_handle_t li_bsh; + void * li_intrhand; }; static int lpc_intc_probe(device_t); static int lpc_intc_attach(device_t); -static void lpc_intc_eoi(void *); - -static struct lpc_intc_softc *intc_softc = NULL; +static int lpc_intc_intr(void *); +static int lpc_intc_config(device_t, int, enum intr_trigger, enum intr_polarity); +static void lpc_intc_mask(device_t, int); +static void lpc_intc_unmask(device_t, int); +static void lpc_intc_eoi(device_t, int); -#define intc_read_4(reg) \ - bus_space_read_4(intc_softc->li_bst, intc_softc->li_bsh, reg) -#define intc_write_4(reg, val) \ - bus_space_write_4(intc_softc->li_bst, intc_softc->li_bsh, reg, val) +#define intc_read_4(_sc, _reg) \ + bus_space_read_4((_sc)->li_bst, (_sc)->li_bsh, _reg) +#define intc_write_4(_sc, _reg, _val) \ + bus_space_write_4((_sc)->li_bst, (_sc)->li_bsh, _reg, _val) static int lpc_intc_probe(device_t dev) @@ -84,144 +92,123 @@ lpc_intc_attach(device_t dev) struct lpc_intc_softc *sc = device_get_softc(dev); int rid = 0; - if (intc_softc) - return (ENXIO); - - sc->li_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + sc->li_dev = dev; + sc->li_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (!sc->li_res) { - device_printf(dev, "could not alloc resources\n"); + if (!sc->li_mem_res) { + device_printf(dev, "could not alloc memory resource\n"); return (ENXIO); } - sc->li_bst = rman_get_bustag(sc->li_res); - sc->li_bsh = rman_get_bushandle(sc->li_res); - intc_softc = sc; - arm_post_filter = lpc_intc_eoi; + rid = 0; + sc->li_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE | RF_SHAREABLE); + if (!sc->li_irq_res) { + device_printf(dev, "could not alloc interrupt resource\n"); + return (ENXIO); // XXX + } - /* Clear interrupt status registers and disable all interrupts */ - intc_write_4(LPC_INTC_MIC_ER, 0); - intc_write_4(LPC_INTC_SIC1_ER, 0); - intc_write_4(LPC_INTC_SIC2_ER, 0); - intc_write_4(LPC_INTC_MIC_RSR, ~0); - intc_write_4(LPC_INTC_SIC1_RSR, ~0); - intc_write_4(LPC_INTC_SIC2_RSR, ~0); - return (0); -} + sc->li_bst = rman_get_bustag(sc->li_mem_res); + sc->li_bsh = rman_get_bushandle(sc->li_mem_res); -static device_method_t lpc_intc_methods[] = { - DEVMETHOD(device_probe, lpc_intc_probe), - DEVMETHOD(device_attach, lpc_intc_attach), - { 0, 0 } -}; + arm_register_pic(dev, 0); -static driver_t lpc_intc_driver = { - "pic", - lpc_intc_methods, - sizeof(struct lpc_intc_softc), -}; - -static devclass_t lpc_intc_devclass; + if (bus_setup_intr(dev, sc->li_irq_res, INTR_TYPE_MISC | INTR_CONTROLLER, + lpc_intc_intr, NULL, sc, &sc->li_intrhand)) { + device_printf(dev, "could not setup interrupt handler\n"); + return (ENXIO); // XXX + } -DRIVER_MODULE(pic, simplebus, lpc_intc_driver, lpc_intc_devclass, 0, 0); + /* Clear interrupt status registers and disable all interrupts */ + intc_write_4(sc, LPC_INTC_ER, 0); + intc_write_4(sc, LPC_INTC_RSR, ~0); + return (0); +} -int -arm_get_next_irq(int last) +static int +lpc_intc_intr(void *arg) { + struct lpc_intc_softc *sc = (struct lpc_intc_softc *)arg; uint32_t value; int i; - /* IRQs 0-31 are mapped to LPC_INTC_MIC_SR */ - value = intc_read_4(LPC_INTC_MIC_SR); + value = intc_read_4(sc, LPC_INTC_SR); for (i = 0; i < 32; i++) { if (value & (1 << i)) - return (i); + arm_dispatch_irq(sc->li_dev, NULL, i); } - /* IRQs 32-63 are mapped to LPC_INTC_SIC1_SR */ - value = intc_read_4(LPC_INTC_SIC1_SR); - for (i = 0; i < 32; i++) { - if (value & (1 << i)) - return (i + 32); - } - - /* IRQs 64-95 are mapped to LPC_INTC_SIC2_SR */ - value = intc_read_4(LPC_INTC_SIC2_SR); - for (i = 0; i < 32; i++) { - if (value & (1 << i)) - return (i + 64); - } + return (FILTER_HANDLED); +} - return (-1); +static int +lpc_intc_config(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + /* no-op */ + return (0); } -void -arm_mask_irq(uintptr_t nb) +static void +lpc_intc_mask(device_t dev, int irq) { - int reg; + struct lpc_intc_softc *sc = device_get_softc(dev); uint32_t value; - /* Make sure that interrupt isn't active already */ - lpc_intc_eoi((void *)nb); - - if (nb > 63) { - nb -= 64; - reg = LPC_INTC_SIC2_ER; - } else if (nb > 31) { - nb -= 32; - reg = LPC_INTC_SIC1_ER; - } else - reg = LPC_INTC_MIC_ER; + /* Make sure interrupt isn't active already */ + lpc_intc_eoi(dev, irq); /* Clear bit in ER register */ - value = intc_read_4(reg); - value &= ~(1 << nb); - intc_write_4(reg, value); + value = intc_read_4(sc, LPC_INTC_ER); + value &= ~(1 << irq); + intc_write_4(sc, LPC_INTC_ER, value); } -void -arm_unmask_irq(uintptr_t nb) +static void +lpc_intc_unmask(device_t dev, int irq) { - int reg; + struct lpc_intc_softc *sc = device_get_softc(dev); uint32_t value; - if (nb > 63) { - nb -= 64; - reg = LPC_INTC_SIC2_ER; - } else if (nb > 31) { - nb -= 32; - reg = LPC_INTC_SIC1_ER; - } else - reg = LPC_INTC_MIC_ER; - /* Set bit in ER register */ - value = intc_read_4(reg); - value |= (1 << nb); - intc_write_4(reg, value); + value = intc_read_4(sc, LPC_INTC_ER); + value |= (1 << irq); + intc_write_4(sc, LPC_INTC_ER, value); } static void -lpc_intc_eoi(void *data) +lpc_intc_eoi(device_t dev, int irq) { - int reg; - int nb = (int)data; + struct lpc_intc_softc *sc = device_get_softc(dev); uint32_t value; + + /* Set bit in RSR register */ + value = intc_read_4(sc, LPC_INTC_RSR); + value |= (1 << irq); + intc_write_4(sc, LPC_INTC_RSR, value); +} - if (nb > 63) { - nb -= 64; - reg = LPC_INTC_SIC2_RSR; - } else if (nb > 31) { - nb -= 32; - reg = LPC_INTC_SIC1_RSR; - } else - reg = LPC_INTC_MIC_RSR; +static device_method_t lpc_intc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, lpc_intc_probe), + DEVMETHOD(device_attach, lpc_intc_attach), + /* Interrupt controller interface */ + DEVMETHOD(pic_config, lpc_intc_config), + DEVMETHOD(pic_mask, lpc_intc_mask), + DEVMETHOD(pic_unmask, lpc_intc_unmask), + DEVMETHOD(pic_eoi, lpc_intc_eoi), + { 0, 0 } +}; - /* Set bit in RSR register */ - value = intc_read_4(reg); - value |= (1 << nb); - intc_write_4(reg, value); +static driver_t lpc_intc_driver = { + "pic", + lpc_intc_methods, + sizeof(struct lpc_intc_softc), +}; -} +static devclass_t lpc_intc_devclass; + +DRIVER_MODULE(pic, simplebus, lpc_intc_driver, lpc_intc_devclass, 0, 0); struct fdt_fixup_entry fdt_fixup_table[] = { { NULL, NULL } diff --git a/sys/arm/lpc/lpcreg.h b/sys/arm/lpc/lpcreg.h index b63dfbc..f094756 100644 --- a/sys/arm/lpc/lpcreg.h +++ b/sys/arm/lpc/lpcreg.h @@ -34,28 +34,17 @@ #define LPC_DEV_P6_PHYS_BASE 0x30000000 #define LPC_DEV_SIZE 0x10000000 + /* * Interrupt controller (from UM10326: LPC32x0 User manual, page 87) */ -#define LPC_INTC_MIC_ER 0x0000 -#define LPC_INTC_MIC_RSR 0x0004 -#define LPC_INTC_MIC_SR 0x0008 -#define LPC_INTC_MIC_APR 0x000c -#define LPC_INTC_MIC_ATR 0x0010 -#define LPC_INTC_MIC_ITR 0x0014 -#define LPC_INTC_SIC1_ER 0x4000 -#define LPC_INTC_SIC1_RSR 0x4004 -#define LPC_INTC_SIC1_SR 0x4008 -#define LPC_INTC_SIC1_APR 0x400c -#define LPC_INTC_SIC1_ATR 0x4010 -#define LPC_INTC_SIC1_ITR 0x4014 -#define LPC_INTC_SIC2_ER 0x8000 -#define LPC_INTC_SIC2_RSR 0x8004 -#define LPC_INTC_SIC2_SR 0x8008 -#define LPC_INTC_SIC2_APR 0x800c -#define LPC_INTC_SIC2_ATR 0x8010 -#define LPC_INTC_SIC2_ITR 0x8014 +#define LPC_INTC_ER 0x0000 +#define LPC_INTC_RSR 0x0004 +#define LPC_INTC_SR 0x0008 +#define LPC_INTC_APR 0x000c +#define LPC_INTC_ATR 0x0010 +#define LPC_INTC_ITR 0x0014 /* diff --git a/sys/arm/ti/aintc.c b/sys/arm/ti/aintc.c index 659db15..8bd01a2 100644 --- a/sys/arm/ti/aintc.c +++ b/sys/arm/ti/aintc.c @@ -45,6 +45,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include "pic_if.h" + #define INTC_REVISION 0x00 #define INTC_SYSCONFIG 0x10 #define INTC_SYSSTATUS 0x14 @@ -61,30 +63,31 @@ struct ti_aintc_softc { struct resource * aintc_res[3]; bus_space_tag_t aintc_bst; bus_space_handle_t aintc_bsh; + void * aintc_intrhand; uint8_t ver; }; static struct resource_spec ti_aintc_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, { -1, 0 } }; +#define aintc_read_4(_sc,reg) \ + bus_space_read_4(_sc->aintc_bst, _sc->aintc_bsh, (reg)) +#define aintc_write_4(_sc, reg, val) \ + bus_space_write_4(_sc->aintc_bst, _sc->aintc_bsh, (reg), (val)) -static struct ti_aintc_softc *ti_aintc_sc = NULL; - -#define aintc_read_4(reg) \ - bus_space_read_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg) -#define aintc_write_4(reg, val) \ - bus_space_write_4(ti_aintc_sc->aintc_bst, ti_aintc_sc->aintc_bsh, reg, val) - +static int ti_aintc_probe(device_t); +static int ti_aintc_attach(device_t); +static void ti_aintc_mask(device_t, int); +static void ti_aintc_unmask(device_t, int); +static void ti_aintc_eoi(device_t, int); +static int ti_aintc_intr(void *); static int ti_aintc_probe(device_t dev) { - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "ti,aintc")) return (ENXIO); device_set_desc(dev, "TI AINTC Interrupt Controller"); @@ -99,9 +102,6 @@ ti_aintc_attach(device_t dev) sc->sc_dev = dev; - if (ti_aintc_sc) - return (ENXIO); - if (bus_alloc_resources(dev, ti_aintc_spec, sc->aintc_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); @@ -110,26 +110,39 @@ ti_aintc_attach(device_t dev) sc->aintc_bst = rman_get_bustag(sc->aintc_res[0]); sc->aintc_bsh = rman_get_bushandle(sc->aintc_res[0]); - ti_aintc_sc = sc; + arm_register_pic(dev); + + if (bus_setup_intr(dev, sc->aintc_res[1], + INTR_TYPE_MISC | INTR_CONTROLLER, ti_aintc_intr, NULL, + sc, &sc->aintc_intrhand)) { + device_printf(dev, "could not install interrupt handler\n"); + return (ENXIO); + } - x = aintc_read_4(INTC_REVISION); + x = aintc_read_4(sc, INTC_REVISION); device_printf(dev, "Revision %u.%u\n",(x >> 4) & 0xF, x & 0xF); /* SoftReset */ - aintc_write_4(INTC_SYSCONFIG, 2); + aintc_write_4(sc, INTC_SYSCONFIG, 2); /* Wait for reset to complete */ - while(!(aintc_read_4(INTC_SYSSTATUS) & 1)); + while(!(aintc_read_4(sc, INTC_SYSSTATUS) & 1)); /*Set Priority Threshold */ - aintc_write_4(INTC_THRESHOLD, 0xFF); + aintc_write_4(sc, INTC_THRESHOLD, 0xFF); return (0); } static device_method_t ti_aintc_methods[] = { + /* Device interface */ DEVMETHOD(device_probe, ti_aintc_probe), DEVMETHOD(device_attach, ti_aintc_attach), + /* PIC interface */ + DEVMETHOD(pic_mask, ti_aintc_mask), + DEVMETHOD(pic_unmask, ti_aintc_unmask), + DEVMETHOD(pic_eoi, ti_aintc_eoi), + { 0, 0 } }; @@ -143,42 +156,49 @@ static devclass_t ti_aintc_devclass; DRIVER_MODULE(aintc, simplebus, ti_aintc_driver, ti_aintc_devclass, 0, 0); -int -arm_get_next_irq(int last_irq) +static int +ti_aintc_intr(void *arg) { + struct ti_aintc_softc *sc = (struct ti_aintc_softc *)arg; uint32_t active_irq; - if (last_irq != -1) { - aintc_write_4(INTC_ISR_CLEAR(last_irq >> 5), - 1UL << (last_irq & 0x1F)); - aintc_write_4(INTC_CONTROL,1); - } - /* Get the next active interrupt */ - active_irq = aintc_read_4(INTC_SIR_IRQ); + active_irq = aintc_read_4(sc, INTC_SIR_IRQ); /* Check for spurious interrupt */ if ((active_irq & 0xffffff80)) { - device_printf(ti_aintc_sc->sc_dev, - "Spurious interrupt detected (0x%08x)\n", active_irq); - aintc_write_4(INTC_SIR_IRQ, 0); - return -1; + device_printf(sc->sc_dev, + "Spurious interrupt detected (0x%08x)\n", active_irq); + return FILTER_HANDLED; } - if (active_irq != last_irq) - return active_irq; - else - return -1; + arm_dispatch_irq(sc->sc_dev, NULL, active_irq); + return FILTER_HANDLED; } -void -arm_mask_irq(uintptr_t nb) +static void +ti_aintc_mask(device_t dev, int irq) { - aintc_write_4(INTC_MIR_SET(nb >> 5), (1UL << (nb & 0x1F))); + struct ti_aintc_softc *sc = device_get_softc(dev); + + aintc_write_4(sc, INTC_MIR_SET(irq >> 5), (1UL << (irq & 0x1F))); } -void -arm_unmask_irq(uintptr_t nb) +static void +ti_aintc_unmask(device_t dev, int irq) { - aintc_write_4(INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F))); + struct ti_aintc_softc *sc = device_get_softc(dev); + + aintc_write_4(sc, INTC_MIR_CLEAR(irq >> 5), (1UL << (irq & 0x1F))); } + +static void +ti_aintc_eoi(device_t dev, int irq) +{ + struct ti_aintc_softc *sc = device_get_softc(dev); + + aintc_write_4(sc, INTC_ISR_CLEAR(irq >> 5), + 1UL << (irq & 0x1F)); + aintc_write_4(sc, INTC_CONTROL,1); +} + diff --git a/sys/arm/ti/files.ti b/sys/arm/ti/files.ti index 0adea06..71abb7a 100644 --- a/sys/arm/ti/files.ti +++ b/sys/arm/ti/files.ti @@ -9,6 +9,7 @@ arm/arm/cpufunc_asm_armv5.S standard arm/arm/cpufunc_asm_arm10.S standard arm/arm/cpufunc_asm_arm11.S standard arm/arm/cpufunc_asm_armv7.S standard +arm/arm/intrng.c standard arm/ti/ti_common.c standard arm/ti/ti_cpuid.c standard diff --git a/sys/arm/ti/omap4/omap4_mp.c b/sys/arm/ti/omap4/omap4_mp.c index 178db20..e298cd1 100644 --- a/sys/arm/ti/omap4/omap4_mp.c +++ b/sys/arm/ti/omap4/omap4_mp.c @@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$"); void platform_mp_init_secondary(void) { - gic_init_secondary(); + arm_init_secondary_ic(); } void diff --git a/sys/boot/fdt/dts/arm/ea3250.dts b/sys/boot/fdt/dts/arm/ea3250.dts index 2c466e3..c45a839 100644 --- a/sys/boot/fdt/dts/arm/ea3250.dts +++ b/sys/boot/fdt/dts/arm/ea3250.dts @@ -37,6 +37,9 @@ aliases { soc = &soc; + pwr = &pwr; + gpio = &gpio; + watchdog = &watchdog; serial4 = &serial4; }; @@ -70,16 +73,35 @@ ranges = <0x0 0x40000000 0x10000000>; bus-frequency = <13000000>; - pwr@4000 { + pwr: pwr@4000 { compatible = "lpc,pwr"; reg = <0x4000 0x4000>; }; - PIC: pic@8000 { + MIC: pic@8000 { interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; - reg = <0x8000 0xc000>; + reg = <0x8000 0x1000>; + interrupts = <0>; + compatible = "lpc,pic"; + }; + + SIC1: pic@c000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0xc000 0x1000>; + interrupts = <0>; + compatible = "lpc,pic"; + }; + + SIC2: pic@10000 { + interrupt-controller; + #address-cells = <0>; + #interrupt-cells = <1>; + reg = <0x10000 0x1000>; + interrupts = <0>; compatible = "lpc,pic"; }; @@ -88,14 +110,14 @@ reg = <0x44000 0x4000 0x4c000 0x4000>; interrupts = <16 17>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; rtc@24000 { compatible = "lpc,rtc"; reg = <0x24000 0x4000>; - interrupts = <52>; - interrupt-parent = <&PIC>; + interrupts = <20>; + interrupt-parent = <&SIC1>; }; serial0: serial@14000 { @@ -105,7 +127,7 @@ reg-shift = <2>; clock-frequency = <0>; interrupts = <26>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; serial1: serial@18000 { @@ -115,7 +137,7 @@ reg-shift = <2>; clock-frequency = <0>; interrupts = <25>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; serial2: serial@80000 { @@ -125,7 +147,7 @@ reg-shift = <2>; clock-frequency = <13000000>; interrupts = <7>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; serial3: serial@88000 { @@ -135,7 +157,7 @@ reg-shift = <2>; clock-frequency = <13000000>; interrupts = <8>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; serial4: serial@90000 { @@ -145,7 +167,7 @@ clock-frequency = <13000000>; current-speed = <115200>; interrupts = <9>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; serial5: serial@98000 { @@ -155,7 +177,7 @@ reg-shift = <2>; clock-frequency = <13000000>; interrupts = <10>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; serial6: serial@1c000 { @@ -165,13 +187,18 @@ reg-shift = <2>; clock-frequency = <0>; interrupts = <24>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; - gpio@28000 { + gpio: gpio@28000 { compatible = "lpc,gpio"; reg = <0x28000 0x4000>; }; + + watchdog: watchdog@3c000 { + compatible = "lpc,watchdog"; + reg = <0x3c000 0x4000>; + }; }; ahb6@30000000 { @@ -184,21 +211,21 @@ compatible = "lpc,dmac"; reg = <0x1000000 0x20000>; interrupts = <28>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; usb@1020000 { compatible = "lpc,usb-ohci", "usb-ohci"; reg = <0x1020000 0x20000>; - interrupts = <59>; - interrupt-parent = <&PIC>; + interrupts = <27>; + interrupt-parent = <&SIC1>; }; lpcfb@1040000 { compatible = "lpc,fb"; reg = <0x1040000 0x20000>; interrupts = <14>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; /* Screen parameters: */ is-tft = <1>; @@ -218,7 +245,7 @@ compatible = "lpc,ethernet"; reg = <0x1060000 0x20000>; interrupts = <29>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; local-mac-address = [ 00 1a f1 01 1f 23 ]; mdio@0 { @@ -244,7 +271,7 @@ compatible = "lpc,spi"; reg = <0x84000 0x4000>; interrupts = <20>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; spi1@8c000 { @@ -252,14 +279,14 @@ status = "disabled"; reg = <0x8c000 0x4000>; interrupts = <21>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; lpcmmc@98000 { compatible = "lpc,mmc"; reg = <0x98000 0x4000>; interrupts = <15 13>; - interrupt-parent = <&PIC>; + interrupt-parent = <&MIC>; }; }; diff --git a/sys/boot/fdt/dts/arm/pandaboard.dts b/sys/boot/fdt/dts/arm/pandaboard.dts index c89bf88..41d2dfe 100644 --- a/sys/boot/fdt/dts/arm/pandaboard.dts +++ b/sys/boot/fdt/dts/arm/pandaboard.dts @@ -36,8 +36,6 @@ #address-cells = <1>; #size-cells = <1>; - interrupt-parent = <&GIC>; - aliases { soc = &SOC; uart3 = &uart3; @@ -60,6 +58,7 @@ interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; + interrupts = < 0 >; reg = < 0x48241000 0x1000 >, /* Distributor Registers */ < 0x48240100 0x0100 >; /* CPU Interface Registers */ }; diff --git a/sys/conf/files.arm b/sys/conf/files.arm index ef709f3..24d4c3b 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -26,7 +26,7 @@ arm/arm/gdb_machdep.c optional gdb arm/arm/identcpu.c standard arm/arm/in_cksum.c optional inet | inet6 arm/arm/in_cksum_arm.S optional inet | inet6 -arm/arm/intr.c standard +arm/arm/intrng.c optional arm_intrng arm/arm/locore.S standard no-obj arm/arm/machdep.c standard arm/arm/mem.c optional mem @@ -34,6 +34,7 @@ arm/arm/minidump_machdep.c optional mem arm/arm/mp_machdep.c optional smp arm/arm/nexus.c standard arm/arm/physmem.c standard +arm/arm/pic_if.m standard arm/arm/pl190.c optional pl190 arm/arm/pl310.c optional pl310 arm/arm/pmap.c optional cpu_arm9 | cpu_arm9e | cpu_fa526 | cpu_xscale_80219 | cpu_xscale_80321 | cpu_xscale_81342 | cpu_xscale_ixp425 | cpu_xscale_ixp435 | cpu_xscale_pxa2x0 diff --git a/sys/conf/options.arm b/sys/conf/options.arm index 4df2b9d..dc1bcb5 100644 --- a/sys/conf/options.arm +++ b/sys/conf/options.arm @@ -2,6 +2,7 @@ ARM9_CACHE_WRITE_THROUGH opt_global.h ARM_CACHE_LOCK_ENABLE opt_global.h ARM_KERN_DIRECTMAP opt_vm.h +ARM_INTRNG opt_global.h ARM_L2_PIPT opt_global.h ARM_MANY_BOARD opt_global.h ARM_WANT_TP_ADDRESS opt_global.h diff --git a/sys/dev/fdt/simplebus.c b/sys/dev/fdt/simplebus.c index 1de4223..26079ef 100644 --- a/sys/dev/fdt/simplebus.c +++ b/sys/dev/fdt/simplebus.c @@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + struct simplebus_range { uint64_t bus; uint64_t host; @@ -68,6 +70,7 @@ static struct resource *simplebus_alloc_resource(device_t, device_t, int, int *, u_long, u_long, u_long, u_int); static void simplebus_probe_nomatch(device_t bus, device_t child); static int simplebus_print_child(device_t bus, device_t child); +static int simplebus_print_irqs(struct resource_list *rl); /* * ofw_bus interface @@ -293,8 +296,8 @@ simplebus_setup_dinfo(device_t dev, phandle_t node) if (OF_searchencprop(node, "interrupt-parent", &iparent, sizeof(iparent)) == -1) { device_printf(dev, "No interrupt-parent found, " - "assuming direct parent\n"); - iparent = OF_parent(node); + "assuming nexus\n"); + iparent = 0xffffffff; } if (OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells", &icells, sizeof(icells)) == -1) { @@ -394,7 +397,7 @@ simplebus_print_res(struct simplebus_devinfo *di) rv = 0; rv += resource_list_print_type(&di->rl, "mem", SYS_RES_MEMORY, "%#lx"); - rv += resource_list_print_type(&di->rl, "irq", SYS_RES_IRQ, "%ld"); + rv += simplebus_print_irqs(&di->rl); return (rv); } @@ -421,6 +424,28 @@ simplebus_probe_nomatch(device_t bus, device_t child) printf(" (no driver attached)\n"); } + +static int +simplebus_print_irqs(struct resource_list *rl) +{ + struct resource_list_entry *rle; + int printed, retval; + + printed = 0; + retval = 0; + + STAILQ_FOREACH(rle, rl, link) { + if (rle->type != SYS_RES_IRQ) + continue; + + retval += printf("%s", printed ? "," : " irq "); + retval += printf("%s", FDT_DESCRIBE_IRQ(rle->start)); + printed++; + } + + return (retval); +} + static int simplebus_print_child(device_t bus, device_t child) { diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c index e4f1c82..41b5088 100644 --- a/sys/kern/kern_intr.c +++ b/sys/kern/kern_intr.c @@ -1422,7 +1422,12 @@ intr_event_handle(struct intr_event *ie, struct trapframe *frame) ret = 0; critical_enter(); oldframe = td->td_intr_frame; - td->td_intr_frame = frame; + + if (frame) + td->td_intr_frame = frame; + else + frame = td->td_intr_frame; + TAILQ_FOREACH(ih, &ie->ie_handlers, ih_next) { if (ih->ih_filter == NULL) { thread = 1;