On Sat, Apr 29, 2017 at 06:45:15PM +0200, Mark Kettenis wrote: > The firefly rk3399 board has a gic-v3, so I'd like to get Dale's > driver into the tree. I did some further cleanup, renamed the driver > to agintc(4) (as jsg@ felt the "new" in angintc(4) did't make sense) > and fixed two bugs: > > * prival in setipl() was used uninitialized > > * apparently a dsb instruction is needed after reading the ICC_IAR1 > register > > I deliberately tried to keep the differences to ampintc(4) as small as > possible such that it easier to compare the code. I have a small > followup diff that will tweak ampintc(4) in the cases where the code > in agintc(4) was cleaner to start with. > > There may be more bugs lurking in this code as I'm still seeing plenty > of weird behaviour. But at least this will get me going. > > ok?
Yes, please. I have seen some whitespace issues which I commented inline, feel free to fix those before committing. Need to do another read later, but please just go ahead. > > > Index: arch/arm64/dev/agintc.c > =================================================================== > RCS file: arch/arm64/dev/agintc.c > diff -N arch/arm64/dev/agintc.c > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ arch/arm64/dev/agintc.c 29 Apr 2017 16:33:50 -0000 > @@ -0,0 +1,785 @@ > +/* $OpenBSD$ */ > +/* > + * Copyright (c) 2007, 2009, 2011, 2017 Dale Rahn <dr...@dalerahn.com> > + * > + * Permission to use, copy, modify, and distribute this software for any > + * purpose with or without fee is hereby granted, provided that the above > + * copyright notice and this permission notice appear in all copies. > + * > + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES > + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR > + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES > + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN > + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF > + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. > + */ > + > +/* > + * This is a device driver for the GICv3/GICv4 IP from ARM as specified > + * in IHI0069C, an example of this hardware is the GIC 500. > + */ > + > +#include <sys/param.h> > +#include <sys/systm.h> > +#include <sys/queue.h> > +#include <sys/malloc.h> > +#include <sys/device.h> > +#include <sys/evcount.h> > + > +#include <machine/bus.h> > +#include <machine/fdt.h> > + > +#include <dev/ofw/fdt.h> > +#include <dev/ofw/openfirm.h> > + > +#define ICC_PMR s3_0_c4_c6_0 > +#define ICC_IAR0 s3_0_c12_c8_0 > +#define ICC_EOIR0 s3_0_c12_c8_1 > +#define ICC_HPPIR0 s3_0_c12_c8_2 > +#define ICC_BPR0 s3_0_c12_c8_3 > + > +#define ICC_DIR s3_0_c12_c11_1 > +#define ICC_SGI1R s3_0_c12_c11_5 > +#define ICC_SGI0R s3_0_c12_c11_7 > + > +#define ICC_IAR1 s3_0_c12_c12_0 > +#define ICC_EOIR1 s3_0_c12_c12_1 > +#define ICC_HPPIR1 s3_0_c12_c12_2 > +#define ICC_BPR1 s3_0_c12_c12_3 > +#define ICC_CTLR s3_0_c12_c12_4 > +#define ICC_SRE_EL1 s3_0_c12_c12_5 > +#define ICC_SRE_EL1_EN 0x7 > +#define ICC_IGRPEN0 s3_0_c12_c12_6 > +#define ICC_IGRPEN1 s3_0_c12_c12_7 > + > +#define _STR(x) #x > +#define STR(x) _STR(x) > + > +/* distributor registers */ > +#define GICD_CTLR 0x0000 > +// non-secure > +#define GICD_CTLR_RWP (1U << 31) Replace the first space with a tab. > +#define GICD_CTRL_EnableGrp1 (1 << 0) > +#define GICD_CTRL_EnableGrp1A (1 << 1) > +#define GICD_CTRL_ARE_NS (1 << 4) > +#define GICD_TYPER 0x0004 > +#define GICD_TYPER_ITLINE_M 0xf > +#define GICD_IIDR 0x0008 > +#define GICD_ISENABLER(i) (0x0100 + (IRQ_TO_REG32(i) * 4)) > +#define GICD_ICENABLER(i) (0x0180 + (IRQ_TO_REG32(i) * 4)) > +#define GICD_ISPENDR(i) (0x0200 + (IRQ_TO_REG32(i) * 4)) > +#define GICD_ICPENDR(i) (0x0280 + (IRQ_TO_REG32(i) * 4)) > +#define GICD_ISACTIVER(i) (0x0300 + (IRQ_TO_REG32(i) * 4)) > +#define GICD_ICACTIVER(i) (0x0380 + (IRQ_TO_REG32(i) * 4)) > +#define GICD_IPRIORITYR(i) (0x0400 + (i)) > +#define GICD_ICFGR(i) (0x0c00 + (IRQ_TO_REG16(i) * 4)) > +#define GICD_IROUTER(i) (0x6000 + ((i) * 8)) > + > +/* redistributor registers */ > +#define GICR_CTLR 0x00000 > +#define GICR_CTLR_RWP ((1U << 31) | (1 << 3)) > +#define GICR_IIDR 0x00004 > +#define GICR_TYPER 0x00008 > +#define GICR_TYPER_LAST (1 << 4) > +#define GICR_TYPER_VLPIS (1 << 1) > +#define GICR_WAKER 0x00014 > +#define GICR_WAKER_X31 (1U << 31) > +#define GICR_WAKER_CHILDRENASLEEP (1 << 2) > +#define GICR_WAKER_PROCESSORSLEEP (1 << 1) > +#define GICR_WAKER_X0 (1 << 0) > +#define GICR_ISENABLE0 0x10100 > +#define GICR_ICENABLE0 0x10180 > +#define GICR_ISPENDR0 0x10200 > +#define GICR_ICPENDR0 0x10280 > +#define GICR_ISACTIVE0 0x10300 > +#define GICR_ICACTIVE0 0x10380 > +#define GICR_IPRIORITYR(i) (0x10400 + (i)) > +#define GICR_ICFGR0 0x10c00 > +#define GICR_ICFGR1 0x10c04 > + > +#define IRQ_TO_REG32(i) (((i) >> 5) & 0x7) > +#define IRQ_TO_REG32BIT(i) ((i) & 0x1f) > + > +#define IRQ_TO_REG16(i) (((i) >> 4) & 0xf) > +#define IRQ_TO_REG16BIT(i) ((i) & 0xf) > + > +#define IRQ_ENABLE 1 > +#define IRQ_DISABLE 0 > + > +/* > + * This is not a true hard limit, but until bigger machines are supported > + * there is no need for this to be 96+, which the interrupt controller > + * does support. It may make sense to move to dynamic allocation of these 3 > + * fields in the future, eg when hardware with 96 cores are supported. > + */ > +#define MAX_CORES 16 > + > +struct agintc_softc { > + struct device sc_dev; > + struct intrq *sc_agintc_handler; > + bus_space_tag_t sc_iot; > + bus_space_handle_t sc_d_ioh; > + bus_space_handle_t sc_r_ioh[MAX_CORES]; > + bus_space_handle_t sc_redist_base; > + uint64_t sc_affinity[MAX_CORES]; > + int sc_cpuremap[MAX_CORES]; /* bsd to redist */ > + int sc_nintr; > + struct evcount sc_spur; > + int sc_ncells; > + int sc_num_redist; > + int sc_pri_shift; > + struct interrupt_controller sc_ic; > +}; > +struct agintc_softc *agintc_sc; > + > +struct intrhand { > + TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */ > + int (*ih_func)(void *); /* handler */ > + void *ih_arg; /* arg for handler */ > + int ih_ipl; /* IPL_* */ > + int ih_irq; /* IRQ number */ > + struct evcount ih_count; > + char *ih_name; > +}; > + > +struct intrq { > + TAILQ_HEAD(, intrhand) iq_list; /* handler list */ > + int iq_irq; /* IRQ to mask while handling */ > + int iq_levels; /* IPL_*'s this IRQ has */ > + int iq_ist; /* share type */ > +}; > + > +int agintc_match(struct device *, void *, void *); > +void agintc_attach(struct device *, struct device *, void *); > +void agintc_cpuinit(void); > +int agintc_spllower(int); > +void agintc_splx(int); > +int agintc_splraise(int); > +void agintc_setipl(int); > +void agintc_calc_mask(void); > +void agintc_calc_irq(struct agintc_softc *sc, int irq); > +void *agintc_intr_establish(int, int, int (*)(void *), void *, > + char *); > +void *agintc_intr_establish_fdt(void *cookie, int *cell, int level, > + int (*func)(void *), void *arg, char *name); > +void agintc_intr_disestablish(void *); > +void agintc_irq_handler(void *); > +uint32_t agintc_iack(void); > +void agintc_eoi(uint32_t); > +void agintc_set_priority(struct agintc_softc *sc, int, int); > +void agintc_intr_enable(struct agintc_softc *, int); > +void agintc_intr_disable(struct agintc_softc *, int); > +void agintc_route(struct agintc_softc *, int, int, > + struct cpu_info *); > +void agintc_wait_rwp(struct agintc_softc *sc); > +void agintc_r_wait_rwp(struct agintc_softc *sc); > +uint32_t agintc_r_ictlr(void); > + > +struct cfattach agintc_ca = { > + sizeof (struct agintc_softc), agintc_match, agintc_attach > +}; > + > +struct cfdriver agintc_cd = { > + NULL, "agintc", DV_DULL > +}; > + > +static char *agintc_compatibles[] = { > + "arm,gic-v3", > + "arm,gic-v4", > + NULL > +}; > + > +int > +agintc_match(struct device *parent, void *cfdata, void *aux) > +{ > + struct fdt_attach_args *faa = aux; > + int i; > + > + for (i = 0; agintc_compatibles[i]; i++) > + if (OF_is_compatible(faa->fa_node, agintc_compatibles[i])) > + return (1); > + > + return (0); > +} > + > +static void > +__isb(void) > +{ > + __asm volatile ("isb"); There's a space between volatile and the (, I think we usually don't have a space there. > +} > + > +void > +agintc_attach(struct device *parent, struct device *self, void *aux) > +{ > + struct agintc_softc *sc = (struct agintc_softc *)self; > + struct fdt_attach_args *faa = aux; Replace the two spaces with a tab. > + int i, j, nintr; > + int psw; > + uint64_t icc_ctlr; > + int offset, nredist; > + int grp1enable; > + > + psw = disable_interrupts(); > + arm_init_smask(); > + > + sc->sc_iot = faa->fa_iot; > + > + /* First row: distributor */ > + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, > + faa->fa_reg[0].size, 0, &sc->sc_d_ioh)) > + panic("%s: ICD bus_space_map failed!", __func__); > + > + /* Second row: redistributor */ > + if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, > + faa->fa_reg[1].size, 0, &sc->sc_redist_base)) > + panic("%s: ICP bus_space_map failed!", __func__); > + > + evcount_attach(&sc->sc_spur, "irq1023/spur", NULL); > + > + __asm volatile("msr "STR(ICC_SRE_EL1)", %x0" : : "r" (ICC_SRE_EL1_EN)); > + __isb(); > + > + nintr = 32 * (bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, GICD_TYPER) & > + GICD_TYPER_ITLINE_M); > + > + nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */ > + sc->sc_nintr = nintr; > + > + __asm volatile ("mrs %x0, "STR(ICC_CTLR) : "=r"(icc_ctlr)); Another space here between volatile and... > + sc->sc_pri_shift = 8 - (((icc_ctlr >> 8) & 0x7)) - 1; > + > + agintc_sc = sc; /* save this for global access */ > + > + /* find and submap the redistributors. */ > + offset = 0; > + for (nredist = 0; ; nredist++) { > + int32_t sz = (64 * 1024 * 2); > + uint64_t typer; > + > + typer = bus_space_read_8(sc->sc_iot, sc->sc_redist_base, > + offset + GICR_TYPER); > + > + if (typer & GICR_TYPER_VLPIS) > + sz += (64 * 1024 * 2); > + > + sc->sc_affinity[nredist] = bus_space_read_8(sc->sc_iot, > + sc->sc_redist_base, offset + GICR_TYPER) >> 32; > + > + bus_space_subregion(sc->sc_iot, sc->sc_redist_base, > + offset, sz, &sc->sc_r_ioh[nredist]); > + > +#ifdef DEBUG_AGINTC > + printf("probing redistributor %d %x %p\n", nredist, offset, > + sc->sc_r_ioh[nredist]); > +#endif > + > + offset += sz; > + > + if (typer & GICR_TYPER_LAST) { > + sc->sc_num_redist = nredist + 1; > + break; > + } > + } > + > + printf(" nirq %d, nredist %d, pri_shift %d\n", nintr, > + sc->sc_num_redist, sc->sc_pri_shift); > + > + /* Disable all interrupts, clear all pending */ > + for (i = 1; i < nintr / 32; i++) { > + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, > + GICD_ICENABLER(i * 32), ~0); > + for(j = 0; j < 32; j++) { Space between for and ( > + __asm volatile("msr "STR(ICC_DIR)", %x0" : : > + "r" ((i * 32) + j)); > + __isb(); > + } > + } > + > + for (i = 4; i < nintr; i += 4) { > + /* lowest priority ?? */ > + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, > + GICD_IPRIORITYR(i), 0xffffffff); > + } > + > + for (i = 2; i < nintr / 16; i++) { > + /* irq 32 - N */ > + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, > + GICD_ICFGR(i * 16), 0); > + } > + > + agintc_cpuinit(); > + > + sc->sc_agintc_handler = mallocarray(nintr, > + sizeof(*sc->sc_agintc_handler), M_DEVBUF, M_ZERO | M_NOWAIT); > + for (i = 0; i < nintr; i++) > + TAILQ_INIT(&sc->sc_agintc_handler[i].iq_list); > + > + /* set priority to IPL_HIGH until configure lowers to desired IPL */ > + agintc_setipl(IPL_HIGH); > + > + /* initialize all interrupts as disabled */ > + agintc_calc_mask(); > + > + /* insert self as interrupt handler */ > + arm_set_intr_handler(agintc_splraise, agintc_spllower, agintc_splx, > + agintc_setipl, agintc_irq_handler); > + > + /* enable interrupts */ > + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, GICD_CTLR, > + GICD_CTRL_ARE_NS|GICD_CTRL_EnableGrp1A|GICD_CTRL_EnableGrp1); > + > + grp1enable = 1; > + __asm volatile ("msr "STR(ICC_PMR)", %x0" :: "r"(0xff)); > + __asm volatile ("msr "STR(ICC_BPR1)", %x0" :: "r"(7)); > + __asm volatile ("msr "STR(ICC_IGRPEN1)", %x0" :: "r"(grp1enable)); > + > + sc->sc_ic.ic_node = faa->fa_node; > + sc->sc_ic.ic_cookie = self; > + sc->sc_ic.ic_establish = agintc_intr_establish_fdt; > + sc->sc_ic.ic_disestablish = agintc_intr_disestablish; > + arm_intr_register_fdt(&sc->sc_ic); > + > + restore_interrupts(psw); > +} > + > +/* Initialize redistributors on each core. */ > +void > +agintc_cpuinit(void) > +{ > + struct cpu_info *ci = curcpu(); > + struct agintc_softc *sc = agintc_sc; > + uint64_t mpidr = READ_SPECIALREG(mpidr_el1); > + uint32_t affinity, waker; > + int timeout = 100000; > + int hwcpu = -1; > + int i; > + > + /* match this processor to one of the redistributors */ > + affinity = (((mpidr >> 8) & 0xff000000) | (mpidr & 0x00ffffff)); > + > + for (i = 0; i < sc->sc_num_redist; i++) { > + if (affinity == sc->sc_affinity[i]) { > + sc->sc_cpuremap[ci->ci_cpuid] = hwcpu = i; > +#ifdef DEBUG_AGINTC > + printf("found cpu%d at %d\n", ci->ci_cpuid, i); > +#endif > + break; > + } > + } > + > + if (hwcpu == -1) { > + printf("cpu mpidr not found mpidr %llx affinity %08x\n", > + mpidr, affinity); > + for (i = 0; i < sc->sc_num_redist; i++) > + printf("rdist%d: %08x\n", i, sc->sc_affinity[i]); > + panic("failed to indentify cpunumber %d \n", ci->ci_cpuid); > + } > + > + waker = bus_space_read_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_WAKER); > + waker &= ~(GICR_WAKER_PROCESSORSLEEP); > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], GICR_WAKER, > + waker); > + > + do { > + waker = bus_space_read_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_WAKER); > + } while (--timeout && (waker & GICR_WAKER_CHILDRENASLEEP)); > + if (timeout == 0) > + printf("%s: waker timed out\n", __func__); > + > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_ICENABLE0, ~0); > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_ICPENDR0, ~0); > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_ICACTIVE0, ~0); > + for (i = 0; i < 32; i += 4) { > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_IPRIORITYR(i), ~0); > + } > +} > + > +void > +agintc_set_priority(struct agintc_softc *sc, int irq, int pri) > +{ > + struct cpu_info *ci = curcpu(); > + int hwcpu = sc->sc_cpuremap[ci->ci_cpuid]; > + uint32_t prival; > + > + /* > + * We only use 16 (13 really) interrupt priorities, > + * and a CPU is only required to implement bit 4-7 of each field > + * so shift into the top bits. > + * also low values are higher priority thus NIPL - pri > + */ > + prival = ((NIPL - pri) << sc->sc_pri_shift); > + if (irq >= 32) { > + bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, > + GICD_IPRIORITYR(irq), prival); > + } else { > + /* only sets local redistributor */ > + bus_space_write_1(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_IPRIORITYR(irq), prival); > + } > +} > + > +void > +agintc_setipl(int new) > +{ > + struct cpu_info *ci = curcpu(); > + struct agintc_softc *sc = agintc_sc; > + int psw; > + uint32_t prival; > + > + /* disable here is only to keep hardware in sync with ci->ci_cpl */ > + psw = disable_interrupts(); > + ci->ci_cpl = new; > + > + /* low values are higher priority thus NIPL - pri */ > + if (new == IPL_NONE) > + prival = 0xff; /* minimum priority */ > + else > + prival = ((NIPL - new) << sc->sc_pri_shift); > + > + __asm volatile("msr "STR(ICC_PMR)", %x0" : : "r" (prival)); > + restore_interrupts(psw); > +} > + > +void > +agintc_intr_enable(struct agintc_softc *sc, int irq) > +{ > + struct cpu_info *ci = curcpu(); > + int hwcpu = sc->sc_cpuremap[ci->ci_cpuid]; > + int bit = 1 << IRQ_TO_REG32BIT(irq); > + > + if (irq >= 32) { > + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, > + GICD_ISENABLER(irq), bit); > + } else { > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_ISENABLE0, bit); > + } > +} > + > +void > +agintc_intr_disable(struct agintc_softc *sc, int irq) > +{ > + struct cpu_info *ci = curcpu(); > + int hwcpu = sc->sc_cpuremap[ci->ci_cpuid]; > + > + if (irq >= 32) { > + bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, > + GICD_ICENABLER(irq), 1 << IRQ_TO_REG32BIT(irq)); > + } else { > + bus_space_write_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], > + GICR_ICENABLE0, 1 << IRQ_TO_REG32BIT(irq)); > + } > +} > + > +void > +agintc_calc_mask(void) > +{ > + struct agintc_softc *sc = agintc_sc; > + int irq; > + > + for (irq = 0; irq < sc->sc_nintr; irq++) > + agintc_calc_irq(sc, irq); > +} > + > +void > +agintc_calc_irq(struct agintc_softc *sc, int irq) > +{ > + struct cpu_info *ci = curcpu(); > + struct intrhand *ih; > + int max = IPL_NONE; > + int min = IPL_HIGH; > + Remove the tab > + TAILQ_FOREACH(ih, &sc->sc_agintc_handler[irq].iq_list, ih_list) { > + if (ih->ih_ipl > max) > + max = ih->ih_ipl; > + > + if (ih->ih_ipl < min) > + min = ih->ih_ipl; > + } > + > + if (sc->sc_agintc_handler[irq].iq_irq == max) > + return; > + sc->sc_agintc_handler[irq].iq_irq = max; > + > + if (max == IPL_NONE) > + min = IPL_NONE; > + > +#ifdef DEBUG_AGINTC > + if (min != IPL_NONE) > + printf("irq %d to block at %d %d \n", irq, max, min ); > +#endif > + /* Enable interrupts at lower levels, clear -> enable */ > + /* Set interrupt priority/enable */ > + if (min != IPL_NONE) { > + agintc_set_priority(sc, irq, min); > + agintc_route(sc, irq, IRQ_ENABLE, ci); > + agintc_intr_enable(sc, irq); > + } else { > + agintc_intr_disable(sc, irq); > + agintc_route(sc, irq, IRQ_DISABLE, ci); > + } > +} > + > +void > +agintc_splx(int new) > +{ > + struct cpu_info *ci = curcpu(); > + > + if (ci->ci_ipending & arm_smask[new]) > + arm_do_pending_intr(new); > + > + agintc_setipl(new); > +} > + > +int > +agintc_spllower(int new) > +{ > + struct cpu_info *ci = curcpu(); > + int old = ci->ci_cpl; > + > + agintc_splx(new); > + return (old); > +} > + > +int > +agintc_splraise(int new) > +{ > + struct cpu_info *ci = curcpu(); > + int old = ci->ci_cpl; > + > + /* > + * setipl must always be called because there is a race window > + * where the variable is updated before the mask is set > + * an interrupt occurs in that window without the mask always > + * being set, the hardware might not get updated on the next > + * splraise completely messing up spl protection. > + */ > + if (old > new) > + new = old; > + > + agintc_setipl(new); > + return (old); > +} > + > +uint32_t > +agintc_iack(void) > +{ > + int irq; > + > + __asm volatile("mrs %x0, "STR(ICC_IAR1) : "=r" (irq)); > + __asm volatile("dsb sy"); > + return irq; > +} > + > +void > +agintc_route(struct agintc_softc *sc, int irq, int enable, struct cpu_info > *ci) > +{ > + uint64_t val; > + > + /* XXX does not yet support 'participating node' */ > + if (irq >= 32) { > + val = ((sc->sc_affinity[ci->ci_cpuid] & 0x00ffffff) | > + ((sc->sc_affinity[ci->ci_cpuid] & 0xff000000) << 8)); > +#ifdef DEBUG_AGINTC > + printf("router %x irq %d val %016llx\n", GICD_IROUTER(irq),irq, > + val); > +#endif > + bus_space_write_8(sc->sc_iot, sc->sc_d_ioh, > + GICD_IROUTER(irq), val); > + } > +} > + > +void > +agintc_irq_handler(void *frame) > +{ > + struct cpu_info *ci = curcpu(); > + struct agintc_softc *sc = agintc_sc; > + struct intrhand *ih; > + void *arg; > + int irq, pri, s, handled; > + > + ci->ci_idepth++; > + irq = agintc_iack(); > + > +#ifdef DEBUG_AGINTC > + if (irq != 30) > + printf("irq %d fired\n", irq); > + else { > + static int cnt = 0; > + if ((cnt++ % 100) == 0) { > + printf("irq %d fired * _100\n", irq); > +#ifdef DDB > + Debugger(); > +#endif > + } > + } > +#endif > + > + if (irq == 1023) { > + sc->sc_spur.ec_count++; > + return; > + } > + > + if (irq >= sc->sc_nintr) > + return; > + > + pri = sc->sc_agintc_handler[irq].iq_irq; > + s = agintc_splraise(pri); > + TAILQ_FOREACH(ih, &sc->sc_agintc_handler[irq].iq_list, ih_list) { > + if (ih->ih_arg != 0) > + arg = ih->ih_arg; > + else > + arg = frame; > + > + enable_interrupts(); > + handled = ih->ih_func(arg); > + disable_interrupts(); > + if (handled) > + ih->ih_count.ec_count++; > + > + } > + agintc_eoi(irq); > + > + agintc_splx(s); > + ci->ci_idepth--; > +} > + > +void * > +agintc_intr_establish_fdt(void *cookie, int *cell, int level, > + int (*func)(void *), void *arg, char *name) > +{ > + struct agintc_softc *sc = agintc_sc; > + int irq; > + > + /* 2nd cell contains the interrupt number */ > + irq = cell[1]; > + > + /* 1st cell contains type: 0 SPI (32-X), 1 PPI (16-31) */ > + if (cell[0] == 0) > + irq += 32; > + else if (cell[0] == 1) > + irq += 16; > + else > + panic("%s: bogus interrupt type", sc->sc_dev.dv_xname); > + > + return agintc_intr_establish(irq, level, func, arg, name); > +} > + > +void * > +agintc_intr_establish(int irqno, int level, int (*func)(void *), > + void *arg, char *name) > +{ > + struct agintc_softc *sc = agintc_sc; > + struct intrhand *ih; > + int psw; > + > + if (irqno < 0 || irqno >= sc->sc_nintr) > + panic("agintc_intr_establish: bogus irqnumber %d: %s", > + irqno, name); > + > + ih = malloc(sizeof *ih, M_DEVBUF, M_WAITOK); > + ih->ih_func = func; > + ih->ih_arg = arg; > + ih->ih_ipl = level; > + ih->ih_irq = irqno; > + ih->ih_name = name; > + > + psw = disable_interrupts(); > + > + TAILQ_INSERT_TAIL(&sc->sc_agintc_handler[irqno].iq_list, ih, ih_list); > + > + if (name != NULL) > + evcount_attach(&ih->ih_count, name, &ih->ih_irq); > + > +#ifdef DEBUG_AGINTC > + printf("%s: irq %d level %d [%s]\n", __func__, irqno, level, name); > +#endif > + > + agintc_calc_irq(sc, irqno); > + > + restore_interrupts(psw); > + return (ih); > +} > + > +void > +agintc_intr_disestablish(void *cookie) > +{ > + struct agintc_softc *sc = agintc_sc; > + struct intrhand *ih = cookie; > + int irqno = ih->ih_irq; > + int psw; > + > + psw = disable_interrupts(); > + > + TAILQ_REMOVE(&sc->sc_agintc_handler[irqno].iq_list, ih, ih_list); > + if (ih->ih_name != NULL) > + evcount_detach(&ih->ih_count); > + > + agintc_calc_irq(sc, irqno); > + > + restore_interrupts(psw); > + > + free(ih, M_DEVBUF, 0); > +} > + > +void > +agintc_eoi(uint32_t eoi) > +{ > + __asm volatile("msr "STR(ICC_EOIR1)", %x0" :: "r" (eoi)); > + __isb(); > +} > + > +uint32_t > +agintc_r_ictlr(void) > +{ > + int ictlr; > + > + __asm volatile("mrs %x0, "STR(ICC_CTLR) : "=r" (ictlr)); > + __isb(); > + return ictlr; > +} > + > +void > +agintc_d_wait_rwp(struct agintc_softc *sc) > +{ > + int count = 100000; > + uint32_t v; > + > + do { > + v = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, GICD_CTLR); > + } while (--count && (v & GICD_CTLR_RWP)); > + > + if (count == 0) > + panic("%s: RWP timed out 0x08%x\n", __func__, v); > +} > + > +void > +agintc_r_wait_rwp(struct agintc_softc *sc) > +{ > + struct cpu_info *ci = curcpu(); > + int hwcpu = sc->sc_cpuremap[ci->ci_cpuid]; > + int count = 100000; > + uint32_t v; > + > + do { > + v = bus_space_read_4(sc->sc_iot, sc->sc_r_ioh[hwcpu], GICR_CTLR); Replace the spaces with a tab. > + } while (--count && (v & GICR_CTLR_RWP)); > + > + if (count == 0) > + panic("%s: RWP timed out 0x08%x\n", __func__, v); > +} > + > +void > +agintc_send_ipi(int sgi, int targetmask) > +{ > + int val = (sgi << 24) | (targetmask); > + > + __asm volatile ("msr "STR(ICC_SGI1R)", %x0" ::"r" (val)); > +} > Index: arch/arm64/conf/GENERIC > =================================================================== > RCS file: /cvs/src/sys/arch/arm64/conf/GENERIC,v > retrieving revision 1.23 > diff -u -p -r1.23 GENERIC > --- arch/arm64/conf/GENERIC 27 Apr 2017 10:23:19 -0000 1.23 > +++ arch/arm64/conf/GENERIC 29 Apr 2017 16:33:50 -0000 > @@ -47,6 +47,7 @@ uk* at scsibus? > > ampintc* at fdt? > ampintcmsi* at fdt? > +agintc* at fdt? > agtimer* at fdt? > ahci* at fdt? > pciecam* at fdt? > Index: arch/arm64/conf/RAMDISK > =================================================================== > RCS file: /cvs/src/sys/arch/arm64/conf/RAMDISK,v > retrieving revision 1.20 > diff -u -p -r1.20 RAMDISK > --- arch/arm64/conf/RAMDISK 27 Apr 2017 10:23:19 -0000 1.20 > +++ arch/arm64/conf/RAMDISK 29 Apr 2017 16:33:50 -0000 > @@ -57,6 +57,7 @@ uk* at scsibus? > > ampintc* at fdt? > ampintcmsi* at fdt? > +agintc* at fdt? > agtimer* at fdt? > ahci* at fdt? > pciecam* at fdt? > Index: arch/arm64/conf/files.arm64 > =================================================================== > RCS file: /cvs/src/sys/arch/arm64/conf/files.arm64,v > retrieving revision 1.12 > diff -u -p -r1.12 files.arm64 > --- arch/arm64/conf/files.arm64 27 Apr 2017 10:23:19 -0000 1.12 > +++ arch/arm64/conf/files.arm64 29 Apr 2017 16:33:50 -0000 > @@ -125,6 +125,10 @@ device ampintcmsi > attach ampintcmsi at fdt > file arch/arm64/dev/ampintc.c ampintc | ampintcmsi > > +device agintc > +attach agintc at fdt > +file arch/arm64/dev/agintc.c agintc > + > device agtimer > attach agtimer at fdt > file arch/arm64/dev/agtimer.c agtimer >