Index: sys/arm/arm/gic.c =================================================================== --- sys/arm/arm/gic.c +++ sys/arm/arm/gic.c @@ -55,6 +55,8 @@ #include #include +#include "pic_if.h" + /* We are using GICv2 register naming */ /* Distributor Registers */ @@ -95,42 +97,49 @@ #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; }; - 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); @@ -140,17 +149,13 @@ 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); + 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); /* Set all the interrupts to be in Group 0 (secure) */ for (i = 0; i < nirqs; i += 32) { @@ -158,14 +163,12 @@ } /* 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*/ /* Activate IRQ 29-30, ie private timer (secure & non-secure) IRQs */ gic_d_write_4(GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); gic_d_write_4(GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F))); @@ -174,21 +177,18 @@ 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); @@ -200,32 +200,35 @@ 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); + gic_d_write_4(sc, GICD_ICFGR(i >> 4), 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) { @@ -235,100 +238,61 @@ /* 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; - -EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0, - BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); - -static void -gic_post_filter(void *arg) -{ - uintptr_t irq = (uintptr_t) arg; - - if (irq > GIC_LAST_IPI) - arm_irq_memory_barrier(irq); - 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) <= GIC_LAST_IPI) - gic_c_write_4(GICC_EOIR, active_irq); + + if ((active_irq & 0x3ff) < 1) + gic_c_write_4(sc, GICC_EOIR, active_irq); active_irq &= 0x3FF; if (active_irq == 0x3FF) { if (last_irq == -1) - printf("Spurious interrupt detected\n"); - return -1; + printf("Spurious interrupt detected [0x%08x]\n", active_irq); + 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) -{ - - if (nb > GIC_LAST_IPI) - arm_irq_memory_barrier(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)) @@ -337,9 +301,9 @@ (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) { @@ -361,32 +325,64 @@ /* 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); + + if (irq > GIC_LAST_IPI) + arm_irq_memory_barrier(irq); + + 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))); + gic_c_write_4(GICC_EOIR, nb); +} + +static void +arm_gic_unmask(device_t dev, int irq) +{ + struct arm_gic_softc *sc = device_get_softc(dev); + + if (nb > GIC_LAST_IPI) + arm_irq_memory_barrier(nb); + + 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) { @@ -394,16 +390,44 @@ * 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); Index: sys/arm/arm/intr.c =================================================================== --- sys/arm/arm/intr.c +++ sys/arm/arm/intr.c @@ -89,6 +89,15 @@ SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL); +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) Index: sys/arm/arm/intrng.c =================================================================== --- sys/arm/arm/intrng.c +++ sys/arm/arm/intrng.c @@ -0,0 +1,444 @@ +/*- + * 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 INTRNAME_LEN (MAXCOMLEN + 1) + +#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. */ +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); + + /* + * If we got null trapframe argument, that probably means + * a call from non-root interrupt controller. In that case, + * we'll just use the saved one. + */ + if (tf == NULL) + tf = PCPU_GET(curthread)->td_intr_frame; + + 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[INTRNAME_LEN]; + static char name[INTRNAME_LEN]; + + pic = &arm_pics[IRQ_PIC_IDX(irq)]; + + if (pic->ic_dev == NULL) { + /* + * Interrupt controller not attached yet, so we'll use it's + * FDT "name" property instead + */ + OF_getprop(pic->ic_node, "name", name, sizeof(name)); + snprintf(buffer, sizeof(buffer), "%s.%d", name, + IRQ_VECTOR_IDX(irq)); + return (buffer); + } + + snprintf(buffer, sizeof(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, + INTRNAME_LEN, "%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) +{ +} + Index: sys/arm/arm/mp_machdep.c =================================================================== --- sys/arm/arm/mp_machdep.c +++ sys/arm/arm/mp_machdep.c @@ -235,7 +235,7 @@ #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 @@ cpu = PCPU_GET(cpuid); - ipi = pic_ipi_get((int)arg); + ipi = pic_ipi_read((int)arg); while ((ipi != 0x3ff)) { switch (ipi) { @@ -328,7 +328,7 @@ } pic_ipi_clear(ipi); - ipi = pic_ipi_get(-1); + ipi = pic_ipi_read(-1); } return (FILTER_HANDLED); @@ -360,11 +360,10 @@ * 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); Index: sys/arm/arm/nexus.c =================================================================== --- sys/arm/arm/nexus.c +++ sys/arm/arm/nexus.c @@ -68,6 +68,8 @@ #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 @@ #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_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 @@ /* 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 @@ #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 } }; @@ -152,6 +172,12 @@ 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 */ @@ -238,9 +264,12 @@ { 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); } @@ -254,10 +283,16 @@ 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); } @@ -332,6 +367,41 @@ 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, @@ -342,6 +412,7 @@ 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]); @@ -351,13 +422,13 @@ 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); } Index: sys/arm/arm/pic_if.m =================================================================== --- sys/arm/arm/pic_if.m +++ 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; Index: sys/arm/broadcom/bcm2835/bcm2835_intr.c =================================================================== --- sys/arm/broadcom/bcm2835/bcm2835_intr.c +++ sys/arm/broadcom/bcm2835/bcm2835_intr.c @@ -45,6 +45,8 @@ #include #include +#include "pic_if.h" + #define INTC_PENDING_BASIC 0x00 #define INTC_PENDING_BANK1 0x04 #define INTC_PENDING_BANK2 0x08 @@ -60,7 +62,6 @@ #define BANK1_END (BANK1_START + 32 - 1) #define BANK2_START (BANK1_START + 32) #define BANK2_END (BANK2_START + 32 - 1) -#define BANK3_START (BANK2_START + 32) #define IS_IRQ_BASIC(n) (((n) >= 0) && ((n) < BANK1_START)) #define IS_IRQ_BANK1(n) (((n) >= BANK1_START) && ((n) <= BANK1_END)) @@ -76,17 +77,24 @@ struct bcm_intc_softc { device_t sc_dev; - struct resource * intc_res; + struct resource * intc_mem_res; + struct resource * intc_irq_res; + void * intc_intrhand; bus_space_tag_t intc_bst; bus_space_handle_t intc_bsh; }; -static struct bcm_intc_softc *bcm_intc_sc = NULL; - -#define intc_read_4(reg) \ - bus_space_read_4(bcm_intc_sc->intc_bst, bcm_intc_sc->intc_bsh, reg) -#define intc_write_4(reg, val) \ - bus_space_write_4(bcm_intc_sc->intc_bst, bcm_intc_sc->intc_bsh, reg, val) +#define intc_read_4(_sc, reg) \ + bus_space_read_4(_sc->intc_bst, _sc->intc_bsh, reg) +#define intc_write_4(_sc, reg, val) \ + bus_space_write_4(_sc->intc_bst, _sc->intc_bsh, reg, val) + +static int bcm_intc_probe(device_t); +static int bcm_intc_attach(device_t); +static int bcm_intc_intr(void *); +static int bcm_intc_config(device_t, int, enum intr_trigger, enum intr_polarity); +static void bcm_intc_mask(device_t, int); +static void bcm_intc_unmask(device_t, int); static int bcm_intc_probe(device_t dev) @@ -105,111 +113,139 @@ bcm_intc_attach(device_t dev) { struct bcm_intc_softc *sc = device_get_softc(dev); - int rid = 0; + int rid; sc->sc_dev = dev; - if (bcm_intc_sc) + rid = 0; + sc->intc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->intc_mem_res == NULL) { + device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); + } - sc->intc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (sc->intc_res == NULL) { - device_printf(dev, "could not allocate memory resource\n"); + rid = 0; + sc->intc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (sc->intc_irq_res == NULL) { + device_printf(dev, "could not alloc interrupt resource\n"); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_mem_res); return (ENXIO); } - sc->intc_bst = rman_get_bustag(sc->intc_res); - sc->intc_bsh = rman_get_bushandle(sc->intc_res); + sc->intc_bst = rman_get_bustag(sc->intc_mem_res); + sc->intc_bsh = rman_get_bushandle(sc->intc_mem_res); + + + if (bus_setup_intr(dev, sc->intc_irq_res, + INTR_TYPE_MISC | INTR_CONTROLLER, bcm_intc_intr, NULL, sc, + &sc->intc_intrhand)) { + device_printf(dev, "could not setup interrupt handler\n"); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->intc_mem_res); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->intc_irq_res); + return (ENXIO); + } - bcm_intc_sc = sc; + arm_register_pic(dev, 0); return (0); } -static device_method_t bcm_intc_methods[] = { - DEVMETHOD(device_probe, bcm_intc_probe), - DEVMETHOD(device_attach, bcm_intc_attach), - { 0, 0 } -}; +static int +bcm_intc_intr(void *arg) +{ + struct bcm_intc_softc *sc = (struct bcm_intc_softc *)arg; + uint32_t pending; + int32_t irq = 0; -static driver_t bcm_intc_driver = { - "intc", - bcm_intc_methods, - sizeof(struct bcm_intc_softc), -}; + /* TODO: should we mask last_irq? */ + pending = intc_read_4(sc, INTC_PENDING_BASIC); + while (irq < BANK1_START) { + if (pending & (1 << irq)) + arm_dispatch_irq(sc->sc_dev, NULL, irq); + irq++; + } -static devclass_t bcm_intc_devclass; + pending = intc_read_4(sc, INTC_PENDING_BANK1); + while (irq < BANK2_START) { + if (pending & (1 << IRQ_BANK1(irq))) + arm_dispatch_irq(sc->sc_dev, NULL, irq); + irq++; + } -DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0); + pending = intc_read_4(sc, INTC_PENDING_BANK2); + while (irq <= BANK2_END) { + if (pending & (1 << IRQ_BANK2(irq))) + arm_dispatch_irq(sc->sc_dev, NULL, irq); + irq++; + } -int -arm_get_next_irq(int last_irq) -{ - uint32_t pending; - int32_t irq = last_irq + 1; + return (FILTER_HANDLED); +} - /* Sanity check */ - if (irq < 0) - irq = 0; +static int +bcm_intc_config(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ - /* TODO: should we mask last_irq? */ - if (irq < BANK1_START) { - pending = intc_read_4(INTC_PENDING_BASIC); - if ((pending & 0xFF) == 0) { - irq = BANK1_START; /* skip to next bank */ - } else do { - if (pending & (1 << irq)) - return irq; - irq++; - } while (irq < BANK1_START); - } - if (irq < BANK2_START) { - pending = intc_read_4(INTC_PENDING_BANK1); - if (pending == 0) { - irq = BANK2_START; /* skip to next bank */ - } else do { - if (pending & (1 << IRQ_BANK1(irq))) - return irq; - irq++; - } while (irq < BANK2_START); - } - if (irq < BANK3_START) { - pending = intc_read_4(INTC_PENDING_BANK2); - if (pending != 0) do { - if (pending & (1 << IRQ_BANK2(irq))) - return irq; - irq++; - } while (irq < BANK3_START); - } - return (-1); + /* no-op */ + return (0); } -void -arm_mask_irq(uintptr_t nb) + +static void +bcm_intc_mask(device_t dev, int nb) { + struct bcm_intc_softc *sc = device_get_softc(dev); dprintf("%s: %d\n", __func__, nb); if (IS_IRQ_BASIC(nb)) - intc_write_4(INTC_DISABLE_BASIC, (1 << nb)); + intc_write_4(sc, INTC_DISABLE_BASIC, (1 << nb)); else if (IS_IRQ_BANK1(nb)) - intc_write_4(INTC_DISABLE_BANK1, (1 << IRQ_BANK1(nb))); + intc_write_4(sc, INTC_DISABLE_BANK1, (1 << IRQ_BANK1(nb))); else if (IS_IRQ_BANK2(nb)) - intc_write_4(INTC_DISABLE_BANK2, (1 << IRQ_BANK2(nb))); + intc_write_4(sc, INTC_DISABLE_BANK2, (1 << IRQ_BANK2(nb))); else printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); } -void -arm_unmask_irq(uintptr_t nb) +static void +bcm_intc_unmask(device_t dev, int nb) { + struct bcm_intc_softc *sc = device_get_softc(dev); dprintf("%s: %d\n", __func__, nb); if (IS_IRQ_BASIC(nb)) - intc_write_4(INTC_ENABLE_BASIC, (1 << nb)); + intc_write_4(sc, INTC_ENABLE_BASIC, (1 << nb)); else if (IS_IRQ_BANK1(nb)) - intc_write_4(INTC_ENABLE_BANK1, (1 << IRQ_BANK1(nb))); + intc_write_4(sc, INTC_ENABLE_BANK1, (1 << IRQ_BANK1(nb))); else if (IS_IRQ_BANK2(nb)) - intc_write_4(INTC_ENABLE_BANK2, (1 << IRQ_BANK2(nb))); + intc_write_4(sc, INTC_ENABLE_BANK2, (1 << IRQ_BANK2(nb))); else printf("arm_mask_irq: Invalid IRQ number: %d\n", nb); } + +static device_method_t bcm_intc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bcm_intc_probe), + DEVMETHOD(device_attach, bcm_intc_attach), + + /* Interrupt controller interface */ + DEVMETHOD(pic_config, bcm_intc_config), + DEVMETHOD(pic_mask, bcm_intc_mask), + DEVMETHOD(pic_unmask, bcm_intc_unmask), + { 0, 0 } +}; + +static driver_t bcm_intc_driver = { + "intc", + bcm_intc_methods, + sizeof(struct bcm_intc_softc), +}; + +static devclass_t bcm_intc_devclass; + +DRIVER_MODULE(intc, simplebus, bcm_intc_driver, bcm_intc_devclass, 0, 0); + + Index: sys/arm/broadcom/bcm2835/files.bcm2835 =================================================================== --- sys/arm/broadcom/bcm2835/files.bcm2835 +++ sys/arm/broadcom/bcm2835/files.bcm2835 @@ -21,6 +21,7 @@ arm/arm/cpufunc_asm_arm11x6.S standard arm/arm/cpufunc_asm_armv5.S standard arm/arm/cpufunc_asm_armv6.S standard +arm/arm/intrng.c standard kern/kern_clocksource.c standard Index: sys/arm/conf/EA3250 =================================================================== --- sys/arm/conf/EA3250 +++ sys/arm/conf/EA3250 @@ -10,7 +10,7 @@ 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_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 pass device da -device mmc -device mmcsd -device lpcmmc +#device mmc +#device mmcsd +#device lpcmmc device gpio device gpioled Index: sys/arm/conf/PANDABOARD =================================================================== --- sys/arm/conf/PANDABOARD +++ sys/arm/conf/PANDABOARD @@ -60,6 +60,7 @@ options FREEBSD_BOOT_LOADER options VFP # vfp/neon options SMP # Enable multiple cores +options ARM_INTRNG # Debugging for use in -current makeoptions DEBUG=-g # Build kernel with gdb(1) debug symbols Index: sys/arm/conf/RPI-B =================================================================== --- sys/arm/conf/RPI-B +++ sys/arm/conf/RPI-B @@ -36,6 +36,7 @@ options GEOM_PART_MBR # MBR partition scheme options TMPFS # Efficient memory filesystem options MSDOSFS # MSDOS Filesystem +options ARM_INTRNG device snp options NFSCL # Network Filesystem Client Index: sys/arm/include/fdt.h =================================================================== --- sys/arm/include/fdt.h +++ sys/arm/include/fdt.h @@ -40,11 +40,25 @@ #include #include +#if defined(ARM_INTRNG) + /* Max interrupt number */ -#define FDT_INTR_MAX NIRQ +#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 @@ int fdt_localbus_devmap(phandle_t, struct arm_devmap_entry *, int, int *); #endif /* _MACHINE_FDT_H_ */ + Index: sys/arm/include/intr.h =================================================================== --- sys/arm/include/intr.h +++ 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,7 +106,6 @@ 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 *); @@ -83,4 +117,9 @@ void gic_init_secondary(void); +#endif /* !ARM_INTRNG */ + +const char *arm_describe_irq(int irq); +void arm_intrnames_init(void); + #endif /* _MACHINE_INTR_H */ Index: sys/arm/include/smp.h =================================================================== --- sys/arm/include/smp.h +++ sys/arm/include/smp.h @@ -24,7 +24,7 @@ /* 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); Index: sys/arm/lpc/files.lpc =================================================================== --- sys/arm/lpc/files.lpc +++ sys/arm/lpc/files.lpc @@ -2,6 +2,7 @@ arm/arm/bus_space_generic.c standard arm/arm/cpufunc_asm_arm9.S standard arm/arm/cpufunc_asm_armv5.S standard +arm/arm/intrng.c standard arm/lpc/lpc_machdep.c standard arm/lpc/lpc_space.c standard arm/lpc/lpc_pwr.c standard Index: sys/arm/lpc/lpc_intc.c =================================================================== --- sys/arm/lpc/lpc_intc.c +++ sys/arm/lpc/lpc_intc.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -47,22 +48,29 @@ #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; - -#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) +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(_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,126 @@ struct lpc_intc_softc *sc = device_get_softc(dev); int rid = 0; - if (intc_softc) + sc->li_dev = dev; + sc->li_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (!sc->li_mem_res) { + device_printf(dev, "could not alloc memory resource\n"); return (ENXIO); + } - sc->li_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, - RF_ACTIVE); - if (!sc->li_res) { - device_printf(dev, "could not alloc resources\n"); + 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"); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->li_mem_res); + return (ENXIO); + } + + sc->li_bst = rman_get_bustag(sc->li_mem_res); + sc->li_bsh = rman_get_bushandle(sc->li_mem_res); + + 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"); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->li_mem_res); + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->li_irq_res); 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; + arm_register_pic(dev, 0); /* 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); + intc_write_4(sc, LPC_INTC_ER, 0); + intc_write_4(sc, LPC_INTC_RSR, ~0); return (0); } -static device_method_t lpc_intc_methods[] = { - DEVMETHOD(device_probe, lpc_intc_probe), - DEVMETHOD(device_attach, lpc_intc_attach), - { 0, 0 } -}; - -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); - -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); - for (i = 0; i < 32; i++) { - if (value & (1 << i)) - return (i); - } - - /* IRQs 32-63 are mapped to LPC_INTC_SIC1_SR */ - value = intc_read_4(LPC_INTC_SIC1_SR); + value = intc_read_4(sc, LPC_INTC_SR); for (i = 0; i < 32; i++) { if (value & (1 << i)) - return (i + 32); + arm_dispatch_irq(sc->li_dev, NULL, i); } - /* 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 } Index: sys/arm/lpc/lpcreg.h =================================================================== --- sys/arm/lpc/lpcreg.h +++ 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 /* Index: sys/arm/ti/aintc.c =================================================================== --- sys/arm/ti/aintc.c +++ sys/arm/ti/aintc.c @@ -45,6 +45,8 @@ #include #include +#include "pic_if.h" + #define INTC_REVISION 0x00 #define INTC_SYSCONFIG 0x10 #define INTC_SYSSTATUS 0x14 @@ -61,30 +63,31 @@ 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 } }; - -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) - +#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 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 @@ 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 @@ 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,44 +156,51 @@ 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) { + struct ti_aintc_softc *sc = device_get_softc(dev); + aintc_write_4(sc, INTC_MIR_CLEAR(irq >> 5), (1UL << (irq & 0x1F))); arm_irq_memory_barrier(nb); + +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); +} + aintc_write_4(INTC_MIR_CLEAR(nb >> 5), (1UL << (nb & 0x1F))); } Index: sys/arm/ti/files.ti =================================================================== --- sys/arm/ti/files.ti +++ sys/arm/ti/files.ti @@ -9,6 +9,7 @@ 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 Index: sys/arm/ti/omap4/omap4_mp.c =================================================================== --- sys/arm/ti/omap4/omap4_mp.c +++ sys/arm/ti/omap4/omap4_mp.c @@ -41,7 +41,7 @@ void platform_mp_init_secondary(void) { - gic_init_secondary(); + arm_init_secondary_ic(); } void Index: sys/boot/fdt/dts/arm/bcm2835.dtsi =================================================================== --- sys/boot/fdt/dts/arm/bcm2835.dtsi +++ sys/boot/fdt/dts/arm/bcm2835.dtsi @@ -50,6 +50,7 @@ interrupt-controller; #interrupt-cells = <1>; + interrupts = <0>; /* Bank 0 * 0: ARM_TIMER Index: sys/boot/fdt/dts/arm/ea3250.dts =================================================================== --- sys/boot/fdt/dts/arm/ea3250.dts +++ 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>; }; }; Index: sys/boot/fdt/dts/arm/pandaboard.dts =================================================================== --- sys/boot/fdt/dts/arm/pandaboard.dts +++ 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 */ }; Index: sys/conf/files.arm =================================================================== --- sys/conf/files.arm +++ sys/conf/files.arm @@ -26,7 +26,7 @@ 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/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/platform.c optional platform Index: sys/conf/options.arm =================================================================== --- sys/conf/options.arm +++ sys/conf/options.arm @@ -3,6 +3,7 @@ ARM_CACHE_LOCK_ENABLE opt_global.h ARM_DEVICE_MULTIPASS 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 Index: sys/dev/fdt/simplebus.c =================================================================== --- sys/dev/fdt/simplebus.c +++ sys/dev/fdt/simplebus.c @@ -38,6 +38,8 @@ #include #include +#include + struct simplebus_range { uint64_t bus; uint64_t host; @@ -68,6 +70,7 @@ 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 @@ -295,8 +298,8 @@ 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) { @@ -396,7 +399,7 @@ 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); } @@ -423,6 +426,28 @@ 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) {