Index: head/sys/arm/conf/ARMADA38X =================================================================== --- head/sys/arm/conf/ARMADA38X +++ head/sys/arm/conf/ARMADA38X @@ -23,6 +23,7 @@ #options SCHED_4BSD # 4BSD scheduler options SMP +options ARM_INTRNG # Debugging #options DEBUG Index: head/sys/arm/mv/armada38x/files.armada38x =================================================================== --- head/sys/arm/mv/armada38x/files.armada38x +++ head/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: head/sys/arm/mv/mpic.c =================================================================== --- head/sys/arm/mv/mpic.c +++ head/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 @@ -48,11 +54,16 @@ #include #include +#include #include #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) @@ -60,46 +71,63 @@ #define debugf(fmt, args...) #endif -#define MPIC_INT_ERR 4 -#define MPIC_INT_MSI 96 +#define MPIC_INT_ERR 4 +#define MPIC_INT_MSI 96 -#define IRQ_MASK 0x3ff +#define IRQ_MASK 0x3ff -#define MPIC_CTRL 0x0 -#define MPIC_SOFT_INT 0x4 -#define MPIC_SOFT_INT_DRBL1 (1 << 5) -#define MPIC_ERR_CAUSE 0x20 -#define MPIC_ISE 0x30 -#define MPIC_ICE 0x34 - - -#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_CTRL 0x0 +#define MPIC_SOFT_INT 0x4 +#define MPIC_SOFT_INT_DRBL1 (1 << 5) +#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 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 +137,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 +170,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 +182,7 @@ { struct mv_mpic_softc *sc; int error; + uint32_t val; sc = (struct mv_mpic_softc *)device_get_softc(dev); @@ -151,11 +192,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 +213,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 +400,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 +432,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 +482,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 +551,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 +598,8 @@ return (0); } -#if defined(SMP) + +#if defined(SMP) && defined(SOC_MV_ARMADAXP) void intr_pic_init_secondary(void) { Index: head/sys/arm/mv/mvreg.h =================================================================== --- head/sys/arm/mv/mvreg.h +++ head/sys/arm/mv/mvreg.h @@ -67,7 +67,10 @@ #elif defined (SOC_MV_ARMADAXP) #define IRQ_CAUSE 0x18 #define IRQ_MASK 0x30 -#else /* !SOC_MV_DISCOVERY && !SOC_MV_LOKIPLUS */ +#elif defined (SOC_MV_ARMADA38X) +#define MSI_IRQ 0x3ff +#define ERR_IRQ 0x3ff +#else #define IRQ_CAUSE 0x0 #define IRQ_MASK 0x4 #define FIQ_MASK 0x8 Index: head/sys/boot/fdt/dts/arm/db78460.dts =================================================================== --- head/sys/boot/fdt/dts/arm/db78460.dts +++ head/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"; };