Index: sys/arm/conf/ARMADA38X =================================================================== --- sys/arm/conf/ARMADA38X +++ sys/arm/conf/ARMADA38X @@ -23,6 +23,7 @@ #options SCHED_4BSD # 4BSD scheduler options SMP +options ARM_INTRNG # Debugging #options DEBUG Index: sys/arm/include/intr.h =================================================================== --- sys/arm/include/intr.h +++ sys/arm/include/intr.h @@ -49,6 +49,11 @@ #define NIRQ 1024 /* XXX - It should be an option. */ #endif +#if defined (SOC_MV_ARMADA38X) +#define MSI_IRQ 0x3ff +#define ERR_IRQ 0x3ff +#endif + #ifdef notyet #define INTR_SOLO INTR_MD1 typedef int intr_irq_filter_t(void *arg, struct trapframe *tf); @@ -163,6 +168,9 @@ #define MSI_IRQ_NUM 32 #define MSI_IRQ (ERR_IRQ + ERR_IRQ_NUM) #define NIRQ (MAIN_IRQ_NUM + ERR_IRQ_NUM + MSI_IRQ_NUM) +#elif defined (SOC_MV_ARMADA38X) +#define MSI_IRQ 0x3ff +#define ERR_IRQ 0x3ff #else #define NIRQ 32 #endif Index: sys/arm/mv/armada38x/files.armada38x =================================================================== --- sys/arm/mv/armada38x/files.armada38x +++ sys/arm/mv/armada38x/files.armada38x @@ -1,4 +1,5 @@ # $FreeBSD$ +arm/mv/mpic.c standard arm/mv/armada38x/armada38x.c standard arm/mv/armada38x/armada38x_mp.c optional smp Index: sys/arm/mv/mpic.c =================================================================== --- sys/arm/mv/mpic.c +++ sys/arm/mv/mpic.c @@ -33,14 +33,20 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include #include #include #include +#include #include +#include +#include #include +#include #include #include @@ -53,6 +59,10 @@ #include #include +#ifdef ARM_INTRNG +#include "pic_if.h" +#endif + #ifdef DEBUG #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ printf(fmt,##args); } while (0) @@ -71,35 +81,52 @@ #define MPIC_ERR_CAUSE 0x20 #define MPIC_ISE 0x30 #define MPIC_ICE 0x34 +#define MPIC_INT_CTL(irq) (0x100 + (irq)*4) +#define MPIC_INT_IRQ_FIQ_MASK(cpuid) (0x101 << (cpuid)) +#define MPIC_CTRL_NIRQS(ctrl) (((ctrl) >> 2) & 0x3ff) -#define MPIC_IN_DRBL 0x78 -#define MPIC_IN_DRBL_MASK 0x7c -#define MPIC_CTP 0xb0 -#define MPIC_CTP 0xb0 -#define MPIC_IIACK 0xb4 -#define MPIC_ISM 0xb8 -#define MPIC_ICM 0xbc -#define MPIC_ERR_MASK 0xec0 +#define MPIC_IN_DRBL 0x08 +#define MPIC_IN_DRBL_MASK 0x0c +#define MPIC_PPI_CAUSE 0x10 +#define MPIC_CTP 0x40 +#define MPIC_IIACK 0x44 +#define MPIC_ISM 0x48 +#define MPIC_ICM 0x4c +#define MPIC_ERR_MASK 0xe50 + +#define MPIC_PPI 32 struct mv_mpic_softc { device_t sc_dev; - struct resource * mpic_res[3]; + struct resource * mpic_res[4]; bus_space_tag_t mpic_bst; bus_space_handle_t mpic_bsh; bus_space_tag_t cpu_bst; bus_space_handle_t cpu_bsh; bus_space_tag_t drbl_bst; bus_space_handle_t drbl_bsh; + struct mtx mtx; + + struct intr_irqsrc ** mpic_isrcs; + int nirqs; + void * intr_hand; }; static struct resource_spec mv_mpic_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_MEMORY, 1, RF_ACTIVE }, - { SYS_RES_MEMORY, 2, RF_ACTIVE }, + { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL }, + { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, { -1, 0 } }; +static struct ofw_compat_data compat_data[] = { + {"mrvl,mpic", true}, + {"marvell,mpic", true}, + {NULL, false} +}; + static struct mv_mpic_softc *mv_mpic_sc = NULL; void mpic_send_ipi(int cpus, u_int ipi); @@ -109,9 +136,21 @@ uint32_t mv_mpic_get_cause(void); uint32_t mv_mpic_get_cause_err(void); uint32_t mv_mpic_get_msi(void); +static void mpic_unmask_irq(uintptr_t nb); +static void mpic_mask_irq(uintptr_t nb); +static void mpic_mask_irq_err(uintptr_t nb); +static void mpic_unmask_irq_err(uintptr_t nb); +static int mpic_intr(void *arg); +static void mpic_unmask_msi(void); +#ifndef ARM_INTRNG static void arm_mask_irq_err(uintptr_t); static void arm_unmask_irq_err(uintptr_t); -static void arm_unmask_msi(void); +#endif + +#define MPIC_WRITE(softc, reg, val) \ + bus_space_write_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg), (val)) +#define MPIC_READ(softc, reg) \ + bus_space_read_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg)) #define MPIC_CPU_WRITE(softc, reg, val) \ bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val)) @@ -130,7 +169,7 @@ if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "mrvl,mpic")) + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) return (ENXIO); device_set_desc(dev, "Marvell Integrated Interrupt Controller"); @@ -142,6 +181,7 @@ { struct mv_mpic_softc *sc; int error; + uint32_t val; sc = (struct mv_mpic_softc *)device_get_softc(dev); @@ -151,11 +191,20 @@ sc->sc_dev = dev; + mtx_init(&sc->mtx, "MPIC lock", NULL, MTX_SPIN); + error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res); if (error) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } +#ifdef ARM_INTRNG + if (sc->mpic_res[3] == NULL) + device_printf(dev, "No interrupt to use.\n"); + else + bus_setup_intr(dev, sc->mpic_res[3], INTR_TYPE_CLK, + mpic_intr, NULL, sc, &sc->intr_hand); +#endif sc->mpic_bst = rman_get_bustag(sc->mpic_res[0]); sc->mpic_bsh = rman_get_bushandle(sc->mpic_res[0]); @@ -163,21 +212,182 @@ sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]); sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]); - sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]); - sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]); + if (sc->mpic_res[2] != NULL) { + /* This is required only if MSIs are used. */ + sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]); + sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]); + } bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh, MPIC_CTRL, 1); MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0); - arm_unmask_msi(); + val = MPIC_READ(mv_mpic_sc, MPIC_CTRL); + sc->nirqs = MPIC_CTRL_NIRQS(val); + +#ifdef ARM_INTRNG + sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF, + M_WAITOK | M_ZERO); + + if (intr_pic_register(dev, OF_xref_from_device(dev)) != 0) { + device_printf(dev, "could not register PIC\n"); + bus_release_resources(dev, mv_mpic_spec, sc->mpic_res); + return (ENXIO); + } +#endif + + mpic_unmask_msi(); + + return (0); +} + +#ifdef ARM_INTRNG +static int +mpic_intr(void *arg) +{ + struct mv_mpic_softc *sc; + struct trapframe *tf; + struct intr_irqsrc *isrc; + uint32_t cause, irqsrc; + unsigned int irq; + u_int cpuid; + + sc = arg; + tf = curthread->td_intr_frame; + cpuid = PCPU_GET(cpuid); + irq = 0; + + for (cause = MPIC_CPU_READ(sc, MPIC_PPI_CAUSE); cause > 0; + cause >>= 1, irq++) { + if (cause & 1) { + irqsrc = MPIC_READ(sc, MPIC_INT_CTL(irq)); + if ((irqsrc & MPIC_INT_IRQ_FIQ_MASK(cpuid)) == 0) + continue; + isrc = sc->mpic_isrcs[irq]; + if (isrc == NULL) { + device_printf(sc->sc_dev, "Stray interrupt %u detected\n", irq); + mpic_mask_irq(irq); + continue; + } + intr_irq_dispatch(isrc, tf); + } + } + + return (FILTER_HANDLED); +} + +static int +mpic_attach_isrc(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int irq) +{ + const char *name; + + mtx_lock_spin(&sc->mtx); + if (sc->mpic_isrcs[irq] != NULL) { + mtx_unlock_spin(&sc->mtx); + return (sc->mpic_isrcs[irq] == isrc ? 0 : EEXIST); + } + sc->mpic_isrcs[irq] = isrc; + isrc->isrc_data = irq; + mtx_unlock_spin(&sc->mtx); + + name = device_get_nameunit(sc->sc_dev); + intr_irq_set_name(isrc, "%s", name); + + return (0); +} + +#ifdef FDT +static int +mpic_map_fdt(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) +{ + u_int irq; + int error; + + if (isrc->isrc_ncells != 1) + return (EINVAL); + + irq = isrc->isrc_cells[0]; + + error = mpic_attach_isrc(sc, isrc, irq); + if (error != 0) + return (error); + + isrc->isrc_nspc_num = irq; + isrc->isrc_trig = INTR_TRIGGER_CONFORM; + isrc->isrc_pol = INTR_POLARITY_CONFORM; + isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; + + *irqp = irq; return (0); } +#endif + +static int +mpic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) +{ + struct mv_mpic_softc *sc; + int error; + u_int irq = 0; + + sc = device_get_softc(dev); + +#ifdef FDT + if (isrc->isrc_type == INTR_ISRCT_FDT) + error = mpic_map_fdt(sc, isrc, &irq); + else +#endif + error = EINVAL; + + if (error == 0) + *is_percpu = irq < MPIC_PPI; + + return (error); +} + +static void +mpic_disable_source(device_t dev, struct intr_irqsrc *isrc) +{ + u_int irq; + + irq = isrc->isrc_data; + mpic_mask_irq(irq); +} + +static void +mpic_enable_source(device_t dev, struct intr_irqsrc *isrc) +{ + u_int irq; + + irq = isrc->isrc_data; + mpic_unmask_irq(irq); +} +static void +mpic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + mpic_disable_source(dev, isrc); +} + +static void +mpic_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + mpic_enable_source(dev, isrc); +} +#endif static device_method_t mv_mpic_methods[] = { DEVMETHOD(device_probe, mv_mpic_probe), DEVMETHOD(device_attach, mv_mpic_attach), + +#ifdef ARM_INTRNG + DEVMETHOD(pic_register, mpic_register), + DEVMETHOD(pic_disable_source, mpic_disable_source), + DEVMETHOD(pic_enable_source, mpic_enable_source), + DEVMETHOD(pic_post_ithread, mpic_post_ithread), + DEVMETHOD(pic_pre_ithread, mpic_pre_ithread), +#endif { 0, 0 } }; @@ -189,8 +399,10 @@ static devclass_t mv_mpic_devclass; -DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0); +EARLY_DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0, + BUS_PASS_INTERRUPT); +#ifndef ARM_INTRNG int arm_get_next_irq(int last) { @@ -219,49 +431,42 @@ arm_mask_irq(uintptr_t nb) { - MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 1); - - if (nb < ERR_IRQ) { - bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh, - MPIC_ICE, nb); - MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb); - } else if (nb < MSI_IRQ) - arm_mask_irq_err(nb); + mpic_mask_irq(nb); } static void arm_mask_irq_err(uintptr_t nb) { - uint32_t mask; - uint8_t bit_off; - bit_off = nb - ERR_IRQ; - mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK); - mask &= ~(1 << bit_off); - MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask); + mpic_mask_irq_err(nb); } void arm_unmask_irq(uintptr_t nb) { - MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0); - - if (nb < ERR_IRQ) { - bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh, - MPIC_ISE, nb); - MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb); - } else if (nb < MSI_IRQ) - arm_unmask_irq_err(nb); - - if (nb == 0) - MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff); + mpic_unmask_irq(nb); } void arm_unmask_irq_err(uintptr_t nb) { + + mpic_unmask_irq_err(nb); +} +#endif + +static void +mpic_unmask_msi(void) +{ + + mpic_unmask_irq(MPIC_INT_MSI); +} + +static void +mpic_unmask_irq_err(uintptr_t nb) +{ uint32_t mask; uint8_t bit_off; @@ -276,10 +481,42 @@ } static void -arm_unmask_msi(void) +mpic_mask_irq_err(uintptr_t nb) +{ + uint32_t mask; + uint8_t bit_off; + + bit_off = nb - ERR_IRQ; + mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK); + mask &= ~(1 << bit_off); + MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask); +} + +static void +mpic_unmask_irq(uintptr_t nb) +{ + + if (nb < ERR_IRQ) { + bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh, + MPIC_ISE, nb); + MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb); + } else if (nb < MSI_IRQ) + mpic_unmask_irq_err(nb); + + if (nb == 0) + MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff); +} + +static void +mpic_mask_irq(uintptr_t nb) { - arm_unmask_irq(MPIC_INT_MSI); + if (nb < ERR_IRQ) { + bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh, + MPIC_ICE, nb); + MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb); + } else if (nb < MSI_IRQ) + mpic_mask_irq_err(nb); } uint32_t @@ -313,6 +550,7 @@ uint32_t cause; uint8_t bit_off; + KASSERT(mv_mpic_sc->drbl_bst != NULL, ("No doorbell in mv_mpic_get_msi")); cause = MPIC_DRBL_READ(mv_mpic_sc, 0); if (cause) @@ -359,7 +597,8 @@ return (0); } -#if defined(SMP) + +#if defined(SMP) && defined(SOC_MV_ARMADAXP) void pic_ipi_send(cpuset_t cpus, u_int ipi) { Index: sys/arm/mv/mv_common.c =================================================================== --- sys/arm/mv/mv_common.c +++ sys/arm/mv/mv_common.c @@ -2181,6 +2181,7 @@ { NULL, NULL } }; +#if !defined(ARM_INTRNG) static int fdt_pic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig, int *pol) @@ -2204,6 +2205,7 @@ &fdt_pic_decode_ic, NULL }; +#endif uint64_t get_sar_value(void) Index: sys/boot/fdt/dts/arm/db78460.dts =================================================================== --- sys/boot/fdt/dts/arm/db78460.dts +++ sys/boot/fdt/dts/arm/db78460.dts @@ -75,7 +75,7 @@ interrupt-controller; #address-cells = <0>; #interrupt-cells = <1>; - reg = <0x20a00 0x500 0x21000 0x800 0x20400 0x100>; + reg = <0x20a00 0x500 0x21870 0x58 0x20400 0x100>; compatible = "mrvl,mpic"; };