[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-arm] [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: a
From: |
Auger Eric |
Subject: |
Re: [Qemu-arm] [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support |
Date: |
Thu, 1 Sep 2016 12:19:52 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.1.1 |
Hi Drew,
On 15/07/2016 15:00, Andrew Jones wrote:
> Signed-off-by: Andrew Jones <address@hidden>
>
> ---
> 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 <address@hidden>
> + *
> + * 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 <address@hidden>
> + *
> + * 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 <address@hidden>
> + *
> + * 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 <address@hidden>
> + *
> + * 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_ */
>
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [Qemu-arm] [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support,
Auger Eric <=