Message ID | 1468587641-7300-8-git-send-email-drjones@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Drew, On 15/07/2016 15:00, Andrew Jones wrote: > Signed-off-by: Andrew Jones <drjones@redhat.com> > > --- > v2: configure irqs as NS GRP1 > --- > lib/arm/asm/arch_gicv3.h | 184 ++++++++++++++++++++++++++ > lib/arm/asm/gic-v3.h | 321 +++++++++++++++++++++++++++++++++++++++++++++ > lib/arm/asm/gic.h | 1 + > lib/arm/gic.c | 73 +++++++++++ > lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++++++ > lib/arm64/asm/gic-v3.h | 1 + > lib/arm64/asm/sysreg.h | 44 +++++++ > 7 files changed, 793 insertions(+) > create mode 100644 lib/arm/asm/arch_gicv3.h > create mode 100644 lib/arm/asm/gic-v3.h > create mode 100644 lib/arm64/asm/arch_gicv3.h > create mode 100644 lib/arm64/asm/gic-v3.h > create mode 100644 lib/arm64/asm/sysreg.h > > diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h > new file mode 100644 > index 0000000000000..d529a7eb62807 > --- /dev/null > +++ b/lib/arm/asm/arch_gicv3.h > @@ -0,0 +1,184 @@ > +/* > + * All ripped off from arch/arm/include/asm/arch_gicv3.h > + * > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM_ARCH_GICV3_H_ > +#define _ASMARM_ARCH_GICV3_H_ > + > +#ifndef __ASSEMBLY__ > + > +#include <libcflat.h> > +#include <asm/barrier.h> > +#include <asm/io.h> > + > +#define __stringify xstr > + > + > +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 > +#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm > + > +#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) > +#define ICC_DIR __ACCESS_CP15(c12, 0, c11, 1) > +#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) > +#define ICC_SGI1R __ACCESS_CP15_64(0, c12) > +#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) > +#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) > +#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) > +#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) > + > +#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) > + > +#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) > +#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0) > +#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1) > +#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2) > +#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3) > +#define ICH_ELSR __ACCESS_CP15(c12, 4, c11, 5) > +#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7) > + > +#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x) > +#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x) > + > +#define ICH_LR0 __LR0(0) > +#define ICH_LR1 __LR0(1) > +#define ICH_LR2 __LR0(2) > +#define ICH_LR3 __LR0(3) > +#define ICH_LR4 __LR0(4) > +#define ICH_LR5 __LR0(5) > +#define ICH_LR6 __LR0(6) > +#define ICH_LR7 __LR0(7) > +#define ICH_LR8 __LR8(0) > +#define ICH_LR9 __LR8(1) > +#define ICH_LR10 __LR8(2) > +#define ICH_LR11 __LR8(3) > +#define ICH_LR12 __LR8(4) > +#define ICH_LR13 __LR8(5) > +#define ICH_LR14 __LR8(6) > +#define ICH_LR15 __LR8(7) > + > +/* LR top half */ > +#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x) > +#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x) > + > +#define ICH_LRC0 __LRC0(0) > +#define ICH_LRC1 __LRC0(1) > +#define ICH_LRC2 __LRC0(2) > +#define ICH_LRC3 __LRC0(3) > +#define ICH_LRC4 __LRC0(4) > +#define ICH_LRC5 __LRC0(5) > +#define ICH_LRC6 __LRC0(6) > +#define ICH_LRC7 __LRC0(7) > +#define ICH_LRC8 __LRC8(0) > +#define ICH_LRC9 __LRC8(1) > +#define ICH_LRC10 __LRC8(2) > +#define ICH_LRC11 __LRC8(3) > +#define ICH_LRC12 __LRC8(4) > +#define ICH_LRC13 __LRC8(5) > +#define ICH_LRC14 __LRC8(6) > +#define ICH_LRC15 __LRC8(7) > + > +#define __AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x) > +#define ICH_AP0R0 __AP0Rx(0) > +#define ICH_AP0R1 __AP0Rx(1) > +#define ICH_AP0R2 __AP0Rx(2) > +#define ICH_AP0R3 __AP0Rx(3) > + > +#define __AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x) > +#define ICH_AP1R0 __AP1Rx(0) > +#define ICH_AP1R1 __AP1Rx(1) > +#define ICH_AP1R2 __AP1Rx(2) > +#define ICH_AP1R3 __AP1Rx(3) > + > +/* Low-level accessors */ > + > +static inline void gicv3_write_eoir(u32 irq) > +{ > + asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (irq)); > + isb(); > +} > + > +static inline void gicv3_write_dir(u32 val) > +{ > + asm volatile("mcr " __stringify(ICC_DIR) : : "r" (val)); > + isb(); > +} > + > +static inline u32 gicv3_read_iar(void) > +{ > + u32 irqstat; > + > + asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat)); > + dsb(sy); > + return irqstat; > +} > + > +static inline void gicv3_write_pmr(u32 val) > +{ > + asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val)); > +} > + > +static inline void gicv3_write_ctlr(u32 val) > +{ > + asm volatile("mcr " __stringify(ICC_CTLR) : : "r" (val)); > + isb(); > +} > + > +static inline void gicv3_write_grpen1(u32 val) > +{ > + asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val)); > + isb(); > +} > + > +static inline void gicv3_write_sgi1r(u64 val) > +{ > + asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val)); > +} > + > +static inline u32 gicv3_read_sre(void) > +{ > + u32 val; > + > + asm volatile("mrc " __stringify(ICC_SRE) : "=r" (val)); > + return val; > +} > + > +static inline void gicv3_write_sre(u32 val) > +{ > + asm volatile("mcr " __stringify(ICC_SRE) : : "r" (val)); > + isb(); > +} > + > +/* > + * Even in 32bit systems that use LPAE, there is no guarantee that the I/O > + * interface provides true 64bit atomic accesses, so using strd/ldrd doesn't > + * make much sense. > + * Moreover, 64bit I/O emulation is extremely difficult to implement on > + * AArch32, since the syndrome register doesn't provide any information for > + * them. > + * Consequently, the following IO helpers use 32bit accesses. > + * > + * There are only two registers that need 64bit accesses in this driver: > + * - GICD_IROUTERn, contain the affinity values associated to each interrupt. > + * The upper-word (aff3) will always be 0, so there is no need for a lock. > + * - GICR_TYPER is an ID register and doesn't need atomicity. > + */ > +static inline void gicv3_write_irouter(u64 val, volatile void __iomem *addr) > +{ > + writel((u32)val, addr); > + writel((u32)(val >> 32), addr + 4); > +} > + > +static inline u64 gicv3_read_typer(const volatile void __iomem *addr) > +{ > + u64 val; > + > + val = readl(addr); > + val |= (u64)readl(addr + 4) << 32; > + return val; > +} > + > +#endif /* !__ASSEMBLY__ */ > +#endif /* _ASMARM_ARCH_GICV3_H_ */ > diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h > new file mode 100644 > index 0000000000000..8831389e2a00d > --- /dev/null > +++ b/lib/arm/asm/gic-v3.h > @@ -0,0 +1,321 @@ > +/* > + * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h There are quite a lot of differences between linux version and this version. May be worth resync'ing. > + * > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM_GIC_V3_H_ > +#define _ASMARM_GIC_V3_H_ > + > +/* > + * Distributor registers. We assume we're running non-secure, with ARE > + * being set. Secure-only and non-ARE registers are not described. > + */ > +#define GICD_CTLR 0x0000 > +#define GICD_TYPER 0x0004 > +#define GICD_IIDR 0x0008 > +#define GICD_STATUSR 0x0010 > +#define GICD_SETSPI_NSR 0x0040 > +#define GICD_CLRSPI_NSR 0x0048 > +#define GICD_SETSPI_SR 0x0050 > +#define GICD_CLRSPI_SR 0x0058 > +#define GICD_SEIR 0x0068 > +#define GICD_IGROUPR 0x0080 > +#define GICD_ISENABLER 0x0100 > +#define GICD_ICENABLER 0x0180 > +#define GICD_ISPENDR 0x0200 > +#define GICD_ICPENDR 0x0280 > +#define GICD_ISACTIVER 0x0300 > +#define GICD_ICACTIVER 0x0380 > +#define GICD_IPRIORITYR 0x0400 > +#define GICD_ICFGR 0x0C00 > +#define GICD_IGRPMODR 0x0D00 > +#define GICD_NSACR 0x0E00 > +#define GICD_IROUTER 0x6000 > +#define GICD_IDREGS 0xFFD0 > +#define GICD_PIDR2 0xFFE8 > + > +/* > + * Those registers are actually from GICv2, but the spec demands that they > + * are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3). > + */ > +#define GICD_ITARGETSR 0x0800 > +#define GICD_SGIR 0x0F00 > +#define GICD_CPENDSGIR 0x0F10 > +#define GICD_SPENDSGIR 0x0F20 > + > +#define GICD_CTLR_RWP (1U << 31) > +#define GICD_CTLR_DS (1U << 6) > +#define GICD_CTLR_ARE_NS (1U << 4) > +#define GICD_CTLR_ENABLE_G1A (1U << 1) > +#define GICD_CTLR_ENABLE_G1 (1U << 0) > + > +/* > + * In systems with a single security state (what we emulate in KVM) > + * the meaning of the interrupt group enable bits is slightly different > + */ > +#define GICD_CTLR_ENABLE_SS_G1 (1U << 1) > +#define GICD_CTLR_ENABLE_SS_G0 (1U << 0) > + > +#define GICD_TYPER_LPIS (1U << 17) > +#define GICD_TYPER_MBIS (1U << 16) > + > +#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) > +#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) > +#define GICD_TYPER_LPIS (1U << 17) > + > +#define GICD_IROUTER_SPI_MODE_ONE (0U << 31) > +#define GICD_IROUTER_SPI_MODE_ANY (1U << 31) > + > +#define GIC_PIDR2_ARCH_MASK 0xf0 > +#define GIC_PIDR2_ARCH_GICv3 0x30 > +#define GIC_PIDR2_ARCH_GICv4 0x40 > + > +#define GIC_V3_DIST_SIZE 0x10000 > + > +/* > + * Re-Distributor registers, offsets from RD_base > + */ > +#define GICR_CTLR GICD_CTLR > +#define GICR_IIDR 0x0004 > +#define GICR_TYPER 0x0008 > +#define GICR_STATUSR GICD_STATUSR > +#define GICR_WAKER 0x0014 > +#define GICR_SETLPIR 0x0040 > +#define GICR_CLRLPIR 0x0048 > +#define GICR_SEIR GICD_SEIR > +#define GICR_PROPBASER 0x0070 > +#define GICR_PENDBASER 0x0078 > +#define GICR_INVLPIR 0x00A0 > +#define GICR_INVALLR 0x00B0 > +#define GICR_SYNCR 0x00C0 > +#define GICR_MOVLPIR 0x0100 > +#define GICR_MOVALLR 0x0110 > +#define GICR_ISACTIVER GICD_ISACTIVER > +#define GICR_ICACTIVER GICD_ICACTIVER > +#define GICR_IDREGS GICD_IDREGS > +#define GICR_PIDR2 GICD_PIDR2 > + > +#define GICR_CTLR_ENABLE_LPIS (1UL << 0) > + > +#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) > + > +#define GICR_WAKER_ProcessorSleep (1U << 1) > +#define GICR_WAKER_ChildrenAsleep (1U << 2) > + > +#define GICR_PROPBASER_NonShareable (0U << 10) > +#define GICR_PROPBASER_InnerShareable (1U << 10) > +#define GICR_PROPBASER_OuterShareable (2U << 10) > +#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10) > +#define GICR_PROPBASER_nCnB (0U << 7) > +#define GICR_PROPBASER_nC (1U << 7) > +#define GICR_PROPBASER_RaWt (2U << 7) > +#define GICR_PROPBASER_RaWb (3U << 7) > +#define GICR_PROPBASER_WaWt (4U << 7) > +#define GICR_PROPBASER_WaWb (5U << 7) > +#define GICR_PROPBASER_RaWaWt (6U << 7) > +#define GICR_PROPBASER_RaWaWb (7U << 7) > +#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) > +#define GICR_PROPBASER_IDBITS_MASK (0x1f) > + > +#define GICR_PENDBASER_NonShareable (0U << 10) > +#define GICR_PENDBASER_InnerShareable (1U << 10) > +#define GICR_PENDBASER_OuterShareable (2U << 10) > +#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10) > +#define GICR_PENDBASER_nCnB (0U << 7) > +#define GICR_PENDBASER_nC (1U << 7) > +#define GICR_PENDBASER_RaWt (2U << 7) > +#define GICR_PENDBASER_RaWb (3U << 7) > +#define GICR_PENDBASER_WaWt (4U << 7) > +#define GICR_PENDBASER_WaWb (5U << 7) > +#define GICR_PENDBASER_RaWaWt (6U << 7) > +#define GICR_PENDBASER_RaWaWb (7U << 7) > +#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) > + > +/* > + * Re-Distributor registers, offsets from SGI_base > + */ > +#define GICR_IGROUPR0 GICD_IGROUPR > +#define GICR_ISENABLER0 GICD_ISENABLER > +#define GICR_ICENABLER0 GICD_ICENABLER > +#define GICR_ISPENDR0 GICD_ISPENDR > +#define GICR_ICPENDR0 GICD_ICPENDR > +#define GICR_ISACTIVER0 GICD_ISACTIVER > +#define GICR_ICACTIVER0 GICD_ICACTIVER > +#define GICR_IPRIORITYR0 GICD_IPRIORITYR > +#define GICR_ICFGR0 GICD_ICFGR > +#define GICR_IGRPMODR0 GICD_IGRPMODR > +#define GICR_NSACR GICD_NSACR > + > +#define GICR_TYPER_PLPIS (1U << 0) > +#define GICR_TYPER_VLPIS (1U << 1) > +#define GICR_TYPER_LAST (1U << 4) > + > +#define GIC_V3_REDIST_SIZE 0x20000 > + > +#define LPI_PROP_GROUP1 (1 << 1) > +#define LPI_PROP_ENABLED (1 << 0) > + > +/* > + * ITS registers, offsets from ITS_base > + */ > +#define GITS_CTLR 0x0000 > +#define GITS_IIDR 0x0004 > +#define GITS_TYPER 0x0008 > +#define GITS_CBASER 0x0080 > +#define GITS_CWRITER 0x0088 > +#define GITS_CREADR 0x0090 > +#define GITS_BASER 0x0100 > +#define GITS_PIDR2 GICR_PIDR2 > + > +#define GITS_TRANSLATER 0x10040 > + > +#define GITS_CTLR_ENABLE (1U << 0) > +#define GITS_CTLR_QUIESCENT (1U << 31) > + > +#define GITS_TYPER_DEVBITS_SHIFT 13 > +#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) > +#define GITS_TYPER_PTA (1UL << 19) > + > +#define GITS_CBASER_VALID (1UL << 63) > +#define GITS_CBASER_nCnB (0UL << 59) > +#define GITS_CBASER_nC (1UL << 59) > +#define GITS_CBASER_RaWt (2UL << 59) > +#define GITS_CBASER_RaWb (3UL << 59) > +#define GITS_CBASER_WaWt (4UL << 59) > +#define GITS_CBASER_WaWb (5UL << 59) > +#define GITS_CBASER_RaWaWt (6UL << 59) > +#define GITS_CBASER_RaWaWb (7UL << 59) > +#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59) > +#define GITS_CBASER_NonShareable (0UL << 10) > +#define GITS_CBASER_InnerShareable (1UL << 10) > +#define GITS_CBASER_OuterShareable (2UL << 10) > +#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10) > + > +#define GITS_BASER_NR_REGS 8 > + > +#define GITS_BASER_VALID (1UL << 63) > +#define GITS_BASER_nCnB (0UL << 59) > +#define GITS_BASER_nC (1UL << 59) > +#define GITS_BASER_RaWt (2UL << 59) > +#define GITS_BASER_RaWb (3UL << 59) > +#define GITS_BASER_WaWt (4UL << 59) > +#define GITS_BASER_WaWb (5UL << 59) > +#define GITS_BASER_RaWaWt (6UL << 59) > +#define GITS_BASER_RaWaWb (7UL << 59) > +#define GITS_BASER_CACHEABILITY_MASK (7UL << 59) > +#define GITS_BASER_TYPE_SHIFT (56) > +#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) > +#define GITS_BASER_ENTRY_SIZE_SHIFT (48) > +#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1) > +#define GITS_BASER_NonShareable (0UL << 10) > +#define GITS_BASER_InnerShareable (1UL << 10) > +#define GITS_BASER_OuterShareable (2UL << 10) > +#define GITS_BASER_SHAREABILITY_SHIFT (10) > +#define GITS_BASER_SHAREABILITY_MASK (3UL << GITS_BASER_SHAREABILITY_SHIFT) > +#define GITS_BASER_PAGE_SIZE_SHIFT (8) > +#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT) > +#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT) > +#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) > +#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) > +#define GITS_BASER_PAGES_MAX 256 > + > +#define GITS_BASER_TYPE_NONE 0 > +#define GITS_BASER_TYPE_DEVICE 1 > +#define GITS_BASER_TYPE_VCPU 2 > +#define GITS_BASER_TYPE_CPU 3 > +#define GITS_BASER_TYPE_COLLECTION 4 > +#define GITS_BASER_TYPE_RESERVED5 5 > +#define GITS_BASER_TYPE_RESERVED6 6 > +#define GITS_BASER_TYPE_RESERVED7 7 > + > +/* > + * ITS commands > + */ > +#define GITS_CMD_MAPD 0x08 > +#define GITS_CMD_MAPC 0x09 > +#define GITS_CMD_MAPVI 0x0a > +#define GITS_CMD_MOVI 0x01 > +#define GITS_CMD_DISCARD 0x0f > +#define GITS_CMD_INV 0x0c > +#define GITS_CMD_MOVALL 0x0e > +#define GITS_CMD_INVALL 0x0d > +#define GITS_CMD_INT 0x03 > +#define GITS_CMD_CLEAR 0x04 > +#define GITS_CMD_SYNC 0x05 > + > +/* > + * CPU interface registers > + */ > +#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1) > +#define ICC_CTLR_EL1_EOImode_drop (1U << 1) > +#define ICC_SRE_EL1_SRE (1U << 0) > + > +#include <asm/arch_gicv3.h> I would personally move this in gic.c > + > +#define SZ_64K 0x10000 > + > +#ifndef __ASSEMBLY__ > +#include <libcflat.h> > +#include <asm/processor.h> > +#include <asm/setup.h> > +#include <asm/smp.h> > +#include <asm/io.h> > + > +struct gicv3_data { > + void *dist_base; > + void *redist_base[NR_CPUS]; > + unsigned int irq_nr; > +}; > +extern struct gicv3_data gicv3_data; > + > +#define gicv3_dist_base() (gicv3_data.dist_base) > +#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()]) > +#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K) > + > +extern int gicv3_init(void); > +extern void gicv3_enable_defaults(void); > + > +static inline void gicv3_do_wait_for_rwp(void *base) > +{ > + int count = 100000; /* 1s */ > + > + while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) { > + if (!--count) { > + printf("GICv3: RWP timeout!\n"); > + abort(); > + } > + cpu_relax(); > + udelay(10); > + }; > +} > + > +static inline void gicv3_dist_wait_for_rwp(void) > +{ > + gicv3_do_wait_for_rwp(gicv3_dist_base()); > +} > + > +static inline void gicv3_redist_wait_for_rwp(void) > +{ > + gicv3_do_wait_for_rwp(gicv3_redist_base()); > +} > + > +static inline u32 mpidr_compress(u64 mpidr) > +{ > + u64 compressed = mpidr & MPIDR_HWID_BITMASK; > + > + compressed = (((compressed >> 32) & 0xff) << 24) | compressed; > + return compressed; > +} > + > +static inline u64 mpidr_uncompress(u32 compressed) > +{ > + u64 mpidr = ((u64)compressed >> 24) << 32; > + > + mpidr |= compressed & MPIDR_HWID_BITMASK; > + return mpidr; > +} > + > +#endif /* !__ASSEMBLY__ */ > +#endif /* _ASMARM_GIC_V3_H_ */ > diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h > index b1237d1c5ef22..849d17cb36a4e 100644 > --- a/lib/arm/asm/gic.h > +++ b/lib/arm/asm/gic.h > @@ -7,6 +7,7 @@ > #define _ASMARM_GIC_H_ > > #include <asm/gic-v2.h> > +#include <asm/gic-v3.h> > > /* > * gic_init will try to find all known gics, and then > diff --git a/lib/arm/gic.c b/lib/arm/gic.c > index 64a3049c9e8ce..bb62407f7286e 100644 > --- a/lib/arm/gic.c > +++ b/lib/arm/gic.c > @@ -10,9 +10,11 @@ > #include <asm/io.h> > > struct gicv2_data gicv2_data; > +struct gicv3_data gicv3_data; > > /* > * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt > + * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt > */ > static bool > gic_get_dt_bases(const char *compatible, void **base1, void **base2) > @@ -50,10 +52,18 @@ int gicv2_init(void) > &gicv2_data.dist_base, &gicv2_data.cpu_base); > } > > +int gicv3_init(void) > +{ > + return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, > + &gicv3_data.redist_base[0]); > +} > + > int gic_init(void) > { > if (gicv2_init()) > return 2; > + else if (gicv3_init()) > + return 3; > return 0; > } > > @@ -67,3 +77,66 @@ void gicv2_enable_defaults(void) > writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK); > writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL); > } > + > +void gicv3_set_redist_base(void) > +{ > + u32 aff = mpidr_compress(get_mpidr()); > + void *ptr = gicv3_data.redist_base[0]; > + u64 typer; > + > + do { > + typer = gicv3_read_typer(ptr + GICR_TYPER); > + if ((typer >> 32) == aff) { > + gicv3_redist_base() = ptr; > + return; > + } > + ptr += SZ_64K * 2; /* skip RD_base and SGI_base */ > + } while (!(typer & GICR_TYPER_LAST)); > + assert(0); > +} > + > +void gicv3_enable_defaults(void) > +{ > + void *dist = gicv3_dist_base(); > + void *sgi_base; > + unsigned int i; > + > + if (smp_processor_id() == 0) { > + u32 typer = readl(dist + GICD_TYPER); > + > + gicv3_data.irq_nr = GICD_TYPER_IRQS(typer); > + if (gicv3_data.irq_nr > 1020) { > + printf("GICD_TYPER_IRQS reported %d! " > + "Clamping to max=1020.\n", 1020); > + gicv3_data.irq_nr = 1020; > + } > + > + writel(0, dist + GICD_CTLR); > + gicv3_dist_wait_for_rwp(); > + > + for (i = 32; i < gicv3_data.irq_nr; i += 32) > + writel(~0, dist + GICD_IGROUPR + i / 8); > + > + writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, > + dist + GICD_CTLR); > + gicv3_dist_wait_for_rwp(); > + } shouldn't we follow the same init as in kernel and maybe also the same structure: gic_dist_init(); gic_cpu_init(); gic_cpu_pm_init(); I am really scared by forgetting settings and debugging this minimal driver. That being said, that's a very tedious task. > + > + if (!gicv3_redist_base()) > + gicv3_set_redist_base(); > + sgi_base = gicv3_sgi_base(); > + > + writel(~0, sgi_base + GICR_IGROUPR0); > + > + writel(GICD_INT_EN_CLR_X32, sgi_base + GIC_DIST_ACTIVE_CLEAR); > + writel(GICD_INT_EN_CLR_PPI, sgi_base + GIC_DIST_ENABLE_CLEAR); > + writel(GICD_INT_EN_SET_SGI, sgi_base + GIC_DIST_ENABLE_SET); > + > + for (i = 0; i < 32; i += 4) > + writel(GICD_INT_DEF_PRI_X4, sgi_base + GIC_DIST_PRI + i); > + gicv3_redist_wait_for_rwp(); > + > + gicv3_write_pmr(0xf0); > + gicv3_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);I think by default we use EOI mode 1 (ICC_CTLR_EL1_EOImode_drop). To be consistent I thing EOIModeNS = 1 should also be set on GICv2 side. Thanks Eric > + gicv3_write_grpen1(1); > +} > diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h > new file mode 100644 > index 0000000000000..eff2efdfe2d4d > --- /dev/null > +++ b/lib/arm64/asm/arch_gicv3.h > @@ -0,0 +1,169 @@ > +/* > + * All ripped off from arch/arm64/include/asm/arch_gicv3.h > + * > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM64_ARCH_GICV3_H_ > +#define _ASMARM64_ARCH_GICV3_H_ > + > +#include <asm/sysreg.h> > + > +#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) > +#define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1) > +#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) > +#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) > +#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) > +#define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4) > +#define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5) > +#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) > + > +#define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5) > + > +/* > + * System register definitions > + */ > +#define ICH_VSEIR_EL2 sys_reg(3, 4, 12, 9, 4) > +#define ICH_HCR_EL2 sys_reg(3, 4, 12, 11, 0) > +#define ICH_VTR_EL2 sys_reg(3, 4, 12, 11, 1) > +#define ICH_MISR_EL2 sys_reg(3, 4, 12, 11, 2) > +#define ICH_EISR_EL2 sys_reg(3, 4, 12, 11, 3) > +#define ICH_ELSR_EL2 sys_reg(3, 4, 12, 11, 5) > +#define ICH_VMCR_EL2 sys_reg(3, 4, 12, 11, 7) > + > +#define __LR0_EL2(x) sys_reg(3, 4, 12, 12, x) > +#define __LR8_EL2(x) sys_reg(3, 4, 12, 13, x) > + > +#define ICH_LR0_EL2 __LR0_EL2(0) > +#define ICH_LR1_EL2 __LR0_EL2(1) > +#define ICH_LR2_EL2 __LR0_EL2(2) > +#define ICH_LR3_EL2 __LR0_EL2(3) > +#define ICH_LR4_EL2 __LR0_EL2(4) > +#define ICH_LR5_EL2 __LR0_EL2(5) > +#define ICH_LR6_EL2 __LR0_EL2(6) > +#define ICH_LR7_EL2 __LR0_EL2(7) > +#define ICH_LR8_EL2 __LR8_EL2(0) > +#define ICH_LR9_EL2 __LR8_EL2(1) > +#define ICH_LR10_EL2 __LR8_EL2(2) > +#define ICH_LR11_EL2 __LR8_EL2(3) > +#define ICH_LR12_EL2 __LR8_EL2(4) > +#define ICH_LR13_EL2 __LR8_EL2(5) > +#define ICH_LR14_EL2 __LR8_EL2(6) > +#define ICH_LR15_EL2 __LR8_EL2(7) > + > +#define __AP0Rx_EL2(x) sys_reg(3, 4, 12, 8, x) > +#define ICH_AP0R0_EL2 __AP0Rx_EL2(0) > +#define ICH_AP0R1_EL2 __AP0Rx_EL2(1) > +#define ICH_AP0R2_EL2 __AP0Rx_EL2(2) > +#define ICH_AP0R3_EL2 __AP0Rx_EL2(3) > + > +#define __AP1Rx_EL2(x) sys_reg(3, 4, 12, 9, x) > +#define ICH_AP1R0_EL2 __AP1Rx_EL2(0) > +#define ICH_AP1R1_EL2 __AP1Rx_EL2(1) > +#define ICH_AP1R2_EL2 __AP1Rx_EL2(2) > +#define ICH_AP1R3_EL2 __AP1Rx_EL2(3) > + > +#ifndef __ASSEMBLY__ > + > +#include <libcflat.h> > +#include <asm/barrier.h> > + > +#define __stringify xstr > + > +/* > + * Low-level accessors > + * > + * These system registers are 32 bits, but we make sure that the compiler > + * sets the GP register's most significant bits to 0 with an explicit cast. > + */ > + > +static inline void gicv3_write_eoir(u32 irq) > +{ > + asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); > + isb(); > +} > + > +static inline void gicv3_write_dir(u32 irq) > +{ > + asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); > + isb(); > +} > + > +static inline u64 gicv3_read_iar_common(void) > +{ > + u64 irqstat; > + > + asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); > + dsb(sy); > + return irqstat; > +} > + > +static inline u32 gicv3_read_iar(void) > +{ > + return (u64)gicv3_read_iar_common(); > +} > + > +/* > + * Cavium ThunderX erratum 23154 > + * > + * The gicv3 of ThunderX requires a modified version for reading the > + * IAR status to ensure data synchronization (access to icc_iar1_el1 > + * is not sync'ed before and after). > + */ > +static inline u64 gicv3_read_iar_cavium_thunderx(void) > +{ > + u64 irqstat; > + > + asm volatile( > + "nop;nop;nop;nop\n\t" > + "nop;nop;nop;nop\n\t" > + "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" > + "nop;nop;nop;nop" > + : "=r" (irqstat)); > + mb(); > + > + return irqstat; > +} > + > +static inline void gicv3_write_pmr(u32 val) > +{ > + asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); > +} > + > +static inline void gicv3_write_ctlr(u32 val) > +{ > + asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" ((u64)val)); > + isb(); > +} > + > +static inline void gicv3_write_grpen1(u32 val) > +{ > + asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); > + isb(); > +} > + > +static inline void gicv3_write_sgi1r(u64 val) > +{ > + asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); > +} > + > +static inline u32 gicv3_read_sre(void) > +{ > + u64 val; > + > + asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); > + return val; > +} > + > +static inline void gicv3_write_sre(u32 val) > +{ > + asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); > + isb(); > +} > + > +#define gicv3_read_typer(c) readq(c) > +#define gicv3_write_irouter(v, c) writeq(v, c) > + > +#endif /* __ASSEMBLY__ */ > +#endif /* _ASMARM64_ARCH_GICV3_H_ */ > diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h > new file mode 100644 > index 0000000000000..8ee5d4d9c1819 > --- /dev/null > +++ b/lib/arm64/asm/gic-v3.h > @@ -0,0 +1 @@ > +#include "../../arm/asm/gic-v3.h" > diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h > new file mode 100644 > index 0000000000000..544a46cb8cc59 > --- /dev/null > +++ b/lib/arm64/asm/sysreg.h > @@ -0,0 +1,44 @@ > +/* > + * Ripped off from arch/arm64/include/asm/sysreg.h > + * > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM64_SYSREG_H_ > +#define _ASMARM64_SYSREG_H_ > + > +#define sys_reg(op0, op1, crn, crm, op2) \ > + ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) > + > +#ifdef __ASSEMBLY__ > + .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 > + .equ .L__reg_num_x\num, \num > + .endr > + .equ .L__reg_num_xzr, 31 > + > + .macro mrs_s, rt, sreg > + .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt) > + .endm > + > + .macro msr_s, sreg, rt > + .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt) > + .endm > +#else > +asm( > +" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" > +" .equ .L__reg_num_x\\num, \\num\n" > +" .endr\n" > +" .equ .L__reg_num_xzr, 31\n" > +"\n" > +" .macro mrs_s, rt, sreg\n" > +" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" > +" .endm\n" > +"\n" > +" .macro msr_s, sreg, rt\n" > +" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" > +" .endm\n" > +); > +#endif > + > +#endif /* _ASMARM64_SYSREG_H_ */ >
On Thu, Sep 01, 2016 at 12:19:52PM +0200, Auger Eric wrote: > Hi Drew, > > On 15/07/2016 15:00, Andrew Jones wrote: > > Signed-off-by: Andrew Jones <drjones@redhat.com> > > > > --- > > v2: configure irqs as NS GRP1 > > --- > > lib/arm/asm/arch_gicv3.h | 184 ++++++++++++++++++++++++++ > > lib/arm/asm/gic-v3.h | 321 +++++++++++++++++++++++++++++++++++++++++++++ > > lib/arm/asm/gic.h | 1 + > > lib/arm/gic.c | 73 +++++++++++ > > lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++++++ > > lib/arm64/asm/gic-v3.h | 1 + > > lib/arm64/asm/sysreg.h | 44 +++++++ > > 7 files changed, 793 insertions(+) > > create mode 100644 lib/arm/asm/arch_gicv3.h > > create mode 100644 lib/arm/asm/gic-v3.h > > create mode 100644 lib/arm64/asm/arch_gicv3.h > > create mode 100644 lib/arm64/asm/gic-v3.h > > create mode 100644 lib/arm64/asm/sysreg.h > > > > diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h > > new file mode 100644 > > index 0000000000000..d529a7eb62807 > > --- /dev/null > > +++ b/lib/arm/asm/arch_gicv3.h > > @@ -0,0 +1,184 @@ > > +/* > > + * All ripped off from arch/arm/include/asm/arch_gicv3.h > > + * > > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#ifndef _ASMARM_ARCH_GICV3_H_ > > +#define _ASMARM_ARCH_GICV3_H_ > > + > > +#ifndef __ASSEMBLY__ > > + > > +#include <libcflat.h> > > +#include <asm/barrier.h> > > +#include <asm/io.h> > > + > > +#define __stringify xstr > > + > > + > > +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 > > +#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm > > + > > +#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) > > +#define ICC_DIR __ACCESS_CP15(c12, 0, c11, 1) > > +#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) > > +#define ICC_SGI1R __ACCESS_CP15_64(0, c12) > > +#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) > > +#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) > > +#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) > > +#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) > > + > > +#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) > > + > > +#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) > > +#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0) > > +#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1) > > +#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2) > > +#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3) > > +#define ICH_ELSR __ACCESS_CP15(c12, 4, c11, 5) > > +#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7) > > + > > +#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x) > > +#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x) > > + > > +#define ICH_LR0 __LR0(0) > > +#define ICH_LR1 __LR0(1) > > +#define ICH_LR2 __LR0(2) > > +#define ICH_LR3 __LR0(3) > > +#define ICH_LR4 __LR0(4) > > +#define ICH_LR5 __LR0(5) > > +#define ICH_LR6 __LR0(6) > > +#define ICH_LR7 __LR0(7) > > +#define ICH_LR8 __LR8(0) > > +#define ICH_LR9 __LR8(1) > > +#define ICH_LR10 __LR8(2) > > +#define ICH_LR11 __LR8(3) > > +#define ICH_LR12 __LR8(4) > > +#define ICH_LR13 __LR8(5) > > +#define ICH_LR14 __LR8(6) > > +#define ICH_LR15 __LR8(7) > > + > > +/* LR top half */ > > +#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x) > > +#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x) > > + > > +#define ICH_LRC0 __LRC0(0) > > +#define ICH_LRC1 __LRC0(1) > > +#define ICH_LRC2 __LRC0(2) > > +#define ICH_LRC3 __LRC0(3) > > +#define ICH_LRC4 __LRC0(4) > > +#define ICH_LRC5 __LRC0(5) > > +#define ICH_LRC6 __LRC0(6) > > +#define ICH_LRC7 __LRC0(7) > > +#define ICH_LRC8 __LRC8(0) > > +#define ICH_LRC9 __LRC8(1) > > +#define ICH_LRC10 __LRC8(2) > > +#define ICH_LRC11 __LRC8(3) > > +#define ICH_LRC12 __LRC8(4) > > +#define ICH_LRC13 __LRC8(5) > > +#define ICH_LRC14 __LRC8(6) > > +#define ICH_LRC15 __LRC8(7) > > + > > +#define __AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x) > > +#define ICH_AP0R0 __AP0Rx(0) > > +#define ICH_AP0R1 __AP0Rx(1) > > +#define ICH_AP0R2 __AP0Rx(2) > > +#define ICH_AP0R3 __AP0Rx(3) > > + > > +#define __AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x) > > +#define ICH_AP1R0 __AP1Rx(0) > > +#define ICH_AP1R1 __AP1Rx(1) > > +#define ICH_AP1R2 __AP1Rx(2) > > +#define ICH_AP1R3 __AP1Rx(3) > > + > > +/* Low-level accessors */ > > + > > +static inline void gicv3_write_eoir(u32 irq) > > +{ > > + asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (irq)); > > + isb(); > > +} > > + > > +static inline void gicv3_write_dir(u32 val) > > +{ > > + asm volatile("mcr " __stringify(ICC_DIR) : : "r" (val)); > > + isb(); > > +} > > + > > +static inline u32 gicv3_read_iar(void) > > +{ > > + u32 irqstat; > > + > > + asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat)); > > + dsb(sy); > > + return irqstat; > > +} > > + > > +static inline void gicv3_write_pmr(u32 val) > > +{ > > + asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val)); > > +} > > + > > +static inline void gicv3_write_ctlr(u32 val) > > +{ > > + asm volatile("mcr " __stringify(ICC_CTLR) : : "r" (val)); > > + isb(); > > +} > > + > > +static inline void gicv3_write_grpen1(u32 val) > > +{ > > + asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val)); > > + isb(); > > +} > > + > > +static inline void gicv3_write_sgi1r(u64 val) > > +{ > > + asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val)); > > +} > > + > > +static inline u32 gicv3_read_sre(void) > > +{ > > + u32 val; > > + > > + asm volatile("mrc " __stringify(ICC_SRE) : "=r" (val)); > > + return val; > > +} > > + > > +static inline void gicv3_write_sre(u32 val) > > +{ > > + asm volatile("mcr " __stringify(ICC_SRE) : : "r" (val)); > > + isb(); > > +} > > + > > +/* > > + * Even in 32bit systems that use LPAE, there is no guarantee that the I/O > > + * interface provides true 64bit atomic accesses, so using strd/ldrd doesn't > > + * make much sense. > > + * Moreover, 64bit I/O emulation is extremely difficult to implement on > > + * AArch32, since the syndrome register doesn't provide any information for > > + * them. > > + * Consequently, the following IO helpers use 32bit accesses. > > + * > > + * There are only two registers that need 64bit accesses in this driver: > > + * - GICD_IROUTERn, contain the affinity values associated to each interrupt. > > + * The upper-word (aff3) will always be 0, so there is no need for a lock. > > + * - GICR_TYPER is an ID register and doesn't need atomicity. > > + */ > > +static inline void gicv3_write_irouter(u64 val, volatile void __iomem *addr) > > +{ > > + writel((u32)val, addr); > > + writel((u32)(val >> 32), addr + 4); > > +} > > + > > +static inline u64 gicv3_read_typer(const volatile void __iomem *addr) > > +{ > > + u64 val; > > + > > + val = readl(addr); > > + val |= (u64)readl(addr + 4) << 32; > > + return val; > > +} > > + > > +#endif /* !__ASSEMBLY__ */ > > +#endif /* _ASMARM_ARCH_GICV3_H_ */ > > diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h > > new file mode 100644 > > index 0000000000000..8831389e2a00d > > --- /dev/null > > +++ b/lib/arm/asm/gic-v3.h > > @@ -0,0 +1,321 @@ > > +/* > > + * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h > There are quite a lot of differences between linux version and this > version. May be worth resync'ing. Yup > > + * > > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#ifndef _ASMARM_GIC_V3_H_ > > +#define _ASMARM_GIC_V3_H_ > > + > > +/* > > + * Distributor registers. We assume we're running non-secure, with ARE > > + * being set. Secure-only and non-ARE registers are not described. > > + */ > > +#define GICD_CTLR 0x0000 > > +#define GICD_TYPER 0x0004 > > +#define GICD_IIDR 0x0008 > > +#define GICD_STATUSR 0x0010 > > +#define GICD_SETSPI_NSR 0x0040 > > +#define GICD_CLRSPI_NSR 0x0048 > > +#define GICD_SETSPI_SR 0x0050 > > +#define GICD_CLRSPI_SR 0x0058 > > +#define GICD_SEIR 0x0068 > > +#define GICD_IGROUPR 0x0080 > > +#define GICD_ISENABLER 0x0100 > > +#define GICD_ICENABLER 0x0180 > > +#define GICD_ISPENDR 0x0200 > > +#define GICD_ICPENDR 0x0280 > > +#define GICD_ISACTIVER 0x0300 > > +#define GICD_ICACTIVER 0x0380 > > +#define GICD_IPRIORITYR 0x0400 > > +#define GICD_ICFGR 0x0C00 > > +#define GICD_IGRPMODR 0x0D00 > > +#define GICD_NSACR 0x0E00 > > +#define GICD_IROUTER 0x6000 > > +#define GICD_IDREGS 0xFFD0 > > +#define GICD_PIDR2 0xFFE8 > > + > > +/* > > + * Those registers are actually from GICv2, but the spec demands that they > > + * are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3). > > + */ > > +#define GICD_ITARGETSR 0x0800 > > +#define GICD_SGIR 0x0F00 > > +#define GICD_CPENDSGIR 0x0F10 > > +#define GICD_SPENDSGIR 0x0F20 > > + > > +#define GICD_CTLR_RWP (1U << 31) > > +#define GICD_CTLR_DS (1U << 6) > > +#define GICD_CTLR_ARE_NS (1U << 4) > > +#define GICD_CTLR_ENABLE_G1A (1U << 1) > > +#define GICD_CTLR_ENABLE_G1 (1U << 0) > > + > > +/* > > + * In systems with a single security state (what we emulate in KVM) > > + * the meaning of the interrupt group enable bits is slightly different > > + */ > > +#define GICD_CTLR_ENABLE_SS_G1 (1U << 1) > > +#define GICD_CTLR_ENABLE_SS_G0 (1U << 0) > > + > > +#define GICD_TYPER_LPIS (1U << 17) > > +#define GICD_TYPER_MBIS (1U << 16) > > + > > +#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) > > +#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) > > +#define GICD_TYPER_LPIS (1U << 17) > > + > > +#define GICD_IROUTER_SPI_MODE_ONE (0U << 31) > > +#define GICD_IROUTER_SPI_MODE_ANY (1U << 31) > > + > > +#define GIC_PIDR2_ARCH_MASK 0xf0 > > +#define GIC_PIDR2_ARCH_GICv3 0x30 > > +#define GIC_PIDR2_ARCH_GICv4 0x40 > > + > > +#define GIC_V3_DIST_SIZE 0x10000 > > + > > +/* > > + * Re-Distributor registers, offsets from RD_base > > + */ > > +#define GICR_CTLR GICD_CTLR > > +#define GICR_IIDR 0x0004 > > +#define GICR_TYPER 0x0008 > > +#define GICR_STATUSR GICD_STATUSR > > +#define GICR_WAKER 0x0014 > > +#define GICR_SETLPIR 0x0040 > > +#define GICR_CLRLPIR 0x0048 > > +#define GICR_SEIR GICD_SEIR > > +#define GICR_PROPBASER 0x0070 > > +#define GICR_PENDBASER 0x0078 > > +#define GICR_INVLPIR 0x00A0 > > +#define GICR_INVALLR 0x00B0 > > +#define GICR_SYNCR 0x00C0 > > +#define GICR_MOVLPIR 0x0100 > > +#define GICR_MOVALLR 0x0110 > > +#define GICR_ISACTIVER GICD_ISACTIVER > > +#define GICR_ICACTIVER GICD_ICACTIVER > > +#define GICR_IDREGS GICD_IDREGS > > +#define GICR_PIDR2 GICD_PIDR2 > > + > > +#define GICR_CTLR_ENABLE_LPIS (1UL << 0) > > + > > +#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) > > + > > +#define GICR_WAKER_ProcessorSleep (1U << 1) > > +#define GICR_WAKER_ChildrenAsleep (1U << 2) > > + > > +#define GICR_PROPBASER_NonShareable (0U << 10) > > +#define GICR_PROPBASER_InnerShareable (1U << 10) > > +#define GICR_PROPBASER_OuterShareable (2U << 10) > > +#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10) > > +#define GICR_PROPBASER_nCnB (0U << 7) > > +#define GICR_PROPBASER_nC (1U << 7) > > +#define GICR_PROPBASER_RaWt (2U << 7) > > +#define GICR_PROPBASER_RaWb (3U << 7) > > +#define GICR_PROPBASER_WaWt (4U << 7) > > +#define GICR_PROPBASER_WaWb (5U << 7) > > +#define GICR_PROPBASER_RaWaWt (6U << 7) > > +#define GICR_PROPBASER_RaWaWb (7U << 7) > > +#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) > > +#define GICR_PROPBASER_IDBITS_MASK (0x1f) > > + > > +#define GICR_PENDBASER_NonShareable (0U << 10) > > +#define GICR_PENDBASER_InnerShareable (1U << 10) > > +#define GICR_PENDBASER_OuterShareable (2U << 10) > > +#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10) > > +#define GICR_PENDBASER_nCnB (0U << 7) > > +#define GICR_PENDBASER_nC (1U << 7) > > +#define GICR_PENDBASER_RaWt (2U << 7) > > +#define GICR_PENDBASER_RaWb (3U << 7) > > +#define GICR_PENDBASER_WaWt (4U << 7) > > +#define GICR_PENDBASER_WaWb (5U << 7) > > +#define GICR_PENDBASER_RaWaWt (6U << 7) > > +#define GICR_PENDBASER_RaWaWb (7U << 7) > > +#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) > > + > > +/* > > + * Re-Distributor registers, offsets from SGI_base > > + */ > > +#define GICR_IGROUPR0 GICD_IGROUPR > > +#define GICR_ISENABLER0 GICD_ISENABLER > > +#define GICR_ICENABLER0 GICD_ICENABLER > > +#define GICR_ISPENDR0 GICD_ISPENDR > > +#define GICR_ICPENDR0 GICD_ICPENDR > > +#define GICR_ISACTIVER0 GICD_ISACTIVER > > +#define GICR_ICACTIVER0 GICD_ICACTIVER > > +#define GICR_IPRIORITYR0 GICD_IPRIORITYR > > +#define GICR_ICFGR0 GICD_ICFGR > > +#define GICR_IGRPMODR0 GICD_IGRPMODR > > +#define GICR_NSACR GICD_NSACR > > + > > +#define GICR_TYPER_PLPIS (1U << 0) > > +#define GICR_TYPER_VLPIS (1U << 1) > > +#define GICR_TYPER_LAST (1U << 4) > > + > > +#define GIC_V3_REDIST_SIZE 0x20000 > > + > > +#define LPI_PROP_GROUP1 (1 << 1) > > +#define LPI_PROP_ENABLED (1 << 0) > > + > > +/* > > + * ITS registers, offsets from ITS_base > > + */ > > +#define GITS_CTLR 0x0000 > > +#define GITS_IIDR 0x0004 > > +#define GITS_TYPER 0x0008 > > +#define GITS_CBASER 0x0080 > > +#define GITS_CWRITER 0x0088 > > +#define GITS_CREADR 0x0090 > > +#define GITS_BASER 0x0100 > > +#define GITS_PIDR2 GICR_PIDR2 > > + > > +#define GITS_TRANSLATER 0x10040 > > + > > +#define GITS_CTLR_ENABLE (1U << 0) > > +#define GITS_CTLR_QUIESCENT (1U << 31) > > + > > +#define GITS_TYPER_DEVBITS_SHIFT 13 > > +#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) > > +#define GITS_TYPER_PTA (1UL << 19) > > + > > +#define GITS_CBASER_VALID (1UL << 63) > > +#define GITS_CBASER_nCnB (0UL << 59) > > +#define GITS_CBASER_nC (1UL << 59) > > +#define GITS_CBASER_RaWt (2UL << 59) > > +#define GITS_CBASER_RaWb (3UL << 59) > > +#define GITS_CBASER_WaWt (4UL << 59) > > +#define GITS_CBASER_WaWb (5UL << 59) > > +#define GITS_CBASER_RaWaWt (6UL << 59) > > +#define GITS_CBASER_RaWaWb (7UL << 59) > > +#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59) > > +#define GITS_CBASER_NonShareable (0UL << 10) > > +#define GITS_CBASER_InnerShareable (1UL << 10) > > +#define GITS_CBASER_OuterShareable (2UL << 10) > > +#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10) > > + > > +#define GITS_BASER_NR_REGS 8 > > + > > +#define GITS_BASER_VALID (1UL << 63) > > +#define GITS_BASER_nCnB (0UL << 59) > > +#define GITS_BASER_nC (1UL << 59) > > +#define GITS_BASER_RaWt (2UL << 59) > > +#define GITS_BASER_RaWb (3UL << 59) > > +#define GITS_BASER_WaWt (4UL << 59) > > +#define GITS_BASER_WaWb (5UL << 59) > > +#define GITS_BASER_RaWaWt (6UL << 59) > > +#define GITS_BASER_RaWaWb (7UL << 59) > > +#define GITS_BASER_CACHEABILITY_MASK (7UL << 59) > > +#define GITS_BASER_TYPE_SHIFT (56) > > +#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) > > +#define GITS_BASER_ENTRY_SIZE_SHIFT (48) > > +#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1) > > +#define GITS_BASER_NonShareable (0UL << 10) > > +#define GITS_BASER_InnerShareable (1UL << 10) > > +#define GITS_BASER_OuterShareable (2UL << 10) > > +#define GITS_BASER_SHAREABILITY_SHIFT (10) > > +#define GITS_BASER_SHAREABILITY_MASK (3UL << GITS_BASER_SHAREABILITY_SHIFT) > > +#define GITS_BASER_PAGE_SIZE_SHIFT (8) > > +#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT) > > +#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT) > > +#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) > > +#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) > > +#define GITS_BASER_PAGES_MAX 256 > > + > > +#define GITS_BASER_TYPE_NONE 0 > > +#define GITS_BASER_TYPE_DEVICE 1 > > +#define GITS_BASER_TYPE_VCPU 2 > > +#define GITS_BASER_TYPE_CPU 3 > > +#define GITS_BASER_TYPE_COLLECTION 4 > > +#define GITS_BASER_TYPE_RESERVED5 5 > > +#define GITS_BASER_TYPE_RESERVED6 6 > > +#define GITS_BASER_TYPE_RESERVED7 7 > > + > > +/* > > + * ITS commands > > + */ > > +#define GITS_CMD_MAPD 0x08 > > +#define GITS_CMD_MAPC 0x09 > > +#define GITS_CMD_MAPVI 0x0a > > +#define GITS_CMD_MOVI 0x01 > > +#define GITS_CMD_DISCARD 0x0f > > +#define GITS_CMD_INV 0x0c > > +#define GITS_CMD_MOVALL 0x0e > > +#define GITS_CMD_INVALL 0x0d > > +#define GITS_CMD_INT 0x03 > > +#define GITS_CMD_CLEAR 0x04 > > +#define GITS_CMD_SYNC 0x05 > > + > > +/* > > + * CPU interface registers > > + */ > > +#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1) > > +#define ICC_CTLR_EL1_EOImode_drop (1U << 1) > > +#define ICC_SRE_EL1_SRE (1U << 0) > > + > > +#include <asm/arch_gicv3.h> > I would personally move this in gic.c But then unit tests would need to explicitly include it, which breaks the goal for non-gic-specific tests to still use a gic for something, but be gic-agnostic. And even tests that do care which gic they're using would have to include this and other headers. Adding it here makes things more convenient. > > + > > +#define SZ_64K 0x10000 > > + > > +#ifndef __ASSEMBLY__ > > +#include <libcflat.h> > > +#include <asm/processor.h> > > +#include <asm/setup.h> > > +#include <asm/smp.h> > > +#include <asm/io.h> > > + > > +struct gicv3_data { > > + void *dist_base; > > + void *redist_base[NR_CPUS]; > > + unsigned int irq_nr; > > +}; > > +extern struct gicv3_data gicv3_data; > > + > > +#define gicv3_dist_base() (gicv3_data.dist_base) > > +#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()]) > > +#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K) > > + > > +extern int gicv3_init(void); > > +extern void gicv3_enable_defaults(void); > > + > > +static inline void gicv3_do_wait_for_rwp(void *base) > > +{ > > + int count = 100000; /* 1s */ > > + > > + while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) { > > + if (!--count) { > > + printf("GICv3: RWP timeout!\n"); > > + abort(); > > + } > > + cpu_relax(); > > + udelay(10); > > + }; > > +} > > + > > +static inline void gicv3_dist_wait_for_rwp(void) > > +{ > > + gicv3_do_wait_for_rwp(gicv3_dist_base()); > > +} > > + > > +static inline void gicv3_redist_wait_for_rwp(void) > > +{ > > + gicv3_do_wait_for_rwp(gicv3_redist_base()); > > +} > > + > > +static inline u32 mpidr_compress(u64 mpidr) > > +{ > > + u64 compressed = mpidr & MPIDR_HWID_BITMASK; > > + > > + compressed = (((compressed >> 32) & 0xff) << 24) | compressed; > > + return compressed; > > +} > > + > > +static inline u64 mpidr_uncompress(u32 compressed) > > +{ > > + u64 mpidr = ((u64)compressed >> 24) << 32; > > + > > + mpidr |= compressed & MPIDR_HWID_BITMASK; > > + return mpidr; > > +} > > + > > +#endif /* !__ASSEMBLY__ */ > > +#endif /* _ASMARM_GIC_V3_H_ */ > > diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h > > index b1237d1c5ef22..849d17cb36a4e 100644 > > --- a/lib/arm/asm/gic.h > > +++ b/lib/arm/asm/gic.h > > @@ -7,6 +7,7 @@ > > #define _ASMARM_GIC_H_ > > > > #include <asm/gic-v2.h> > > +#include <asm/gic-v3.h> > > > > /* > > * gic_init will try to find all known gics, and then > > diff --git a/lib/arm/gic.c b/lib/arm/gic.c > > index 64a3049c9e8ce..bb62407f7286e 100644 > > --- a/lib/arm/gic.c > > +++ b/lib/arm/gic.c > > @@ -10,9 +10,11 @@ > > #include <asm/io.h> > > > > struct gicv2_data gicv2_data; > > +struct gicv3_data gicv3_data; > > > > /* > > * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt > > + * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt > > */ > > static bool > > gic_get_dt_bases(const char *compatible, void **base1, void **base2) > > @@ -50,10 +52,18 @@ int gicv2_init(void) > > &gicv2_data.dist_base, &gicv2_data.cpu_base); > > } > > > > +int gicv3_init(void) > > +{ > > + return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, > > + &gicv3_data.redist_base[0]); > > +} > > + > > int gic_init(void) > > { > > if (gicv2_init()) > > return 2; > > + else if (gicv3_init()) > > + return 3; > > return 0; > > } > > > > @@ -67,3 +77,66 @@ void gicv2_enable_defaults(void) > > writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK); > > writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL); > > } > > + > > +void gicv3_set_redist_base(void) > > +{ > > + u32 aff = mpidr_compress(get_mpidr()); > > + void *ptr = gicv3_data.redist_base[0]; > > + u64 typer; > > + > > + do { > > + typer = gicv3_read_typer(ptr + GICR_TYPER); > > + if ((typer >> 32) == aff) { > > + gicv3_redist_base() = ptr; > > + return; > > + } > > + ptr += SZ_64K * 2; /* skip RD_base and SGI_base */ > > + } while (!(typer & GICR_TYPER_LAST)); > > + assert(0); > > +} > > + > > +void gicv3_enable_defaults(void) > > +{ > > + void *dist = gicv3_dist_base(); > > + void *sgi_base; > > + unsigned int i; > > + > > + if (smp_processor_id() == 0) { > > + u32 typer = readl(dist + GICD_TYPER); > > + > > + gicv3_data.irq_nr = GICD_TYPER_IRQS(typer); > > + if (gicv3_data.irq_nr > 1020) { > > + printf("GICD_TYPER_IRQS reported %d! " > > + "Clamping to max=1020.\n", 1020); > > + gicv3_data.irq_nr = 1020; > > + } > > + > > + writel(0, dist + GICD_CTLR); > > + gicv3_dist_wait_for_rwp(); > > + > > + for (i = 32; i < gicv3_data.irq_nr; i += 32) > > + writel(~0, dist + GICD_IGROUPR + i / 8); > > + > > + writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, > > + dist + GICD_CTLR); > > + gicv3_dist_wait_for_rwp(); > > + } > shouldn't we follow the same init as in kernel and maybe also the same > structure: > gic_dist_init(); > gic_cpu_init(); > gic_cpu_pm_init(); > I am really scared by forgetting settings and debugging this minimal > driver. That being said, that's a very tedious task. I used gic_dist_init and gic_cpu_init as inspiration, but wanted to minimize the default enable as much as possible for simplicity. If a unit test cares about PM, then it should write it's own enable that includes PM in its setup. These enables are just provided by the framework for a convenience to unit tests that don't care. Any unit test that does care should write their enable from scratch. The only function they should use from lib/arm/gic.c is gic_init(), which does nothing but set base addresses and tell you what gic you have. Of course defines and helper functions are provided in headers too, so the unit tests don't have to reproduce/duplicate them. > > > > + > > + if (!gicv3_redist_base()) > > + gicv3_set_redist_base(); > > + sgi_base = gicv3_sgi_base(); > > + > > + writel(~0, sgi_base + GICR_IGROUPR0); > > + > > + writel(GICD_INT_EN_CLR_X32, sgi_base + GIC_DIST_ACTIVE_CLEAR); > > + writel(GICD_INT_EN_CLR_PPI, sgi_base + GIC_DIST_ENABLE_CLEAR); > > + writel(GICD_INT_EN_SET_SGI, sgi_base + GIC_DIST_ENABLE_SET); > > + > > + for (i = 0; i < 32; i += 4) > > + writel(GICD_INT_DEF_PRI_X4, sgi_base + GIC_DIST_PRI + i); > > + gicv3_redist_wait_for_rwp(); > > + > > + gicv3_write_pmr(0xf0); > > + gicv3_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir);I think by default we use EOI mode 1 (ICC_CTLR_EL1_EOImode_drop). > To be consistent I thing EOIModeNS = 1 should also be set on GICv2 side. OK Thanks, drew > > Thanks > > Eric > > > + gicv3_write_grpen1(1); > > +} > > diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h > > new file mode 100644 > > index 0000000000000..eff2efdfe2d4d > > --- /dev/null > > +++ b/lib/arm64/asm/arch_gicv3.h > > @@ -0,0 +1,169 @@ > > +/* > > + * All ripped off from arch/arm64/include/asm/arch_gicv3.h > > + * > > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#ifndef _ASMARM64_ARCH_GICV3_H_ > > +#define _ASMARM64_ARCH_GICV3_H_ > > + > > +#include <asm/sysreg.h> > > + > > +#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) > > +#define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1) > > +#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) > > +#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) > > +#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) > > +#define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4) > > +#define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5) > > +#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) > > + > > +#define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5) > > + > > +/* > > + * System register definitions > > + */ > > +#define ICH_VSEIR_EL2 sys_reg(3, 4, 12, 9, 4) > > +#define ICH_HCR_EL2 sys_reg(3, 4, 12, 11, 0) > > +#define ICH_VTR_EL2 sys_reg(3, 4, 12, 11, 1) > > +#define ICH_MISR_EL2 sys_reg(3, 4, 12, 11, 2) > > +#define ICH_EISR_EL2 sys_reg(3, 4, 12, 11, 3) > > +#define ICH_ELSR_EL2 sys_reg(3, 4, 12, 11, 5) > > +#define ICH_VMCR_EL2 sys_reg(3, 4, 12, 11, 7) > > + > > +#define __LR0_EL2(x) sys_reg(3, 4, 12, 12, x) > > +#define __LR8_EL2(x) sys_reg(3, 4, 12, 13, x) > > + > > +#define ICH_LR0_EL2 __LR0_EL2(0) > > +#define ICH_LR1_EL2 __LR0_EL2(1) > > +#define ICH_LR2_EL2 __LR0_EL2(2) > > +#define ICH_LR3_EL2 __LR0_EL2(3) > > +#define ICH_LR4_EL2 __LR0_EL2(4) > > +#define ICH_LR5_EL2 __LR0_EL2(5) > > +#define ICH_LR6_EL2 __LR0_EL2(6) > > +#define ICH_LR7_EL2 __LR0_EL2(7) > > +#define ICH_LR8_EL2 __LR8_EL2(0) > > +#define ICH_LR9_EL2 __LR8_EL2(1) > > +#define ICH_LR10_EL2 __LR8_EL2(2) > > +#define ICH_LR11_EL2 __LR8_EL2(3) > > +#define ICH_LR12_EL2 __LR8_EL2(4) > > +#define ICH_LR13_EL2 __LR8_EL2(5) > > +#define ICH_LR14_EL2 __LR8_EL2(6) > > +#define ICH_LR15_EL2 __LR8_EL2(7) > > + > > +#define __AP0Rx_EL2(x) sys_reg(3, 4, 12, 8, x) > > +#define ICH_AP0R0_EL2 __AP0Rx_EL2(0) > > +#define ICH_AP0R1_EL2 __AP0Rx_EL2(1) > > +#define ICH_AP0R2_EL2 __AP0Rx_EL2(2) > > +#define ICH_AP0R3_EL2 __AP0Rx_EL2(3) > > + > > +#define __AP1Rx_EL2(x) sys_reg(3, 4, 12, 9, x) > > +#define ICH_AP1R0_EL2 __AP1Rx_EL2(0) > > +#define ICH_AP1R1_EL2 __AP1Rx_EL2(1) > > +#define ICH_AP1R2_EL2 __AP1Rx_EL2(2) > > +#define ICH_AP1R3_EL2 __AP1Rx_EL2(3) > > + > > +#ifndef __ASSEMBLY__ > > + > > +#include <libcflat.h> > > +#include <asm/barrier.h> > > + > > +#define __stringify xstr > > + > > +/* > > + * Low-level accessors > > + * > > + * These system registers are 32 bits, but we make sure that the compiler > > + * sets the GP register's most significant bits to 0 with an explicit cast. > > + */ > > + > > +static inline void gicv3_write_eoir(u32 irq) > > +{ > > + asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); > > + isb(); > > +} > > + > > +static inline void gicv3_write_dir(u32 irq) > > +{ > > + asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); > > + isb(); > > +} > > + > > +static inline u64 gicv3_read_iar_common(void) > > +{ > > + u64 irqstat; > > + > > + asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); > > + dsb(sy); > > + return irqstat; > > +} > > + > > +static inline u32 gicv3_read_iar(void) > > +{ > > + return (u64)gicv3_read_iar_common(); > > +} > > + > > +/* > > + * Cavium ThunderX erratum 23154 > > + * > > + * The gicv3 of ThunderX requires a modified version for reading the > > + * IAR status to ensure data synchronization (access to icc_iar1_el1 > > + * is not sync'ed before and after). > > + */ > > +static inline u64 gicv3_read_iar_cavium_thunderx(void) > > +{ > > + u64 irqstat; > > + > > + asm volatile( > > + "nop;nop;nop;nop\n\t" > > + "nop;nop;nop;nop\n\t" > > + "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" > > + "nop;nop;nop;nop" > > + : "=r" (irqstat)); > > + mb(); > > + > > + return irqstat; > > +} > > + > > +static inline void gicv3_write_pmr(u32 val) > > +{ > > + asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); > > +} > > + > > +static inline void gicv3_write_ctlr(u32 val) > > +{ > > + asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" ((u64)val)); > > + isb(); > > +} > > + > > +static inline void gicv3_write_grpen1(u32 val) > > +{ > > + asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); > > + isb(); > > +} > > + > > +static inline void gicv3_write_sgi1r(u64 val) > > +{ > > + asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); > > +} > > + > > +static inline u32 gicv3_read_sre(void) > > +{ > > + u64 val; > > + > > + asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); > > + return val; > > +} > > + > > +static inline void gicv3_write_sre(u32 val) > > +{ > > + asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); > > + isb(); > > +} > > + > > +#define gicv3_read_typer(c) readq(c) > > +#define gicv3_write_irouter(v, c) writeq(v, c) > > + > > +#endif /* __ASSEMBLY__ */ > > +#endif /* _ASMARM64_ARCH_GICV3_H_ */ > > diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h > > new file mode 100644 > > index 0000000000000..8ee5d4d9c1819 > > --- /dev/null > > +++ b/lib/arm64/asm/gic-v3.h > > @@ -0,0 +1 @@ > > +#include "../../arm/asm/gic-v3.h" > > diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h > > new file mode 100644 > > index 0000000000000..544a46cb8cc59 > > --- /dev/null > > +++ b/lib/arm64/asm/sysreg.h > > @@ -0,0 +1,44 @@ > > +/* > > + * Ripped off from arch/arm64/include/asm/sysreg.h > > + * > > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#ifndef _ASMARM64_SYSREG_H_ > > +#define _ASMARM64_SYSREG_H_ > > + > > +#define sys_reg(op0, op1, crn, crm, op2) \ > > + ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) > > + > > +#ifdef __ASSEMBLY__ > > + .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 > > + .equ .L__reg_num_x\num, \num > > + .endr > > + .equ .L__reg_num_xzr, 31 > > + > > + .macro mrs_s, rt, sreg > > + .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt) > > + .endm > > + > > + .macro msr_s, sreg, rt > > + .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt) > > + .endm > > +#else > > +asm( > > +" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" > > +" .equ .L__reg_num_x\\num, \\num\n" > > +" .endr\n" > > +" .equ .L__reg_num_xzr, 31\n" > > +"\n" > > +" .macro mrs_s, rt, sreg\n" > > +" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" > > +" .endm\n" > > +"\n" > > +" .macro msr_s, sreg, rt\n" > > +" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" > > +" .endm\n" > > +); > > +#endif > > + > > +#endif /* _ASMARM64_SYSREG_H_ */ > > >
Hi Drew, On 15/07/16 14:00, Andrew Jones wrote: > Signed-off-by: Andrew Jones <drjones@redhat.com> > > --- > v2: configure irqs as NS GRP1 > --- > lib/arm/asm/arch_gicv3.h | 184 ++++++++++++++++++++++++++ > lib/arm/asm/gic-v3.h | 321 +++++++++++++++++++++++++++++++++++++++++++++ > lib/arm/asm/gic.h | 1 + > lib/arm/gic.c | 73 +++++++++++ > lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++++++ > lib/arm64/asm/gic-v3.h | 1 + > lib/arm64/asm/sysreg.h | 44 +++++++ > 7 files changed, 793 insertions(+) > create mode 100644 lib/arm/asm/arch_gicv3.h > create mode 100644 lib/arm/asm/gic-v3.h > create mode 100644 lib/arm64/asm/arch_gicv3.h > create mode 100644 lib/arm64/asm/gic-v3.h > create mode 100644 lib/arm64/asm/sysreg.h > > diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h > new file mode 100644 > index 0000000000000..d529a7eb62807 > --- /dev/null > +++ b/lib/arm/asm/arch_gicv3.h > @@ -0,0 +1,184 @@ > +/* > + * All ripped off from arch/arm/include/asm/arch_gicv3.h So I was wondering if - from a test suite's perspective - it's really clever to pull in copies of Linux headers here. First it's really a lot of text we pull in while not using most of it (at least now). Also they keep changing (4.9-rc1 saw so me changes, for instance). So do we update them? But more importantly those headers are also used in the emulation code, so we would just copy any bugs or typos and would probably not detect them here. IIRC there was a fix for a bitmask lately. It's probably fine to copy the register offsets, but anything that defines Linux specific things like default priorities or more complex macros should be avoided, I think. This just makes kvm-unit-test copying Linux behaviour. Maybe we stick to the Linux naming, but pull in only the fields as we need them? This would both limit the amount of lines being merged, as would simplify the review effort (and quality), as people would just need to look at a very limited number of defines, allowing them to actually check it against the specification? I gave this a try and could reduce the header files significantly. Please let me know if you need any bits from this effort to be shared. > + * > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > + * > + * This work is licensed under the terms of the GNU LGPL, version 2. > + */ > +#ifndef _ASMARM_ARCH_GICV3_H_ > +#define _ASMARM_ARCH_GICV3_H_ > + > +#ifndef __ASSEMBLY__ > + > +#include <libcflat.h> > +#include <asm/barrier.h> > +#include <asm/io.h> > + > +#define __stringify xstr > + > + > +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 > +#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm > + > +#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) > +#define ICC_DIR __ACCESS_CP15(c12, 0, c11, 1) > +#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) > +#define ICC_SGI1R __ACCESS_CP15_64(0, c12) > +#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) > +#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) > +#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) > +#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) > + > +#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) > + > +#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) > +#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0) > +#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1) > +#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2) > +#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3) > +#define ICH_ELSR __ACCESS_CP15(c12, 4, c11, 5) > +#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7) > + > +#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x) > +#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x) So for instance we clearly don't need those defines (the list registers being hypervisor only). > + > +#define ICH_LR0 __LR0(0) > +#define ICH_LR1 __LR0(1) > +#define ICH_LR2 __LR0(2) > +#define ICH_LR3 __LR0(3) > +#define ICH_LR4 __LR0(4) > +#define ICH_LR5 __LR0(5) > +#define ICH_LR6 __LR0(6) > +#define ICH_LR7 __LR0(7) > +#define ICH_LR8 __LR8(0) > +#define ICH_LR9 __LR8(1) > +#define ICH_LR10 __LR8(2) > +#define ICH_LR11 __LR8(3) > +#define ICH_LR12 __LR8(4) > +#define ICH_LR13 __LR8(5) > +#define ICH_LR14 __LR8(6) > +#define ICH_LR15 __LR8(7) > + > +/* LR top half */ > +#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x) > +#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x) > + > +#define ICH_LRC0 __LRC0(0) > +#define ICH_LRC1 __LRC0(1) > +#define ICH_LRC2 __LRC0(2) > +#define ICH_LRC3 __LRC0(3) > +#define ICH_LRC4 __LRC0(4) > +#define ICH_LRC5 __LRC0(5) > +#define ICH_LRC6 __LRC0(6) > +#define ICH_LRC7 __LRC0(7) > +#define ICH_LRC8 __LRC8(0) > +#define ICH_LRC9 __LRC8(1) > +#define ICH_LRC10 __LRC8(2) > +#define ICH_LRC11 __LRC8(3) > +#define ICH_LRC12 __LRC8(4) > +#define ICH_LRC13 __LRC8(5) > +#define ICH_LRC14 __LRC8(6) > +#define ICH_LRC15 __LRC8(7) .... > + > +/* > + * Cavium ThunderX erratum 23154 > + * > + * The gicv3 of ThunderX requires a modified version for reading the > + * IAR status to ensure data synchronization (access to icc_iar1_el1 > + * is not sync'ed before and after). > + */ > +static inline u64 gicv3_read_iar_cavium_thunderx(void) Are we looking at including those errata workarounds? I think this may be needed if we want to run tests on those machines, but may open up a can of worms.... Cheers, Andre. > +{ > + u64 irqstat; > + > + asm volatile( > + "nop;nop;nop;nop\n\t" > + "nop;nop;nop;nop\n\t" > + "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" > + "nop;nop;nop;nop" > + : "=r" (irqstat)); > + mb(); > + > + return irqstat; > +} > +
Hi Andre, On Thu, Oct 20, 2016 at 06:29:01PM +0100, Andre Przywara wrote: > Hi Drew, > > On 15/07/16 14:00, Andrew Jones wrote: > > Signed-off-by: Andrew Jones <drjones@redhat.com> > > > > --- > > v2: configure irqs as NS GRP1 > > --- > > lib/arm/asm/arch_gicv3.h | 184 ++++++++++++++++++++++++++ > > lib/arm/asm/gic-v3.h | 321 +++++++++++++++++++++++++++++++++++++++++++++ > > lib/arm/asm/gic.h | 1 + > > lib/arm/gic.c | 73 +++++++++++ > > lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++++++ > > lib/arm64/asm/gic-v3.h | 1 + > > lib/arm64/asm/sysreg.h | 44 +++++++ > > 7 files changed, 793 insertions(+) > > create mode 100644 lib/arm/asm/arch_gicv3.h > > create mode 100644 lib/arm/asm/gic-v3.h > > create mode 100644 lib/arm64/asm/arch_gicv3.h > > create mode 100644 lib/arm64/asm/gic-v3.h > > create mode 100644 lib/arm64/asm/sysreg.h > > > > diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h > > new file mode 100644 > > index 0000000000000..d529a7eb62807 > > --- /dev/null > > +++ b/lib/arm/asm/arch_gicv3.h > > @@ -0,0 +1,184 @@ > > +/* > > + * All ripped off from arch/arm/include/asm/arch_gicv3.h > > So I was wondering if - from a test suite's perspective - it's really > clever to pull in copies of Linux headers here. > First it's really a lot of text we pull in while not using most of it > (at least now). Also they keep changing (4.9-rc1 saw so me changes, for > instance). So do we update them? The thought was we'd synchronize occasionally as needed. If somebody adds new gic tests that require new defines, then they'd just synch everything. I agree it's less than ideal to try and maintain duplicate copies of stuff though. > > But more importantly those headers are also used in the emulation code, > so we would just copy any bugs or typos and would probably not detect > them here. IIRC there was a fix for a bitmask lately. This is certainly a bigger concern. Duplicating blindly would indeed just copy bugs. OTOH, I found a couple of bitmask bugs in the kernel precisely because I was reviewing them while duplicating. I think I agree with you though that we should be extra cautious with macros, and even have the spec open to confirm register offsets aren't wrong while copying. > It's probably fine to copy the register offsets, but anything that > defines Linux specific things like default priorities or more complex > macros should be avoided, I think. This just makes kvm-unit-test copying > Linux behaviour. I agree the Linux defaults should not be the only inputs kvm-unit-tests uses. That was never the plan. In this series I've introduced gicv[23]_enable_defaults, which do indeed mimic Linux (but with much simplification). They serve two purposes, 1) I can confirm the framework works as least as well as Linux in order to provide a solid base for new tests and 2) unit tests that need a gic, but don't plan to test it specifically, and thus don't care much about how it's enabled, can use these enable functions just to get a functioning one. However, gic unit test writers (like you :-) should only use gic_init(), which does nothing other than probe DT for the base addresses. > > Maybe we stick to the Linux naming, but pull in only the fields as we > need them? This would both limit the amount of lines being merged, as > would simplify the review effort (and quality), as people would just > need to look at a very limited number of defines, allowing them to > actually check it against the specification? It's a similar idea to what we were going to do - synchronizing as we go, but instead of seeding the file with everything Linux has today we only seed it with what we use today. If, however, somebody writes the test Christoffer and you both proposed independently, which is to write all registers and then read them all back to make sure they have the expected values after considering their behaviors, then we'll be importing nearly all register defines at once anyway. That said, we haven't written that test yet, so I can live with this initial series only taking what it needs. > > I gave this a try and could reduce the header files significantly. > Please let me know if you need any bits from this effort to be shared. Yes please. I'll take your advise on this and post with minimal defines for now. Do you have patches that apply to my branch? If so, I'll integrate them for the v4 posting. > > > + * > > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> > > + * > > + * This work is licensed under the terms of the GNU LGPL, version 2. > > + */ > > +#ifndef _ASMARM_ARCH_GICV3_H_ > > +#define _ASMARM_ARCH_GICV3_H_ > > + > > +#ifndef __ASSEMBLY__ > > + > > +#include <libcflat.h> > > +#include <asm/barrier.h> > > +#include <asm/io.h> > > + > > +#define __stringify xstr > > + > > + > > +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 > > +#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm > > + > > +#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) > > +#define ICC_DIR __ACCESS_CP15(c12, 0, c11, 1) > > +#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) > > +#define ICC_SGI1R __ACCESS_CP15_64(0, c12) > > +#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) > > +#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) > > +#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) > > +#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) > > + > > +#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) > > + > > +#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) > > +#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0) > > +#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1) > > +#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2) > > +#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3) > > +#define ICH_ELSR __ACCESS_CP15(c12, 4, c11, 5) > > +#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7) > > + > > +#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x) > > +#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x) > > So for instance we clearly don't need those defines (the list registers > being hypervisor only). > > > + > > +#define ICH_LR0 __LR0(0) > > +#define ICH_LR1 __LR0(1) > > +#define ICH_LR2 __LR0(2) > > +#define ICH_LR3 __LR0(3) > > +#define ICH_LR4 __LR0(4) > > +#define ICH_LR5 __LR0(5) > > +#define ICH_LR6 __LR0(6) > > +#define ICH_LR7 __LR0(7) > > +#define ICH_LR8 __LR8(0) > > +#define ICH_LR9 __LR8(1) > > +#define ICH_LR10 __LR8(2) > > +#define ICH_LR11 __LR8(3) > > +#define ICH_LR12 __LR8(4) > > +#define ICH_LR13 __LR8(5) > > +#define ICH_LR14 __LR8(6) > > +#define ICH_LR15 __LR8(7) > > + > > +/* LR top half */ > > +#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x) > > +#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x) > > + > > +#define ICH_LRC0 __LRC0(0) > > +#define ICH_LRC1 __LRC0(1) > > +#define ICH_LRC2 __LRC0(2) > > +#define ICH_LRC3 __LRC0(3) > > +#define ICH_LRC4 __LRC0(4) > > +#define ICH_LRC5 __LRC0(5) > > +#define ICH_LRC6 __LRC0(6) > > +#define ICH_LRC7 __LRC0(7) > > +#define ICH_LRC8 __LRC8(0) > > +#define ICH_LRC9 __LRC8(1) > > +#define ICH_LRC10 __LRC8(2) > > +#define ICH_LRC11 __LRC8(3) > > +#define ICH_LRC12 __LRC8(4) > > +#define ICH_LRC13 __LRC8(5) > > +#define ICH_LRC14 __LRC8(6) > > +#define ICH_LRC15 __LRC8(7) > > .... > > + > > +/* > > + * Cavium ThunderX erratum 23154 > > + * > > + * The gicv3 of ThunderX requires a modified version for reading the > > + * IAR status to ensure data synchronization (access to icc_iar1_el1 > > + * is not sync'ed before and after). > > + */ > > +static inline u64 gicv3_read_iar_cavium_thunderx(void) > > Are we looking at including those errata workarounds? > I think this may be needed if we want to run tests on those machines, > but may open up a can of worms.... We can drop these erratas for now, and then add them as necessary. I wouldn't want kvm-unit-tests to discriminate hardware though. Thanks for looking at this! drew
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h new file mode 100644 index 0000000000000..d529a7eb62807 --- /dev/null +++ b/lib/arm/asm/arch_gicv3.h @@ -0,0 +1,184 @@ +/* + * All ripped off from arch/arm/include/asm/arch_gicv3.h + * + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#ifndef _ASMARM_ARCH_GICV3_H_ +#define _ASMARM_ARCH_GICV3_H_ + +#ifndef __ASSEMBLY__ + +#include <libcflat.h> +#include <asm/barrier.h> +#include <asm/io.h> + +#define __stringify xstr + + +#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2 +#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm + +#define ICC_EOIR1 __ACCESS_CP15(c12, 0, c12, 1) +#define ICC_DIR __ACCESS_CP15(c12, 0, c11, 1) +#define ICC_IAR1 __ACCESS_CP15(c12, 0, c12, 0) +#define ICC_SGI1R __ACCESS_CP15_64(0, c12) +#define ICC_PMR __ACCESS_CP15(c4, 0, c6, 0) +#define ICC_CTLR __ACCESS_CP15(c12, 0, c12, 4) +#define ICC_SRE __ACCESS_CP15(c12, 0, c12, 5) +#define ICC_IGRPEN1 __ACCESS_CP15(c12, 0, c12, 7) + +#define ICC_HSRE __ACCESS_CP15(c12, 4, c9, 5) + +#define ICH_VSEIR __ACCESS_CP15(c12, 4, c9, 4) +#define ICH_HCR __ACCESS_CP15(c12, 4, c11, 0) +#define ICH_VTR __ACCESS_CP15(c12, 4, c11, 1) +#define ICH_MISR __ACCESS_CP15(c12, 4, c11, 2) +#define ICH_EISR __ACCESS_CP15(c12, 4, c11, 3) +#define ICH_ELSR __ACCESS_CP15(c12, 4, c11, 5) +#define ICH_VMCR __ACCESS_CP15(c12, 4, c11, 7) + +#define __LR0(x) __ACCESS_CP15(c12, 4, c12, x) +#define __LR8(x) __ACCESS_CP15(c12, 4, c13, x) + +#define ICH_LR0 __LR0(0) +#define ICH_LR1 __LR0(1) +#define ICH_LR2 __LR0(2) +#define ICH_LR3 __LR0(3) +#define ICH_LR4 __LR0(4) +#define ICH_LR5 __LR0(5) +#define ICH_LR6 __LR0(6) +#define ICH_LR7 __LR0(7) +#define ICH_LR8 __LR8(0) +#define ICH_LR9 __LR8(1) +#define ICH_LR10 __LR8(2) +#define ICH_LR11 __LR8(3) +#define ICH_LR12 __LR8(4) +#define ICH_LR13 __LR8(5) +#define ICH_LR14 __LR8(6) +#define ICH_LR15 __LR8(7) + +/* LR top half */ +#define __LRC0(x) __ACCESS_CP15(c12, 4, c14, x) +#define __LRC8(x) __ACCESS_CP15(c12, 4, c15, x) + +#define ICH_LRC0 __LRC0(0) +#define ICH_LRC1 __LRC0(1) +#define ICH_LRC2 __LRC0(2) +#define ICH_LRC3 __LRC0(3) +#define ICH_LRC4 __LRC0(4) +#define ICH_LRC5 __LRC0(5) +#define ICH_LRC6 __LRC0(6) +#define ICH_LRC7 __LRC0(7) +#define ICH_LRC8 __LRC8(0) +#define ICH_LRC9 __LRC8(1) +#define ICH_LRC10 __LRC8(2) +#define ICH_LRC11 __LRC8(3) +#define ICH_LRC12 __LRC8(4) +#define ICH_LRC13 __LRC8(5) +#define ICH_LRC14 __LRC8(6) +#define ICH_LRC15 __LRC8(7) + +#define __AP0Rx(x) __ACCESS_CP15(c12, 4, c8, x) +#define ICH_AP0R0 __AP0Rx(0) +#define ICH_AP0R1 __AP0Rx(1) +#define ICH_AP0R2 __AP0Rx(2) +#define ICH_AP0R3 __AP0Rx(3) + +#define __AP1Rx(x) __ACCESS_CP15(c12, 4, c9, x) +#define ICH_AP1R0 __AP1Rx(0) +#define ICH_AP1R1 __AP1Rx(1) +#define ICH_AP1R2 __AP1Rx(2) +#define ICH_AP1R3 __AP1Rx(3) + +/* Low-level accessors */ + +static inline void gicv3_write_eoir(u32 irq) +{ + asm volatile("mcr " __stringify(ICC_EOIR1) : : "r" (irq)); + isb(); +} + +static inline void gicv3_write_dir(u32 val) +{ + asm volatile("mcr " __stringify(ICC_DIR) : : "r" (val)); + isb(); +} + +static inline u32 gicv3_read_iar(void) +{ + u32 irqstat; + + asm volatile("mrc " __stringify(ICC_IAR1) : "=r" (irqstat)); + dsb(sy); + return irqstat; +} + +static inline void gicv3_write_pmr(u32 val) +{ + asm volatile("mcr " __stringify(ICC_PMR) : : "r" (val)); +} + +static inline void gicv3_write_ctlr(u32 val) +{ + asm volatile("mcr " __stringify(ICC_CTLR) : : "r" (val)); + isb(); +} + +static inline void gicv3_write_grpen1(u32 val) +{ + asm volatile("mcr " __stringify(ICC_IGRPEN1) : : "r" (val)); + isb(); +} + +static inline void gicv3_write_sgi1r(u64 val) +{ + asm volatile("mcrr " __stringify(ICC_SGI1R) : : "r" (val)); +} + +static inline u32 gicv3_read_sre(void) +{ + u32 val; + + asm volatile("mrc " __stringify(ICC_SRE) : "=r" (val)); + return val; +} + +static inline void gicv3_write_sre(u32 val) +{ + asm volatile("mcr " __stringify(ICC_SRE) : : "r" (val)); + isb(); +} + +/* + * Even in 32bit systems that use LPAE, there is no guarantee that the I/O + * interface provides true 64bit atomic accesses, so using strd/ldrd doesn't + * make much sense. + * Moreover, 64bit I/O emulation is extremely difficult to implement on + * AArch32, since the syndrome register doesn't provide any information for + * them. + * Consequently, the following IO helpers use 32bit accesses. + * + * There are only two registers that need 64bit accesses in this driver: + * - GICD_IROUTERn, contain the affinity values associated to each interrupt. + * The upper-word (aff3) will always be 0, so there is no need for a lock. + * - GICR_TYPER is an ID register and doesn't need atomicity. + */ +static inline void gicv3_write_irouter(u64 val, volatile void __iomem *addr) +{ + writel((u32)val, addr); + writel((u32)(val >> 32), addr + 4); +} + +static inline u64 gicv3_read_typer(const volatile void __iomem *addr) +{ + u64 val; + + val = readl(addr); + val |= (u64)readl(addr + 4) << 32; + return val; +} + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASMARM_ARCH_GICV3_H_ */ diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h new file mode 100644 index 0000000000000..8831389e2a00d --- /dev/null +++ b/lib/arm/asm/gic-v3.h @@ -0,0 +1,321 @@ +/* + * All GIC* defines are lifted from include/linux/irqchip/arm-gic-v3.h + * + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#ifndef _ASMARM_GIC_V3_H_ +#define _ASMARM_GIC_V3_H_ + +/* + * Distributor registers. We assume we're running non-secure, with ARE + * being set. Secure-only and non-ARE registers are not described. + */ +#define GICD_CTLR 0x0000 +#define GICD_TYPER 0x0004 +#define GICD_IIDR 0x0008 +#define GICD_STATUSR 0x0010 +#define GICD_SETSPI_NSR 0x0040 +#define GICD_CLRSPI_NSR 0x0048 +#define GICD_SETSPI_SR 0x0050 +#define GICD_CLRSPI_SR 0x0058 +#define GICD_SEIR 0x0068 +#define GICD_IGROUPR 0x0080 +#define GICD_ISENABLER 0x0100 +#define GICD_ICENABLER 0x0180 +#define GICD_ISPENDR 0x0200 +#define GICD_ICPENDR 0x0280 +#define GICD_ISACTIVER 0x0300 +#define GICD_ICACTIVER 0x0380 +#define GICD_IPRIORITYR 0x0400 +#define GICD_ICFGR 0x0C00 +#define GICD_IGRPMODR 0x0D00 +#define GICD_NSACR 0x0E00 +#define GICD_IROUTER 0x6000 +#define GICD_IDREGS 0xFFD0 +#define GICD_PIDR2 0xFFE8 + +/* + * Those registers are actually from GICv2, but the spec demands that they + * are implemented as RES0 if ARE is 1 (which we do in KVM's emulated GICv3). + */ +#define GICD_ITARGETSR 0x0800 +#define GICD_SGIR 0x0F00 +#define GICD_CPENDSGIR 0x0F10 +#define GICD_SPENDSGIR 0x0F20 + +#define GICD_CTLR_RWP (1U << 31) +#define GICD_CTLR_DS (1U << 6) +#define GICD_CTLR_ARE_NS (1U << 4) +#define GICD_CTLR_ENABLE_G1A (1U << 1) +#define GICD_CTLR_ENABLE_G1 (1U << 0) + +/* + * In systems with a single security state (what we emulate in KVM) + * the meaning of the interrupt group enable bits is slightly different + */ +#define GICD_CTLR_ENABLE_SS_G1 (1U << 1) +#define GICD_CTLR_ENABLE_SS_G0 (1U << 0) + +#define GICD_TYPER_LPIS (1U << 17) +#define GICD_TYPER_MBIS (1U << 16) + +#define GICD_TYPER_ID_BITS(typer) ((((typer) >> 19) & 0x1f) + 1) +#define GICD_TYPER_IRQS(typer) ((((typer) & 0x1f) + 1) * 32) +#define GICD_TYPER_LPIS (1U << 17) + +#define GICD_IROUTER_SPI_MODE_ONE (0U << 31) +#define GICD_IROUTER_SPI_MODE_ANY (1U << 31) + +#define GIC_PIDR2_ARCH_MASK 0xf0 +#define GIC_PIDR2_ARCH_GICv3 0x30 +#define GIC_PIDR2_ARCH_GICv4 0x40 + +#define GIC_V3_DIST_SIZE 0x10000 + +/* + * Re-Distributor registers, offsets from RD_base + */ +#define GICR_CTLR GICD_CTLR +#define GICR_IIDR 0x0004 +#define GICR_TYPER 0x0008 +#define GICR_STATUSR GICD_STATUSR +#define GICR_WAKER 0x0014 +#define GICR_SETLPIR 0x0040 +#define GICR_CLRLPIR 0x0048 +#define GICR_SEIR GICD_SEIR +#define GICR_PROPBASER 0x0070 +#define GICR_PENDBASER 0x0078 +#define GICR_INVLPIR 0x00A0 +#define GICR_INVALLR 0x00B0 +#define GICR_SYNCR 0x00C0 +#define GICR_MOVLPIR 0x0100 +#define GICR_MOVALLR 0x0110 +#define GICR_ISACTIVER GICD_ISACTIVER +#define GICR_ICACTIVER GICD_ICACTIVER +#define GICR_IDREGS GICD_IDREGS +#define GICR_PIDR2 GICD_PIDR2 + +#define GICR_CTLR_ENABLE_LPIS (1UL << 0) + +#define GICR_TYPER_CPU_NUMBER(r) (((r) >> 8) & 0xffff) + +#define GICR_WAKER_ProcessorSleep (1U << 1) +#define GICR_WAKER_ChildrenAsleep (1U << 2) + +#define GICR_PROPBASER_NonShareable (0U << 10) +#define GICR_PROPBASER_InnerShareable (1U << 10) +#define GICR_PROPBASER_OuterShareable (2U << 10) +#define GICR_PROPBASER_SHAREABILITY_MASK (3UL << 10) +#define GICR_PROPBASER_nCnB (0U << 7) +#define GICR_PROPBASER_nC (1U << 7) +#define GICR_PROPBASER_RaWt (2U << 7) +#define GICR_PROPBASER_RaWb (3U << 7) +#define GICR_PROPBASER_WaWt (4U << 7) +#define GICR_PROPBASER_WaWb (5U << 7) +#define GICR_PROPBASER_RaWaWt (6U << 7) +#define GICR_PROPBASER_RaWaWb (7U << 7) +#define GICR_PROPBASER_CACHEABILITY_MASK (7U << 7) +#define GICR_PROPBASER_IDBITS_MASK (0x1f) + +#define GICR_PENDBASER_NonShareable (0U << 10) +#define GICR_PENDBASER_InnerShareable (1U << 10) +#define GICR_PENDBASER_OuterShareable (2U << 10) +#define GICR_PENDBASER_SHAREABILITY_MASK (3UL << 10) +#define GICR_PENDBASER_nCnB (0U << 7) +#define GICR_PENDBASER_nC (1U << 7) +#define GICR_PENDBASER_RaWt (2U << 7) +#define GICR_PENDBASER_RaWb (3U << 7) +#define GICR_PENDBASER_WaWt (4U << 7) +#define GICR_PENDBASER_WaWb (5U << 7) +#define GICR_PENDBASER_RaWaWt (6U << 7) +#define GICR_PENDBASER_RaWaWb (7U << 7) +#define GICR_PENDBASER_CACHEABILITY_MASK (7U << 7) + +/* + * Re-Distributor registers, offsets from SGI_base + */ +#define GICR_IGROUPR0 GICD_IGROUPR +#define GICR_ISENABLER0 GICD_ISENABLER +#define GICR_ICENABLER0 GICD_ICENABLER +#define GICR_ISPENDR0 GICD_ISPENDR +#define GICR_ICPENDR0 GICD_ICPENDR +#define GICR_ISACTIVER0 GICD_ISACTIVER +#define GICR_ICACTIVER0 GICD_ICACTIVER +#define GICR_IPRIORITYR0 GICD_IPRIORITYR +#define GICR_ICFGR0 GICD_ICFGR +#define GICR_IGRPMODR0 GICD_IGRPMODR +#define GICR_NSACR GICD_NSACR + +#define GICR_TYPER_PLPIS (1U << 0) +#define GICR_TYPER_VLPIS (1U << 1) +#define GICR_TYPER_LAST (1U << 4) + +#define GIC_V3_REDIST_SIZE 0x20000 + +#define LPI_PROP_GROUP1 (1 << 1) +#define LPI_PROP_ENABLED (1 << 0) + +/* + * ITS registers, offsets from ITS_base + */ +#define GITS_CTLR 0x0000 +#define GITS_IIDR 0x0004 +#define GITS_TYPER 0x0008 +#define GITS_CBASER 0x0080 +#define GITS_CWRITER 0x0088 +#define GITS_CREADR 0x0090 +#define GITS_BASER 0x0100 +#define GITS_PIDR2 GICR_PIDR2 + +#define GITS_TRANSLATER 0x10040 + +#define GITS_CTLR_ENABLE (1U << 0) +#define GITS_CTLR_QUIESCENT (1U << 31) + +#define GITS_TYPER_DEVBITS_SHIFT 13 +#define GITS_TYPER_DEVBITS(r) ((((r) >> GITS_TYPER_DEVBITS_SHIFT) & 0x1f) + 1) +#define GITS_TYPER_PTA (1UL << 19) + +#define GITS_CBASER_VALID (1UL << 63) +#define GITS_CBASER_nCnB (0UL << 59) +#define GITS_CBASER_nC (1UL << 59) +#define GITS_CBASER_RaWt (2UL << 59) +#define GITS_CBASER_RaWb (3UL << 59) +#define GITS_CBASER_WaWt (4UL << 59) +#define GITS_CBASER_WaWb (5UL << 59) +#define GITS_CBASER_RaWaWt (6UL << 59) +#define GITS_CBASER_RaWaWb (7UL << 59) +#define GITS_CBASER_CACHEABILITY_MASK (7UL << 59) +#define GITS_CBASER_NonShareable (0UL << 10) +#define GITS_CBASER_InnerShareable (1UL << 10) +#define GITS_CBASER_OuterShareable (2UL << 10) +#define GITS_CBASER_SHAREABILITY_MASK (3UL << 10) + +#define GITS_BASER_NR_REGS 8 + +#define GITS_BASER_VALID (1UL << 63) +#define GITS_BASER_nCnB (0UL << 59) +#define GITS_BASER_nC (1UL << 59) +#define GITS_BASER_RaWt (2UL << 59) +#define GITS_BASER_RaWb (3UL << 59) +#define GITS_BASER_WaWt (4UL << 59) +#define GITS_BASER_WaWb (5UL << 59) +#define GITS_BASER_RaWaWt (6UL << 59) +#define GITS_BASER_RaWaWb (7UL << 59) +#define GITS_BASER_CACHEABILITY_MASK (7UL << 59) +#define GITS_BASER_TYPE_SHIFT (56) +#define GITS_BASER_TYPE(r) (((r) >> GITS_BASER_TYPE_SHIFT) & 7) +#define GITS_BASER_ENTRY_SIZE_SHIFT (48) +#define GITS_BASER_ENTRY_SIZE(r) ((((r) >> GITS_BASER_ENTRY_SIZE_SHIFT) & 0xff) + 1) +#define GITS_BASER_NonShareable (0UL << 10) +#define GITS_BASER_InnerShareable (1UL << 10) +#define GITS_BASER_OuterShareable (2UL << 10) +#define GITS_BASER_SHAREABILITY_SHIFT (10) +#define GITS_BASER_SHAREABILITY_MASK (3UL << GITS_BASER_SHAREABILITY_SHIFT) +#define GITS_BASER_PAGE_SIZE_SHIFT (8) +#define GITS_BASER_PAGE_SIZE_4K (0UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_16K (1UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_64K (2UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGE_SIZE_MASK (3UL << GITS_BASER_PAGE_SIZE_SHIFT) +#define GITS_BASER_PAGES_MAX 256 + +#define GITS_BASER_TYPE_NONE 0 +#define GITS_BASER_TYPE_DEVICE 1 +#define GITS_BASER_TYPE_VCPU 2 +#define GITS_BASER_TYPE_CPU 3 +#define GITS_BASER_TYPE_COLLECTION 4 +#define GITS_BASER_TYPE_RESERVED5 5 +#define GITS_BASER_TYPE_RESERVED6 6 +#define GITS_BASER_TYPE_RESERVED7 7 + +/* + * ITS commands + */ +#define GITS_CMD_MAPD 0x08 +#define GITS_CMD_MAPC 0x09 +#define GITS_CMD_MAPVI 0x0a +#define GITS_CMD_MOVI 0x01 +#define GITS_CMD_DISCARD 0x0f +#define GITS_CMD_INV 0x0c +#define GITS_CMD_MOVALL 0x0e +#define GITS_CMD_INVALL 0x0d +#define GITS_CMD_INT 0x03 +#define GITS_CMD_CLEAR 0x04 +#define GITS_CMD_SYNC 0x05 + +/* + * CPU interface registers + */ +#define ICC_CTLR_EL1_EOImode_drop_dir (0U << 1) +#define ICC_CTLR_EL1_EOImode_drop (1U << 1) +#define ICC_SRE_EL1_SRE (1U << 0) + +#include <asm/arch_gicv3.h> + +#define SZ_64K 0x10000 + +#ifndef __ASSEMBLY__ +#include <libcflat.h> +#include <asm/processor.h> +#include <asm/setup.h> +#include <asm/smp.h> +#include <asm/io.h> + +struct gicv3_data { + void *dist_base; + void *redist_base[NR_CPUS]; + unsigned int irq_nr; +}; +extern struct gicv3_data gicv3_data; + +#define gicv3_dist_base() (gicv3_data.dist_base) +#define gicv3_redist_base() (gicv3_data.redist_base[smp_processor_id()]) +#define gicv3_sgi_base() (gicv3_data.redist_base[smp_processor_id()] + SZ_64K) + +extern int gicv3_init(void); +extern void gicv3_enable_defaults(void); + +static inline void gicv3_do_wait_for_rwp(void *base) +{ + int count = 100000; /* 1s */ + + while (readl(base + GICD_CTLR) & GICD_CTLR_RWP) { + if (!--count) { + printf("GICv3: RWP timeout!\n"); + abort(); + } + cpu_relax(); + udelay(10); + }; +} + +static inline void gicv3_dist_wait_for_rwp(void) +{ + gicv3_do_wait_for_rwp(gicv3_dist_base()); +} + +static inline void gicv3_redist_wait_for_rwp(void) +{ + gicv3_do_wait_for_rwp(gicv3_redist_base()); +} + +static inline u32 mpidr_compress(u64 mpidr) +{ + u64 compressed = mpidr & MPIDR_HWID_BITMASK; + + compressed = (((compressed >> 32) & 0xff) << 24) | compressed; + return compressed; +} + +static inline u64 mpidr_uncompress(u32 compressed) +{ + u64 mpidr = ((u64)compressed >> 24) << 32; + + mpidr |= compressed & MPIDR_HWID_BITMASK; + return mpidr; +} + +#endif /* !__ASSEMBLY__ */ +#endif /* _ASMARM_GIC_V3_H_ */ diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h index b1237d1c5ef22..849d17cb36a4e 100644 --- a/lib/arm/asm/gic.h +++ b/lib/arm/asm/gic.h @@ -7,6 +7,7 @@ #define _ASMARM_GIC_H_ #include <asm/gic-v2.h> +#include <asm/gic-v3.h> /* * gic_init will try to find all known gics, and then diff --git a/lib/arm/gic.c b/lib/arm/gic.c index 64a3049c9e8ce..bb62407f7286e 100644 --- a/lib/arm/gic.c +++ b/lib/arm/gic.c @@ -10,9 +10,11 @@ #include <asm/io.h> struct gicv2_data gicv2_data; +struct gicv3_data gicv3_data; /* * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt + * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt */ static bool gic_get_dt_bases(const char *compatible, void **base1, void **base2) @@ -50,10 +52,18 @@ int gicv2_init(void) &gicv2_data.dist_base, &gicv2_data.cpu_base); } +int gicv3_init(void) +{ + return gic_get_dt_bases("arm,gic-v3", &gicv3_data.dist_base, + &gicv3_data.redist_base[0]); +} + int gic_init(void) { if (gicv2_init()) return 2; + else if (gicv3_init()) + return 3; return 0; } @@ -67,3 +77,66 @@ void gicv2_enable_defaults(void) writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK); writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL); } + +void gicv3_set_redist_base(void) +{ + u32 aff = mpidr_compress(get_mpidr()); + void *ptr = gicv3_data.redist_base[0]; + u64 typer; + + do { + typer = gicv3_read_typer(ptr + GICR_TYPER); + if ((typer >> 32) == aff) { + gicv3_redist_base() = ptr; + return; + } + ptr += SZ_64K * 2; /* skip RD_base and SGI_base */ + } while (!(typer & GICR_TYPER_LAST)); + assert(0); +} + +void gicv3_enable_defaults(void) +{ + void *dist = gicv3_dist_base(); + void *sgi_base; + unsigned int i; + + if (smp_processor_id() == 0) { + u32 typer = readl(dist + GICD_TYPER); + + gicv3_data.irq_nr = GICD_TYPER_IRQS(typer); + if (gicv3_data.irq_nr > 1020) { + printf("GICD_TYPER_IRQS reported %d! " + "Clamping to max=1020.\n", 1020); + gicv3_data.irq_nr = 1020; + } + + writel(0, dist + GICD_CTLR); + gicv3_dist_wait_for_rwp(); + + for (i = 32; i < gicv3_data.irq_nr; i += 32) + writel(~0, dist + GICD_IGROUPR + i / 8); + + writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1, + dist + GICD_CTLR); + gicv3_dist_wait_for_rwp(); + } + + if (!gicv3_redist_base()) + gicv3_set_redist_base(); + sgi_base = gicv3_sgi_base(); + + writel(~0, sgi_base + GICR_IGROUPR0); + + writel(GICD_INT_EN_CLR_X32, sgi_base + GIC_DIST_ACTIVE_CLEAR); + writel(GICD_INT_EN_CLR_PPI, sgi_base + GIC_DIST_ENABLE_CLEAR); + writel(GICD_INT_EN_SET_SGI, sgi_base + GIC_DIST_ENABLE_SET); + + for (i = 0; i < 32; i += 4) + writel(GICD_INT_DEF_PRI_X4, sgi_base + GIC_DIST_PRI + i); + gicv3_redist_wait_for_rwp(); + + gicv3_write_pmr(0xf0); + gicv3_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); + gicv3_write_grpen1(1); +} diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h new file mode 100644 index 0000000000000..eff2efdfe2d4d --- /dev/null +++ b/lib/arm64/asm/arch_gicv3.h @@ -0,0 +1,169 @@ +/* + * All ripped off from arch/arm64/include/asm/arch_gicv3.h + * + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#ifndef _ASMARM64_ARCH_GICV3_H_ +#define _ASMARM64_ARCH_GICV3_H_ + +#include <asm/sysreg.h> + +#define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) +#define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1) +#define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) +#define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) +#define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) +#define ICC_CTLR_EL1 sys_reg(3, 0, 12, 12, 4) +#define ICC_SRE_EL1 sys_reg(3, 0, 12, 12, 5) +#define ICC_GRPEN1_EL1 sys_reg(3, 0, 12, 12, 7) + +#define ICC_SRE_EL2 sys_reg(3, 4, 12, 9, 5) + +/* + * System register definitions + */ +#define ICH_VSEIR_EL2 sys_reg(3, 4, 12, 9, 4) +#define ICH_HCR_EL2 sys_reg(3, 4, 12, 11, 0) +#define ICH_VTR_EL2 sys_reg(3, 4, 12, 11, 1) +#define ICH_MISR_EL2 sys_reg(3, 4, 12, 11, 2) +#define ICH_EISR_EL2 sys_reg(3, 4, 12, 11, 3) +#define ICH_ELSR_EL2 sys_reg(3, 4, 12, 11, 5) +#define ICH_VMCR_EL2 sys_reg(3, 4, 12, 11, 7) + +#define __LR0_EL2(x) sys_reg(3, 4, 12, 12, x) +#define __LR8_EL2(x) sys_reg(3, 4, 12, 13, x) + +#define ICH_LR0_EL2 __LR0_EL2(0) +#define ICH_LR1_EL2 __LR0_EL2(1) +#define ICH_LR2_EL2 __LR0_EL2(2) +#define ICH_LR3_EL2 __LR0_EL2(3) +#define ICH_LR4_EL2 __LR0_EL2(4) +#define ICH_LR5_EL2 __LR0_EL2(5) +#define ICH_LR6_EL2 __LR0_EL2(6) +#define ICH_LR7_EL2 __LR0_EL2(7) +#define ICH_LR8_EL2 __LR8_EL2(0) +#define ICH_LR9_EL2 __LR8_EL2(1) +#define ICH_LR10_EL2 __LR8_EL2(2) +#define ICH_LR11_EL2 __LR8_EL2(3) +#define ICH_LR12_EL2 __LR8_EL2(4) +#define ICH_LR13_EL2 __LR8_EL2(5) +#define ICH_LR14_EL2 __LR8_EL2(6) +#define ICH_LR15_EL2 __LR8_EL2(7) + +#define __AP0Rx_EL2(x) sys_reg(3, 4, 12, 8, x) +#define ICH_AP0R0_EL2 __AP0Rx_EL2(0) +#define ICH_AP0R1_EL2 __AP0Rx_EL2(1) +#define ICH_AP0R2_EL2 __AP0Rx_EL2(2) +#define ICH_AP0R3_EL2 __AP0Rx_EL2(3) + +#define __AP1Rx_EL2(x) sys_reg(3, 4, 12, 9, x) +#define ICH_AP1R0_EL2 __AP1Rx_EL2(0) +#define ICH_AP1R1_EL2 __AP1Rx_EL2(1) +#define ICH_AP1R2_EL2 __AP1Rx_EL2(2) +#define ICH_AP1R3_EL2 __AP1Rx_EL2(3) + +#ifndef __ASSEMBLY__ + +#include <libcflat.h> +#include <asm/barrier.h> + +#define __stringify xstr + +/* + * Low-level accessors + * + * These system registers are 32 bits, but we make sure that the compiler + * sets the GP register's most significant bits to 0 with an explicit cast. + */ + +static inline void gicv3_write_eoir(u32 irq) +{ + asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); + isb(); +} + +static inline void gicv3_write_dir(u32 irq) +{ + asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); + isb(); +} + +static inline u64 gicv3_read_iar_common(void) +{ + u64 irqstat; + + asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); + dsb(sy); + return irqstat; +} + +static inline u32 gicv3_read_iar(void) +{ + return (u64)gicv3_read_iar_common(); +} + +/* + * Cavium ThunderX erratum 23154 + * + * The gicv3 of ThunderX requires a modified version for reading the + * IAR status to ensure data synchronization (access to icc_iar1_el1 + * is not sync'ed before and after). + */ +static inline u64 gicv3_read_iar_cavium_thunderx(void) +{ + u64 irqstat; + + asm volatile( + "nop;nop;nop;nop\n\t" + "nop;nop;nop;nop\n\t" + "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" + "nop;nop;nop;nop" + : "=r" (irqstat)); + mb(); + + return irqstat; +} + +static inline void gicv3_write_pmr(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); +} + +static inline void gicv3_write_ctlr(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" ((u64)val)); + isb(); +} + +static inline void gicv3_write_grpen1(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); + isb(); +} + +static inline void gicv3_write_sgi1r(u64 val) +{ + asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); +} + +static inline u32 gicv3_read_sre(void) +{ + u64 val; + + asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); + return val; +} + +static inline void gicv3_write_sre(u32 val) +{ + asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); + isb(); +} + +#define gicv3_read_typer(c) readq(c) +#define gicv3_write_irouter(v, c) writeq(v, c) + +#endif /* __ASSEMBLY__ */ +#endif /* _ASMARM64_ARCH_GICV3_H_ */ diff --git a/lib/arm64/asm/gic-v3.h b/lib/arm64/asm/gic-v3.h new file mode 100644 index 0000000000000..8ee5d4d9c1819 --- /dev/null +++ b/lib/arm64/asm/gic-v3.h @@ -0,0 +1 @@ +#include "../../arm/asm/gic-v3.h" diff --git a/lib/arm64/asm/sysreg.h b/lib/arm64/asm/sysreg.h new file mode 100644 index 0000000000000..544a46cb8cc59 --- /dev/null +++ b/lib/arm64/asm/sysreg.h @@ -0,0 +1,44 @@ +/* + * Ripped off from arch/arm64/include/asm/sysreg.h + * + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com> + * + * This work is licensed under the terms of the GNU LGPL, version 2. + */ +#ifndef _ASMARM64_SYSREG_H_ +#define _ASMARM64_SYSREG_H_ + +#define sys_reg(op0, op1, crn, crm, op2) \ + ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) + +#ifdef __ASSEMBLY__ + .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 + .equ .L__reg_num_x\num, \num + .endr + .equ .L__reg_num_xzr, 31 + + .macro mrs_s, rt, sreg + .inst 0xd5200000|(\sreg)|(.L__reg_num_\rt) + .endm + + .macro msr_s, sreg, rt + .inst 0xd5000000|(\sreg)|(.L__reg_num_\rt) + .endm +#else +asm( +" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" +" .equ .L__reg_num_x\\num, \\num\n" +" .endr\n" +" .equ .L__reg_num_xzr, 31\n" +"\n" +" .macro mrs_s, rt, sreg\n" +" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" +" .endm\n" +"\n" +" .macro msr_s, sreg, rt\n" +" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" +" .endm\n" +); +#endif + +#endif /* _ASMARM64_SYSREG_H_ */
Signed-off-by: Andrew Jones <drjones@redhat.com> --- v2: configure irqs as NS GRP1 --- lib/arm/asm/arch_gicv3.h | 184 ++++++++++++++++++++++++++ lib/arm/asm/gic-v3.h | 321 +++++++++++++++++++++++++++++++++++++++++++++ lib/arm/asm/gic.h | 1 + lib/arm/gic.c | 73 +++++++++++ lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++++++ lib/arm64/asm/gic-v3.h | 1 + lib/arm64/asm/sysreg.h | 44 +++++++ 7 files changed, 793 insertions(+) create mode 100644 lib/arm/asm/arch_gicv3.h create mode 100644 lib/arm/asm/gic-v3.h create mode 100644 lib/arm64/asm/arch_gicv3.h create mode 100644 lib/arm64/asm/gic-v3.h create mode 100644 lib/arm64/asm/sysreg.h