All of lore.kernel.org
 help / color / mirror / Atom feed
* [kvm-unit-tests PATCH v3 00/10] arm/arm64: add gic framework
@ 2016-07-15 13:00 ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

v3:
 - Rebased on latest master
 - Added Alex's r-b's

v2:
 Rebased on latest master + my "populate argv[0]" series (will
 send a REPOST for that shortly. Additionally a few patches got
 fixes/features;
 07/10 got same fix as kernel 7c9b973061 "irqchip/gic-v3: Configure
       all interrupts as non-secure Group-1" in order to continue
       working over TCG, as the gicv3 code for TCG removed a hack
       it had there to make Linux happy.
 08/10 added more output for when things fail (if they fail)
 09/10 switched gicv3 broadcast implementation to using IRM. This
       found a bug in a recent (but not tip) kernel, which I was
       about to fix, but then I saw MarcZ beat me to it.
 10/10 actually check that the input irq is the received irq


Import defines, and steal enough helper functions, from Linux to
enable programming of the gic (v2 and v3). Then use the framework
to add an initial test (an ipi test; self, target-list, broadcast).

It's my hope that this framework will be a suitable base on which
more tests may be easily added, particularly because we have
vgic-new and tcg gicv3 emulation getting close to merge. (v3 UPDATE:
vgic-new and tcg gicv3 are merged now)

To run it, along with other tests, just do

 ./configure [ --arch=[arm|arm64] --cross-prefix=$PREFIX ]
 make
 export QEMU=$PATH_TO_QEMU
 ./run_tests.sh

To run it separately do, e.g.

$QEMU -machine virt,accel=tcg -cpu cortex-a57 \
 -device virtio-serial-device \
 -device virtconsole,chardev=ctd -chardev testdev,id=ctd \
 -display none -serial stdio \
 -kernel arm/gic.flat \
 -smp 123 -machine gic-version=3 -append ipi

      ^^ note, we can go nuts with nr-cpus on TCG :-)

Or, a KVM example using a different "sender" cpu and irq (other than zero)

$QEMU -machine virt,accel=kvm -cpu host \
 -device virtio-serial-device \
 -device virtconsole,chardev=ctd -chardev testdev,id=ctd \
 -display none -serial stdio \
 -kernel arm/gic.flat \
 -smp 48 -machine gic-version=3 -append 'ipi sender=42 irq=1'


Patches:
01-05: fixes and functionality needed by the later gic patches
06-07: code theft from Linux (defines, helper functions)
08-10: arm/gic.flat (the base of the gic unit test), currently just IPI

Available here: https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic


Andrew Jones (10):
  lib: xstr: allow multiple args
  arm64: fix get_"sysreg32" and make MPIDR 64bit
  arm/arm64: smp: support more than 8 cpus
  arm/arm64: add some delay routines
  arm/arm64: irq enable/disable
  arm/arm64: add initial gicv2 support
  arm/arm64: add initial gicv3 support
  arm/arm64: gicv2: add an IPI test
  arm/arm64: gicv3: add an IPI test
  arm/arm64: gic: don't just use zero

 arm/Makefile.common        |   7 +-
 arm/gic.c                  | 381 +++++++++++++++++++++++++++++++++++++++++++++
 arm/run                    |  19 ++-
 arm/selftest.c             |   5 +-
 arm/unittests.cfg          |  13 ++
 lib/arm/asm/arch_gicv3.h   | 184 ++++++++++++++++++++++
 lib/arm/asm/gic-v2.h       |  74 +++++++++
 lib/arm/asm/gic-v3.h       | 321 ++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h          |  21 +++
 lib/arm/asm/processor.h    |  38 ++++-
 lib/arm/asm/setup.h        |   4 +-
 lib/arm/gic.c              | 142 +++++++++++++++++
 lib/arm/processor.c        |  15 ++
 lib/arm/setup.c            |  12 +-
 lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++
 lib/arm64/asm/gic-v2.h     |   1 +
 lib/arm64/asm/gic-v3.h     |   1 +
 lib/arm64/asm/gic.h        |   1 +
 lib/arm64/asm/processor.h  |  53 ++++++-
 lib/arm64/asm/sysreg.h     |  44 ++++++
 lib/arm64/processor.c      |  15 ++
 lib/libcflat.h             |   4 +-
 22 files changed, 1498 insertions(+), 26 deletions(-)
 create mode 100644 arm/gic.c
 create mode 100644 lib/arm/asm/arch_gicv3.h
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic-v3.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm/gic.c
 create mode 100644 lib/arm64/asm/arch_gicv3.h
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic-v3.h
 create mode 100644 lib/arm64/asm/gic.h
 create mode 100644 lib/arm64/asm/sysreg.h

-- 
2.7.4


^ permalink raw reply	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 00/10] arm/arm64: add gic framework
@ 2016-07-15 13:00 ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

v3:
 - Rebased on latest master
 - Added Alex's r-b's

v2:
 Rebased on latest master + my "populate argv[0]" series (will
 send a REPOST for that shortly. Additionally a few patches got
 fixes/features;
 07/10 got same fix as kernel 7c9b973061 "irqchip/gic-v3: Configure
       all interrupts as non-secure Group-1" in order to continue
       working over TCG, as the gicv3 code for TCG removed a hack
       it had there to make Linux happy.
 08/10 added more output for when things fail (if they fail)
 09/10 switched gicv3 broadcast implementation to using IRM. This
       found a bug in a recent (but not tip) kernel, which I was
       about to fix, but then I saw MarcZ beat me to it.
 10/10 actually check that the input irq is the received irq


Import defines, and steal enough helper functions, from Linux to
enable programming of the gic (v2 and v3). Then use the framework
to add an initial test (an ipi test; self, target-list, broadcast).

It's my hope that this framework will be a suitable base on which
more tests may be easily added, particularly because we have
vgic-new and tcg gicv3 emulation getting close to merge. (v3 UPDATE:
vgic-new and tcg gicv3 are merged now)

To run it, along with other tests, just do

 ./configure [ --arch=[arm|arm64] --cross-prefix=$PREFIX ]
 make
 export QEMU=$PATH_TO_QEMU
 ./run_tests.sh

To run it separately do, e.g.

$QEMU -machine virt,accel=tcg -cpu cortex-a57 \
 -device virtio-serial-device \
 -device virtconsole,chardev=ctd -chardev testdev,id=ctd \
 -display none -serial stdio \
 -kernel arm/gic.flat \
 -smp 123 -machine gic-version=3 -append ipi

      ^^ note, we can go nuts with nr-cpus on TCG :-)

Or, a KVM example using a different "sender" cpu and irq (other than zero)

$QEMU -machine virt,accel=kvm -cpu host \
 -device virtio-serial-device \
 -device virtconsole,chardev=ctd -chardev testdev,id=ctd \
 -display none -serial stdio \
 -kernel arm/gic.flat \
 -smp 48 -machine gic-version=3 -append 'ipi sender=42 irq=1'


Patches:
01-05: fixes and functionality needed by the later gic patches
06-07: code theft from Linux (defines, helper functions)
08-10: arm/gic.flat (the base of the gic unit test), currently just IPI

Available here: https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic


Andrew Jones (10):
  lib: xstr: allow multiple args
  arm64: fix get_"sysreg32" and make MPIDR 64bit
  arm/arm64: smp: support more than 8 cpus
  arm/arm64: add some delay routines
  arm/arm64: irq enable/disable
  arm/arm64: add initial gicv2 support
  arm/arm64: add initial gicv3 support
  arm/arm64: gicv2: add an IPI test
  arm/arm64: gicv3: add an IPI test
  arm/arm64: gic: don't just use zero

 arm/Makefile.common        |   7 +-
 arm/gic.c                  | 381 +++++++++++++++++++++++++++++++++++++++++++++
 arm/run                    |  19 ++-
 arm/selftest.c             |   5 +-
 arm/unittests.cfg          |  13 ++
 lib/arm/asm/arch_gicv3.h   | 184 ++++++++++++++++++++++
 lib/arm/asm/gic-v2.h       |  74 +++++++++
 lib/arm/asm/gic-v3.h       | 321 ++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h          |  21 +++
 lib/arm/asm/processor.h    |  38 ++++-
 lib/arm/asm/setup.h        |   4 +-
 lib/arm/gic.c              | 142 +++++++++++++++++
 lib/arm/processor.c        |  15 ++
 lib/arm/setup.c            |  12 +-
 lib/arm64/asm/arch_gicv3.h | 169 ++++++++++++++++++++
 lib/arm64/asm/gic-v2.h     |   1 +
 lib/arm64/asm/gic-v3.h     |   1 +
 lib/arm64/asm/gic.h        |   1 +
 lib/arm64/asm/processor.h  |  53 ++++++-
 lib/arm64/asm/sysreg.h     |  44 ++++++
 lib/arm64/processor.c      |  15 ++
 lib/libcflat.h             |   4 +-
 22 files changed, 1498 insertions(+), 26 deletions(-)
 create mode 100644 arm/gic.c
 create mode 100644 lib/arm/asm/arch_gicv3.h
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic-v3.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm/gic.c
 create mode 100644 lib/arm64/asm/arch_gicv3.h
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic-v3.h
 create mode 100644 lib/arm64/asm/gic.h
 create mode 100644 lib/arm64/asm/sysreg.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 01/10] lib: xstr: allow multiple args
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Make implementation equivalent to Linux's include/linux/stringify.h

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/libcflat.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 72b1bf9668ef1..82005f5d014fb 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -27,8 +27,8 @@
 
 #define __unused __attribute__((__unused__))
 
-#define xstr(s) xxstr(s)
-#define xxstr(s) #s
+#define xstr(s...) xxstr(s)
+#define xxstr(s...) #s
 
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
 #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 01/10] lib: xstr: allow multiple args
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Make implementation equivalent to Linux's include/linux/stringify.h

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/libcflat.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 72b1bf9668ef1..82005f5d014fb 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -27,8 +27,8 @@
 
 #define __unused __attribute__((__unused__))
 
-#define xstr(s) xxstr(s)
-#define xxstr(s) #s
+#define xstr(s...) xxstr(s)
+#define xxstr(s...) #s
 
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
 #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 02/10] arm64: fix get_"sysreg32" and make MPIDR 64bit
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

mrs is always 64bit, so we should always use a 64bit register.
Sometimes we'll only want to return the lower 32, but not for
MPIDR, as that does define fields in the upper 32.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm64/asm/processor.h | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 84d5c7ce752b0..9a208ff729b7e 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -66,14 +66,17 @@ static inline unsigned long current_level(void)
 	return el & 0xc;
 }
 
-#define DEFINE_GET_SYSREG32(reg)				\
-static inline unsigned int get_##reg(void)			\
+#define DEFINE_GET_SYSREG(reg, type)				\
+static inline type get_##reg(void)				\
 {								\
-	unsigned int reg;					\
-	asm volatile("mrs %0, " #reg "_el1" : "=r" (reg));	\
-	return reg;						\
+	unsigned long r;					\
+	asm volatile("mrs %0, " #reg "_el1" : "=r" (r));	\
+	return (type)r;						\
 }
-DEFINE_GET_SYSREG32(mpidr)
+#define DEFINE_GET_SYSREG32(reg) DEFINE_GET_SYSREG(reg, unsigned int)
+#define DEFINE_GET_SYSREG64(reg) DEFINE_GET_SYSREG(reg, unsigned long)
+
+DEFINE_GET_SYSREG64(mpidr)
 
 /* Only support Aff0 for now, gicv2 only */
 #define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 02/10] arm64: fix get_"sysreg32" and make MPIDR 64bit
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

mrs is always 64bit, so we should always use a 64bit register.
Sometimes we'll only want to return the lower 32, but not for
MPIDR, as that does define fields in the upper 32.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm64/asm/processor.h | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 84d5c7ce752b0..9a208ff729b7e 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -66,14 +66,17 @@ static inline unsigned long current_level(void)
 	return el & 0xc;
 }
 
-#define DEFINE_GET_SYSREG32(reg)				\
-static inline unsigned int get_##reg(void)			\
+#define DEFINE_GET_SYSREG(reg, type)				\
+static inline type get_##reg(void)				\
 {								\
-	unsigned int reg;					\
-	asm volatile("mrs %0, " #reg "_el1" : "=r" (reg));	\
-	return reg;						\
+	unsigned long r;					\
+	asm volatile("mrs %0, " #reg "_el1" : "=r" (r));	\
+	return (type)r;						\
 }
-DEFINE_GET_SYSREG32(mpidr)
+#define DEFINE_GET_SYSREG32(reg) DEFINE_GET_SYSREG(reg, unsigned int)
+#define DEFINE_GET_SYSREG64(reg) DEFINE_GET_SYSREG(reg, unsigned long)
+
+DEFINE_GET_SYSREG64(mpidr)
 
 /* Only support Aff0 for now, gicv2 only */
 #define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 arm/run                   | 19 ++++++++++++-------
 arm/selftest.c            |  5 ++++-
 lib/arm/asm/processor.h   |  9 +++++++--
 lib/arm/asm/setup.h       |  4 ++--
 lib/arm/setup.c           | 12 +++++++++++-
 lib/arm64/asm/processor.h |  9 +++++++--
 6 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/arm/run b/arm/run
index a2f35ef6a7e63..2d0698619606e 100755
--- a/arm/run
+++ b/arm/run
@@ -31,13 +31,6 @@ if [ -z "$ACCEL" ]; then
 	fi
 fi
 
-if [ "$HOST" = "aarch64" ] && [ "$ACCEL" = "kvm" ]; then
-	processor="host"
-	if [ "$ARCH" = "arm" ]; then
-		processor+=",aarch64=off"
-	fi
-fi
-
 qemu="${QEMU:-qemu-system-$ARCH_NAME}"
 qpath=$(which $qemu 2>/dev/null)
 
@@ -53,6 +46,18 @@ fi
 
 M='-machine virt'
 
+if [ "$ACCEL" = "kvm" ]; then
+	if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then
+		M+=',gic-version=host'
+	fi
+	if [ "$HOST" = "aarch64" ]; then
+		processor="host"
+		if [ "$ARCH" = "arm" ]; then
+			processor+=",aarch64=off"
+		fi
+	fi
+fi
+
 if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then
 	echo "$qpath doesn't support virtio-console for chr-testdev. Exiting."
 	exit 2
diff --git a/arm/selftest.c b/arm/selftest.c
index 196164f5313de..2f117f795d2dc 100644
--- a/arm/selftest.c
+++ b/arm/selftest.c
@@ -312,9 +312,10 @@ static bool psci_check(void)
 static cpumask_t smp_reported;
 static void cpu_report(void)
 {
+	unsigned long mpidr = get_mpidr();
 	int cpu = smp_processor_id();
 
-	report("CPU%d online", true, cpu);
+	report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
 	cpumask_set_cpu(cpu, &smp_reported);
 	halt();
 }
@@ -343,6 +344,7 @@ int main(int argc, char **argv)
 
 	} else if (strcmp(argv[1], "smp") == 0) {
 
+		unsigned long mpidr = get_mpidr();
 		int cpu;
 
 		report("PSCI version", psci_check());
@@ -353,6 +355,7 @@ int main(int argc, char **argv)
 			smp_boot_secondary(cpu, cpu_report);
 		}
 
+		report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == 0, 0, mpidr);
 		cpumask_set_cpu(0, &smp_reported);
 		while (!cpumask_full(&smp_reported))
 			cpu_relax();
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index f25e7eee3666c..d2048f5f5f7e6 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -40,8 +40,13 @@ static inline unsigned int get_mpidr(void)
 	return mpidr;
 }
 
-/* Only support Aff0 for now, up to 4 cpus */
-#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
+#define MPIDR_HWID_BITMASK 0xffffff
+extern int mpidr_to_cpu(unsigned long mpidr);
+
+#define MPIDR_LEVEL_SHIFT(level) \
+	(((1 << level) >> 1) << 3)
+#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
+	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
 
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
index cb8fdbd38dd5d..c501c6ddd8657 100644
--- a/lib/arm/asm/setup.h
+++ b/lib/arm/asm/setup.h
@@ -10,8 +10,8 @@
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 
-#define NR_CPUS			8
-extern u32 cpus[NR_CPUS];
+#define NR_CPUS			255
+extern u64 cpus[NR_CPUS];
 extern int nr_cpus;
 
 #define NR_MEM_REGIONS		8
diff --git a/lib/arm/setup.c b/lib/arm/setup.c
index 7e7b39f11dde1..b6e2d5815e723 100644
--- a/lib/arm/setup.c
+++ b/lib/arm/setup.c
@@ -24,12 +24,22 @@ extern unsigned long stacktop;
 extern void io_init(void);
 extern void setup_args_progname(const char *args);
 
-u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
+u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
 int nr_cpus;
 
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __phys_offset, __phys_end;
 
+int mpidr_to_cpu(unsigned long mpidr)
+{
+	int i;
+
+	for (i = 0; i < nr_cpus; ++i)
+		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
+			return i;
+	return -1;
+}
+
 static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
 {
 	int cpu = nr_cpus++;
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 9a208ff729b7e..7e448dc81a6aa 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -78,8 +78,13 @@ static inline type get_##reg(void)				\
 
 DEFINE_GET_SYSREG64(mpidr)
 
-/* Only support Aff0 for now, gicv2 only */
-#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
+#define MPIDR_HWID_BITMASK 0xff00ffffff
+extern int mpidr_to_cpu(unsigned long mpidr);
+
+#define MPIDR_LEVEL_SHIFT(level) \
+	(((1 << level) >> 1) << 3)
+#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
+	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
 
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 arm/run                   | 19 ++++++++++++-------
 arm/selftest.c            |  5 ++++-
 lib/arm/asm/processor.h   |  9 +++++++--
 lib/arm/asm/setup.h       |  4 ++--
 lib/arm/setup.c           | 12 +++++++++++-
 lib/arm64/asm/processor.h |  9 +++++++--
 6 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/arm/run b/arm/run
index a2f35ef6a7e63..2d0698619606e 100755
--- a/arm/run
+++ b/arm/run
@@ -31,13 +31,6 @@ if [ -z "$ACCEL" ]; then
 	fi
 fi
 
-if [ "$HOST" = "aarch64" ] && [ "$ACCEL" = "kvm" ]; then
-	processor="host"
-	if [ "$ARCH" = "arm" ]; then
-		processor+=",aarch64=off"
-	fi
-fi
-
 qemu="${QEMU:-qemu-system-$ARCH_NAME}"
 qpath=$(which $qemu 2>/dev/null)
 
@@ -53,6 +46,18 @@ fi
 
 M='-machine virt'
 
+if [ "$ACCEL" = "kvm" ]; then
+	if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then
+		M+=',gic-version=host'
+	fi
+	if [ "$HOST" = "aarch64" ]; then
+		processor="host"
+		if [ "$ARCH" = "arm" ]; then
+			processor+=",aarch64=off"
+		fi
+	fi
+fi
+
 if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then
 	echo "$qpath doesn't support virtio-console for chr-testdev. Exiting."
 	exit 2
diff --git a/arm/selftest.c b/arm/selftest.c
index 196164f5313de..2f117f795d2dc 100644
--- a/arm/selftest.c
+++ b/arm/selftest.c
@@ -312,9 +312,10 @@ static bool psci_check(void)
 static cpumask_t smp_reported;
 static void cpu_report(void)
 {
+	unsigned long mpidr = get_mpidr();
 	int cpu = smp_processor_id();
 
-	report("CPU%d online", true, cpu);
+	report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
 	cpumask_set_cpu(cpu, &smp_reported);
 	halt();
 }
@@ -343,6 +344,7 @@ int main(int argc, char **argv)
 
 	} else if (strcmp(argv[1], "smp") == 0) {
 
+		unsigned long mpidr = get_mpidr();
 		int cpu;
 
 		report("PSCI version", psci_check());
@@ -353,6 +355,7 @@ int main(int argc, char **argv)
 			smp_boot_secondary(cpu, cpu_report);
 		}
 
+		report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == 0, 0, mpidr);
 		cpumask_set_cpu(0, &smp_reported);
 		while (!cpumask_full(&smp_reported))
 			cpu_relax();
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index f25e7eee3666c..d2048f5f5f7e6 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -40,8 +40,13 @@ static inline unsigned int get_mpidr(void)
 	return mpidr;
 }
 
-/* Only support Aff0 for now, up to 4 cpus */
-#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
+#define MPIDR_HWID_BITMASK 0xffffff
+extern int mpidr_to_cpu(unsigned long mpidr);
+
+#define MPIDR_LEVEL_SHIFT(level) \
+	(((1 << level) >> 1) << 3)
+#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
+	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
 
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
index cb8fdbd38dd5d..c501c6ddd8657 100644
--- a/lib/arm/asm/setup.h
+++ b/lib/arm/asm/setup.h
@@ -10,8 +10,8 @@
 #include <asm/page.h>
 #include <asm/pgtable-hwdef.h>
 
-#define NR_CPUS			8
-extern u32 cpus[NR_CPUS];
+#define NR_CPUS			255
+extern u64 cpus[NR_CPUS];
 extern int nr_cpus;
 
 #define NR_MEM_REGIONS		8
diff --git a/lib/arm/setup.c b/lib/arm/setup.c
index 7e7b39f11dde1..b6e2d5815e723 100644
--- a/lib/arm/setup.c
+++ b/lib/arm/setup.c
@@ -24,12 +24,22 @@ extern unsigned long stacktop;
 extern void io_init(void);
 extern void setup_args_progname(const char *args);
 
-u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
+u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
 int nr_cpus;
 
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __phys_offset, __phys_end;
 
+int mpidr_to_cpu(unsigned long mpidr)
+{
+	int i;
+
+	for (i = 0; i < nr_cpus; ++i)
+		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
+			return i;
+	return -1;
+}
+
 static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
 {
 	int cpu = nr_cpus++;
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 9a208ff729b7e..7e448dc81a6aa 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -78,8 +78,13 @@ static inline type get_##reg(void)				\
 
 DEFINE_GET_SYSREG64(mpidr)
 
-/* Only support Aff0 for now, gicv2 only */
-#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
+#define MPIDR_HWID_BITMASK 0xff00ffffff
+extern int mpidr_to_cpu(unsigned long mpidr);
+
+#define MPIDR_LEVEL_SHIFT(level) \
+	(((1 << level) >> 1) << 3)
+#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
+	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
 
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 04/10] arm/arm64: add some delay routines
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Allow a thread to wait some specified amount of time. Can
specify in cycles, usecs, and msecs.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm/asm/processor.h   | 19 +++++++++++++++++++
 lib/arm/processor.c       | 15 +++++++++++++++
 lib/arm64/asm/processor.h | 19 +++++++++++++++++++
 lib/arm64/processor.c     | 15 +++++++++++++++
 4 files changed, 68 insertions(+)

diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index d2048f5f5f7e6..afc903ca7d4ab 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -5,7 +5,9 @@
  *
  * This work is licensed under the terms of the GNU LGPL, version 2.
  */
+#include <libcflat.h>
 #include <asm/ptrace.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EXCPTN_RST,
@@ -51,4 +53,21 @@ extern int mpidr_to_cpu(unsigned long mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+static inline u64 get_cntvct(void)
+{
+	u64 vct;
+	isb();
+	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (vct));
+	return vct;
+}
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+
+static inline void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}
+
 #endif /* _ASMARM_PROCESSOR_H_ */
diff --git a/lib/arm/processor.c b/lib/arm/processor.c
index 54fdb87ef0196..c2ee360df6884 100644
--- a/lib/arm/processor.c
+++ b/lib/arm/processor.c
@@ -9,6 +9,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/barrier.h>
 
 static const char *processor_modes[] = {
 	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
@@ -141,3 +142,17 @@ bool is_user(void)
 {
 	return current_thread_info()->flags & TIF_USER_MODE;
 }
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	unsigned int frq;
+	asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq));
+	delay((u64)usec * frq / 1000000);
+}
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 7e448dc81a6aa..94f7ce35b65c1 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -17,8 +17,10 @@
 #define SCTLR_EL1_M	(1 << 0)
 
 #ifndef __ASSEMBLY__
+#include <libcflat.h>
 #include <asm/ptrace.h>
 #include <asm/esr.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EL1T_SYNC,
@@ -89,5 +91,22 @@ extern int mpidr_to_cpu(unsigned long mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+static inline u64 get_cntvct(void)
+{
+	u64 vct;
+	isb();
+	asm volatile("mrs %0, cntvct_el0" : "=r" (vct));
+	return vct;
+}
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+
+static inline void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM64_PROCESSOR_H_ */
diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c
index deeab4ec9c8ac..50fa835c6f1e3 100644
--- a/lib/arm64/processor.c
+++ b/lib/arm64/processor.c
@@ -9,6 +9,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/barrier.h>
 
 static const char *vector_names[] = {
 	"el1t_sync",
@@ -253,3 +254,17 @@ bool is_user(void)
 {
 	return current_thread_info()->flags & TIF_USER_MODE;
 }
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	unsigned int frq;
+	asm volatile("mrs %0, cntfrq_el0" : "=r" (frq));
+	delay((u64)usec * frq / 1000000);
+}
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 04/10] arm/arm64: add some delay routines
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Allow a thread to wait some specified amount of time. Can
specify in cycles, usecs, and msecs.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm/asm/processor.h   | 19 +++++++++++++++++++
 lib/arm/processor.c       | 15 +++++++++++++++
 lib/arm64/asm/processor.h | 19 +++++++++++++++++++
 lib/arm64/processor.c     | 15 +++++++++++++++
 4 files changed, 68 insertions(+)

diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index d2048f5f5f7e6..afc903ca7d4ab 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -5,7 +5,9 @@
  *
  * This work is licensed under the terms of the GNU LGPL, version 2.
  */
+#include <libcflat.h>
 #include <asm/ptrace.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EXCPTN_RST,
@@ -51,4 +53,21 @@ extern int mpidr_to_cpu(unsigned long mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+static inline u64 get_cntvct(void)
+{
+	u64 vct;
+	isb();
+	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (vct));
+	return vct;
+}
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+
+static inline void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}
+
 #endif /* _ASMARM_PROCESSOR_H_ */
diff --git a/lib/arm/processor.c b/lib/arm/processor.c
index 54fdb87ef0196..c2ee360df6884 100644
--- a/lib/arm/processor.c
+++ b/lib/arm/processor.c
@@ -9,6 +9,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/barrier.h>
 
 static const char *processor_modes[] = {
 	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
@@ -141,3 +142,17 @@ bool is_user(void)
 {
 	return current_thread_info()->flags & TIF_USER_MODE;
 }
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	unsigned int frq;
+	asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq));
+	delay((u64)usec * frq / 1000000);
+}
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 7e448dc81a6aa..94f7ce35b65c1 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -17,8 +17,10 @@
 #define SCTLR_EL1_M	(1 << 0)
 
 #ifndef __ASSEMBLY__
+#include <libcflat.h>
 #include <asm/ptrace.h>
 #include <asm/esr.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EL1T_SYNC,
@@ -89,5 +91,22 @@ extern int mpidr_to_cpu(unsigned long mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+static inline u64 get_cntvct(void)
+{
+	u64 vct;
+	isb();
+	asm volatile("mrs %0, cntvct_el0" : "=r" (vct));
+	return vct;
+}
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+
+static inline void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM64_PROCESSOR_H_ */
diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c
index deeab4ec9c8ac..50fa835c6f1e3 100644
--- a/lib/arm64/processor.c
+++ b/lib/arm64/processor.c
@@ -9,6 +9,7 @@
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/thread_info.h>
+#include <asm/barrier.h>
 
 static const char *vector_names[] = {
 	"el1t_sync",
@@ -253,3 +254,17 @@ bool is_user(void)
 {
 	return current_thread_info()->flags & TIF_USER_MODE;
 }
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	unsigned int frq;
+	asm volatile("mrs %0, cntfrq_el0" : "=r" (frq));
+	delay((u64)usec * frq / 1000000);
+}
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 05/10] arm/arm64: irq enable/disable
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm/asm/processor.h   | 10 ++++++++++
 lib/arm64/asm/processor.h | 10 ++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index afc903ca7d4ab..75a8d08b89330 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -35,6 +35,16 @@ static inline unsigned long current_cpsr(void)
 
 #define current_mode() (current_cpsr() & MODE_MASK)
 
+static inline void local_irq_enable(void)
+{
+	asm volatile("cpsie i" : : : "memory", "cc");
+}
+
+static inline void local_irq_disable(void)
+{
+	asm volatile("cpsid i" : : : "memory", "cc");
+}
+
 static inline unsigned int get_mpidr(void)
 {
 	unsigned int mpidr;
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 94f7ce35b65c1..d54a4ed1c1876 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -68,6 +68,16 @@ static inline unsigned long current_level(void)
 	return el & 0xc;
 }
 
+static inline void local_irq_enable(void)
+{
+	asm volatile("msr daifclr, #2" : : : "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+	asm volatile("msr daifset, #2" : : : "memory");
+}
+
 #define DEFINE_GET_SYSREG(reg, type)				\
 static inline type get_##reg(void)				\
 {								\
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 05/10] arm/arm64: irq enable/disable
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 lib/arm/asm/processor.h   | 10 ++++++++++
 lib/arm64/asm/processor.h | 10 ++++++++++
 2 files changed, 20 insertions(+)

diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index afc903ca7d4ab..75a8d08b89330 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -35,6 +35,16 @@ static inline unsigned long current_cpsr(void)
 
 #define current_mode() (current_cpsr() & MODE_MASK)
 
+static inline void local_irq_enable(void)
+{
+	asm volatile("cpsie i" : : : "memory", "cc");
+}
+
+static inline void local_irq_disable(void)
+{
+	asm volatile("cpsid i" : : : "memory", "cc");
+}
+
 static inline unsigned int get_mpidr(void)
 {
 	unsigned int mpidr;
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 94f7ce35b65c1..d54a4ed1c1876 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -68,6 +68,16 @@ static inline unsigned long current_level(void)
 	return el & 0xc;
 }
 
+static inline void local_irq_enable(void)
+{
+	asm volatile("msr daifclr, #2" : : : "memory");
+}
+
+static inline void local_irq_disable(void)
+{
+	asm volatile("msr daifset, #2" : : : "memory");
+}
+
 #define DEFINE_GET_SYSREG(reg, type)				\
 static inline type get_##reg(void)				\
 {								\
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: marc.zyngier

Add some gicv2 support. This just adds init and enable
functions, allowing unit tests to start messing with it.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 arm/Makefile.common    |  1 +
 lib/arm/asm/gic-v2.h   | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h      | 20 ++++++++++++++
 lib/arm/gic.c          | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm64/asm/gic-v2.h |  1 +
 lib/arm64/asm/gic.h    |  1 +
 6 files changed, 166 insertions(+)
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm/gic.c
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic.h

diff --git a/arm/Makefile.common b/arm/Makefile.common
index ccb554d9251a4..41239c37e0920 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
 cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/gic.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
new file mode 100644
index 0000000000000..973c2bf3cc796
--- /dev/null
+++ b/lib/arm/asm/gic-v2.h
@@ -0,0 +1,74 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic.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_V2_H_
+#define _ASMARM_GIC_V2_H_
+
+#define GIC_CPU_CTRL			0x00
+#define GIC_CPU_PRIMASK			0x04
+#define GIC_CPU_BINPOINT		0x08
+#define GIC_CPU_INTACK			0x0c
+#define GIC_CPU_EOI			0x10
+#define GIC_CPU_RUNNINGPRI		0x14
+#define GIC_CPU_HIGHPRI			0x18
+#define GIC_CPU_ALIAS_BINPOINT		0x1c
+#define GIC_CPU_ACTIVEPRIO		0xd0
+#define GIC_CPU_IDENT			0xfc
+#define GIC_CPU_DEACTIVATE		0x1000
+
+#define GICC_ENABLE			0x1
+#define GICC_INT_PRI_THRESHOLD		0xf0
+
+#define GIC_CPU_CTRL_EOImodeNS		(1 << 9)
+
+#define GICC_IAR_INT_ID_MASK		0x3ff
+#define GICC_INT_SPURIOUS		1023
+#define GICC_DIS_BYPASS_MASK		0x1e0
+
+#define GIC_DIST_CTRL			0x000
+#define GIC_DIST_CTR			0x004
+#define GIC_DIST_IGROUP			0x080
+#define GIC_DIST_ENABLE_SET		0x100
+#define GIC_DIST_ENABLE_CLEAR		0x180
+#define GIC_DIST_PENDING_SET		0x200
+#define GIC_DIST_PENDING_CLEAR		0x280
+#define GIC_DIST_ACTIVE_SET		0x300
+#define GIC_DIST_ACTIVE_CLEAR		0x380
+#define GIC_DIST_PRI			0x400
+#define GIC_DIST_TARGET			0x800
+#define GIC_DIST_CONFIG			0xc00
+#define GIC_DIST_SOFTINT		0xf00
+#define GIC_DIST_SGI_PENDING_CLEAR	0xf10
+#define GIC_DIST_SGI_PENDING_SET	0xf20
+
+#define GICD_ENABLE			0x1
+#define GICD_DISABLE			0x0
+#define GICD_INT_ACTLOW_LVLTRIG		0x0
+#define GICD_INT_EN_CLR_X32		0xffffffff
+#define GICD_INT_EN_SET_SGI		0x0000ffff
+#define GICD_INT_EN_CLR_PPI		0xffff0000
+#define GICD_INT_DEF_PRI		0xa0
+#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
+					(GICD_INT_DEF_PRI << 16) |\
+					(GICD_INT_DEF_PRI << 8) |\
+					GICD_INT_DEF_PRI)
+#ifndef __ASSEMBLY__
+
+struct gicv2_data {
+	void *dist_base;
+	void *cpu_base;
+};
+extern struct gicv2_data gicv2_data;
+
+#define gicv2_dist_base()		(gicv2_data.dist_base)
+#define gicv2_cpu_base()		(gicv2_data.cpu_base)
+
+extern int gicv2_init(void);
+extern void gicv2_enable_defaults(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V2_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
new file mode 100644
index 0000000000000..b1237d1c5ef22
--- /dev/null
+++ b/lib/arm/asm/gic.h
@@ -0,0 +1,20 @@
+/*
+ * 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_H_
+#define _ASMARM_GIC_H_
+
+#include <asm/gic-v2.h>
+
+/*
+ * gic_init will try to find all known gics, and then
+ * initialize the gic data for the one found.
+ * returns
+ *  0   : no gic was found
+ *  > 0 : the gic version of the gic found
+ */
+extern int gic_init(void);
+
+#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
new file mode 100644
index 0000000000000..64a3049c9e8ce
--- /dev/null
+++ b/lib/arm/gic.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <devicetree.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/io.h>
+
+struct gicv2_data gicv2_data;
+
+/*
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ */
+static bool
+gic_get_dt_bases(const char *compatible, void **base1, void **base2)
+{
+	struct dt_pbus_reg reg;
+	struct dt_device gic;
+	struct dt_bus bus;
+	int node, ret;
+
+	dt_bus_init_defaults(&bus);
+	dt_device_init(&gic, &bus, NULL);
+
+	node = dt_device_find_compatible(&gic, compatible);
+	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
+
+	if (node == -FDT_ERR_NOTFOUND)
+		return false;
+
+	dt_device_bind_node(&gic, node);
+
+	ret = dt_pbus_translate(&gic, 0, &reg);
+	assert(ret == 0);
+	*base1 = ioremap(reg.addr, reg.size);
+
+	ret = dt_pbus_translate(&gic, 1, &reg);
+	assert(ret == 0);
+	*base2 = ioremap(reg.addr, reg.size);
+
+	return true;
+}
+
+int gicv2_init(void)
+{
+	return gic_get_dt_bases("arm,cortex-a15-gic",
+			&gicv2_data.dist_base, &gicv2_data.cpu_base);
+}
+
+int gic_init(void)
+{
+	if (gicv2_init())
+		return 2;
+	return 0;
+}
+
+void gicv2_enable_defaults(void)
+{
+	if (smp_processor_id() == 0) {
+		writel(GICD_INT_DEF_PRI_X4, gicv2_dist_base() + GIC_DIST_PRI);
+		writel(GICD_INT_EN_SET_SGI, gicv2_dist_base() + GIC_DIST_ENABLE_SET);
+		writel(GICD_ENABLE, gicv2_dist_base() + GIC_DIST_CTRL);
+	}
+	writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK);
+	writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL);
+}
diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
new file mode 100644
index 0000000000000..52226624a2092
--- /dev/null
+++ b/lib/arm64/asm/gic-v2.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v2.h"
diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
new file mode 100644
index 0000000000000..e5eb302a31b4d
--- /dev/null
+++ b/lib/arm64/asm/gic.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic.h"
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Add some gicv2 support. This just adds init and enable
functions, allowing unit tests to start messing with it.

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
 arm/Makefile.common    |  1 +
 lib/arm/asm/gic-v2.h   | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h      | 20 ++++++++++++++
 lib/arm/gic.c          | 69 ++++++++++++++++++++++++++++++++++++++++++++++
 lib/arm64/asm/gic-v2.h |  1 +
 lib/arm64/asm/gic.h    |  1 +
 6 files changed, 166 insertions(+)
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm/gic.c
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic.h

diff --git a/arm/Makefile.common b/arm/Makefile.common
index ccb554d9251a4..41239c37e0920 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
 cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/gic.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
new file mode 100644
index 0000000000000..973c2bf3cc796
--- /dev/null
+++ b/lib/arm/asm/gic-v2.h
@@ -0,0 +1,74 @@
+/*
+ * All GIC* defines are lifted from include/linux/irqchip/arm-gic.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_V2_H_
+#define _ASMARM_GIC_V2_H_
+
+#define GIC_CPU_CTRL			0x00
+#define GIC_CPU_PRIMASK			0x04
+#define GIC_CPU_BINPOINT		0x08
+#define GIC_CPU_INTACK			0x0c
+#define GIC_CPU_EOI			0x10
+#define GIC_CPU_RUNNINGPRI		0x14
+#define GIC_CPU_HIGHPRI			0x18
+#define GIC_CPU_ALIAS_BINPOINT		0x1c
+#define GIC_CPU_ACTIVEPRIO		0xd0
+#define GIC_CPU_IDENT			0xfc
+#define GIC_CPU_DEACTIVATE		0x1000
+
+#define GICC_ENABLE			0x1
+#define GICC_INT_PRI_THRESHOLD		0xf0
+
+#define GIC_CPU_CTRL_EOImodeNS		(1 << 9)
+
+#define GICC_IAR_INT_ID_MASK		0x3ff
+#define GICC_INT_SPURIOUS		1023
+#define GICC_DIS_BYPASS_MASK		0x1e0
+
+#define GIC_DIST_CTRL			0x000
+#define GIC_DIST_CTR			0x004
+#define GIC_DIST_IGROUP			0x080
+#define GIC_DIST_ENABLE_SET		0x100
+#define GIC_DIST_ENABLE_CLEAR		0x180
+#define GIC_DIST_PENDING_SET		0x200
+#define GIC_DIST_PENDING_CLEAR		0x280
+#define GIC_DIST_ACTIVE_SET		0x300
+#define GIC_DIST_ACTIVE_CLEAR		0x380
+#define GIC_DIST_PRI			0x400
+#define GIC_DIST_TARGET			0x800
+#define GIC_DIST_CONFIG			0xc00
+#define GIC_DIST_SOFTINT		0xf00
+#define GIC_DIST_SGI_PENDING_CLEAR	0xf10
+#define GIC_DIST_SGI_PENDING_SET	0xf20
+
+#define GICD_ENABLE			0x1
+#define GICD_DISABLE			0x0
+#define GICD_INT_ACTLOW_LVLTRIG		0x0
+#define GICD_INT_EN_CLR_X32		0xffffffff
+#define GICD_INT_EN_SET_SGI		0x0000ffff
+#define GICD_INT_EN_CLR_PPI		0xffff0000
+#define GICD_INT_DEF_PRI		0xa0
+#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
+					(GICD_INT_DEF_PRI << 16) |\
+					(GICD_INT_DEF_PRI << 8) |\
+					GICD_INT_DEF_PRI)
+#ifndef __ASSEMBLY__
+
+struct gicv2_data {
+	void *dist_base;
+	void *cpu_base;
+};
+extern struct gicv2_data gicv2_data;
+
+#define gicv2_dist_base()		(gicv2_data.dist_base)
+#define gicv2_cpu_base()		(gicv2_data.cpu_base)
+
+extern int gicv2_init(void);
+extern void gicv2_enable_defaults(void);
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_V2_H_ */
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
new file mode 100644
index 0000000000000..b1237d1c5ef22
--- /dev/null
+++ b/lib/arm/asm/gic.h
@@ -0,0 +1,20 @@
+/*
+ * 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_H_
+#define _ASMARM_GIC_H_
+
+#include <asm/gic-v2.h>
+
+/*
+ * gic_init will try to find all known gics, and then
+ * initialize the gic data for the one found.
+ * returns
+ *  0   : no gic was found
+ *  > 0 : the gic version of the gic found
+ */
+extern int gic_init(void);
+
+#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
new file mode 100644
index 0000000000000..64a3049c9e8ce
--- /dev/null
+++ b/lib/arm/gic.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <devicetree.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/io.h>
+
+struct gicv2_data gicv2_data;
+
+/*
+ * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+ */
+static bool
+gic_get_dt_bases(const char *compatible, void **base1, void **base2)
+{
+	struct dt_pbus_reg reg;
+	struct dt_device gic;
+	struct dt_bus bus;
+	int node, ret;
+
+	dt_bus_init_defaults(&bus);
+	dt_device_init(&gic, &bus, NULL);
+
+	node = dt_device_find_compatible(&gic, compatible);
+	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
+
+	if (node == -FDT_ERR_NOTFOUND)
+		return false;
+
+	dt_device_bind_node(&gic, node);
+
+	ret = dt_pbus_translate(&gic, 0, &reg);
+	assert(ret == 0);
+	*base1 = ioremap(reg.addr, reg.size);
+
+	ret = dt_pbus_translate(&gic, 1, &reg);
+	assert(ret == 0);
+	*base2 = ioremap(reg.addr, reg.size);
+
+	return true;
+}
+
+int gicv2_init(void)
+{
+	return gic_get_dt_bases("arm,cortex-a15-gic",
+			&gicv2_data.dist_base, &gicv2_data.cpu_base);
+}
+
+int gic_init(void)
+{
+	if (gicv2_init())
+		return 2;
+	return 0;
+}
+
+void gicv2_enable_defaults(void)
+{
+	if (smp_processor_id() == 0) {
+		writel(GICD_INT_DEF_PRI_X4, gicv2_dist_base() + GIC_DIST_PRI);
+		writel(GICD_INT_EN_SET_SGI, gicv2_dist_base() + GIC_DIST_ENABLE_SET);
+		writel(GICD_ENABLE, gicv2_dist_base() + GIC_DIST_CTRL);
+	}
+	writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK);
+	writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL);
+}
diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
new file mode 100644
index 0000000000000..52226624a2092
--- /dev/null
+++ b/lib/arm64/asm/gic-v2.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic-v2.h"
diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
new file mode 100644
index 0000000000000..e5eb302a31b4d
--- /dev/null
+++ b/lib/arm64/asm/gic.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic.h"
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: marc.zyngier

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
+ *
+ * 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_ */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

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
+ *
+ * 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_ */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v2: add more details in the output if a test fails,
    report spurious interrupts if we get them
---
 arm/Makefile.common |   6 +-
 arm/gic.c           | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 arm/unittests.cfg   |   7 ++
 3 files changed, 204 insertions(+), 3 deletions(-)
 create mode 100644 arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 41239c37e0920..bc38183ab86e0 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
 	LOADADDR = 0x40000000
 endif
 
-tests-common = \
-	$(TEST_DIR)/selftest.flat \
-	$(TEST_DIR)/spinlock-test.flat
+tests-common  = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/gic.flat
 
 all: test_cases
 
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 0000000000000..cf7ec1c90413c
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,194 @@
+/*
+ * GIC tests
+ *
+ * GICv2
+ *   . test sending/receiving IPIs
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+static int gic_version;
+static int acked[NR_CPUS], spurious[NR_CPUS];
+static cpumask_t ready;
+
+static void nr_cpu_check(int nr)
+{
+	if (nr_cpus < nr)
+		report_abort("At least %d cpus required", nr);
+}
+
+static void wait_on_ready(void)
+{
+	cpumask_set_cpu(smp_processor_id(), &ready);
+	while (!cpumask_full(&ready))
+		cpu_relax();
+}
+
+static void check_acked(cpumask_t *mask)
+{
+	int missing = 0, extra = 0, unexpected = 0;
+	int nr_pass, cpu, i;
+
+	/* Wait up to 5s for all interrupts to be delivered */
+	for (i = 0; i < 50; ++i) {
+		mdelay(100);
+		nr_pass = 0;
+		for_each_present_cpu(cpu) {
+			smp_rmb();
+			nr_pass += cpumask_test_cpu(cpu, mask) ?
+				acked[cpu] == 1 : acked[cpu] == 0;
+		}
+		if (nr_pass == nr_cpus) {
+			report("Completed in %d ms", true, ++i * 100);
+			return;
+		}
+	}
+
+	for_each_present_cpu(cpu) {
+		if (cpumask_test_cpu(cpu, mask)) {
+			if (!acked[cpu])
+				++missing;
+			else if (acked[cpu] > 1)
+				++extra;
+		} else {
+			if (acked[cpu])
+				++unexpected;
+		}
+	}
+
+	report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
+	       false, missing, extra, unexpected);
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+
+	if (iar != GICC_INT_SPURIOUS) {
+		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
+		smp_rmb(); /* pairs with wmb in ipi_test functions */
+		++acked[smp_processor_id()];
+		smp_wmb(); /* pairs with rmb in check_acked */
+	} else {
+		++spurious[smp_processor_id()];
+		smp_wmb();
+	}
+}
+
+static void ipi_test_self(void)
+{
+	cpumask_t mask;
+
+	report_prefix_push("self");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	cpumask_clear(&mask);
+	cpumask_set_cpu(0, &mask);
+	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+}
+
+static void ipi_test_smp(void)
+{
+	cpumask_t mask;
+	unsigned long tlist;
+
+	report_prefix_push("target-list");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
+	cpumask_bits(&mask)[0] = tlist;
+	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+
+	report_prefix_push("broadcast");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	cpumask_copy(&mask, &cpu_present_mask);
+	cpumask_clear_cpu(0, &mask);
+	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+}
+
+static void ipi_enable(void)
+{
+	gicv2_enable_defaults();
+#ifdef __arm__
+	install_exception_handler(EXCPTN_IRQ, ipi_handler);
+#else
+	install_irq_handler(EL1H_IRQ, ipi_handler);
+#endif
+	local_irq_enable();
+}
+
+static void ipi_recv(void)
+{
+	ipi_enable();
+	cpumask_set_cpu(smp_processor_id(), &ready);
+	while (1)
+		wfi();
+}
+
+int main(int argc, char **argv)
+{
+	char pfx[8];
+	int cpu;
+
+	gic_version = gic_init();
+	if (!gic_version)
+		report_abort("No gic present!");
+
+	snprintf(pfx, 8, "gicv%d", gic_version);
+	report_prefix_push(pfx);
+
+	if (argc < 2) {
+
+		report_prefix_push("ipi");
+		ipi_enable();
+		ipi_test_self();
+		report_prefix_pop();
+
+	} else if (!strcmp(argv[1], "ipi")) {
+
+		report_prefix_push(argv[1]);
+		nr_cpu_check(2);
+		ipi_enable();
+
+		for_each_present_cpu(cpu) {
+			if (cpu == 0)
+				continue;
+			smp_boot_secondary(cpu, ipi_recv);
+		}
+		wait_on_ready();
+		ipi_test_self();
+		ipi_test_smp();
+
+		smp_rmb();
+		for_each_present_cpu(cpu) {
+			if (spurious[cpu]) {
+				printf("ipi: WARN: cpu%d got %d spurious "
+				       "interrupts\n",
+				       spurious[cpu], smp_processor_id());
+			}
+		}
+
+		report_prefix_pop();
+
+	} else {
+		report_abort("Unknown subtest '%s'", argv[1]);
+	}
+
+	return report_summary();
+}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index ffd12e5794aa0..bb364675043f0 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -51,3 +51,10 @@ file = selftest.flat
 smp = $MAX_SMP
 extra_params = -append 'smp'
 groups = selftest
+
+# Test GIC emulation
+[gicv2-ipi]
+file = gic.flat
+smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
+extra_params = -machine gic-version=2 -append 'ipi'
+groups = gic
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v2: add more details in the output if a test fails,
    report spurious interrupts if we get them
---
 arm/Makefile.common |   6 +-
 arm/gic.c           | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 arm/unittests.cfg   |   7 ++
 3 files changed, 204 insertions(+), 3 deletions(-)
 create mode 100644 arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 41239c37e0920..bc38183ab86e0 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
 	LOADADDR = 0x40000000
 endif
 
-tests-common = \
-	$(TEST_DIR)/selftest.flat \
-	$(TEST_DIR)/spinlock-test.flat
+tests-common  = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/gic.flat
 
 all: test_cases
 
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 0000000000000..cf7ec1c90413c
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,194 @@
+/*
+ * GIC tests
+ *
+ * GICv2
+ *   . test sending/receiving IPIs
+ *
+ * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.
+ */
+#include <libcflat.h>
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/gic.h>
+#include <asm/smp.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+static int gic_version;
+static int acked[NR_CPUS], spurious[NR_CPUS];
+static cpumask_t ready;
+
+static void nr_cpu_check(int nr)
+{
+	if (nr_cpus < nr)
+		report_abort("At least %d cpus required", nr);
+}
+
+static void wait_on_ready(void)
+{
+	cpumask_set_cpu(smp_processor_id(), &ready);
+	while (!cpumask_full(&ready))
+		cpu_relax();
+}
+
+static void check_acked(cpumask_t *mask)
+{
+	int missing = 0, extra = 0, unexpected = 0;
+	int nr_pass, cpu, i;
+
+	/* Wait up to 5s for all interrupts to be delivered */
+	for (i = 0; i < 50; ++i) {
+		mdelay(100);
+		nr_pass = 0;
+		for_each_present_cpu(cpu) {
+			smp_rmb();
+			nr_pass += cpumask_test_cpu(cpu, mask) ?
+				acked[cpu] == 1 : acked[cpu] == 0;
+		}
+		if (nr_pass == nr_cpus) {
+			report("Completed in %d ms", true, ++i * 100);
+			return;
+		}
+	}
+
+	for_each_present_cpu(cpu) {
+		if (cpumask_test_cpu(cpu, mask)) {
+			if (!acked[cpu])
+				++missing;
+			else if (acked[cpu] > 1)
+				++extra;
+		} else {
+			if (acked[cpu])
+				++unexpected;
+		}
+	}
+
+	report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
+	       false, missing, extra, unexpected);
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+
+	if (iar != GICC_INT_SPURIOUS) {
+		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
+		smp_rmb(); /* pairs with wmb in ipi_test functions */
+		++acked[smp_processor_id()];
+		smp_wmb(); /* pairs with rmb in check_acked */
+	} else {
+		++spurious[smp_processor_id()];
+		smp_wmb();
+	}
+}
+
+static void ipi_test_self(void)
+{
+	cpumask_t mask;
+
+	report_prefix_push("self");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	cpumask_clear(&mask);
+	cpumask_set_cpu(0, &mask);
+	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+}
+
+static void ipi_test_smp(void)
+{
+	cpumask_t mask;
+	unsigned long tlist;
+
+	report_prefix_push("target-list");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
+	cpumask_bits(&mask)[0] = tlist;
+	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+
+	report_prefix_push("broadcast");
+	memset(acked, 0, sizeof(acked));
+	smp_wmb();
+	cpumask_copy(&mask, &cpu_present_mask);
+	cpumask_clear_cpu(0, &mask);
+	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	check_acked(&mask);
+	report_prefix_pop();
+}
+
+static void ipi_enable(void)
+{
+	gicv2_enable_defaults();
+#ifdef __arm__
+	install_exception_handler(EXCPTN_IRQ, ipi_handler);
+#else
+	install_irq_handler(EL1H_IRQ, ipi_handler);
+#endif
+	local_irq_enable();
+}
+
+static void ipi_recv(void)
+{
+	ipi_enable();
+	cpumask_set_cpu(smp_processor_id(), &ready);
+	while (1)
+		wfi();
+}
+
+int main(int argc, char **argv)
+{
+	char pfx[8];
+	int cpu;
+
+	gic_version = gic_init();
+	if (!gic_version)
+		report_abort("No gic present!");
+
+	snprintf(pfx, 8, "gicv%d", gic_version);
+	report_prefix_push(pfx);
+
+	if (argc < 2) {
+
+		report_prefix_push("ipi");
+		ipi_enable();
+		ipi_test_self();
+		report_prefix_pop();
+
+	} else if (!strcmp(argv[1], "ipi")) {
+
+		report_prefix_push(argv[1]);
+		nr_cpu_check(2);
+		ipi_enable();
+
+		for_each_present_cpu(cpu) {
+			if (cpu == 0)
+				continue;
+			smp_boot_secondary(cpu, ipi_recv);
+		}
+		wait_on_ready();
+		ipi_test_self();
+		ipi_test_smp();
+
+		smp_rmb();
+		for_each_present_cpu(cpu) {
+			if (spurious[cpu]) {
+				printf("ipi: WARN: cpu%d got %d spurious "
+				       "interrupts\n",
+				       spurious[cpu], smp_processor_id());
+			}
+		}
+
+		report_prefix_pop();
+
+	} else {
+		report_abort("Unknown subtest '%s'", argv[1]);
+	}
+
+	return report_summary();
+}
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index ffd12e5794aa0..bb364675043f0 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -51,3 +51,10 @@ file = selftest.flat
 smp = $MAX_SMP
 extra_params = -append 'smp'
 groups = selftest
+
+# Test GIC emulation
+[gicv2-ipi]
+file = gic.flat
+smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
+extra_params = -machine gic-version=2 -append 'ipi'
+groups = gic
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 09/10] arm/arm64: gicv3: add an IPI test
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v2: use IRM for gicv3 broadcast
---
 arm/gic.c         | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 arm/unittests.cfg |   6 +++
 2 files changed, 154 insertions(+), 9 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index cf7ec1c90413c..fc7ef241de3e2 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -3,6 +3,8 @@
  *
  * GICv2
  *   . test sending/receiving IPIs
+ * GICv3
+ *   . test sending/receiving IPIs
  *
  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
@@ -16,6 +18,18 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
+struct gic {
+	struct {
+		void (*enable)(void);
+		void (*send_self)(void);
+		void (*send_tlist)(cpumask_t *);
+		void (*send_broadcast)(void);
+	} ipi;
+	u32 (*read_iar)(void);
+	void (*write_eoi)(u32);
+};
+
+static struct gic *gic;
 static int gic_version;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
@@ -69,12 +83,22 @@ static void check_acked(cpumask_t *mask)
 	       false, missing, extra, unexpected);
 }
 
+static u32 gicv2_read_iar(void)
+{
+	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+}
+
+static void gicv2_write_eoi(u32 irq)
+{
+	writel(irq, gicv2_cpu_base() + GIC_CPU_EOI);
+}
+
 static void ipi_handler(struct pt_regs *regs __unused)
 {
-	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	u32 iar = gic->read_iar();
 
 	if (iar != GICC_INT_SPURIOUS) {
-		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
+		gic->write_eoi(iar);
 		smp_rmb(); /* pairs with wmb in ipi_test functions */
 		++acked[smp_processor_id()];
 		smp_wmb(); /* pairs with rmb in check_acked */
@@ -84,6 +108,89 @@ static void ipi_handler(struct pt_regs *regs __unused)
 	}
 }
 
+static void gicv2_ipi_send_self(void)
+{
+	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+static void gicv2_ipi_send_tlist(cpumask_t *mask)
+{
+	u8 tlist = (u8)cpumask_bits(mask)[0];
+
+	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+static void gicv2_ipi_send_broadcast(void)
+{
+	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+#define ICC_SGI1R_AFFINITY_1_SHIFT	16
+#define ICC_SGI1R_AFFINITY_2_SHIFT	32
+#define ICC_SGI1R_AFFINITY_3_SHIFT	48
+#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
+	(MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
+
+static void gicv3_ipi_send_tlist(cpumask_t *mask)
+{
+	u16 tlist;
+	int cpu;
+
+	for_each_cpu(cpu, mask) {
+		u64 mpidr = cpus[cpu], sgi1r;
+		u64 cluster_id = mpidr & ~0xffUL;
+
+		tlist = 0;
+
+		while (cpu < nr_cpus) {
+			if ((mpidr & 0xff) >= 16) {
+				printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
+					cpu, (int)(mpidr & 0xff));
+				break;
+			}
+
+			tlist |= 1 << (mpidr & 0xf);
+
+			cpu = cpumask_next(cpu, mask);
+			if (cpu >= nr_cpus)
+				break;
+
+			mpidr = cpus[cpu];
+
+			if (cluster_id != (mpidr & ~0xffUL)) {
+				--cpu;
+				break;
+			}
+		}
+
+		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
+			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
+			 /* irq << 24				| */
+			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
+			 tlist);
+
+		gicv3_write_sgi1r(sgi1r);
+	}
+
+	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
+	isb();
+}
+
+static void gicv3_ipi_send_self(void)
+{
+	cpumask_t mask;
+
+	cpumask_clear(&mask);
+	cpumask_set_cpu(smp_processor_id(), &mask);
+	gicv3_ipi_send_tlist(&mask);
+}
+
+static void gicv3_ipi_send_broadcast(void)
+{
+	gicv3_write_sgi1r(1ULL << 40);
+	isb();
+}
+
 static void ipi_test_self(void)
 {
 	cpumask_t mask;
@@ -93,7 +200,7 @@ static void ipi_test_self(void)
 	smp_wmb();
 	cpumask_clear(&mask);
 	cpumask_set_cpu(0, &mask);
-	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
 }
@@ -101,14 +208,15 @@ static void ipi_test_self(void)
 static void ipi_test_smp(void)
 {
 	cpumask_t mask;
-	unsigned long tlist;
+	int i;
 
 	report_prefix_push("target-list");
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
-	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
-	cpumask_bits(&mask)[0] = tlist;
-	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	cpumask_copy(&mask, &cpu_present_mask);
+	for (i = 0; i < nr_cpus; i += 2)
+		cpumask_clear_cpu(i, &mask);
+	gic->ipi.send_tlist(&mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
@@ -117,14 +225,14 @@ static void ipi_test_smp(void)
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
 	cpumask_clear_cpu(0, &mask);
-	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
 }
 
 static void ipi_enable(void)
 {
-	gicv2_enable_defaults();
+	gic->ipi.enable();
 #ifdef __arm__
 	install_exception_handler(EXCPTN_IRQ, ipi_handler);
 #else
@@ -141,6 +249,28 @@ static void ipi_recv(void)
 		wfi();
 }
 
+struct gic gicv2 = {
+	.ipi = {
+		.enable = gicv2_enable_defaults,
+		.send_self = gicv2_ipi_send_self,
+		.send_tlist = gicv2_ipi_send_tlist,
+		.send_broadcast = gicv2_ipi_send_broadcast,
+	},
+	.read_iar = gicv2_read_iar,
+	.write_eoi = gicv2_write_eoi,
+};
+
+struct gic gicv3 = {
+	.ipi = {
+		.enable = gicv3_enable_defaults,
+		.send_self = gicv3_ipi_send_self,
+		.send_tlist = gicv3_ipi_send_tlist,
+		.send_broadcast = gicv3_ipi_send_broadcast,
+	},
+	.read_iar = gicv3_read_iar,
+	.write_eoi = gicv3_write_eoir,
+};
+
 int main(int argc, char **argv)
 {
 	char pfx[8];
@@ -153,6 +283,15 @@ int main(int argc, char **argv)
 	snprintf(pfx, 8, "gicv%d", gic_version);
 	report_prefix_push(pfx);
 
+	switch (gic_version) {
+	case 2:
+		gic = &gicv2;
+		break;
+	case 3:
+		gic = &gicv3;
+		break;
+	}
+
 	if (argc < 2) {
 
 		report_prefix_push("ipi");
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index bb364675043f0..043a20e26e98c 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -58,3 +58,9 @@ file = gic.flat
 smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
 extra_params = -machine gic-version=2 -append 'ipi'
 groups = gic
+
+[gicv3-ipi]
+file = gic.flat
+smp = $MAX_SMP
+extra_params = -machine gic-version=3 -append 'ipi'
+groups = gic
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 09/10] arm/arm64: gicv3: add an IPI test
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v2: use IRM for gicv3 broadcast
---
 arm/gic.c         | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 arm/unittests.cfg |   6 +++
 2 files changed, 154 insertions(+), 9 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index cf7ec1c90413c..fc7ef241de3e2 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -3,6 +3,8 @@
  *
  * GICv2
  *   . test sending/receiving IPIs
+ * GICv3
+ *   . test sending/receiving IPIs
  *
  * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
  *
@@ -16,6 +18,18 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
+struct gic {
+	struct {
+		void (*enable)(void);
+		void (*send_self)(void);
+		void (*send_tlist)(cpumask_t *);
+		void (*send_broadcast)(void);
+	} ipi;
+	u32 (*read_iar)(void);
+	void (*write_eoi)(u32);
+};
+
+static struct gic *gic;
 static int gic_version;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
@@ -69,12 +83,22 @@ static void check_acked(cpumask_t *mask)
 	       false, missing, extra, unexpected);
 }
 
+static u32 gicv2_read_iar(void)
+{
+	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+}
+
+static void gicv2_write_eoi(u32 irq)
+{
+	writel(irq, gicv2_cpu_base() + GIC_CPU_EOI);
+}
+
 static void ipi_handler(struct pt_regs *regs __unused)
 {
-	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	u32 iar = gic->read_iar();
 
 	if (iar != GICC_INT_SPURIOUS) {
-		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
+		gic->write_eoi(iar);
 		smp_rmb(); /* pairs with wmb in ipi_test functions */
 		++acked[smp_processor_id()];
 		smp_wmb(); /* pairs with rmb in check_acked */
@@ -84,6 +108,89 @@ static void ipi_handler(struct pt_regs *regs __unused)
 	}
 }
 
+static void gicv2_ipi_send_self(void)
+{
+	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+static void gicv2_ipi_send_tlist(cpumask_t *mask)
+{
+	u8 tlist = (u8)cpumask_bits(mask)[0];
+
+	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+static void gicv2_ipi_send_broadcast(void)
+{
+	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+}
+
+#define ICC_SGI1R_AFFINITY_1_SHIFT	16
+#define ICC_SGI1R_AFFINITY_2_SHIFT	32
+#define ICC_SGI1R_AFFINITY_3_SHIFT	48
+#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
+	(MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
+
+static void gicv3_ipi_send_tlist(cpumask_t *mask)
+{
+	u16 tlist;
+	int cpu;
+
+	for_each_cpu(cpu, mask) {
+		u64 mpidr = cpus[cpu], sgi1r;
+		u64 cluster_id = mpidr & ~0xffUL;
+
+		tlist = 0;
+
+		while (cpu < nr_cpus) {
+			if ((mpidr & 0xff) >= 16) {
+				printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
+					cpu, (int)(mpidr & 0xff));
+				break;
+			}
+
+			tlist |= 1 << (mpidr & 0xf);
+
+			cpu = cpumask_next(cpu, mask);
+			if (cpu >= nr_cpus)
+				break;
+
+			mpidr = cpus[cpu];
+
+			if (cluster_id != (mpidr & ~0xffUL)) {
+				--cpu;
+				break;
+			}
+		}
+
+		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
+			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
+			 /* irq << 24				| */
+			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
+			 tlist);
+
+		gicv3_write_sgi1r(sgi1r);
+	}
+
+	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
+	isb();
+}
+
+static void gicv3_ipi_send_self(void)
+{
+	cpumask_t mask;
+
+	cpumask_clear(&mask);
+	cpumask_set_cpu(smp_processor_id(), &mask);
+	gicv3_ipi_send_tlist(&mask);
+}
+
+static void gicv3_ipi_send_broadcast(void)
+{
+	gicv3_write_sgi1r(1ULL << 40);
+	isb();
+}
+
 static void ipi_test_self(void)
 {
 	cpumask_t mask;
@@ -93,7 +200,7 @@ static void ipi_test_self(void)
 	smp_wmb();
 	cpumask_clear(&mask);
 	cpumask_set_cpu(0, &mask);
-	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
 }
@@ -101,14 +208,15 @@ static void ipi_test_self(void)
 static void ipi_test_smp(void)
 {
 	cpumask_t mask;
-	unsigned long tlist;
+	int i;
 
 	report_prefix_push("target-list");
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
-	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
-	cpumask_bits(&mask)[0] = tlist;
-	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	cpumask_copy(&mask, &cpu_present_mask);
+	for (i = 0; i < nr_cpus; i += 2)
+		cpumask_clear_cpu(i, &mask);
+	gic->ipi.send_tlist(&mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
@@ -117,14 +225,14 @@ static void ipi_test_smp(void)
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
 	cpumask_clear_cpu(0, &mask);
-	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
 }
 
 static void ipi_enable(void)
 {
-	gicv2_enable_defaults();
+	gic->ipi.enable();
 #ifdef __arm__
 	install_exception_handler(EXCPTN_IRQ, ipi_handler);
 #else
@@ -141,6 +249,28 @@ static void ipi_recv(void)
 		wfi();
 }
 
+struct gic gicv2 = {
+	.ipi = {
+		.enable = gicv2_enable_defaults,
+		.send_self = gicv2_ipi_send_self,
+		.send_tlist = gicv2_ipi_send_tlist,
+		.send_broadcast = gicv2_ipi_send_broadcast,
+	},
+	.read_iar = gicv2_read_iar,
+	.write_eoi = gicv2_write_eoi,
+};
+
+struct gic gicv3 = {
+	.ipi = {
+		.enable = gicv3_enable_defaults,
+		.send_self = gicv3_ipi_send_self,
+		.send_tlist = gicv3_ipi_send_tlist,
+		.send_broadcast = gicv3_ipi_send_broadcast,
+	},
+	.read_iar = gicv3_read_iar,
+	.write_eoi = gicv3_write_eoir,
+};
+
 int main(int argc, char **argv)
 {
 	char pfx[8];
@@ -153,6 +283,15 @@ int main(int argc, char **argv)
 	snprintf(pfx, 8, "gicv%d", gic_version);
 	report_prefix_push(pfx);
 
+	switch (gic_version) {
+	case 2:
+		gic = &gicv2;
+		break;
+	case 3:
+		gic = &gicv3;
+		break;
+	}
+
 	if (argc < 2) {
 
 		report_prefix_push("ipi");
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index bb364675043f0..043a20e26e98c 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -58,3 +58,9 @@ file = gic.flat
 smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
 extra_params = -machine gic-version=2 -append 'ipi'
 groups = gic
+
+[gicv3-ipi]
+file = gic.flat
+smp = $MAX_SMP
+extra_params = -machine gic-version=3 -append 'ipi'
+groups = gic
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [kvm-unit-tests PATCH v3 10/10] arm/arm64: gic: don't just use zero
  2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
@ 2016-07-15 13:00   ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Allow user to select who sends ipis and with which irq,
rather than just always sending irq=0 from cpu0.

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v2: actually check that the irq received was the irq sent,
    and (for gicv2) that the sender is the expected one.
---
 arm/gic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 64 insertions(+), 16 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index fc7ef241de3e2..d3ab97d4ae470 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -11,6 +11,7 @@
  * This work is licensed under the terms of the GNU LGPL, version 2.
  */
 #include <libcflat.h>
+#include <util.h>
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/gic.h>
@@ -33,6 +34,8 @@ static struct gic *gic;
 static int gic_version;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
+static int sender;
+static u32 irq;
 
 static void nr_cpu_check(int nr)
 {
@@ -85,7 +88,16 @@ static void check_acked(cpumask_t *mask)
 
 static u32 gicv2_read_iar(void)
 {
-	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	int src = (iar >> 10) & 7;
+
+	if (src != sender) {
+		report("cpu%d received IPI from unexpected source cpu%d "
+		       "(expected cpu%d)",
+		       false, smp_processor_id(), src, sender);
+	}
+
+	return iar & 0x3ff;
 }
 
 static void gicv2_write_eoi(u32 irq)
@@ -99,9 +111,15 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 	if (iar != GICC_INT_SPURIOUS) {
 		gic->write_eoi(iar);
-		smp_rmb(); /* pairs with wmb in ipi_test functions */
-		++acked[smp_processor_id()];
-		smp_wmb(); /* pairs with rmb in check_acked */
+		if (iar == irq) {
+			smp_rmb(); /* pairs with wmb in ipi_test functions */
+			++acked[smp_processor_id()];
+			smp_wmb(); /* pairs with rmb in check_acked */
+		} else {
+			report("cpu%d received unexpected irq %u "
+			       "(expected %u)",
+			       false, smp_processor_id(), iar, irq);
+		}
 	} else {
 		++spurious[smp_processor_id()];
 		smp_wmb();
@@ -110,19 +128,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 static void gicv2_ipi_send_self(void)
 {
-	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(2 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 static void gicv2_ipi_send_tlist(cpumask_t *mask)
 {
 	u8 tlist = (u8)cpumask_bits(mask)[0];
 
-	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(tlist << 16 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 static void gicv2_ipi_send_broadcast(void)
 {
-	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(1 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 #define ICC_SGI1R_AFFINITY_1_SHIFT	16
@@ -165,7 +183,7 @@ static void gicv3_ipi_send_tlist(cpumask_t *mask)
 
 		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
 			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
-			 /* irq << 24				| */
+			 irq << 24				|
 			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
 			 tlist);
 
@@ -187,7 +205,7 @@ static void gicv3_ipi_send_self(void)
 
 static void gicv3_ipi_send_broadcast(void)
 {
-	gicv3_write_sgi1r(1ULL << 40);
+	gicv3_write_sgi1r(1ULL << 40 | irq << 24);
 	isb();
 }
 
@@ -199,7 +217,7 @@ static void ipi_test_self(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_clear(&mask);
-	cpumask_set_cpu(0, &mask);
+	cpumask_set_cpu(smp_processor_id(), &mask);
 	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
@@ -214,7 +232,7 @@ static void ipi_test_smp(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
-	for (i = 0; i < nr_cpus; i += 2)
+	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
 		cpumask_clear_cpu(i, &mask);
 	gic->ipi.send_tlist(&mask);
 	check_acked(&mask);
@@ -224,7 +242,7 @@ static void ipi_test_smp(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
-	cpumask_clear_cpu(0, &mask);
+	cpumask_clear_cpu(smp_processor_id(), &mask);
 	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
@@ -241,6 +259,15 @@ static void ipi_enable(void)
 	local_irq_enable();
 }
 
+static void ipi_send(void)
+{
+	ipi_enable();
+	wait_on_ready();
+	ipi_test_self();
+	ipi_test_smp();
+	exit(report_summary());
+}
+
 static void ipi_recv(void)
 {
 	ipi_enable();
@@ -300,19 +327,40 @@ int main(int argc, char **argv)
 		report_prefix_pop();
 
 	} else if (!strcmp(argv[1], "ipi")) {
+		int off, i = 1;
+		long val;
 
 		report_prefix_push(argv[1]);
+
+		while (--argc != 1) {
+			off = parse_keyval(argv[++i], &val);
+			if (off == -1)
+				continue;
+			argv[i][off] = '\0';
+			if (strcmp(argv[i], "sender") == 0)
+				sender = val;
+			else if (strcmp(argv[i], "irq") == 0)
+				irq = val;
+		}
+
 		nr_cpu_check(2);
 		ipi_enable();
 
 		for_each_present_cpu(cpu) {
 			if (cpu == 0)
 				continue;
-			smp_boot_secondary(cpu, ipi_recv);
+			if (cpu == sender)
+				smp_boot_secondary(cpu, ipi_send);
+			else
+				smp_boot_secondary(cpu, ipi_recv);
+		}
+		if (sender == 0)  {
+			wait_on_ready();
+			ipi_test_self();
+			ipi_test_smp();
+		} else {
+			ipi_recv();
 		}
-		wait_on_ready();
-		ipi_test_self();
-		ipi_test_smp();
 
 		smp_rmb();
 		for_each_present_cpu(cpu) {
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 51+ messages in thread

* [Qemu-devel] [kvm-unit-tests PATCH v3 10/10] arm/arm64: gic: don't just use zero
@ 2016-07-15 13:00   ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-07-15 13:00 UTC (permalink / raw)
  To: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

Allow user to select who sends ipis and with which irq,
rather than just always sending irq=0 from cpu0.

Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v2: actually check that the irq received was the irq sent,
    and (for gicv2) that the sender is the expected one.
---
 arm/gic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 64 insertions(+), 16 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index fc7ef241de3e2..d3ab97d4ae470 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -11,6 +11,7 @@
  * This work is licensed under the terms of the GNU LGPL, version 2.
  */
 #include <libcflat.h>
+#include <util.h>
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/gic.h>
@@ -33,6 +34,8 @@ static struct gic *gic;
 static int gic_version;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
+static int sender;
+static u32 irq;
 
 static void nr_cpu_check(int nr)
 {
@@ -85,7 +88,16 @@ static void check_acked(cpumask_t *mask)
 
 static u32 gicv2_read_iar(void)
 {
-	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
+	int src = (iar >> 10) & 7;
+
+	if (src != sender) {
+		report("cpu%d received IPI from unexpected source cpu%d "
+		       "(expected cpu%d)",
+		       false, smp_processor_id(), src, sender);
+	}
+
+	return iar & 0x3ff;
 }
 
 static void gicv2_write_eoi(u32 irq)
@@ -99,9 +111,15 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 	if (iar != GICC_INT_SPURIOUS) {
 		gic->write_eoi(iar);
-		smp_rmb(); /* pairs with wmb in ipi_test functions */
-		++acked[smp_processor_id()];
-		smp_wmb(); /* pairs with rmb in check_acked */
+		if (iar == irq) {
+			smp_rmb(); /* pairs with wmb in ipi_test functions */
+			++acked[smp_processor_id()];
+			smp_wmb(); /* pairs with rmb in check_acked */
+		} else {
+			report("cpu%d received unexpected irq %u "
+			       "(expected %u)",
+			       false, smp_processor_id(), iar, irq);
+		}
 	} else {
 		++spurious[smp_processor_id()];
 		smp_wmb();
@@ -110,19 +128,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 static void gicv2_ipi_send_self(void)
 {
-	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(2 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 static void gicv2_ipi_send_tlist(cpumask_t *mask)
 {
 	u8 tlist = (u8)cpumask_bits(mask)[0];
 
-	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(tlist << 16 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 static void gicv2_ipi_send_broadcast(void)
 {
-	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
+	writel(1 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
 }
 
 #define ICC_SGI1R_AFFINITY_1_SHIFT	16
@@ -165,7 +183,7 @@ static void gicv3_ipi_send_tlist(cpumask_t *mask)
 
 		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
 			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
-			 /* irq << 24				| */
+			 irq << 24				|
 			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
 			 tlist);
 
@@ -187,7 +205,7 @@ static void gicv3_ipi_send_self(void)
 
 static void gicv3_ipi_send_broadcast(void)
 {
-	gicv3_write_sgi1r(1ULL << 40);
+	gicv3_write_sgi1r(1ULL << 40 | irq << 24);
 	isb();
 }
 
@@ -199,7 +217,7 @@ static void ipi_test_self(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_clear(&mask);
-	cpumask_set_cpu(0, &mask);
+	cpumask_set_cpu(smp_processor_id(), &mask);
 	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
@@ -214,7 +232,7 @@ static void ipi_test_smp(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
-	for (i = 0; i < nr_cpus; i += 2)
+	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
 		cpumask_clear_cpu(i, &mask);
 	gic->ipi.send_tlist(&mask);
 	check_acked(&mask);
@@ -224,7 +242,7 @@ static void ipi_test_smp(void)
 	memset(acked, 0, sizeof(acked));
 	smp_wmb();
 	cpumask_copy(&mask, &cpu_present_mask);
-	cpumask_clear_cpu(0, &mask);
+	cpumask_clear_cpu(smp_processor_id(), &mask);
 	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
@@ -241,6 +259,15 @@ static void ipi_enable(void)
 	local_irq_enable();
 }
 
+static void ipi_send(void)
+{
+	ipi_enable();
+	wait_on_ready();
+	ipi_test_self();
+	ipi_test_smp();
+	exit(report_summary());
+}
+
 static void ipi_recv(void)
 {
 	ipi_enable();
@@ -300,19 +327,40 @@ int main(int argc, char **argv)
 		report_prefix_pop();
 
 	} else if (!strcmp(argv[1], "ipi")) {
+		int off, i = 1;
+		long val;
 
 		report_prefix_push(argv[1]);
+
+		while (--argc != 1) {
+			off = parse_keyval(argv[++i], &val);
+			if (off == -1)
+				continue;
+			argv[i][off] = '\0';
+			if (strcmp(argv[i], "sender") == 0)
+				sender = val;
+			else if (strcmp(argv[i], "irq") == 0)
+				irq = val;
+		}
+
 		nr_cpu_check(2);
 		ipi_enable();
 
 		for_each_present_cpu(cpu) {
 			if (cpu == 0)
 				continue;
-			smp_boot_secondary(cpu, ipi_recv);
+			if (cpu == sender)
+				smp_boot_secondary(cpu, ipi_send);
+			else
+				smp_boot_secondary(cpu, ipi_recv);
+		}
+		if (sender == 0)  {
+			wait_on_ready();
+			ipi_test_self();
+			ipi_test_smp();
+		} else {
+			ipi_recv();
 		}
-		wait_on_ready();
-		ipi_test_self();
-		ipi_test_smp();
 
 		smp_rmb();
 		for_each_present_cpu(cpu) {
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 01/10] lib: xstr: allow multiple args
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
@ 2016-08-30 14:28     ` Auger Eric
  -1 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-08-30 14:28 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier


Hi Drew,
On 15/07/2016 15:00, Andrew Jones wrote:
> Make implementation equivalent to Linux's include/linux/stringify.h
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/libcflat.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index 72b1bf9668ef1..82005f5d014fb 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -27,8 +27,8 @@
>  
>  #define __unused __attribute__((__unused__))
>  
> -#define xstr(s) xxstr(s)
> -#define xxstr(s) #s
> +#define xstr(s...) xxstr(s)
> +#define xxstr(s...) #s
>  
>  #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
>  #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
> 
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 01/10] lib: xstr: allow multiple args
@ 2016-08-30 14:28     ` Auger Eric
  0 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-08-30 14:28 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall


Hi Drew,
On 15/07/2016 15:00, Andrew Jones wrote:
> Make implementation equivalent to Linux's include/linux/stringify.h
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/libcflat.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index 72b1bf9668ef1..82005f5d014fb 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -27,8 +27,8 @@
>  
>  #define __unused __attribute__((__unused__))
>  
> -#define xstr(s) xxstr(s)
> -#define xxstr(s) #s
> +#define xstr(s...) xxstr(s)
> +#define xxstr(s...) #s
>  
>  #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
>  #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
> 
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 02/10] arm64: fix get_"sysreg32" and make MPIDR 64bit
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-08-30 14:28   ` Auger Eric
  -1 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-08-30 14:28 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi,

On 15/07/2016 15:00, Andrew Jones wrote:
> mrs is always 64bit, so we should always use a 64bit register.
> Sometimes we'll only want to return the lower 32, but not for
> MPIDR, as that does define fields in the upper 32.
> 
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/arm64/asm/processor.h | 15 +++++++++------
>  1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 84d5c7ce752b0..9a208ff729b7e 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -66,14 +66,17 @@ static inline unsigned long current_level(void)
>  	return el & 0xc;
>  }
>  
> -#define DEFINE_GET_SYSREG32(reg)				\
> -static inline unsigned int get_##reg(void)			\
> +#define DEFINE_GET_SYSREG(reg, type)				\
> +static inline type get_##reg(void)				\
>  {								\
> -	unsigned int reg;					\
> -	asm volatile("mrs %0, " #reg "_el1" : "=r" (reg));	\
> -	return reg;						\
> +	unsigned long r;					\
> +	asm volatile("mrs %0, " #reg "_el1" : "=r" (r));	\
> +	return (type)r;						\
>  }
> -DEFINE_GET_SYSREG32(mpidr)
> +#define DEFINE_GET_SYSREG32(reg) DEFINE_GET_SYSREG(reg, unsigned int)
> +#define DEFINE_GET_SYSREG64(reg) DEFINE_GET_SYSREG(reg, unsigned long)
> +
> +DEFINE_GET_SYSREG64(mpidr)
>  
>  /* Only support Aff0 for now, gicv2 only */
>  #define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> 
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-08-30 14:28   ` Auger Eric
  2016-08-31 22:01     ` Auger Eric
  2016-10-17 12:24       ` Andrew Jones
  -1 siblings, 2 replies; 51+ messages in thread
From: Auger Eric @ 2016-08-30 14:28 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi Drew,

Proper commit message?
... also selects the vgic model corresponding to the host
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  arm/run                   | 19 ++++++++++++-------
>  arm/selftest.c            |  5 ++++-
>  lib/arm/asm/processor.h   |  9 +++++++--
>  lib/arm/asm/setup.h       |  4 ++--
>  lib/arm/setup.c           | 12 +++++++++++-
>  lib/arm64/asm/processor.h |  9 +++++++--
>  6 files changed, 43 insertions(+), 15 deletions(-)
> 
> diff --git a/arm/run b/arm/run
> index a2f35ef6a7e63..2d0698619606e 100755
> --- a/arm/run
> +++ b/arm/run
> @@ -31,13 +31,6 @@ if [ -z "$ACCEL" ]; then
>  	fi
>  fi
>  
> -if [ "$HOST" = "aarch64" ] && [ "$ACCEL" = "kvm" ]; then
> -	processor="host"
> -	if [ "$ARCH" = "arm" ]; then
> -		processor+=",aarch64=off"
> -	fi
> -fi
> -
>  qemu="${QEMU:-qemu-system-$ARCH_NAME}"
>  qpath=$(which $qemu 2>/dev/null)
>  
> @@ -53,6 +46,18 @@ fi
>  
>  M='-machine virt'
>  
> +if [ "$ACCEL" = "kvm" ]; then
> +	if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then
> +		M+=',gic-version=host'
> +	fi
> +	if [ "$HOST" = "aarch64" ]; then
> +		processor="host"
> +		if [ "$ARCH" = "arm" ]; then
> +			processor+=",aarch64=off"
> +		fi
> +	fi
> +fi
> +
>  if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then
>  	echo "$qpath doesn't support virtio-console for chr-testdev. Exiting."
>  	exit 2
> diff --git a/arm/selftest.c b/arm/selftest.c
> index 196164f5313de..2f117f795d2dc 100644
> --- a/arm/selftest.c
> +++ b/arm/selftest.c
> @@ -312,9 +312,10 @@ static bool psci_check(void)
>  static cpumask_t smp_reported;
>  static void cpu_report(void)
>  {
> +	unsigned long mpidr = get_mpidr();
>  	int cpu = smp_processor_id();
>  
> -	report("CPU%d online", true, cpu);
> +	report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
>  	cpumask_set_cpu(cpu, &smp_reported);
>  	halt();
>  }
> @@ -343,6 +344,7 @@ int main(int argc, char **argv)
>  
>  	} else if (strcmp(argv[1], "smp") == 0) {
>  
> +		unsigned long mpidr = get_mpidr();
>  		int cpu;
>  
>  		report("PSCI version", psci_check());
> @@ -353,6 +355,7 @@ int main(int argc, char **argv)
>  			smp_boot_secondary(cpu, cpu_report);
>  		}
>  
> +		report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == 0, 0, mpidr);
>  		cpumask_set_cpu(0, &smp_reported);
>  		while (!cpumask_full(&smp_reported))
>  			cpu_relax();
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index f25e7eee3666c..d2048f5f5f7e6 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -40,8 +40,13 @@ static inline unsigned int get_mpidr(void)
>  	return mpidr;
>  }
>  
> -/* Only support Aff0 for now, up to 4 cpus */
> -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> +#define MPIDR_HWID_BITMASK 0xffffff
> +extern int mpidr_to_cpu(unsigned long mpidr);
> +
> +#define MPIDR_LEVEL_SHIFT(level) \
> +	(((1 << level) >> 1) << 3)
can't we have level << 3?
> +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
>  
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
> diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
> index cb8fdbd38dd5d..c501c6ddd8657 100644
> --- a/lib/arm/asm/setup.h
> +++ b/lib/arm/asm/setup.h
> @@ -10,8 +10,8 @@
>  #include <asm/page.h>
>  #include <asm/pgtable-hwdef.h>
>  
> -#define NR_CPUS			8
> -extern u32 cpus[NR_CPUS];
> +#define NR_CPUS			255
256?
> +extern u64 cpus[NR_CPUS];
maybe worth commenting the semantic of cpus[i]?
>  extern int nr_cpus;
what about MAX_CPUS instead of NR_CPUS?
>  
>  #define NR_MEM_REGIONS		8
> diff --git a/lib/arm/setup.c b/lib/arm/setup.c
> index 7e7b39f11dde1..b6e2d5815e723 100644
> --- a/lib/arm/setup.c
> +++ b/lib/arm/setup.c
> @@ -24,12 +24,22 @@ extern unsigned long stacktop;
>  extern void io_init(void);
>  extern void setup_args_progname(const char *args);
>  
> -u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
> +u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
>  int nr_cpus;
>  
>  struct mem_region mem_regions[NR_MEM_REGIONS];
>  phys_addr_t __phys_offset, __phys_end;
>  
> +int mpidr_to_cpu(unsigned long mpidr)
> +{
> +	int i;
> +
> +	for (i = 0; i < nr_cpus; ++i)
> +		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
> +			return i;
> +	return -1;
> +}
> +
>  static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
>  {
>  	int cpu = nr_cpus++;
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 9a208ff729b7e..7e448dc81a6aa 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -78,8 +78,13 @@ static inline type get_##reg(void)				\
>  
>  DEFINE_GET_SYSREG64(mpidr)
>  
> -/* Only support Aff0 for now, gicv2 only */
> -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> +#define MPIDR_HWID_BITMASK 0xff00ffffff
> +extern int mpidr_to_cpu(unsigned long mpidr);
> +
> +#define MPIDR_LEVEL_SHIFT(level) \
> +	(((1 << level) >> 1) << 3)
what about level 3? the macro would fail fetching affinity level 3.

Thanks

Eric
> +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
>  
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus
  2016-08-30 14:28   ` Auger Eric
@ 2016-08-31 22:01     ` Auger Eric
  2016-10-17 12:24       ` Andrew Jones
  1 sibling, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-08-31 22:01 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi Drew,

On 30/08/2016 16:28, Auger Eric wrote:
> Hi Drew,
> 
> Proper commit message?
> ... also selects the vgic model corresponding to the host
>> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
>> Signed-off-by: Andrew Jones <drjones@redhat.com>
>> ---
>>  arm/run                   | 19 ++++++++++++-------
>>  arm/selftest.c            |  5 ++++-
>>  lib/arm/asm/processor.h   |  9 +++++++--
>>  lib/arm/asm/setup.h       |  4 ++--
>>  lib/arm/setup.c           | 12 +++++++++++-
>>  lib/arm64/asm/processor.h |  9 +++++++--
>>  6 files changed, 43 insertions(+), 15 deletions(-)
>>
>> diff --git a/arm/run b/arm/run
>> index a2f35ef6a7e63..2d0698619606e 100755
>> --- a/arm/run
>> +++ b/arm/run
>> @@ -31,13 +31,6 @@ if [ -z "$ACCEL" ]; then
>>  	fi
>>  fi
>>  
>> -if [ "$HOST" = "aarch64" ] && [ "$ACCEL" = "kvm" ]; then
>> -	processor="host"
>> -	if [ "$ARCH" = "arm" ]; then
>> -		processor+=",aarch64=off"
>> -	fi
>> -fi
>> -
>>  qemu="${QEMU:-qemu-system-$ARCH_NAME}"
>>  qpath=$(which $qemu 2>/dev/null)
>>  
>> @@ -53,6 +46,18 @@ fi
>>  
>>  M='-machine virt'
>>  
>> +if [ "$ACCEL" = "kvm" ]; then
>> +	if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then
>> +		M+=',gic-version=host'
>> +	fi
>> +	if [ "$HOST" = "aarch64" ]; then
>> +		processor="host"
>> +		if [ "$ARCH" = "arm" ]; then
>> +			processor+=",aarch64=off"
>> +		fi
>> +	fi
>> +fi
>> +
>>  if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then
>>  	echo "$qpath doesn't support virtio-console for chr-testdev. Exiting."
>>  	exit 2
>> diff --git a/arm/selftest.c b/arm/selftest.c
>> index 196164f5313de..2f117f795d2dc 100644
>> --- a/arm/selftest.c
>> +++ b/arm/selftest.c
>> @@ -312,9 +312,10 @@ static bool psci_check(void)
>>  static cpumask_t smp_reported;
>>  static void cpu_report(void)
>>  {
>> +	unsigned long mpidr = get_mpidr();
>>  	int cpu = smp_processor_id();
>>  
>> -	report("CPU%d online", true, cpu);
>> +	report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
>>  	cpumask_set_cpu(cpu, &smp_reported);
>>  	halt();
>>  }
>> @@ -343,6 +344,7 @@ int main(int argc, char **argv)
>>  
>>  	} else if (strcmp(argv[1], "smp") == 0) {
>>  
>> +		unsigned long mpidr = get_mpidr();
>>  		int cpu;
>>  
>>  		report("PSCI version", psci_check());
>> @@ -353,6 +355,7 @@ int main(int argc, char **argv)
>>  			smp_boot_secondary(cpu, cpu_report);
>>  		}
>>  
>> +		report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == 0, 0, mpidr);
>>  		cpumask_set_cpu(0, &smp_reported);
>>  		while (!cpumask_full(&smp_reported))
>>  			cpu_relax();
>> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
>> index f25e7eee3666c..d2048f5f5f7e6 100644
>> --- a/lib/arm/asm/processor.h
>> +++ b/lib/arm/asm/processor.h
>> @@ -40,8 +40,13 @@ static inline unsigned int get_mpidr(void)
>>  	return mpidr;
>>  }
>>  
>> -/* Only support Aff0 for now, up to 4 cpus */
>> -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
>> +#define MPIDR_HWID_BITMASK 0xffffff
>> +extern int mpidr_to_cpu(unsigned long mpidr);
>> +
>> +#define MPIDR_LEVEL_SHIFT(level) \
>> +	(((1 << level) >> 1) << 3)
> can't we have level << 3?
Forget this, see below
>> +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
>> +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
>>  
>>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>>  extern bool is_user(void);
>> diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
>> index cb8fdbd38dd5d..c501c6ddd8657 100644
>> --- a/lib/arm/asm/setup.h
>> +++ b/lib/arm/asm/setup.h
>> @@ -10,8 +10,8 @@
>>  #include <asm/page.h>
>>  #include <asm/pgtable-hwdef.h>
>>  
>> -#define NR_CPUS			8
>> -extern u32 cpus[NR_CPUS];
>> +#define NR_CPUS			255
> 256?
>> +extern u64 cpus[NR_CPUS];
> maybe worth commenting the semantic of cpus[i]?
>>  extern int nr_cpus;
> what about MAX_CPUS instead of NR_CPUS?
>>  
>>  #define NR_MEM_REGIONS		8
>> diff --git a/lib/arm/setup.c b/lib/arm/setup.c
>> index 7e7b39f11dde1..b6e2d5815e723 100644
>> --- a/lib/arm/setup.c
>> +++ b/lib/arm/setup.c
>> @@ -24,12 +24,22 @@ extern unsigned long stacktop;
>>  extern void io_init(void);
>>  extern void setup_args_progname(const char *args);
>>  
>> -u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
>> +u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
>>  int nr_cpus;
>>  
>>  struct mem_region mem_regions[NR_MEM_REGIONS];
>>  phys_addr_t __phys_offset, __phys_end;
>>  
>> +int mpidr_to_cpu(unsigned long mpidr)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < nr_cpus; ++i)
>> +		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
>> +			return i;
>> +	return -1;
>> +}
>> +
>>  static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
>>  {
>>  	int cpu = nr_cpus++;
>> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
>> index 9a208ff729b7e..7e448dc81a6aa 100644
>> --- a/lib/arm64/asm/processor.h
>> +++ b/lib/arm64/asm/processor.h
>> @@ -78,8 +78,13 @@ static inline type get_##reg(void)				\
>>  
>>  DEFINE_GET_SYSREG64(mpidr)
>>  
>> -/* Only support Aff0 for now, gicv2 only */
>> -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
>> +#define MPIDR_HWID_BITMASK 0xff00ffffff
>> +extern int mpidr_to_cpu(unsigned long mpidr);
>> +
>> +#define MPIDR_LEVEL_SHIFT(level) \
>> +	(((1 << level) >> 1) << 3)
> what about level 3? the macro would fail fetching affinity level 3.
Forget that remark too. I read the magic behind in the patch's history.
Sorry for the noise.

Thanks

Eric
> 
> Thanks
> 
> Eric
>> +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
>> +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
>>  
>>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>>  extern bool is_user(void);
>>

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 04/10] arm/arm64: add some delay routines
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-09-01 10:19   ` Auger Eric
  -1 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-09-01 10:19 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi Drew,

On 15/07/2016 15:00, Andrew Jones wrote:
> Allow a thread to wait some specified amount of time. Can
> specify in cycles, usecs, and msecs.
> 
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/arm/asm/processor.h   | 19 +++++++++++++++++++
>  lib/arm/processor.c       | 15 +++++++++++++++
>  lib/arm64/asm/processor.h | 19 +++++++++++++++++++
>  lib/arm64/processor.c     | 15 +++++++++++++++
>  4 files changed, 68 insertions(+)
> 
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index d2048f5f5f7e6..afc903ca7d4ab 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -5,7 +5,9 @@
>   *
>   * This work is licensed under the terms of the GNU LGPL, version 2.
>   */
> +#include <libcflat.h>
>  #include <asm/ptrace.h>
> +#include <asm/barrier.h>
>  
>  enum vector {
>  	EXCPTN_RST,
> @@ -51,4 +53,21 @@ extern int mpidr_to_cpu(unsigned long mpidr);
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
>  
> +static inline u64 get_cntvct(void)
> +{
> +	u64 vct;
> +	isb();
> +	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (vct));
> +	return vct;
> +}
> +
> +extern void delay(u64 cycles);
> +extern void udelay(unsigned long usecs);
> +
> +static inline void mdelay(unsigned long msecs)
> +{
> +	while (msecs--)
> +		udelay(1000);
> +}
> +
>  #endif /* _ASMARM_PROCESSOR_H_ */
> diff --git a/lib/arm/processor.c b/lib/arm/processor.c
> index 54fdb87ef0196..c2ee360df6884 100644
> --- a/lib/arm/processor.c
> +++ b/lib/arm/processor.c
> @@ -9,6 +9,7 @@
>  #include <asm/ptrace.h>
>  #include <asm/processor.h>
>  #include <asm/thread_info.h>
> +#include <asm/barrier.h>
>  
>  static const char *processor_modes[] = {
>  	"USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" ,
> @@ -141,3 +142,17 @@ bool is_user(void)
>  {
>  	return current_thread_info()->flags & TIF_USER_MODE;
>  }
> +
> +void delay(u64 cycles)
> +{
> +	u64 start = get_cntvct();
> +	while ((get_cntvct() - start) < cycles)
> +		cpu_relax();
> +}
> +
> +void udelay(unsigned long usec)
> +{
> +	unsigned int frq;
> +	asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (frq));
> +	delay((u64)usec * frq / 1000000);
> +}
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 7e448dc81a6aa..94f7ce35b65c1 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -17,8 +17,10 @@
>  #define SCTLR_EL1_M	(1 << 0)
>  
>  #ifndef __ASSEMBLY__
> +#include <libcflat.h>
>  #include <asm/ptrace.h>
>  #include <asm/esr.h>
> +#include <asm/barrier.h>
>  
>  enum vector {
>  	EL1T_SYNC,
> @@ -89,5 +91,22 @@ extern int mpidr_to_cpu(unsigned long mpidr);
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
>  
> +static inline u64 get_cntvct(void)
> +{
> +	u64 vct;
> +	isb();
> +	asm volatile("mrs %0, cntvct_el0" : "=r" (vct));
> +	return vct;
> +}
> +
> +extern void delay(u64 cycles);
> +extern void udelay(unsigned long usecs);
> +
> +static inline void mdelay(unsigned long msecs)
> +{
> +	while (msecs--)
> +		udelay(1000);
> +}
> +
>  #endif /* !__ASSEMBLY__ */
>  #endif /* _ASMARM64_PROCESSOR_H_ */
> diff --git a/lib/arm64/processor.c b/lib/arm64/processor.c
> index deeab4ec9c8ac..50fa835c6f1e3 100644
> --- a/lib/arm64/processor.c
> +++ b/lib/arm64/processor.c
> @@ -9,6 +9,7 @@
>  #include <asm/ptrace.h>
>  #include <asm/processor.h>
>  #include <asm/thread_info.h>
> +#include <asm/barrier.h>
>  
>  static const char *vector_names[] = {
>  	"el1t_sync",
> @@ -253,3 +254,17 @@ bool is_user(void)
>  {
>  	return current_thread_info()->flags & TIF_USER_MODE;
>  }
> +
> +void delay(u64 cycles)
> +{
> +	u64 start = get_cntvct();
> +	while ((get_cntvct() - start) < cycles)
> +		cpu_relax();
> +}
> +
> +void udelay(unsigned long usec)
> +{
> +	unsigned int frq;
> +	asm volatile("mrs %0, cntfrq_el0" : "=r" (frq));
> +	delay((u64)usec * frq / 1000000);
> +}
> 
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 05/10] arm/arm64: irq enable/disable
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-09-01 10:19   ` Auger Eric
  -1 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-09-01 10:19 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi,

On 15/07/2016 15:00, Andrew Jones wrote:
> Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  lib/arm/asm/processor.h   | 10 ++++++++++
>  lib/arm64/asm/processor.h | 10 ++++++++++
>  2 files changed, 20 insertions(+)
> 
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index afc903ca7d4ab..75a8d08b89330 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -35,6 +35,16 @@ static inline unsigned long current_cpsr(void)
>  
>  #define current_mode() (current_cpsr() & MODE_MASK)
>  
> +static inline void local_irq_enable(void)
> +{
> +	asm volatile("cpsie i" : : : "memory", "cc");
> +}
> +
> +static inline void local_irq_disable(void)
> +{
> +	asm volatile("cpsid i" : : : "memory", "cc");
> +}
> +
>  static inline unsigned int get_mpidr(void)
>  {
>  	unsigned int mpidr;
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 94f7ce35b65c1..d54a4ed1c1876 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -68,6 +68,16 @@ static inline unsigned long current_level(void)
>  	return el & 0xc;
>  }
>  
> +static inline void local_irq_enable(void)
> +{
> +	asm volatile("msr daifclr, #2" : : : "memory");
> +}
> +
> +static inline void local_irq_disable(void)
> +{
> +	asm volatile("msr daifset, #2" : : : "memory");
> +}
> +
>  #define DEFINE_GET_SYSREG(reg, type)				\
>  static inline type get_##reg(void)				\
>  {								\
> 
Besides the non existing commit msg - looks like the kvm-unit-tests
practices are different from kernel ones ;-)-,

Reviewed-by: Eric Auger <eric.auger@redhat.com>

Eric

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
@ 2016-09-01 10:19     ` Auger Eric
  -1 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-09-01 10:19 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier

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_ */
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
@ 2016-09-01 10:19     ` Auger Eric
  0 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-09-01 10:19 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

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_ */
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
@ 2016-09-01 10:20     ` Auger Eric
  -1 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-09-01 10:20 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier



On 15/07/2016 15:00, Andrew Jones wrote:
> Add some gicv2 support. This just adds init and enable
> functions, allowing unit tests to start messing with it.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  arm/Makefile.common    |  1 +
>  lib/arm/asm/gic-v2.h   | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm/asm/gic.h      | 20 ++++++++++++++
>  lib/arm/gic.c          | 69 ++++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm64/asm/gic-v2.h |  1 +
>  lib/arm64/asm/gic.h    |  1 +
>  6 files changed, 166 insertions(+)
>  create mode 100644 lib/arm/asm/gic-v2.h
>  create mode 100644 lib/arm/asm/gic.h
>  create mode 100644 lib/arm/gic.c
>  create mode 100644 lib/arm64/asm/gic-v2.h
>  create mode 100644 lib/arm64/asm/gic.h
> 
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index ccb554d9251a4..41239c37e0920 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/gic.o
>  
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
> new file mode 100644
> index 0000000000000..973c2bf3cc796
> --- /dev/null
> +++ b/lib/arm/asm/gic-v2.h
> @@ -0,0 +1,74 @@
> +/*
> + * All GIC* defines are lifted from include/linux/irqchip/arm-gic.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_V2_H_
> +#define _ASMARM_GIC_V2_H_
> +
> +#define GIC_CPU_CTRL			0x00
> +#define GIC_CPU_PRIMASK			0x04
> +#define GIC_CPU_BINPOINT		0x08
> +#define GIC_CPU_INTACK			0x0c
> +#define GIC_CPU_EOI			0x10
> +#define GIC_CPU_RUNNINGPRI		0x14
> +#define GIC_CPU_HIGHPRI			0x18
> +#define GIC_CPU_ALIAS_BINPOINT		0x1c
> +#define GIC_CPU_ACTIVEPRIO		0xd0
> +#define GIC_CPU_IDENT			0xfc
> +#define GIC_CPU_DEACTIVATE		0x1000
> +
> +#define GICC_ENABLE			0x1
> +#define GICC_INT_PRI_THRESHOLD		0xf0
> +
> +#define GIC_CPU_CTRL_EOImodeNS		(1 << 9)
> +
> +#define GICC_IAR_INT_ID_MASK		0x3ff
> +#define GICC_INT_SPURIOUS		1023
> +#define GICC_DIS_BYPASS_MASK		0x1e0
> +
> +#define GIC_DIST_CTRL			0x000
> +#define GIC_DIST_CTR			0x004
you could add #define GIC_DIST_IIDR			0x008
which can be found in arm-gic.h
> +#define GIC_DIST_IGROUP			0x080
> +#define GIC_DIST_ENABLE_SET		0x100
> +#define GIC_DIST_ENABLE_CLEAR		0x180
> +#define GIC_DIST_PENDING_SET		0x200
> +#define GIC_DIST_PENDING_CLEAR		0x280
> +#define GIC_DIST_ACTIVE_SET		0x300
> +#define GIC_DIST_ACTIVE_CLEAR		0x380
> +#define GIC_DIST_PRI			0x400
> +#define GIC_DIST_TARGET			0x800
> +#define GIC_DIST_CONFIG			0xc00
> +#define GIC_DIST_SOFTINT		0xf00
> +#define GIC_DIST_SGI_PENDING_CLEAR	0xf10
> +#define GIC_DIST_SGI_PENDING_SET	0xf20
> +
> +#define GICD_ENABLE			0x1
> +#define GICD_DISABLE			0x0
> +#define GICD_INT_ACTLOW_LVLTRIG		0x0
> +#define GICD_INT_EN_CLR_X32		0xffffffff
> +#define GICD_INT_EN_SET_SGI		0x0000ffff
> +#define GICD_INT_EN_CLR_PPI		0xffff0000
> +#define GICD_INT_DEF_PRI		0xa0
> +#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
> +					(GICD_INT_DEF_PRI << 16) |\
> +					(GICD_INT_DEF_PRI << 8) |\
> +					GICD_INT_DEF_PRI)
> +#ifndef __ASSEMBLY__
> +
> +struct gicv2_data {
> +	void *dist_base;
> +	void *cpu_base;
> +};
> +extern struct gicv2_data gicv2_data;
> +
> +#define gicv2_dist_base()		(gicv2_data.dist_base)
> +#define gicv2_cpu_base()		(gicv2_data.cpu_base)
> +
> +extern int gicv2_init(void);
> +extern void gicv2_enable_defaults(void);
> +
> +#endif /* !__ASSEMBLY__ */
> +#endif /* _ASMARM_GIC_V2_H_ */
> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
> new file mode 100644
> index 0000000000000..b1237d1c5ef22
> --- /dev/null
> +++ b/lib/arm/asm/gic.h
> @@ -0,0 +1,20 @@
> +/*
> + * 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_H_
> +#define _ASMARM_GIC_H_
> +
> +#include <asm/gic-v2.h>
to be moved in gic.c?
> +
> +/*
> + * gic_init will try to find all known gics, and then
> + * initialize the gic data for the one found.
> + * returns
> + *  0   : no gic was found
> + *  > 0 : the gic version of the gic found
> + */
> +extern int gic_init(void);
> +
> +#endif /* _ASMARM_GIC_H_ */
> diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> new file mode 100644
> index 0000000000000..64a3049c9e8ce
> --- /dev/null
> +++ b/lib/arm/gic.c
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.
> + */
> +#include <libcflat.h>
> +#include <devicetree.h>
> +#include <asm/gic.h>
gic-v2.h?
> +#include <asm/smp.h>
> +#include <asm/io.h>
> +
> +struct gicv2_data gicv2_data;
> +
> +/*
> + * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
> + */
> +static bool
> +gic_get_dt_bases(const char *compatible, void **base1, void **base2)
> +{
> +	struct dt_pbus_reg reg;
> +	struct dt_device gic;
> +	struct dt_bus bus;
> +	int node, ret;
> +
> +	dt_bus_init_defaults(&bus);
> +	dt_device_init(&gic, &bus, NULL);
> +
> +	node = dt_device_find_compatible(&gic, compatible);
> +	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
> +
> +	if (node == -FDT_ERR_NOTFOUND)
> +		return false;
> +
> +	dt_device_bind_node(&gic, node);
> +
> +	ret = dt_pbus_translate(&gic, 0, &reg);
> +	assert(ret == 0);
> +	*base1 = ioremap(reg.addr, reg.size);
> +
> +	ret = dt_pbus_translate(&gic, 1, &reg);
> +	assert(ret == 0);
> +	*base2 = ioremap(reg.addr, reg.size);
> +
> +	return true;
> +}
> +
> +int gicv2_init(void)
> +{
> +	return gic_get_dt_bases("arm,cortex-a15-gic",
> +			&gicv2_data.dist_base, &gicv2_data.cpu_base);
what about the other possible compat strings. Is it safe to look only
for that one?
> +}
> +
> +int gic_init(void)
> +{
> +	if (gicv2_init())
> +		return 2;
> +	return 0;
> +}
> +
> +void gicv2_enable_defaults(void)
> +{
> +	if (smp_processor_id() == 0) {
> +		writel(GICD_INT_DEF_PRI_X4, gicv2_dist_base() + GIC_DIST_PRI);
I don't get this. There are (8*(GICD_TYPER.ITLinesNumber+1)) such
registers. See irq-gic-common.c/gic_dist_config

More generally shouldn't we implement something like gic_dist_config and
gic_cpu_config

Thanks

Eric

> +		writel(GICD_INT_EN_SET_SGI, gicv2_dist_base() + GIC_DIST_ENABLE_SET);
> +		writel(GICD_ENABLE, gicv2_dist_base() + GIC_DIST_CTRL);
> +	}
> +	writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK);
> +	writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL);
> +}
> diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
> new file mode 100644
> index 0000000000000..52226624a2092
> --- /dev/null
> +++ b/lib/arm64/asm/gic-v2.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/gic-v2.h"
> diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
> new file mode 100644
> index 0000000000000..e5eb302a31b4d
> --- /dev/null
> +++ b/lib/arm64/asm/gic.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/gic.h"
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support
@ 2016-09-01 10:20     ` Auger Eric
  0 siblings, 0 replies; 51+ messages in thread
From: Auger Eric @ 2016-09-01 10:20 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall



On 15/07/2016 15:00, Andrew Jones wrote:
> Add some gicv2 support. This just adds init and enable
> functions, allowing unit tests to start messing with it.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
>  arm/Makefile.common    |  1 +
>  lib/arm/asm/gic-v2.h   | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm/asm/gic.h      | 20 ++++++++++++++
>  lib/arm/gic.c          | 69 ++++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm64/asm/gic-v2.h |  1 +
>  lib/arm64/asm/gic.h    |  1 +
>  6 files changed, 166 insertions(+)
>  create mode 100644 lib/arm/asm/gic-v2.h
>  create mode 100644 lib/arm/asm/gic.h
>  create mode 100644 lib/arm/gic.c
>  create mode 100644 lib/arm64/asm/gic-v2.h
>  create mode 100644 lib/arm64/asm/gic.h
> 
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index ccb554d9251a4..41239c37e0920 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/gic.o
>  
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
> new file mode 100644
> index 0000000000000..973c2bf3cc796
> --- /dev/null
> +++ b/lib/arm/asm/gic-v2.h
> @@ -0,0 +1,74 @@
> +/*
> + * All GIC* defines are lifted from include/linux/irqchip/arm-gic.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_V2_H_
> +#define _ASMARM_GIC_V2_H_
> +
> +#define GIC_CPU_CTRL			0x00
> +#define GIC_CPU_PRIMASK			0x04
> +#define GIC_CPU_BINPOINT		0x08
> +#define GIC_CPU_INTACK			0x0c
> +#define GIC_CPU_EOI			0x10
> +#define GIC_CPU_RUNNINGPRI		0x14
> +#define GIC_CPU_HIGHPRI			0x18
> +#define GIC_CPU_ALIAS_BINPOINT		0x1c
> +#define GIC_CPU_ACTIVEPRIO		0xd0
> +#define GIC_CPU_IDENT			0xfc
> +#define GIC_CPU_DEACTIVATE		0x1000
> +
> +#define GICC_ENABLE			0x1
> +#define GICC_INT_PRI_THRESHOLD		0xf0
> +
> +#define GIC_CPU_CTRL_EOImodeNS		(1 << 9)
> +
> +#define GICC_IAR_INT_ID_MASK		0x3ff
> +#define GICC_INT_SPURIOUS		1023
> +#define GICC_DIS_BYPASS_MASK		0x1e0
> +
> +#define GIC_DIST_CTRL			0x000
> +#define GIC_DIST_CTR			0x004
you could add #define GIC_DIST_IIDR			0x008
which can be found in arm-gic.h
> +#define GIC_DIST_IGROUP			0x080
> +#define GIC_DIST_ENABLE_SET		0x100
> +#define GIC_DIST_ENABLE_CLEAR		0x180
> +#define GIC_DIST_PENDING_SET		0x200
> +#define GIC_DIST_PENDING_CLEAR		0x280
> +#define GIC_DIST_ACTIVE_SET		0x300
> +#define GIC_DIST_ACTIVE_CLEAR		0x380
> +#define GIC_DIST_PRI			0x400
> +#define GIC_DIST_TARGET			0x800
> +#define GIC_DIST_CONFIG			0xc00
> +#define GIC_DIST_SOFTINT		0xf00
> +#define GIC_DIST_SGI_PENDING_CLEAR	0xf10
> +#define GIC_DIST_SGI_PENDING_SET	0xf20
> +
> +#define GICD_ENABLE			0x1
> +#define GICD_DISABLE			0x0
> +#define GICD_INT_ACTLOW_LVLTRIG		0x0
> +#define GICD_INT_EN_CLR_X32		0xffffffff
> +#define GICD_INT_EN_SET_SGI		0x0000ffff
> +#define GICD_INT_EN_CLR_PPI		0xffff0000
> +#define GICD_INT_DEF_PRI		0xa0
> +#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
> +					(GICD_INT_DEF_PRI << 16) |\
> +					(GICD_INT_DEF_PRI << 8) |\
> +					GICD_INT_DEF_PRI)
> +#ifndef __ASSEMBLY__
> +
> +struct gicv2_data {
> +	void *dist_base;
> +	void *cpu_base;
> +};
> +extern struct gicv2_data gicv2_data;
> +
> +#define gicv2_dist_base()		(gicv2_data.dist_base)
> +#define gicv2_cpu_base()		(gicv2_data.cpu_base)
> +
> +extern int gicv2_init(void);
> +extern void gicv2_enable_defaults(void);
> +
> +#endif /* !__ASSEMBLY__ */
> +#endif /* _ASMARM_GIC_V2_H_ */
> diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
> new file mode 100644
> index 0000000000000..b1237d1c5ef22
> --- /dev/null
> +++ b/lib/arm/asm/gic.h
> @@ -0,0 +1,20 @@
> +/*
> + * 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_H_
> +#define _ASMARM_GIC_H_
> +
> +#include <asm/gic-v2.h>
to be moved in gic.c?
> +
> +/*
> + * gic_init will try to find all known gics, and then
> + * initialize the gic data for the one found.
> + * returns
> + *  0   : no gic was found
> + *  > 0 : the gic version of the gic found
> + */
> +extern int gic_init(void);
> +
> +#endif /* _ASMARM_GIC_H_ */
> diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> new file mode 100644
> index 0000000000000..64a3049c9e8ce
> --- /dev/null
> +++ b/lib/arm/gic.c
> @@ -0,0 +1,69 @@
> +/*
> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.
> + */
> +#include <libcflat.h>
> +#include <devicetree.h>
> +#include <asm/gic.h>
gic-v2.h?
> +#include <asm/smp.h>
> +#include <asm/io.h>
> +
> +struct gicv2_data gicv2_data;
> +
> +/*
> + * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
> + */
> +static bool
> +gic_get_dt_bases(const char *compatible, void **base1, void **base2)
> +{
> +	struct dt_pbus_reg reg;
> +	struct dt_device gic;
> +	struct dt_bus bus;
> +	int node, ret;
> +
> +	dt_bus_init_defaults(&bus);
> +	dt_device_init(&gic, &bus, NULL);
> +
> +	node = dt_device_find_compatible(&gic, compatible);
> +	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
> +
> +	if (node == -FDT_ERR_NOTFOUND)
> +		return false;
> +
> +	dt_device_bind_node(&gic, node);
> +
> +	ret = dt_pbus_translate(&gic, 0, &reg);
> +	assert(ret == 0);
> +	*base1 = ioremap(reg.addr, reg.size);
> +
> +	ret = dt_pbus_translate(&gic, 1, &reg);
> +	assert(ret == 0);
> +	*base2 = ioremap(reg.addr, reg.size);
> +
> +	return true;
> +}
> +
> +int gicv2_init(void)
> +{
> +	return gic_get_dt_bases("arm,cortex-a15-gic",
> +			&gicv2_data.dist_base, &gicv2_data.cpu_base);
what about the other possible compat strings. Is it safe to look only
for that one?
> +}
> +
> +int gic_init(void)
> +{
> +	if (gicv2_init())
> +		return 2;
> +	return 0;
> +}
> +
> +void gicv2_enable_defaults(void)
> +{
> +	if (smp_processor_id() == 0) {
> +		writel(GICD_INT_DEF_PRI_X4, gicv2_dist_base() + GIC_DIST_PRI);
I don't get this. There are (8*(GICD_TYPER.ITLinesNumber+1)) such
registers. See irq-gic-common.c/gic_dist_config

More generally shouldn't we implement something like gic_dist_config and
gic_cpu_config

Thanks

Eric

> +		writel(GICD_INT_EN_SET_SGI, gicv2_dist_base() + GIC_DIST_ENABLE_SET);
> +		writel(GICD_ENABLE, gicv2_dist_base() + GIC_DIST_CTRL);
> +	}
> +	writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK);
> +	writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL);
> +}
> diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
> new file mode 100644
> index 0000000000000..52226624a2092
> --- /dev/null
> +++ b/lib/arm64/asm/gic-v2.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/gic-v2.h"
> diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
> new file mode 100644
> index 0000000000000..e5eb302a31b4d
> --- /dev/null
> +++ b/lib/arm64/asm/gic.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/gic.h"
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 09/10] arm/arm64: gicv3: add an IPI test
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-09-01 16:42   ` Auger Eric
  2016-10-17 13:36       ` Andrew Jones
  -1 siblings, 1 reply; 51+ messages in thread
From: Auger Eric @ 2016-09-01 16:42 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi Drew,

On 15/07/2016 15:00, Andrew Jones wrote:
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v2: use IRM for gicv3 broadcast
> ---
>  arm/gic.c         | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++----
>  arm/unittests.cfg |   6 +++
>  2 files changed, 154 insertions(+), 9 deletions(-)
> 
> diff --git a/arm/gic.c b/arm/gic.c
> index cf7ec1c90413c..fc7ef241de3e2 100644
> --- a/arm/gic.c
> +++ b/arm/gic.c
> @@ -3,6 +3,8 @@
>   *
>   * GICv2
>   *   . test sending/receiving IPIs
> + * GICv3
> + *   . test sending/receiving IPIs
>   *
>   * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
>   *
> @@ -16,6 +18,18 @@
>  #include <asm/barrier.h>
>  #include <asm/io.h>
>  
> +struct gic {
> +	struct {
> +		void (*enable)(void);
> +		void (*send_self)(void);
> +		void (*send_tlist)(cpumask_t *);
> +		void (*send_broadcast)(void);
> +	} ipi;
> +	u32 (*read_iar)(void);
> +	void (*write_eoi)(u32);
> +};
> +
> +static struct gic *gic;
>  static int gic_version;
>  static int acked[NR_CPUS], spurious[NR_CPUS];
>  static cpumask_t ready;
> @@ -69,12 +83,22 @@ static void check_acked(cpumask_t *mask)
>  	       false, missing, extra, unexpected);
>  }
>  
> +static u32 gicv2_read_iar(void)
> +{
> +	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> +}
> +
> +static void gicv2_write_eoi(u32 irq)
> +{
> +	writel(irq, gicv2_cpu_base() + GIC_CPU_EOI);
> +}
> +
>  static void ipi_handler(struct pt_regs *regs __unused)
>  {
> -	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> +	u32 iar = gic->read_iar();
>  
>  	if (iar != GICC_INT_SPURIOUS) {
> -		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
> +		gic->write_eoi(iar);
>  		smp_rmb(); /* pairs with wmb in ipi_test functions */
>  		++acked[smp_processor_id()];
>  		smp_wmb(); /* pairs with rmb in check_acked */
> @@ -84,6 +108,89 @@ static void ipi_handler(struct pt_regs *regs __unused)
>  	}
>  }
>  
> +static void gicv2_ipi_send_self(void)
> +{
> +	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +}
> +
> +static void gicv2_ipi_send_tlist(cpumask_t *mask)
> +{
> +	u8 tlist = (u8)cpumask_bits(mask)[0];
> +
> +	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +}
> +
> +static void gicv2_ipi_send_broadcast(void)
> +{
> +	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +}
> +
> +#define ICC_SGI1R_AFFINITY_1_SHIFT	16
> +#define ICC_SGI1R_AFFINITY_2_SHIFT	32
> +#define ICC_SGI1R_AFFINITY_3_SHIFT	48
> +#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
> +	(MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
> +
> +static void gicv3_ipi_send_tlist(cpumask_t *mask)
> +{
This function really is indigestible to me. Can't we reuse the linux
kernel gic_compute_target_list routine. Since the code looks similar why
not trying to be as close as possible to the kernel?

Thanks

Eric
> +	u16 tlist;
> +	int cpu;
> +
> +	for_each_cpu(cpu, mask) {
> +		u64 mpidr = cpus[cpu], sgi1r;
> +		u64 cluster_id = mpidr & ~0xffUL;
> +
> +		tlist = 0;
> +
> +		while (cpu < nr_cpus) {
> +			if ((mpidr & 0xff) >= 16) {
> +				printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
> +					cpu, (int)(mpidr & 0xff));
> +				break;
> +			}
> +
> +			tlist |= 1 << (mpidr & 0xf);
> +
> +			cpu = cpumask_next(cpu, mask);
> +			if (cpu >= nr_cpus)
> +				break;
> +
> +			mpidr = cpus[cpu];
> +
> +			if (cluster_id != (mpidr & ~0xffUL)) {
> +				--cpu;
> +				break;
> +			}
> +		}
> +
> +		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
> +			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
> +			 /* irq << 24				| */
> +			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
> +			 tlist);
> +
> +		gicv3_write_sgi1r(sgi1r);
> +	}
> +
> +	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
> +	isb();
> +}
> +
> +static void gicv3_ipi_send_self(void)
> +{
> +	cpumask_t mask;
> +
> +	cpumask_clear(&mask);
> +	cpumask_set_cpu(smp_processor_id(), &mask);
> +	gicv3_ipi_send_tlist(&mask);
> +}
> +
> +static void gicv3_ipi_send_broadcast(void)
> +{
> +	gicv3_write_sgi1r(1ULL << 40);
> +	isb();
> +}
> +
>  static void ipi_test_self(void)
>  {
>  	cpumask_t mask;
> @@ -93,7 +200,7 @@ static void ipi_test_self(void)
>  	smp_wmb();
>  	cpumask_clear(&mask);
>  	cpumask_set_cpu(0, &mask);
> -	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	gic->ipi.send_self();
>  	check_acked(&mask);
>  	report_prefix_pop();
>  }
> @@ -101,14 +208,15 @@ static void ipi_test_self(void)
>  static void ipi_test_smp(void)
>  {
>  	cpumask_t mask;
> -	unsigned long tlist;
> +	int i;
>  
>  	report_prefix_push("target-list");
>  	memset(acked, 0, sizeof(acked));
>  	smp_wmb();
> -	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> -	cpumask_bits(&mask)[0] = tlist;
> -	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	cpumask_copy(&mask, &cpu_present_mask);
> +	for (i = 0; i < nr_cpus; i += 2)
> +		cpumask_clear_cpu(i, &mask);
> +	gic->ipi.send_tlist(&mask);
>  	check_acked(&mask);
>  	report_prefix_pop();
>  
> @@ -117,14 +225,14 @@ static void ipi_test_smp(void)
>  	smp_wmb();
>  	cpumask_copy(&mask, &cpu_present_mask);
>  	cpumask_clear_cpu(0, &mask);
> -	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	gic->ipi.send_broadcast();
>  	check_acked(&mask);
>  	report_prefix_pop();
>  }
>  
>  static void ipi_enable(void)
>  {
> -	gicv2_enable_defaults();
> +	gic->ipi.enable();
>  #ifdef __arm__
>  	install_exception_handler(EXCPTN_IRQ, ipi_handler);
>  #else
> @@ -141,6 +249,28 @@ static void ipi_recv(void)
>  		wfi();
>  }
>  
> +struct gic gicv2 = {
> +	.ipi = {
> +		.enable = gicv2_enable_defaults,
> +		.send_self = gicv2_ipi_send_self,
> +		.send_tlist = gicv2_ipi_send_tlist,
> +		.send_broadcast = gicv2_ipi_send_broadcast,
> +	},
> +	.read_iar = gicv2_read_iar,
> +	.write_eoi = gicv2_write_eoi,
> +};
> +
> +struct gic gicv3 = {
> +	.ipi = {
> +		.enable = gicv3_enable_defaults,
> +		.send_self = gicv3_ipi_send_self,
> +		.send_tlist = gicv3_ipi_send_tlist,
> +		.send_broadcast = gicv3_ipi_send_broadcast,
> +	},
> +	.read_iar = gicv3_read_iar,
> +	.write_eoi = gicv3_write_eoir,
> +};
> +
>  int main(int argc, char **argv)
>  {
>  	char pfx[8];
> @@ -153,6 +283,15 @@ int main(int argc, char **argv)
>  	snprintf(pfx, 8, "gicv%d", gic_version);
>  	report_prefix_push(pfx);
>  
> +	switch (gic_version) {
> +	case 2:
> +		gic = &gicv2;
> +		break;
> +	case 3:
> +		gic = &gicv3;
> +		break;
> +	}
> +
>  	if (argc < 2) {
>  
>  		report_prefix_push("ipi");
> diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> index bb364675043f0..043a20e26e98c 100644
> --- a/arm/unittests.cfg
> +++ b/arm/unittests.cfg
> @@ -58,3 +58,9 @@ file = gic.flat
>  smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
>  extra_params = -machine gic-version=2 -append 'ipi'
>  groups = gic
> +
> +[gicv3-ipi]
> +file = gic.flat
> +smp = $MAX_SMP
> +extra_params = -machine gic-version=3 -append 'ipi'
> +groups = gic
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-09-01 16:42   ` Auger Eric
  2016-10-17 19:15       ` Andrew Jones
  -1 siblings, 1 reply; 51+ messages in thread
From: Auger Eric @ 2016-09-01 16:42 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi Drew,

On 15/07/2016 15:00, Andrew Jones wrote:
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> ---
> v2: add more details in the output if a test fails,
>     report spurious interrupts if we get them
> ---
>  arm/Makefile.common |   6 +-
>  arm/gic.c           | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  arm/unittests.cfg   |   7 ++
>  3 files changed, 204 insertions(+), 3 deletions(-)
>  create mode 100644 arm/gic.c
> 
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index 41239c37e0920..bc38183ab86e0 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
>  	LOADADDR = 0x40000000
>  endif
>  
> -tests-common = \
> -	$(TEST_DIR)/selftest.flat \
> -	$(TEST_DIR)/spinlock-test.flat
> +tests-common  = $(TEST_DIR)/selftest.flat
> +tests-common += $(TEST_DIR)/spinlock-test.flat
> +tests-common += $(TEST_DIR)/gic.flat
>  
>  all: test_cases
>  
> diff --git a/arm/gic.c b/arm/gic.c
> new file mode 100644
> index 0000000000000..cf7ec1c90413c
> --- /dev/null
> +++ b/arm/gic.c
> @@ -0,0 +1,194 @@
> +/*
> + * GIC tests
> + *
> + * GICv2
> + *   . test sending/receiving IPIs
> + *
> + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU LGPL, version 2.
> + */
> +#include <libcflat.h>
> +#include <asm/setup.h>
> +#include <asm/processor.h>
> +#include <asm/gic.h>
> +#include <asm/smp.h>
> +#include <asm/barrier.h>
> +#include <asm/io.h>
> +
> +static int gic_version;
> +static int acked[NR_CPUS], spurious[NR_CPUS];
> +static cpumask_t ready;
> +
> +static void nr_cpu_check(int nr)
> +{
> +	if (nr_cpus < nr)
> +		report_abort("At least %d cpus required", nr);
> +}
> +
> +static void wait_on_ready(void)
> +{
> +	cpumask_set_cpu(smp_processor_id(), &ready);
> +	while (!cpumask_full(&ready))
> +		cpu_relax();
> +}
> +
> +static void check_acked(cpumask_t *mask)
> +{
> +	int missing = 0, extra = 0, unexpected = 0;
> +	int nr_pass, cpu, i;
> +
> +	/* Wait up to 5s for all interrupts to be delivered */
> +	for (i = 0; i < 50; ++i) {
> +		mdelay(100);
> +		nr_pass = 0;
> +		for_each_present_cpu(cpu) {
Couldn't we use for_each_cpu(cpu, mask)?
> +			smp_rmb();
> +			nr_pass += cpumask_test_cpu(cpu, mask) ?
> +				acked[cpu] == 1 : acked[cpu] == 0;
> +		}
> +		if (nr_pass == nr_cpus) {
> +			report("Completed in %d ms", true, ++i * 100);
> +			return;
> +		}
> +	}
> +
> +	for_each_present_cpu(cpu) {
> +		if (cpumask_test_cpu(cpu, mask)) {
here we can't since we count unexpected

> +			if (!acked[cpu])
> +				++missing;
> +			else if (acked[cpu] > 1)
> +				++extra;
> +		} else {
> +			if (acked[cpu])
> +				++unexpected;
> +		}
> +	}
> +
> +	report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
> +	       false, missing, extra, unexpected);
> +}
> +
> +static void ipi_handler(struct pt_regs *regs __unused)
> +{
> +	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> +
> +	if (iar != GICC_INT_SPURIOUS) {
> +		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
if EOIMode is set may need to DIR as well.
> +		smp_rmb(); /* pairs with wmb in ipi_test functions */
> +		++acked[smp_processor_id()];
> +		smp_wmb(); /* pairs with rmb in check_acked */
> +	} else {
> +		++spurious[smp_processor_id()];
> +		smp_wmb();
> +	}
> +}
> +
> +static void ipi_test_self(void)
> +{
> +	cpumask_t mask;
> +
> +	report_prefix_push("self");
> +	memset(acked, 0, sizeof(acked));
> +	smp_wmb();
> +	cpumask_clear(&mask);
> +	cpumask_set_cpu(0, &mask);
> +	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	check_acked(&mask);
> +	report_prefix_pop();
> +}
> +
> +static void ipi_test_smp(void)
> +{
> +	cpumask_t mask;
> +	unsigned long tlist;
> +
> +	report_prefix_push("target-list");
> +	memset(acked, 0, sizeof(acked));
> +	smp_wmb();
> +	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> +	cpumask_bits(&mask)[0] = tlist;
> +	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	check_acked(&mask);
> +	report_prefix_pop();
> +
> +	report_prefix_push("broadcast");
> +	memset(acked, 0, sizeof(acked));
> +	smp_wmb();
> +	cpumask_copy(&mask, &cpu_present_mask);
> +	cpumask_clear_cpu(0, &mask);
> +	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	check_acked(&mask);
> +	report_prefix_pop();
> +}
> +
> +static void ipi_enable(void)
> +{
> +	gicv2_enable_defaults();
> +#ifdef __arm__
> +	install_exception_handler(EXCPTN_IRQ, ipi_handler);
> +#else
> +	install_irq_handler(EL1H_IRQ, ipi_handler);
> +#endif
> +	local_irq_enable();
> +}
> +
> +static void ipi_recv(void)
> +{
> +	ipi_enable();
> +	cpumask_set_cpu(smp_processor_id(), &ready);
> +	while (1)
> +		wfi();
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	char pfx[8];
> +	int cpu;
> +
> +	gic_version = gic_init();
> +	if (!gic_version)
> +		report_abort("No gic present!");
> +
> +	snprintf(pfx, 8, "gicv%d", gic_version);
> +	report_prefix_push(pfx);
> +
> +	if (argc < 2) {
> +
spare void line
> +		report_prefix_push("ipi");
> +		ipi_enable();
> +		ipi_test_self();
> +		report_prefix_pop();
> +
same
> +	} else if (!strcmp(argv[1], "ipi")) {
> +
same or maybe this is just another style convention?
> +		report_prefix_push(argv[1]);
> +		nr_cpu_check(2);
> +		ipi_enable();
> +
> +		for_each_present_cpu(cpu) {
> +			if (cpu == 0)
> +				continue;
> +			smp_boot_secondary(cpu, ipi_recv);
> +		}
> +		wait_on_ready();
> +		ipi_test_self();
> +		ipi_test_smp();
> +
> +		smp_rmb();
> +		for_each_present_cpu(cpu) {
> +			if (spurious[cpu]) {
> +				printf("ipi: WARN: cpu%d got %d spurious "
> +				       "interrupts\n",
> +				       spurious[cpu], smp_processor_id());
> +			}
> +		}
> +
> +		report_prefix_pop();
> +
> +	} else {
> +		report_abort("Unknown subtest '%s'", argv[1]);
> +	}
> +
> +	return report_summary();
> +}
> diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> index ffd12e5794aa0..bb364675043f0 100644
> --- a/arm/unittests.cfg
> +++ b/arm/unittests.cfg
> @@ -51,3 +51,10 @@ file = selftest.flat
>  smp = $MAX_SMP
>  extra_params = -append 'smp'
>  groups = selftest
> +
> +# Test GIC emulation
> +[gicv2-ipi]
> +file = gic.flat
> +smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
> +extra_params = -machine gic-version=2 -append 'ipi'
> +groups = gic
> 
Aside the minor comments above,
Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks

Eric


^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 10/10] arm/arm64: gic: don't just use zero
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
  (?)
@ 2016-09-02  9:43   ` Auger Eric
  2016-10-17 19:53       ` Andrew Jones
  -1 siblings, 1 reply; 51+ messages in thread
From: Auger Eric @ 2016-09-02  9:43 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	andre.przywara, peter.maydell, alex.bennee
  Cc: marc.zyngier, wei, christoffer.dall

Hi Drew,

On 15/07/2016 15:00, Andrew Jones wrote:
> Allow user to select who sends ipis and with which irq,
> rather than just always sending irq=0 from cpu0.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v2: actually check that the irq received was the irq sent,
>     and (for gicv2) that the sender is the expected one.
> ---
>  arm/gic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 64 insertions(+), 16 deletions(-)
> 
> diff --git a/arm/gic.c b/arm/gic.c
> index fc7ef241de3e2..d3ab97d4ae470 100644
> --- a/arm/gic.c
> +++ b/arm/gic.c
> @@ -11,6 +11,7 @@
>   * This work is licensed under the terms of the GNU LGPL, version 2.
>   */
>  #include <libcflat.h>
> +#include <util.h>
>  #include <asm/setup.h>
>  #include <asm/processor.h>
>  #include <asm/gic.h>
> @@ -33,6 +34,8 @@ static struct gic *gic;
>  static int gic_version;
>  static int acked[NR_CPUS], spurious[NR_CPUS];
>  static cpumask_t ready;
> +static int sender;
> +static u32 irq;
>  
>  static void nr_cpu_check(int nr)
>  {
> @@ -85,7 +88,16 @@ static void check_acked(cpumask_t *mask)
>  
>  static u32 gicv2_read_iar(void)
>  {
> -	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> +	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> +	int src = (iar >> 10) & 7;
> +
> +	if (src != sender) {
> +		report("cpu%d received IPI from unexpected source cpu%d "
> +		       "(expected cpu%d)",
> +		       false, smp_processor_id(), src, sender);
> +	}
> +
> +	return iar & 0x3ff;
you can use GICC_IAR_INT_ID_MASK instead
>  }
>  
>  static void gicv2_write_eoi(u32 irq)
> @@ -99,9 +111,15 @@ static void ipi_handler(struct pt_regs *regs __unused)
>  
>  	if (iar != GICC_INT_SPURIOUS) {
>  		gic->write_eoi(iar);
> -		smp_rmb(); /* pairs with wmb in ipi_test functions */
> -		++acked[smp_processor_id()];
> -		smp_wmb(); /* pairs with rmb in check_acked */
> +		if (iar == irq) {
> +			smp_rmb(); /* pairs with wmb in ipi_test functions */
> +			++acked[smp_processor_id()];
> +			smp_wmb(); /* pairs with rmb in check_acked */
> +		} else {
> +			report("cpu%d received unexpected irq %u "
> +			       "(expected %u)",
> +			       false, smp_processor_id(), iar, irq);
> +		}
>  	} else {
>  		++spurious[smp_processor_id()];
>  		smp_wmb();
> @@ -110,19 +128,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
>  
>  static void gicv2_ipi_send_self(void)
>  {
> -	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	writel(2 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
>  }
>  
>  static void gicv2_ipi_send_tlist(cpumask_t *mask)
>  {
>  	u8 tlist = (u8)cpumask_bits(mask)[0];
>  
> -	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	writel(tlist << 16 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
>  }
>  
>  static void gicv2_ipi_send_broadcast(void)
>  {
> -	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> +	writel(1 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
>  }
>  
>  #define ICC_SGI1R_AFFINITY_1_SHIFT	16
> @@ -165,7 +183,7 @@ static void gicv3_ipi_send_tlist(cpumask_t *mask)
>  
>  		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
>  			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
> -			 /* irq << 24				| */
> +			 irq << 24				|
>  			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
>  			 tlist);
>  
> @@ -187,7 +205,7 @@ static void gicv3_ipi_send_self(void)
>  
>  static void gicv3_ipi_send_broadcast(void)
>  {
> -	gicv3_write_sgi1r(1ULL << 40);
> +	gicv3_write_sgi1r(1ULL << 40 | irq << 24);
>  	isb();
>  }
>  
> @@ -199,7 +217,7 @@ static void ipi_test_self(void)
>  	memset(acked, 0, sizeof(acked));
>  	smp_wmb();
>  	cpumask_clear(&mask);
> -	cpumask_set_cpu(0, &mask);
> +	cpumask_set_cpu(smp_processor_id(), &mask);
>  	gic->ipi.send_self();
>  	check_acked(&mask);
>  	report_prefix_pop();
> @@ -214,7 +232,7 @@ static void ipi_test_smp(void)
>  	memset(acked, 0, sizeof(acked));
>  	smp_wmb();
>  	cpumask_copy(&mask, &cpu_present_mask);
> -	for (i = 0; i < nr_cpus; i += 2)
> +	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
>  		cpumask_clear_cpu(i, &mask);
>  	gic->ipi.send_tlist(&mask);
>  	check_acked(&mask);
> @@ -224,7 +242,7 @@ static void ipi_test_smp(void)
>  	memset(acked, 0, sizeof(acked));
>  	smp_wmb();
>  	cpumask_copy(&mask, &cpu_present_mask);
> -	cpumask_clear_cpu(0, &mask);
> +	cpumask_clear_cpu(smp_processor_id(), &mask);
>  	gic->ipi.send_broadcast();
>  	check_acked(&mask);
>  	report_prefix_pop();
> @@ -241,6 +259,15 @@ static void ipi_enable(void)
>  	local_irq_enable();
>  }
>  
> +static void ipi_send(void)
> +{
> +	ipi_enable();
> +	wait_on_ready();
> +	ipi_test_self();
> +	ipi_test_smp();
> +	exit(report_summary());
> +}
> +
>  static void ipi_recv(void)
>  {
>  	ipi_enable();
> @@ -300,19 +327,40 @@ int main(int argc, char **argv)
>  		report_prefix_pop();
>  
>  	} else if (!strcmp(argv[1], "ipi")) {
> +		int off, i = 1;
> +		long val;
>  
>  		report_prefix_push(argv[1]);
> +
> +		while (--argc != 1) {
> +			off = parse_keyval(argv[++i], &val);
> +			if (off == -1)
> +				continue;
> +			argv[i][off] = '\0';
> +			if (strcmp(argv[i], "sender") == 0)
> +				sender = val;
> +			else if (strcmp(argv[i], "irq") == 0)
> +				irq = val;
> +		}
> +
>  		nr_cpu_check(2);
>  		ipi_enable();
>  
>  		for_each_present_cpu(cpu) {
>  			if (cpu == 0)
>  				continue;
> -			smp_boot_secondary(cpu, ipi_recv);
> +			if (cpu == sender)
> +				smp_boot_secondary(cpu, ipi_send);
> +			else
> +				smp_boot_secondary(cpu, ipi_recv);
> +		}
> +		if (sender == 0)  {
> +			wait_on_ready();
> +			ipi_test_self();
> +			ipi_test_smp();
> +		} else {
> +			ipi_recv();
>  		}
> -		wait_on_ready();
> -		ipi_test_self();
> -		ipi_test_smp();
>  
>  		smp_rmb();
>  		for_each_present_cpu(cpu) {
> 

I ran the tests on both Cavium & Seattle HW without noticing issues.

I guess the file organization & infra will need to change while adding
some new tests, removing some globals ... but that's a good start to
show how to write new tests. I am a bit concerned by the LOCs and
redundancies with the kernel with possible out-of-sync macros but well I
think there is no other way.

I will spend some time writing some tests within the next weeks.

Thanks!

Eric

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus
  2016-08-30 14:28   ` Auger Eric
@ 2016-10-17 12:24       ` Andrew Jones
  2016-10-17 12:24       ` Andrew Jones
  1 sibling, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 12:24 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm

On Tue, Aug 30, 2016 at 04:28:52PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> Proper commit message?
> ... also selects the vgic model corresponding to the host

Sure

> > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  arm/run                   | 19 ++++++++++++-------
> >  arm/selftest.c            |  5 ++++-
> >  lib/arm/asm/processor.h   |  9 +++++++--
> >  lib/arm/asm/setup.h       |  4 ++--
> >  lib/arm/setup.c           | 12 +++++++++++-
> >  lib/arm64/asm/processor.h |  9 +++++++--
> >  6 files changed, 43 insertions(+), 15 deletions(-)
> > 
> > diff --git a/arm/run b/arm/run
> > index a2f35ef6a7e63..2d0698619606e 100755
> > --- a/arm/run
> > +++ b/arm/run
> > @@ -31,13 +31,6 @@ if [ -z "$ACCEL" ]; then
> >  	fi
> >  fi
> >  
> > -if [ "$HOST" = "aarch64" ] && [ "$ACCEL" = "kvm" ]; then
> > -	processor="host"
> > -	if [ "$ARCH" = "arm" ]; then
> > -		processor+=",aarch64=off"
> > -	fi
> > -fi
> > -
> >  qemu="${QEMU:-qemu-system-$ARCH_NAME}"
> >  qpath=$(which $qemu 2>/dev/null)
> >  
> > @@ -53,6 +46,18 @@ fi
> >  
> >  M='-machine virt'
> >  
> > +if [ "$ACCEL" = "kvm" ]; then
> > +	if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then
> > +		M+=',gic-version=host'
> > +	fi
> > +	if [ "$HOST" = "aarch64" ]; then
> > +		processor="host"
> > +		if [ "$ARCH" = "arm" ]; then
> > +			processor+=",aarch64=off"
> > +		fi
> > +	fi
> > +fi
> > +
> >  if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then
> >  	echo "$qpath doesn't support virtio-console for chr-testdev. Exiting."
> >  	exit 2
> > diff --git a/arm/selftest.c b/arm/selftest.c
> > index 196164f5313de..2f117f795d2dc 100644
> > --- a/arm/selftest.c
> > +++ b/arm/selftest.c
> > @@ -312,9 +312,10 @@ static bool psci_check(void)
> >  static cpumask_t smp_reported;
> >  static void cpu_report(void)
> >  {
> > +	unsigned long mpidr = get_mpidr();
> >  	int cpu = smp_processor_id();
> >  
> > -	report("CPU%d online", true, cpu);
> > +	report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
> >  	cpumask_set_cpu(cpu, &smp_reported);
> >  	halt();
> >  }
> > @@ -343,6 +344,7 @@ int main(int argc, char **argv)
> >  
> >  	} else if (strcmp(argv[1], "smp") == 0) {
> >  
> > +		unsigned long mpidr = get_mpidr();
> >  		int cpu;
> >  
> >  		report("PSCI version", psci_check());
> > @@ -353,6 +355,7 @@ int main(int argc, char **argv)
> >  			smp_boot_secondary(cpu, cpu_report);
> >  		}
> >  
> > +		report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == 0, 0, mpidr);
> >  		cpumask_set_cpu(0, &smp_reported);
> >  		while (!cpumask_full(&smp_reported))
> >  			cpu_relax();
> > diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> > index f25e7eee3666c..d2048f5f5f7e6 100644
> > --- a/lib/arm/asm/processor.h
> > +++ b/lib/arm/asm/processor.h
> > @@ -40,8 +40,13 @@ static inline unsigned int get_mpidr(void)
> >  	return mpidr;
> >  }
> >  
> > -/* Only support Aff0 for now, up to 4 cpus */
> > -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> > +#define MPIDR_HWID_BITMASK 0xffffff
> > +extern int mpidr_to_cpu(unsigned long mpidr);
> > +
> > +#define MPIDR_LEVEL_SHIFT(level) \
> > +	(((1 << level) >> 1) << 3)
> can't we have level << 3?
> > +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> > +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
> >  
> >  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
> >  extern bool is_user(void);
> > diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
> > index cb8fdbd38dd5d..c501c6ddd8657 100644
> > --- a/lib/arm/asm/setup.h
> > +++ b/lib/arm/asm/setup.h
> > @@ -10,8 +10,8 @@
> >  #include <asm/page.h>
> >  #include <asm/pgtable-hwdef.h>
> >  
> > -#define NR_CPUS			8
> > -extern u32 cpus[NR_CPUS];
> > +#define NR_CPUS			255
> 256?

The kernel defines KVM_MAX_VCPUS as VGIC_V3_MAX_CPUS, which is
currently defined as 255. I was just being consistent.

> > +extern u64 cpus[NR_CPUS];
> maybe worth commenting the semantic of cpus[i]?

sure

> >  extern int nr_cpus;
> what about MAX_CPUS instead of NR_CPUS?

kernel uses NR_CPUS, I want to be consistent.

> >  
> >  #define NR_MEM_REGIONS		8
> > diff --git a/lib/arm/setup.c b/lib/arm/setup.c
> > index 7e7b39f11dde1..b6e2d5815e723 100644
> > --- a/lib/arm/setup.c
> > +++ b/lib/arm/setup.c
> > @@ -24,12 +24,22 @@ extern unsigned long stacktop;
> >  extern void io_init(void);
> >  extern void setup_args_progname(const char *args);
> >  
> > -u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
> > +u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
> >  int nr_cpus;
> >  
> >  struct mem_region mem_regions[NR_MEM_REGIONS];
> >  phys_addr_t __phys_offset, __phys_end;
> >  
> > +int mpidr_to_cpu(unsigned long mpidr)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < nr_cpus; ++i)
> > +		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
> > +			return i;
> > +	return -1;
> > +}
> > +
> >  static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
> >  {
> >  	int cpu = nr_cpus++;
> > diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> > index 9a208ff729b7e..7e448dc81a6aa 100644
> > --- a/lib/arm64/asm/processor.h
> > +++ b/lib/arm64/asm/processor.h
> > @@ -78,8 +78,13 @@ static inline type get_##reg(void)				\
> >  
> >  DEFINE_GET_SYSREG64(mpidr)
> >  
> > -/* Only support Aff0 for now, gicv2 only */
> > -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> > +#define MPIDR_HWID_BITMASK 0xff00ffffff
> > +extern int mpidr_to_cpu(unsigned long mpidr);
> > +
> > +#define MPIDR_LEVEL_SHIFT(level) \
> > +	(((1 << level) >> 1) << 3)
> what about level 3? the macro would fail fetching affinity level 3.
> 
> Thanks
> 
> Eric
> > +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> > +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
> >  
> >  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
> >  extern bool is_user(void);
> > 
>

Thanks,
drew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus
@ 2016-10-17 12:24       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 12:24 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee, marc.zyngier, wei, christoffer.dall

On Tue, Aug 30, 2016 at 04:28:52PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> Proper commit message?
> ... also selects the vgic model corresponding to the host

Sure

> > Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  arm/run                   | 19 ++++++++++++-------
> >  arm/selftest.c            |  5 ++++-
> >  lib/arm/asm/processor.h   |  9 +++++++--
> >  lib/arm/asm/setup.h       |  4 ++--
> >  lib/arm/setup.c           | 12 +++++++++++-
> >  lib/arm64/asm/processor.h |  9 +++++++--
> >  6 files changed, 43 insertions(+), 15 deletions(-)
> > 
> > diff --git a/arm/run b/arm/run
> > index a2f35ef6a7e63..2d0698619606e 100755
> > --- a/arm/run
> > +++ b/arm/run
> > @@ -31,13 +31,6 @@ if [ -z "$ACCEL" ]; then
> >  	fi
> >  fi
> >  
> > -if [ "$HOST" = "aarch64" ] && [ "$ACCEL" = "kvm" ]; then
> > -	processor="host"
> > -	if [ "$ARCH" = "arm" ]; then
> > -		processor+=",aarch64=off"
> > -	fi
> > -fi
> > -
> >  qemu="${QEMU:-qemu-system-$ARCH_NAME}"
> >  qpath=$(which $qemu 2>/dev/null)
> >  
> > @@ -53,6 +46,18 @@ fi
> >  
> >  M='-machine virt'
> >  
> > +if [ "$ACCEL" = "kvm" ]; then
> > +	if $qemu $M,\? 2>&1 | grep gic-version > /dev/null; then
> > +		M+=',gic-version=host'
> > +	fi
> > +	if [ "$HOST" = "aarch64" ]; then
> > +		processor="host"
> > +		if [ "$ARCH" = "arm" ]; then
> > +			processor+=",aarch64=off"
> > +		fi
> > +	fi
> > +fi
> > +
> >  if ! $qemu $M -device '?' 2>&1 | grep virtconsole > /dev/null; then
> >  	echo "$qpath doesn't support virtio-console for chr-testdev. Exiting."
> >  	exit 2
> > diff --git a/arm/selftest.c b/arm/selftest.c
> > index 196164f5313de..2f117f795d2dc 100644
> > --- a/arm/selftest.c
> > +++ b/arm/selftest.c
> > @@ -312,9 +312,10 @@ static bool psci_check(void)
> >  static cpumask_t smp_reported;
> >  static void cpu_report(void)
> >  {
> > +	unsigned long mpidr = get_mpidr();
> >  	int cpu = smp_processor_id();
> >  
> > -	report("CPU%d online", true, cpu);
> > +	report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
> >  	cpumask_set_cpu(cpu, &smp_reported);
> >  	halt();
> >  }
> > @@ -343,6 +344,7 @@ int main(int argc, char **argv)
> >  
> >  	} else if (strcmp(argv[1], "smp") == 0) {
> >  
> > +		unsigned long mpidr = get_mpidr();
> >  		int cpu;
> >  
> >  		report("PSCI version", psci_check());
> > @@ -353,6 +355,7 @@ int main(int argc, char **argv)
> >  			smp_boot_secondary(cpu, cpu_report);
> >  		}
> >  
> > +		report("CPU(%3d) mpidr=%lx", mpidr_to_cpu(mpidr) == 0, 0, mpidr);
> >  		cpumask_set_cpu(0, &smp_reported);
> >  		while (!cpumask_full(&smp_reported))
> >  			cpu_relax();
> > diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> > index f25e7eee3666c..d2048f5f5f7e6 100644
> > --- a/lib/arm/asm/processor.h
> > +++ b/lib/arm/asm/processor.h
> > @@ -40,8 +40,13 @@ static inline unsigned int get_mpidr(void)
> >  	return mpidr;
> >  }
> >  
> > -/* Only support Aff0 for now, up to 4 cpus */
> > -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> > +#define MPIDR_HWID_BITMASK 0xffffff
> > +extern int mpidr_to_cpu(unsigned long mpidr);
> > +
> > +#define MPIDR_LEVEL_SHIFT(level) \
> > +	(((1 << level) >> 1) << 3)
> can't we have level << 3?
> > +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> > +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
> >  
> >  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
> >  extern bool is_user(void);
> > diff --git a/lib/arm/asm/setup.h b/lib/arm/asm/setup.h
> > index cb8fdbd38dd5d..c501c6ddd8657 100644
> > --- a/lib/arm/asm/setup.h
> > +++ b/lib/arm/asm/setup.h
> > @@ -10,8 +10,8 @@
> >  #include <asm/page.h>
> >  #include <asm/pgtable-hwdef.h>
> >  
> > -#define NR_CPUS			8
> > -extern u32 cpus[NR_CPUS];
> > +#define NR_CPUS			255
> 256?

The kernel defines KVM_MAX_VCPUS as VGIC_V3_MAX_CPUS, which is
currently defined as 255. I was just being consistent.

> > +extern u64 cpus[NR_CPUS];
> maybe worth commenting the semantic of cpus[i]?

sure

> >  extern int nr_cpus;
> what about MAX_CPUS instead of NR_CPUS?

kernel uses NR_CPUS, I want to be consistent.

> >  
> >  #define NR_MEM_REGIONS		8
> > diff --git a/lib/arm/setup.c b/lib/arm/setup.c
> > index 7e7b39f11dde1..b6e2d5815e723 100644
> > --- a/lib/arm/setup.c
> > +++ b/lib/arm/setup.c
> > @@ -24,12 +24,22 @@ extern unsigned long stacktop;
> >  extern void io_init(void);
> >  extern void setup_args_progname(const char *args);
> >  
> > -u32 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
> > +u64 cpus[NR_CPUS] = { [0 ... NR_CPUS-1] = (~0U) };
> >  int nr_cpus;
> >  
> >  struct mem_region mem_regions[NR_MEM_REGIONS];
> >  phys_addr_t __phys_offset, __phys_end;
> >  
> > +int mpidr_to_cpu(unsigned long mpidr)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < nr_cpus; ++i)
> > +		if (cpus[i] == (mpidr & MPIDR_HWID_BITMASK))
> > +			return i;
> > +	return -1;
> > +}
> > +
> >  static void cpu_set(int fdtnode __unused, u32 regval, void *info __unused)
> >  {
> >  	int cpu = nr_cpus++;
> > diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> > index 9a208ff729b7e..7e448dc81a6aa 100644
> > --- a/lib/arm64/asm/processor.h
> > +++ b/lib/arm64/asm/processor.h
> > @@ -78,8 +78,13 @@ static inline type get_##reg(void)				\
> >  
> >  DEFINE_GET_SYSREG64(mpidr)
> >  
> > -/* Only support Aff0 for now, gicv2 only */
> > -#define mpidr_to_cpu(mpidr) ((int)((mpidr) & 0xff))
> > +#define MPIDR_HWID_BITMASK 0xff00ffffff
> > +extern int mpidr_to_cpu(unsigned long mpidr);
> > +
> > +#define MPIDR_LEVEL_SHIFT(level) \
> > +	(((1 << level) >> 1) << 3)
> what about level 3? the macro would fail fetching affinity level 3.
> 
> Thanks
> 
> Eric
> > +#define MPIDR_AFFINITY_LEVEL(mpidr, level) \
> > +	((mpidr >> MPIDR_LEVEL_SHIFT(level)) & 0xff)
> >  
> >  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
> >  extern bool is_user(void);
> > 
>

Thanks,
drew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support
  2016-09-01 10:20     ` Auger Eric
@ 2016-10-17 13:14       ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 13:14 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm

On Thu, Sep 01, 2016 at 12:20:06PM +0200, Auger Eric wrote:
> 
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Add some gicv2 support. This just adds init and enable
> > functions, allowing unit tests to start messing with it.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  arm/Makefile.common    |  1 +
> >  lib/arm/asm/gic-v2.h   | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/arm/asm/gic.h      | 20 ++++++++++++++
> >  lib/arm/gic.c          | 69 ++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/arm64/asm/gic-v2.h |  1 +
> >  lib/arm64/asm/gic.h    |  1 +
> >  6 files changed, 166 insertions(+)
> >  create mode 100644 lib/arm/asm/gic-v2.h
> >  create mode 100644 lib/arm/asm/gic.h
> >  create mode 100644 lib/arm/gic.c
> >  create mode 100644 lib/arm64/asm/gic-v2.h
> >  create mode 100644 lib/arm64/asm/gic.h
> > 
> > diff --git a/arm/Makefile.common b/arm/Makefile.common
> > index ccb554d9251a4..41239c37e0920 100644
> > --- a/arm/Makefile.common
> > +++ b/arm/Makefile.common
> > @@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
> >  cflatobjs += lib/arm/bitops.o
> >  cflatobjs += lib/arm/psci.o
> >  cflatobjs += lib/arm/smp.o
> > +cflatobjs += lib/arm/gic.o
> >  
> >  libeabi = lib/arm/libeabi.a
> >  eabiobjs = lib/arm/eabi_compat.o
> > diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
> > new file mode 100644
> > index 0000000000000..973c2bf3cc796
> > --- /dev/null
> > +++ b/lib/arm/asm/gic-v2.h
> > @@ -0,0 +1,74 @@
> > +/*
> > + * All GIC* defines are lifted from include/linux/irqchip/arm-gic.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_V2_H_
> > +#define _ASMARM_GIC_V2_H_
> > +
> > +#define GIC_CPU_CTRL			0x00
> > +#define GIC_CPU_PRIMASK			0x04
> > +#define GIC_CPU_BINPOINT		0x08
> > +#define GIC_CPU_INTACK			0x0c
> > +#define GIC_CPU_EOI			0x10
> > +#define GIC_CPU_RUNNINGPRI		0x14
> > +#define GIC_CPU_HIGHPRI			0x18
> > +#define GIC_CPU_ALIAS_BINPOINT		0x1c
> > +#define GIC_CPU_ACTIVEPRIO		0xd0
> > +#define GIC_CPU_IDENT			0xfc
> > +#define GIC_CPU_DEACTIVATE		0x1000
> > +
> > +#define GICC_ENABLE			0x1
> > +#define GICC_INT_PRI_THRESHOLD		0xf0
> > +
> > +#define GIC_CPU_CTRL_EOImodeNS		(1 << 9)
> > +
> > +#define GICC_IAR_INT_ID_MASK		0x3ff
> > +#define GICC_INT_SPURIOUS		1023
> > +#define GICC_DIS_BYPASS_MASK		0x1e0
> > +
> > +#define GIC_DIST_CTRL			0x000
> > +#define GIC_DIST_CTR			0x004
> you could add #define GIC_DIST_IIDR			0x008
> which can be found in arm-gic.h

I'll resync with the latest kernel headers.

> > +#define GIC_DIST_IGROUP			0x080
> > +#define GIC_DIST_ENABLE_SET		0x100
> > +#define GIC_DIST_ENABLE_CLEAR		0x180
> > +#define GIC_DIST_PENDING_SET		0x200
> > +#define GIC_DIST_PENDING_CLEAR		0x280
> > +#define GIC_DIST_ACTIVE_SET		0x300
> > +#define GIC_DIST_ACTIVE_CLEAR		0x380
> > +#define GIC_DIST_PRI			0x400
> > +#define GIC_DIST_TARGET			0x800
> > +#define GIC_DIST_CONFIG			0xc00
> > +#define GIC_DIST_SOFTINT		0xf00
> > +#define GIC_DIST_SGI_PENDING_CLEAR	0xf10
> > +#define GIC_DIST_SGI_PENDING_SET	0xf20
> > +
> > +#define GICD_ENABLE			0x1
> > +#define GICD_DISABLE			0x0
> > +#define GICD_INT_ACTLOW_LVLTRIG		0x0
> > +#define GICD_INT_EN_CLR_X32		0xffffffff
> > +#define GICD_INT_EN_SET_SGI		0x0000ffff
> > +#define GICD_INT_EN_CLR_PPI		0xffff0000
> > +#define GICD_INT_DEF_PRI		0xa0
> > +#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
> > +					(GICD_INT_DEF_PRI << 16) |\
> > +					(GICD_INT_DEF_PRI << 8) |\
> > +					GICD_INT_DEF_PRI)
> > +#ifndef __ASSEMBLY__
> > +
> > +struct gicv2_data {
> > +	void *dist_base;
> > +	void *cpu_base;
> > +};
> > +extern struct gicv2_data gicv2_data;
> > +
> > +#define gicv2_dist_base()		(gicv2_data.dist_base)
> > +#define gicv2_cpu_base()		(gicv2_data.cpu_base)
> > +
> > +extern int gicv2_init(void);
> > +extern void gicv2_enable_defaults(void);
> > +
> > +#endif /* !__ASSEMBLY__ */
> > +#endif /* _ASMARM_GIC_V2_H_ */
> > diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
> > new file mode 100644
> > index 0000000000000..b1237d1c5ef22
> > --- /dev/null
> > +++ b/lib/arm/asm/gic.h
> > @@ -0,0 +1,20 @@
> > +/*
> > + * 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_H_
> > +#define _ASMARM_GIC_H_
> > +
> > +#include <asm/gic-v2.h>
> to be moved in gic.c?

The idea is that we can strive to create a common interface for basic
gic features, as some unit tests will use such a minimal feature set
of the gic that it won't matter if it's a v2 or v3. Those unit tests
would then just include the generic 'asm/gic.h' and use generic
functions only. This series doesn't introduce any generic functions,
except gic_init, but going forward we may.

> > +
> > +/*
> > + * gic_init will try to find all known gics, and then
> > + * initialize the gic data for the one found.
> > + * returns
> > + *  0   : no gic was found
> > + *  > 0 : the gic version of the gic found
> > + */
> > +extern int gic_init(void);
> > +
> > +#endif /* _ASMARM_GIC_H_ */
> > diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> > new file mode 100644
> > index 0000000000000..64a3049c9e8ce
> > --- /dev/null
> > +++ b/lib/arm/gic.c
> > @@ -0,0 +1,69 @@
> > +/*
> > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> > + *
> > + * This work is licensed under the terms of the GNU LGPL, version 2.
> > + */
> > +#include <libcflat.h>
> > +#include <devicetree.h>
> > +#include <asm/gic.h>
> gic-v2.h?

We'll need both -v2 and -v3, and gic.h does that for us. In the future
we may need gic.h too, so just gic.h seems like the better choice from
the start.

> > +#include <asm/smp.h>
> > +#include <asm/io.h>
> > +
> > +struct gicv2_data gicv2_data;
> > +
> > +/*
> > + * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
> > + */
> > +static bool
> > +gic_get_dt_bases(const char *compatible, void **base1, void **base2)
> > +{
> > +	struct dt_pbus_reg reg;
> > +	struct dt_device gic;
> > +	struct dt_bus bus;
> > +	int node, ret;
> > +
> > +	dt_bus_init_defaults(&bus);
> > +	dt_device_init(&gic, &bus, NULL);
> > +
> > +	node = dt_device_find_compatible(&gic, compatible);
> > +	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
> > +
> > +	if (node == -FDT_ERR_NOTFOUND)
> > +		return false;
> > +
> > +	dt_device_bind_node(&gic, node);
> > +
> > +	ret = dt_pbus_translate(&gic, 0, &reg);
> > +	assert(ret == 0);
> > +	*base1 = ioremap(reg.addr, reg.size);
> > +
> > +	ret = dt_pbus_translate(&gic, 1, &reg);
> > +	assert(ret == 0);
> > +	*base2 = ioremap(reg.addr, reg.size);
> > +
> > +	return true;
> > +}
> > +
> > +int gicv2_init(void)
> > +{
> > +	return gic_get_dt_bases("arm,cortex-a15-gic",
> > +			&gicv2_data.dist_base, &gicv2_data.cpu_base);
> what about the other possible compat strings. Is it safe to look only
> for that one?

Currently, yes. Currently we only care about mach-virt, and thus far
mach-virt uses only this. Let's only add new compat strings as we test
models that use them.

> > +}
> > +
> > +int gic_init(void)
> > +{
> > +	if (gicv2_init())
> > +		return 2;
> > +	return 0;
> > +}
> > +
> > +void gicv2_enable_defaults(void)
> > +{
> > +	if (smp_processor_id() == 0) {
> > +		writel(GICD_INT_DEF_PRI_X4, gicv2_dist_base() + GIC_DIST_PRI);
> I don't get this. There are (8*(GICD_TYPER.ITLinesNumber+1)) such
> registers. See irq-gic-common.c/gic_dist_config
> 
> More generally shouldn't we implement something like gic_dist_config and
> gic_cpu_config

So the gic*_enable_defaults functions are certainly places I could have
messed up. I appreciate the review trying to get it right. In the least
I should have commented my intentions better, because I hardly remember
them now myself... Here's what I was trying to achieve

1) Create an enable function for unit tests which don't really care about
   what's enabled, i.e. provide a functioning, but minimally configured,
   gic.
2) While using gic_dist_config and gic_cpu_config as inspiration, cut
   it down to just a handful of register writes in order to make it
   easy for unit test writers to understand on a quick read.
3) Only one cpu sets up the distributor.

I think you're right that I screwed up on gicv2's enable. I should have
an irq_nr, like I do for gicv3, in order to set all registers.

Also, in both the v2 and v3 cases I should probably improve how I
determine by whom and when the distributor is set up. Rather than
requiring only cpu0 to do the setup, and the secondaries to not even
try until it's done, I can probably let any cpu do it, and force the
others to wait until it's ready to setup the cpu interfaces.

I'll give this another pass...

Thanks,
drew

> 
> Thanks
> 
> Eric
> 
> > +		writel(GICD_INT_EN_SET_SGI, gicv2_dist_base() + GIC_DIST_ENABLE_SET);
> > +		writel(GICD_ENABLE, gicv2_dist_base() + GIC_DIST_CTRL);
> > +	}
> > +	writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK);
> > +	writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL);
> > +}
> > diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
> > new file mode 100644
> > index 0000000000000..52226624a2092
> > --- /dev/null
> > +++ b/lib/arm64/asm/gic-v2.h
> > @@ -0,0 +1 @@
> > +#include "../../arm/asm/gic-v2.h"
> > diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
> > new file mode 100644
> > index 0000000000000..e5eb302a31b4d
> > --- /dev/null
> > +++ b/lib/arm64/asm/gic.h
> > @@ -0,0 +1 @@
> > +#include "../../arm/asm/gic.h"
> > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support
@ 2016-10-17 13:14       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 13:14 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee, marc.zyngier, wei, christoffer.dall

On Thu, Sep 01, 2016 at 12:20:06PM +0200, Auger Eric wrote:
> 
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Add some gicv2 support. This just adds init and enable
> > functions, allowing unit tests to start messing with it.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> >  arm/Makefile.common    |  1 +
> >  lib/arm/asm/gic-v2.h   | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/arm/asm/gic.h      | 20 ++++++++++++++
> >  lib/arm/gic.c          | 69 ++++++++++++++++++++++++++++++++++++++++++++++
> >  lib/arm64/asm/gic-v2.h |  1 +
> >  lib/arm64/asm/gic.h    |  1 +
> >  6 files changed, 166 insertions(+)
> >  create mode 100644 lib/arm/asm/gic-v2.h
> >  create mode 100644 lib/arm/asm/gic.h
> >  create mode 100644 lib/arm/gic.c
> >  create mode 100644 lib/arm64/asm/gic-v2.h
> >  create mode 100644 lib/arm64/asm/gic.h
> > 
> > diff --git a/arm/Makefile.common b/arm/Makefile.common
> > index ccb554d9251a4..41239c37e0920 100644
> > --- a/arm/Makefile.common
> > +++ b/arm/Makefile.common
> > @@ -42,6 +42,7 @@ cflatobjs += lib/arm/mmu.o
> >  cflatobjs += lib/arm/bitops.o
> >  cflatobjs += lib/arm/psci.o
> >  cflatobjs += lib/arm/smp.o
> > +cflatobjs += lib/arm/gic.o
> >  
> >  libeabi = lib/arm/libeabi.a
> >  eabiobjs = lib/arm/eabi_compat.o
> > diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
> > new file mode 100644
> > index 0000000000000..973c2bf3cc796
> > --- /dev/null
> > +++ b/lib/arm/asm/gic-v2.h
> > @@ -0,0 +1,74 @@
> > +/*
> > + * All GIC* defines are lifted from include/linux/irqchip/arm-gic.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_V2_H_
> > +#define _ASMARM_GIC_V2_H_
> > +
> > +#define GIC_CPU_CTRL			0x00
> > +#define GIC_CPU_PRIMASK			0x04
> > +#define GIC_CPU_BINPOINT		0x08
> > +#define GIC_CPU_INTACK			0x0c
> > +#define GIC_CPU_EOI			0x10
> > +#define GIC_CPU_RUNNINGPRI		0x14
> > +#define GIC_CPU_HIGHPRI			0x18
> > +#define GIC_CPU_ALIAS_BINPOINT		0x1c
> > +#define GIC_CPU_ACTIVEPRIO		0xd0
> > +#define GIC_CPU_IDENT			0xfc
> > +#define GIC_CPU_DEACTIVATE		0x1000
> > +
> > +#define GICC_ENABLE			0x1
> > +#define GICC_INT_PRI_THRESHOLD		0xf0
> > +
> > +#define GIC_CPU_CTRL_EOImodeNS		(1 << 9)
> > +
> > +#define GICC_IAR_INT_ID_MASK		0x3ff
> > +#define GICC_INT_SPURIOUS		1023
> > +#define GICC_DIS_BYPASS_MASK		0x1e0
> > +
> > +#define GIC_DIST_CTRL			0x000
> > +#define GIC_DIST_CTR			0x004
> you could add #define GIC_DIST_IIDR			0x008
> which can be found in arm-gic.h

I'll resync with the latest kernel headers.

> > +#define GIC_DIST_IGROUP			0x080
> > +#define GIC_DIST_ENABLE_SET		0x100
> > +#define GIC_DIST_ENABLE_CLEAR		0x180
> > +#define GIC_DIST_PENDING_SET		0x200
> > +#define GIC_DIST_PENDING_CLEAR		0x280
> > +#define GIC_DIST_ACTIVE_SET		0x300
> > +#define GIC_DIST_ACTIVE_CLEAR		0x380
> > +#define GIC_DIST_PRI			0x400
> > +#define GIC_DIST_TARGET			0x800
> > +#define GIC_DIST_CONFIG			0xc00
> > +#define GIC_DIST_SOFTINT		0xf00
> > +#define GIC_DIST_SGI_PENDING_CLEAR	0xf10
> > +#define GIC_DIST_SGI_PENDING_SET	0xf20
> > +
> > +#define GICD_ENABLE			0x1
> > +#define GICD_DISABLE			0x0
> > +#define GICD_INT_ACTLOW_LVLTRIG		0x0
> > +#define GICD_INT_EN_CLR_X32		0xffffffff
> > +#define GICD_INT_EN_SET_SGI		0x0000ffff
> > +#define GICD_INT_EN_CLR_PPI		0xffff0000
> > +#define GICD_INT_DEF_PRI		0xa0
> > +#define GICD_INT_DEF_PRI_X4		((GICD_INT_DEF_PRI << 24) |\
> > +					(GICD_INT_DEF_PRI << 16) |\
> > +					(GICD_INT_DEF_PRI << 8) |\
> > +					GICD_INT_DEF_PRI)
> > +#ifndef __ASSEMBLY__
> > +
> > +struct gicv2_data {
> > +	void *dist_base;
> > +	void *cpu_base;
> > +};
> > +extern struct gicv2_data gicv2_data;
> > +
> > +#define gicv2_dist_base()		(gicv2_data.dist_base)
> > +#define gicv2_cpu_base()		(gicv2_data.cpu_base)
> > +
> > +extern int gicv2_init(void);
> > +extern void gicv2_enable_defaults(void);
> > +
> > +#endif /* !__ASSEMBLY__ */
> > +#endif /* _ASMARM_GIC_V2_H_ */
> > diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
> > new file mode 100644
> > index 0000000000000..b1237d1c5ef22
> > --- /dev/null
> > +++ b/lib/arm/asm/gic.h
> > @@ -0,0 +1,20 @@
> > +/*
> > + * 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_H_
> > +#define _ASMARM_GIC_H_
> > +
> > +#include <asm/gic-v2.h>
> to be moved in gic.c?

The idea is that we can strive to create a common interface for basic
gic features, as some unit tests will use such a minimal feature set
of the gic that it won't matter if it's a v2 or v3. Those unit tests
would then just include the generic 'asm/gic.h' and use generic
functions only. This series doesn't introduce any generic functions,
except gic_init, but going forward we may.

> > +
> > +/*
> > + * gic_init will try to find all known gics, and then
> > + * initialize the gic data for the one found.
> > + * returns
> > + *  0   : no gic was found
> > + *  > 0 : the gic version of the gic found
> > + */
> > +extern int gic_init(void);
> > +
> > +#endif /* _ASMARM_GIC_H_ */
> > diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> > new file mode 100644
> > index 0000000000000..64a3049c9e8ce
> > --- /dev/null
> > +++ b/lib/arm/gic.c
> > @@ -0,0 +1,69 @@
> > +/*
> > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> > + *
> > + * This work is licensed under the terms of the GNU LGPL, version 2.
> > + */
> > +#include <libcflat.h>
> > +#include <devicetree.h>
> > +#include <asm/gic.h>
> gic-v2.h?

We'll need both -v2 and -v3, and gic.h does that for us. In the future
we may need gic.h too, so just gic.h seems like the better choice from
the start.

> > +#include <asm/smp.h>
> > +#include <asm/io.h>
> > +
> > +struct gicv2_data gicv2_data;
> > +
> > +/*
> > + * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
> > + */
> > +static bool
> > +gic_get_dt_bases(const char *compatible, void **base1, void **base2)
> > +{
> > +	struct dt_pbus_reg reg;
> > +	struct dt_device gic;
> > +	struct dt_bus bus;
> > +	int node, ret;
> > +
> > +	dt_bus_init_defaults(&bus);
> > +	dt_device_init(&gic, &bus, NULL);
> > +
> > +	node = dt_device_find_compatible(&gic, compatible);
> > +	assert(node >= 0 || node == -FDT_ERR_NOTFOUND);
> > +
> > +	if (node == -FDT_ERR_NOTFOUND)
> > +		return false;
> > +
> > +	dt_device_bind_node(&gic, node);
> > +
> > +	ret = dt_pbus_translate(&gic, 0, &reg);
> > +	assert(ret == 0);
> > +	*base1 = ioremap(reg.addr, reg.size);
> > +
> > +	ret = dt_pbus_translate(&gic, 1, &reg);
> > +	assert(ret == 0);
> > +	*base2 = ioremap(reg.addr, reg.size);
> > +
> > +	return true;
> > +}
> > +
> > +int gicv2_init(void)
> > +{
> > +	return gic_get_dt_bases("arm,cortex-a15-gic",
> > +			&gicv2_data.dist_base, &gicv2_data.cpu_base);
> what about the other possible compat strings. Is it safe to look only
> for that one?

Currently, yes. Currently we only care about mach-virt, and thus far
mach-virt uses only this. Let's only add new compat strings as we test
models that use them.

> > +}
> > +
> > +int gic_init(void)
> > +{
> > +	if (gicv2_init())
> > +		return 2;
> > +	return 0;
> > +}
> > +
> > +void gicv2_enable_defaults(void)
> > +{
> > +	if (smp_processor_id() == 0) {
> > +		writel(GICD_INT_DEF_PRI_X4, gicv2_dist_base() + GIC_DIST_PRI);
> I don't get this. There are (8*(GICD_TYPER.ITLinesNumber+1)) such
> registers. See irq-gic-common.c/gic_dist_config
> 
> More generally shouldn't we implement something like gic_dist_config and
> gic_cpu_config

So the gic*_enable_defaults functions are certainly places I could have
messed up. I appreciate the review trying to get it right. In the least
I should have commented my intentions better, because I hardly remember
them now myself... Here's what I was trying to achieve

1) Create an enable function for unit tests which don't really care about
   what's enabled, i.e. provide a functioning, but minimally configured,
   gic.
2) While using gic_dist_config and gic_cpu_config as inspiration, cut
   it down to just a handful of register writes in order to make it
   easy for unit test writers to understand on a quick read.
3) Only one cpu sets up the distributor.

I think you're right that I screwed up on gicv2's enable. I should have
an irq_nr, like I do for gicv3, in order to set all registers.

Also, in both the v2 and v3 cases I should probably improve how I
determine by whom and when the distributor is set up. Rather than
requiring only cpu0 to do the setup, and the secondaries to not even
try until it's done, I can probably let any cpu do it, and force the
others to wait until it's ready to setup the cpu interfaces.

I'll give this another pass...

Thanks,
drew

> 
> Thanks
> 
> Eric
> 
> > +		writel(GICD_INT_EN_SET_SGI, gicv2_dist_base() + GIC_DIST_ENABLE_SET);
> > +		writel(GICD_ENABLE, gicv2_dist_base() + GIC_DIST_CTRL);
> > +	}
> > +	writel(GICC_INT_PRI_THRESHOLD, gicv2_cpu_base() + GIC_CPU_PRIMASK);
> > +	writel(GICC_ENABLE, gicv2_cpu_base() + GIC_CPU_CTRL);
> > +}
> > diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
> > new file mode 100644
> > index 0000000000000..52226624a2092
> > --- /dev/null
> > +++ b/lib/arm64/asm/gic-v2.h
> > @@ -0,0 +1 @@
> > +#include "../../arm/asm/gic-v2.h"
> > diff --git a/lib/arm64/asm/gic.h b/lib/arm64/asm/gic.h
> > new file mode 100644
> > index 0000000000000..e5eb302a31b4d
> > --- /dev/null
> > +++ b/lib/arm64/asm/gic.h
> > @@ -0,0 +1 @@
> > +#include "../../arm/asm/gic.h"
> > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
  2016-09-01 10:19     ` Auger Eric
  (?)
@ 2016-10-17 13:30     ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 13:30 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee, marc.zyngier, wei, christoffer.dall

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_ */
> > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 09/10] arm/arm64: gicv3: add an IPI test
  2016-09-01 16:42   ` Auger Eric
@ 2016-10-17 13:36       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 13:36 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm

On Thu, Sep 01, 2016 at 06:42:44PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > 
> > ---
> > v2: use IRM for gicv3 broadcast
> > ---
> >  arm/gic.c         | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++----
> >  arm/unittests.cfg |   6 +++
> >  2 files changed, 154 insertions(+), 9 deletions(-)
> > 
> > diff --git a/arm/gic.c b/arm/gic.c
> > index cf7ec1c90413c..fc7ef241de3e2 100644
> > --- a/arm/gic.c
> > +++ b/arm/gic.c
> > @@ -3,6 +3,8 @@
> >   *
> >   * GICv2
> >   *   . test sending/receiving IPIs
> > + * GICv3
> > + *   . test sending/receiving IPIs
> >   *
> >   * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> >   *
> > @@ -16,6 +18,18 @@
> >  #include <asm/barrier.h>
> >  #include <asm/io.h>
> >  
> > +struct gic {
> > +	struct {
> > +		void (*enable)(void);
> > +		void (*send_self)(void);
> > +		void (*send_tlist)(cpumask_t *);
> > +		void (*send_broadcast)(void);
> > +	} ipi;
> > +	u32 (*read_iar)(void);
> > +	void (*write_eoi)(u32);
> > +};
> > +
> > +static struct gic *gic;
> >  static int gic_version;
> >  static int acked[NR_CPUS], spurious[NR_CPUS];
> >  static cpumask_t ready;
> > @@ -69,12 +83,22 @@ static void check_acked(cpumask_t *mask)
> >  	       false, missing, extra, unexpected);
> >  }
> >  
> > +static u32 gicv2_read_iar(void)
> > +{
> > +	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +}
> > +
> > +static void gicv2_write_eoi(u32 irq)
> > +{
> > +	writel(irq, gicv2_cpu_base() + GIC_CPU_EOI);
> > +}
> > +
> >  static void ipi_handler(struct pt_regs *regs __unused)
> >  {
> > -	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +	u32 iar = gic->read_iar();
> >  
> >  	if (iar != GICC_INT_SPURIOUS) {
> > -		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
> > +		gic->write_eoi(iar);
> >  		smp_rmb(); /* pairs with wmb in ipi_test functions */
> >  		++acked[smp_processor_id()];
> >  		smp_wmb(); /* pairs with rmb in check_acked */
> > @@ -84,6 +108,89 @@ static void ipi_handler(struct pt_regs *regs __unused)
> >  	}
> >  }
> >  
> > +static void gicv2_ipi_send_self(void)
> > +{
> > +	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +}
> > +
> > +static void gicv2_ipi_send_tlist(cpumask_t *mask)
> > +{
> > +	u8 tlist = (u8)cpumask_bits(mask)[0];
> > +
> > +	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +}
> > +
> > +static void gicv2_ipi_send_broadcast(void)
> > +{
> > +	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +}
> > +
> > +#define ICC_SGI1R_AFFINITY_1_SHIFT	16
> > +#define ICC_SGI1R_AFFINITY_2_SHIFT	32
> > +#define ICC_SGI1R_AFFINITY_3_SHIFT	48
> > +#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
> > +	(MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
> > +
> > +static void gicv3_ipi_send_tlist(cpumask_t *mask)
> > +{
> This function really is indigestible to me. Can't we reuse the linux
> kernel gic_compute_target_list routine. Since the code looks similar why
> not trying to be as close as possible to the kernel?

It is the same, but simplified :-) In Linux, gic_compute_target_list is
not the only function you need for the implementation. You also need to
look at the one caller, which is gic_raise_softirq. I'll add a couple of
comments to this version, which simply inlines the kernel's version.

Thanks,
drew 

> 
> Thanks
> 
> Eric
> > +	u16 tlist;
> > +	int cpu;
> > +
> > +	for_each_cpu(cpu, mask) {
> > +		u64 mpidr = cpus[cpu], sgi1r;
> > +		u64 cluster_id = mpidr & ~0xffUL;
> > +
> > +		tlist = 0;
> > +
> > +		while (cpu < nr_cpus) {
> > +			if ((mpidr & 0xff) >= 16) {
> > +				printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
> > +					cpu, (int)(mpidr & 0xff));
> > +				break;
> > +			}
> > +
> > +			tlist |= 1 << (mpidr & 0xf);
> > +
> > +			cpu = cpumask_next(cpu, mask);
> > +			if (cpu >= nr_cpus)
> > +				break;
> > +
> > +			mpidr = cpus[cpu];
> > +
> > +			if (cluster_id != (mpidr & ~0xffUL)) {
> > +				--cpu;
> > +				break;
> > +			}
> > +		}
> > +
> > +		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
> > +			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
> > +			 /* irq << 24				| */
> > +			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
> > +			 tlist);
> > +
> > +		gicv3_write_sgi1r(sgi1r);
> > +	}
> > +
> > +	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
> > +	isb();
> > +}
> > +
> > +static void gicv3_ipi_send_self(void)
> > +{
> > +	cpumask_t mask;
> > +
> > +	cpumask_clear(&mask);
> > +	cpumask_set_cpu(smp_processor_id(), &mask);
> > +	gicv3_ipi_send_tlist(&mask);
> > +}
> > +
> > +static void gicv3_ipi_send_broadcast(void)
> > +{
> > +	gicv3_write_sgi1r(1ULL << 40);
> > +	isb();
> > +}
> > +
> >  static void ipi_test_self(void)
> >  {
> >  	cpumask_t mask;
> > @@ -93,7 +200,7 @@ static void ipi_test_self(void)
> >  	smp_wmb();
> >  	cpumask_clear(&mask);
> >  	cpumask_set_cpu(0, &mask);
> > -	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	gic->ipi.send_self();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> >  }
> > @@ -101,14 +208,15 @@ static void ipi_test_self(void)
> >  static void ipi_test_smp(void)
> >  {
> >  	cpumask_t mask;
> > -	unsigned long tlist;
> > +	int i;
> >  
> >  	report_prefix_push("target-list");
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> > -	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> > -	cpumask_bits(&mask)[0] = tlist;
> > -	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	cpumask_copy(&mask, &cpu_present_mask);
> > +	for (i = 0; i < nr_cpus; i += 2)
> > +		cpumask_clear_cpu(i, &mask);
> > +	gic->ipi.send_tlist(&mask);
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> >  
> > @@ -117,14 +225,14 @@ static void ipi_test_smp(void)
> >  	smp_wmb();
> >  	cpumask_copy(&mask, &cpu_present_mask);
> >  	cpumask_clear_cpu(0, &mask);
> > -	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	gic->ipi.send_broadcast();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> >  }
> >  
> >  static void ipi_enable(void)
> >  {
> > -	gicv2_enable_defaults();
> > +	gic->ipi.enable();
> >  #ifdef __arm__
> >  	install_exception_handler(EXCPTN_IRQ, ipi_handler);
> >  #else
> > @@ -141,6 +249,28 @@ static void ipi_recv(void)
> >  		wfi();
> >  }
> >  
> > +struct gic gicv2 = {
> > +	.ipi = {
> > +		.enable = gicv2_enable_defaults,
> > +		.send_self = gicv2_ipi_send_self,
> > +		.send_tlist = gicv2_ipi_send_tlist,
> > +		.send_broadcast = gicv2_ipi_send_broadcast,
> > +	},
> > +	.read_iar = gicv2_read_iar,
> > +	.write_eoi = gicv2_write_eoi,
> > +};
> > +
> > +struct gic gicv3 = {
> > +	.ipi = {
> > +		.enable = gicv3_enable_defaults,
> > +		.send_self = gicv3_ipi_send_self,
> > +		.send_tlist = gicv3_ipi_send_tlist,
> > +		.send_broadcast = gicv3_ipi_send_broadcast,
> > +	},
> > +	.read_iar = gicv3_read_iar,
> > +	.write_eoi = gicv3_write_eoir,
> > +};
> > +
> >  int main(int argc, char **argv)
> >  {
> >  	char pfx[8];
> > @@ -153,6 +283,15 @@ int main(int argc, char **argv)
> >  	snprintf(pfx, 8, "gicv%d", gic_version);
> >  	report_prefix_push(pfx);
> >  
> > +	switch (gic_version) {
> > +	case 2:
> > +		gic = &gicv2;
> > +		break;
> > +	case 3:
> > +		gic = &gicv3;
> > +		break;
> > +	}
> > +
> >  	if (argc < 2) {
> >  
> >  		report_prefix_push("ipi");
> > diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> > index bb364675043f0..043a20e26e98c 100644
> > --- a/arm/unittests.cfg
> > +++ b/arm/unittests.cfg
> > @@ -58,3 +58,9 @@ file = gic.flat
> >  smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
> >  extra_params = -machine gic-version=2 -append 'ipi'
> >  groups = gic
> > +
> > +[gicv3-ipi]
> > +file = gic.flat
> > +smp = $MAX_SMP
> > +extra_params = -machine gic-version=3 -append 'ipi'
> > +groups = gic
> > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 09/10] arm/arm64: gicv3: add an IPI test
@ 2016-10-17 13:36       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 13:36 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee, marc.zyngier, wei, christoffer.dall

On Thu, Sep 01, 2016 at 06:42:44PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > 
> > ---
> > v2: use IRM for gicv3 broadcast
> > ---
> >  arm/gic.c         | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++----
> >  arm/unittests.cfg |   6 +++
> >  2 files changed, 154 insertions(+), 9 deletions(-)
> > 
> > diff --git a/arm/gic.c b/arm/gic.c
> > index cf7ec1c90413c..fc7ef241de3e2 100644
> > --- a/arm/gic.c
> > +++ b/arm/gic.c
> > @@ -3,6 +3,8 @@
> >   *
> >   * GICv2
> >   *   . test sending/receiving IPIs
> > + * GICv3
> > + *   . test sending/receiving IPIs
> >   *
> >   * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> >   *
> > @@ -16,6 +18,18 @@
> >  #include <asm/barrier.h>
> >  #include <asm/io.h>
> >  
> > +struct gic {
> > +	struct {
> > +		void (*enable)(void);
> > +		void (*send_self)(void);
> > +		void (*send_tlist)(cpumask_t *);
> > +		void (*send_broadcast)(void);
> > +	} ipi;
> > +	u32 (*read_iar)(void);
> > +	void (*write_eoi)(u32);
> > +};
> > +
> > +static struct gic *gic;
> >  static int gic_version;
> >  static int acked[NR_CPUS], spurious[NR_CPUS];
> >  static cpumask_t ready;
> > @@ -69,12 +83,22 @@ static void check_acked(cpumask_t *mask)
> >  	       false, missing, extra, unexpected);
> >  }
> >  
> > +static u32 gicv2_read_iar(void)
> > +{
> > +	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +}
> > +
> > +static void gicv2_write_eoi(u32 irq)
> > +{
> > +	writel(irq, gicv2_cpu_base() + GIC_CPU_EOI);
> > +}
> > +
> >  static void ipi_handler(struct pt_regs *regs __unused)
> >  {
> > -	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +	u32 iar = gic->read_iar();
> >  
> >  	if (iar != GICC_INT_SPURIOUS) {
> > -		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
> > +		gic->write_eoi(iar);
> >  		smp_rmb(); /* pairs with wmb in ipi_test functions */
> >  		++acked[smp_processor_id()];
> >  		smp_wmb(); /* pairs with rmb in check_acked */
> > @@ -84,6 +108,89 @@ static void ipi_handler(struct pt_regs *regs __unused)
> >  	}
> >  }
> >  
> > +static void gicv2_ipi_send_self(void)
> > +{
> > +	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +}
> > +
> > +static void gicv2_ipi_send_tlist(cpumask_t *mask)
> > +{
> > +	u8 tlist = (u8)cpumask_bits(mask)[0];
> > +
> > +	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +}
> > +
> > +static void gicv2_ipi_send_broadcast(void)
> > +{
> > +	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +}
> > +
> > +#define ICC_SGI1R_AFFINITY_1_SHIFT	16
> > +#define ICC_SGI1R_AFFINITY_2_SHIFT	32
> > +#define ICC_SGI1R_AFFINITY_3_SHIFT	48
> > +#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
> > +	(MPIDR_AFFINITY_LEVEL(cluster_id, level) << ICC_SGI1R_AFFINITY_## level ## _SHIFT)
> > +
> > +static void gicv3_ipi_send_tlist(cpumask_t *mask)
> > +{
> This function really is indigestible to me. Can't we reuse the linux
> kernel gic_compute_target_list routine. Since the code looks similar why
> not trying to be as close as possible to the kernel?

It is the same, but simplified :-) In Linux, gic_compute_target_list is
not the only function you need for the implementation. You also need to
look at the one caller, which is gic_raise_softirq. I'll add a couple of
comments to this version, which simply inlines the kernel's version.

Thanks,
drew 

> 
> Thanks
> 
> Eric
> > +	u16 tlist;
> > +	int cpu;
> > +
> > +	for_each_cpu(cpu, mask) {
> > +		u64 mpidr = cpus[cpu], sgi1r;
> > +		u64 cluster_id = mpidr & ~0xffUL;
> > +
> > +		tlist = 0;
> > +
> > +		while (cpu < nr_cpus) {
> > +			if ((mpidr & 0xff) >= 16) {
> > +				printf("cpu%d MPIDR:aff0 is %d (>= 16)!\n",
> > +					cpu, (int)(mpidr & 0xff));
> > +				break;
> > +			}
> > +
> > +			tlist |= 1 << (mpidr & 0xf);
> > +
> > +			cpu = cpumask_next(cpu, mask);
> > +			if (cpu >= nr_cpus)
> > +				break;
> > +
> > +			mpidr = cpus[cpu];
> > +
> > +			if (cluster_id != (mpidr & ~0xffUL)) {
> > +				--cpu;
> > +				break;
> > +			}
> > +		}
> > +
> > +		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
> > +			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
> > +			 /* irq << 24				| */
> > +			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
> > +			 tlist);
> > +
> > +		gicv3_write_sgi1r(sgi1r);
> > +	}
> > +
> > +	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
> > +	isb();
> > +}
> > +
> > +static void gicv3_ipi_send_self(void)
> > +{
> > +	cpumask_t mask;
> > +
> > +	cpumask_clear(&mask);
> > +	cpumask_set_cpu(smp_processor_id(), &mask);
> > +	gicv3_ipi_send_tlist(&mask);
> > +}
> > +
> > +static void gicv3_ipi_send_broadcast(void)
> > +{
> > +	gicv3_write_sgi1r(1ULL << 40);
> > +	isb();
> > +}
> > +
> >  static void ipi_test_self(void)
> >  {
> >  	cpumask_t mask;
> > @@ -93,7 +200,7 @@ static void ipi_test_self(void)
> >  	smp_wmb();
> >  	cpumask_clear(&mask);
> >  	cpumask_set_cpu(0, &mask);
> > -	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	gic->ipi.send_self();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> >  }
> > @@ -101,14 +208,15 @@ static void ipi_test_self(void)
> >  static void ipi_test_smp(void)
> >  {
> >  	cpumask_t mask;
> > -	unsigned long tlist;
> > +	int i;
> >  
> >  	report_prefix_push("target-list");
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> > -	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> > -	cpumask_bits(&mask)[0] = tlist;
> > -	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	cpumask_copy(&mask, &cpu_present_mask);
> > +	for (i = 0; i < nr_cpus; i += 2)
> > +		cpumask_clear_cpu(i, &mask);
> > +	gic->ipi.send_tlist(&mask);
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> >  
> > @@ -117,14 +225,14 @@ static void ipi_test_smp(void)
> >  	smp_wmb();
> >  	cpumask_copy(&mask, &cpu_present_mask);
> >  	cpumask_clear_cpu(0, &mask);
> > -	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	gic->ipi.send_broadcast();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> >  }
> >  
> >  static void ipi_enable(void)
> >  {
> > -	gicv2_enable_defaults();
> > +	gic->ipi.enable();
> >  #ifdef __arm__
> >  	install_exception_handler(EXCPTN_IRQ, ipi_handler);
> >  #else
> > @@ -141,6 +249,28 @@ static void ipi_recv(void)
> >  		wfi();
> >  }
> >  
> > +struct gic gicv2 = {
> > +	.ipi = {
> > +		.enable = gicv2_enable_defaults,
> > +		.send_self = gicv2_ipi_send_self,
> > +		.send_tlist = gicv2_ipi_send_tlist,
> > +		.send_broadcast = gicv2_ipi_send_broadcast,
> > +	},
> > +	.read_iar = gicv2_read_iar,
> > +	.write_eoi = gicv2_write_eoi,
> > +};
> > +
> > +struct gic gicv3 = {
> > +	.ipi = {
> > +		.enable = gicv3_enable_defaults,
> > +		.send_self = gicv3_ipi_send_self,
> > +		.send_tlist = gicv3_ipi_send_tlist,
> > +		.send_broadcast = gicv3_ipi_send_broadcast,
> > +	},
> > +	.read_iar = gicv3_read_iar,
> > +	.write_eoi = gicv3_write_eoir,
> > +};
> > +
> >  int main(int argc, char **argv)
> >  {
> >  	char pfx[8];
> > @@ -153,6 +283,15 @@ int main(int argc, char **argv)
> >  	snprintf(pfx, 8, "gicv%d", gic_version);
> >  	report_prefix_push(pfx);
> >  
> > +	switch (gic_version) {
> > +	case 2:
> > +		gic = &gicv2;
> > +		break;
> > +	case 3:
> > +		gic = &gicv3;
> > +		break;
> > +	}
> > +
> >  	if (argc < 2) {
> >  
> >  		report_prefix_push("ipi");
> > diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> > index bb364675043f0..043a20e26e98c 100644
> > --- a/arm/unittests.cfg
> > +++ b/arm/unittests.cfg
> > @@ -58,3 +58,9 @@ file = gic.flat
> >  smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
> >  extra_params = -machine gic-version=2 -append 'ipi'
> >  groups = gic
> > +
> > +[gicv3-ipi]
> > +file = gic.flat
> > +smp = $MAX_SMP
> > +extra_params = -machine gic-version=3 -append 'ipi'
> > +groups = gic
> > 
> 

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test
  2016-09-01 16:42   ` Auger Eric
@ 2016-10-17 19:15       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 19:15 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm

On Thu, Sep 01, 2016 at 06:42:50PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> > v2: add more details in the output if a test fails,
> >     report spurious interrupts if we get them
> > ---
> >  arm/Makefile.common |   6 +-
> >  arm/gic.c           | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  arm/unittests.cfg   |   7 ++
> >  3 files changed, 204 insertions(+), 3 deletions(-)
> >  create mode 100644 arm/gic.c
> > 
> > diff --git a/arm/Makefile.common b/arm/Makefile.common
> > index 41239c37e0920..bc38183ab86e0 100644
> > --- a/arm/Makefile.common
> > +++ b/arm/Makefile.common
> > @@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
> >  	LOADADDR = 0x40000000
> >  endif
> >  
> > -tests-common = \
> > -	$(TEST_DIR)/selftest.flat \
> > -	$(TEST_DIR)/spinlock-test.flat
> > +tests-common  = $(TEST_DIR)/selftest.flat
> > +tests-common += $(TEST_DIR)/spinlock-test.flat
> > +tests-common += $(TEST_DIR)/gic.flat
> >  
> >  all: test_cases
> >  
> > diff --git a/arm/gic.c b/arm/gic.c
> > new file mode 100644
> > index 0000000000000..cf7ec1c90413c
> > --- /dev/null
> > +++ b/arm/gic.c
> > @@ -0,0 +1,194 @@
> > +/*
> > + * GIC tests
> > + *
> > + * GICv2
> > + *   . test sending/receiving IPIs
> > + *
> > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> > + *
> > + * This work is licensed under the terms of the GNU LGPL, version 2.
> > + */
> > +#include <libcflat.h>
> > +#include <asm/setup.h>
> > +#include <asm/processor.h>
> > +#include <asm/gic.h>
> > +#include <asm/smp.h>
> > +#include <asm/barrier.h>
> > +#include <asm/io.h>
> > +
> > +static int gic_version;
> > +static int acked[NR_CPUS], spurious[NR_CPUS];
> > +static cpumask_t ready;
> > +
> > +static void nr_cpu_check(int nr)
> > +{
> > +	if (nr_cpus < nr)
> > +		report_abort("At least %d cpus required", nr);
> > +}
> > +
> > +static void wait_on_ready(void)
> > +{
> > +	cpumask_set_cpu(smp_processor_id(), &ready);
> > +	while (!cpumask_full(&ready))
> > +		cpu_relax();
> > +}
> > +
> > +static void check_acked(cpumask_t *mask)
> > +{
> > +	int missing = 0, extra = 0, unexpected = 0;
> > +	int nr_pass, cpu, i;
> > +
> > +	/* Wait up to 5s for all interrupts to be delivered */
> > +	for (i = 0; i < 50; ++i) {
> > +		mdelay(100);
> > +		nr_pass = 0;
> > +		for_each_present_cpu(cpu) {
> Couldn't we use for_each_cpu(cpu, mask)?

If we did, then we wouldn't be able to detect delivery of interrupts to
the wrong cpus. Note, we don't run the second loop if everything looks
good here. That one is just to better report a detected problem(s).

> > +			smp_rmb();
> > +			nr_pass += cpumask_test_cpu(cpu, mask) ?
> > +				acked[cpu] == 1 : acked[cpu] == 0;
> > +		}
> > +		if (nr_pass == nr_cpus) {
> > +			report("Completed in %d ms", true, ++i * 100);
> > +			return;
> > +		}
> > +	}
> > +
> > +	for_each_present_cpu(cpu) {
> > +		if (cpumask_test_cpu(cpu, mask)) {
> here we can't since we count unexpected
> 
> > +			if (!acked[cpu])
> > +				++missing;
> > +			else if (acked[cpu] > 1)
> > +				++extra;
> > +		} else {
> > +			if (acked[cpu])
> > +				++unexpected;
> > +		}
> > +	}
> > +
> > +	report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
> > +	       false, missing, extra, unexpected);
> > +}
> > +
> > +static void ipi_handler(struct pt_regs *regs __unused)
> > +{
> > +	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +
> > +	if (iar != GICC_INT_SPURIOUS) {
> > +		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
> if EOIMode is set may need to DIR as well.

OK, I'll look into that

> > +		smp_rmb(); /* pairs with wmb in ipi_test functions */
> > +		++acked[smp_processor_id()];
> > +		smp_wmb(); /* pairs with rmb in check_acked */
> > +	} else {
> > +		++spurious[smp_processor_id()];
> > +		smp_wmb();
> > +	}
> > +}
> > +
> > +static void ipi_test_self(void)
> > +{
> > +	cpumask_t mask;
> > +
> > +	report_prefix_push("self");
> > +	memset(acked, 0, sizeof(acked));
> > +	smp_wmb();
> > +	cpumask_clear(&mask);
> > +	cpumask_set_cpu(0, &mask);
> > +	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	check_acked(&mask);
> > +	report_prefix_pop();
> > +}
> > +
> > +static void ipi_test_smp(void)
> > +{
> > +	cpumask_t mask;
> > +	unsigned long tlist;
> > +
> > +	report_prefix_push("target-list");
> > +	memset(acked, 0, sizeof(acked));
> > +	smp_wmb();
> > +	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> > +	cpumask_bits(&mask)[0] = tlist;
> > +	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	check_acked(&mask);
> > +	report_prefix_pop();
> > +
> > +	report_prefix_push("broadcast");
> > +	memset(acked, 0, sizeof(acked));
> > +	smp_wmb();
> > +	cpumask_copy(&mask, &cpu_present_mask);
> > +	cpumask_clear_cpu(0, &mask);
> > +	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	check_acked(&mask);
> > +	report_prefix_pop();
> > +}
> > +
> > +static void ipi_enable(void)
> > +{
> > +	gicv2_enable_defaults();
> > +#ifdef __arm__
> > +	install_exception_handler(EXCPTN_IRQ, ipi_handler);
> > +#else
> > +	install_irq_handler(EL1H_IRQ, ipi_handler);
> > +#endif
> > +	local_irq_enable();
> > +}
> > +
> > +static void ipi_recv(void)
> > +{
> > +	ipi_enable();
> > +	cpumask_set_cpu(smp_processor_id(), &ready);
> > +	while (1)
> > +		wfi();
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	char pfx[8];
> > +	int cpu;
> > +
> > +	gic_version = gic_init();
> > +	if (!gic_version)
> > +		report_abort("No gic present!");
> > +
> > +	snprintf(pfx, 8, "gicv%d", gic_version);
> > +	report_prefix_push(pfx);
> > +
> > +	if (argc < 2) {
> > +
> spare void line
> > +		report_prefix_push("ipi");
> > +		ipi_enable();
> > +		ipi_test_self();
> > +		report_prefix_pop();
> > +
> same
> > +	} else if (!strcmp(argv[1], "ipi")) {
> > +
> same or maybe this is just another style convention?

Indeed it is. I don't think the kernel's checkpatch
complains about it and I find it much easier to read.

> > +		report_prefix_push(argv[1]);
> > +		nr_cpu_check(2);
> > +		ipi_enable();
> > +
> > +		for_each_present_cpu(cpu) {
> > +			if (cpu == 0)
> > +				continue;
> > +			smp_boot_secondary(cpu, ipi_recv);
> > +		}
> > +		wait_on_ready();
> > +		ipi_test_self();
> > +		ipi_test_smp();
> > +
> > +		smp_rmb();
> > +		for_each_present_cpu(cpu) {
> > +			if (spurious[cpu]) {
> > +				printf("ipi: WARN: cpu%d got %d spurious "
> > +				       "interrupts\n",
> > +				       spurious[cpu], smp_processor_id());
> > +			}
> > +		}
> > +
> > +		report_prefix_pop();
> > +
> > +	} else {
> > +		report_abort("Unknown subtest '%s'", argv[1]);
> > +	}
> > +
> > +	return report_summary();
> > +}
> > diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> > index ffd12e5794aa0..bb364675043f0 100644
> > --- a/arm/unittests.cfg
> > +++ b/arm/unittests.cfg
> > @@ -51,3 +51,10 @@ file = selftest.flat
> >  smp = $MAX_SMP
> >  extra_params = -append 'smp'
> >  groups = selftest
> > +
> > +# Test GIC emulation
> > +[gicv2-ipi]
> > +file = gic.flat
> > +smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
> > +extra_params = -machine gic-version=2 -append 'ipi'
> > +groups = gic
> > 
> Aside the minor comments above,
> Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks!
drew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test
@ 2016-10-17 19:15       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 19:15 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee, marc.zyngier, wei, christoffer.dall

On Thu, Sep 01, 2016 at 06:42:50PM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > ---
> > v2: add more details in the output if a test fails,
> >     report spurious interrupts if we get them
> > ---
> >  arm/Makefile.common |   6 +-
> >  arm/gic.c           | 194 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  arm/unittests.cfg   |   7 ++
> >  3 files changed, 204 insertions(+), 3 deletions(-)
> >  create mode 100644 arm/gic.c
> > 
> > diff --git a/arm/Makefile.common b/arm/Makefile.common
> > index 41239c37e0920..bc38183ab86e0 100644
> > --- a/arm/Makefile.common
> > +++ b/arm/Makefile.common
> > @@ -9,9 +9,9 @@ ifeq ($(LOADADDR),)
> >  	LOADADDR = 0x40000000
> >  endif
> >  
> > -tests-common = \
> > -	$(TEST_DIR)/selftest.flat \
> > -	$(TEST_DIR)/spinlock-test.flat
> > +tests-common  = $(TEST_DIR)/selftest.flat
> > +tests-common += $(TEST_DIR)/spinlock-test.flat
> > +tests-common += $(TEST_DIR)/gic.flat
> >  
> >  all: test_cases
> >  
> > diff --git a/arm/gic.c b/arm/gic.c
> > new file mode 100644
> > index 0000000000000..cf7ec1c90413c
> > --- /dev/null
> > +++ b/arm/gic.c
> > @@ -0,0 +1,194 @@
> > +/*
> > + * GIC tests
> > + *
> > + * GICv2
> > + *   . test sending/receiving IPIs
> > + *
> > + * Copyright (C) 2016, Red Hat Inc, Andrew Jones <drjones@redhat.com>
> > + *
> > + * This work is licensed under the terms of the GNU LGPL, version 2.
> > + */
> > +#include <libcflat.h>
> > +#include <asm/setup.h>
> > +#include <asm/processor.h>
> > +#include <asm/gic.h>
> > +#include <asm/smp.h>
> > +#include <asm/barrier.h>
> > +#include <asm/io.h>
> > +
> > +static int gic_version;
> > +static int acked[NR_CPUS], spurious[NR_CPUS];
> > +static cpumask_t ready;
> > +
> > +static void nr_cpu_check(int nr)
> > +{
> > +	if (nr_cpus < nr)
> > +		report_abort("At least %d cpus required", nr);
> > +}
> > +
> > +static void wait_on_ready(void)
> > +{
> > +	cpumask_set_cpu(smp_processor_id(), &ready);
> > +	while (!cpumask_full(&ready))
> > +		cpu_relax();
> > +}
> > +
> > +static void check_acked(cpumask_t *mask)
> > +{
> > +	int missing = 0, extra = 0, unexpected = 0;
> > +	int nr_pass, cpu, i;
> > +
> > +	/* Wait up to 5s for all interrupts to be delivered */
> > +	for (i = 0; i < 50; ++i) {
> > +		mdelay(100);
> > +		nr_pass = 0;
> > +		for_each_present_cpu(cpu) {
> Couldn't we use for_each_cpu(cpu, mask)?

If we did, then we wouldn't be able to detect delivery of interrupts to
the wrong cpus. Note, we don't run the second loop if everything looks
good here. That one is just to better report a detected problem(s).

> > +			smp_rmb();
> > +			nr_pass += cpumask_test_cpu(cpu, mask) ?
> > +				acked[cpu] == 1 : acked[cpu] == 0;
> > +		}
> > +		if (nr_pass == nr_cpus) {
> > +			report("Completed in %d ms", true, ++i * 100);
> > +			return;
> > +		}
> > +	}
> > +
> > +	for_each_present_cpu(cpu) {
> > +		if (cpumask_test_cpu(cpu, mask)) {
> here we can't since we count unexpected
> 
> > +			if (!acked[cpu])
> > +				++missing;
> > +			else if (acked[cpu] > 1)
> > +				++extra;
> > +		} else {
> > +			if (acked[cpu])
> > +				++unexpected;
> > +		}
> > +	}
> > +
> > +	report("Timed-out (5s). ACKS: missing=%d extra=%d unexpected=%d",
> > +	       false, missing, extra, unexpected);
> > +}
> > +
> > +static void ipi_handler(struct pt_regs *regs __unused)
> > +{
> > +	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +
> > +	if (iar != GICC_INT_SPURIOUS) {
> > +		writel(iar, gicv2_cpu_base() + GIC_CPU_EOI);
> if EOIMode is set may need to DIR as well.

OK, I'll look into that

> > +		smp_rmb(); /* pairs with wmb in ipi_test functions */
> > +		++acked[smp_processor_id()];
> > +		smp_wmb(); /* pairs with rmb in check_acked */
> > +	} else {
> > +		++spurious[smp_processor_id()];
> > +		smp_wmb();
> > +	}
> > +}
> > +
> > +static void ipi_test_self(void)
> > +{
> > +	cpumask_t mask;
> > +
> > +	report_prefix_push("self");
> > +	memset(acked, 0, sizeof(acked));
> > +	smp_wmb();
> > +	cpumask_clear(&mask);
> > +	cpumask_set_cpu(0, &mask);
> > +	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	check_acked(&mask);
> > +	report_prefix_pop();
> > +}
> > +
> > +static void ipi_test_smp(void)
> > +{
> > +	cpumask_t mask;
> > +	unsigned long tlist;
> > +
> > +	report_prefix_push("target-list");
> > +	memset(acked, 0, sizeof(acked));
> > +	smp_wmb();
> > +	tlist = cpumask_bits(&cpu_present_mask)[0] & 0xaa;
> > +	cpumask_bits(&mask)[0] = tlist;
> > +	writel((u8)tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	check_acked(&mask);
> > +	report_prefix_pop();
> > +
> > +	report_prefix_push("broadcast");
> > +	memset(acked, 0, sizeof(acked));
> > +	smp_wmb();
> > +	cpumask_copy(&mask, &cpu_present_mask);
> > +	cpumask_clear_cpu(0, &mask);
> > +	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	check_acked(&mask);
> > +	report_prefix_pop();
> > +}
> > +
> > +static void ipi_enable(void)
> > +{
> > +	gicv2_enable_defaults();
> > +#ifdef __arm__
> > +	install_exception_handler(EXCPTN_IRQ, ipi_handler);
> > +#else
> > +	install_irq_handler(EL1H_IRQ, ipi_handler);
> > +#endif
> > +	local_irq_enable();
> > +}
> > +
> > +static void ipi_recv(void)
> > +{
> > +	ipi_enable();
> > +	cpumask_set_cpu(smp_processor_id(), &ready);
> > +	while (1)
> > +		wfi();
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	char pfx[8];
> > +	int cpu;
> > +
> > +	gic_version = gic_init();
> > +	if (!gic_version)
> > +		report_abort("No gic present!");
> > +
> > +	snprintf(pfx, 8, "gicv%d", gic_version);
> > +	report_prefix_push(pfx);
> > +
> > +	if (argc < 2) {
> > +
> spare void line
> > +		report_prefix_push("ipi");
> > +		ipi_enable();
> > +		ipi_test_self();
> > +		report_prefix_pop();
> > +
> same
> > +	} else if (!strcmp(argv[1], "ipi")) {
> > +
> same or maybe this is just another style convention?

Indeed it is. I don't think the kernel's checkpatch
complains about it and I find it much easier to read.

> > +		report_prefix_push(argv[1]);
> > +		nr_cpu_check(2);
> > +		ipi_enable();
> > +
> > +		for_each_present_cpu(cpu) {
> > +			if (cpu == 0)
> > +				continue;
> > +			smp_boot_secondary(cpu, ipi_recv);
> > +		}
> > +		wait_on_ready();
> > +		ipi_test_self();
> > +		ipi_test_smp();
> > +
> > +		smp_rmb();
> > +		for_each_present_cpu(cpu) {
> > +			if (spurious[cpu]) {
> > +				printf("ipi: WARN: cpu%d got %d spurious "
> > +				       "interrupts\n",
> > +				       spurious[cpu], smp_processor_id());
> > +			}
> > +		}
> > +
> > +		report_prefix_pop();
> > +
> > +	} else {
> > +		report_abort("Unknown subtest '%s'", argv[1]);
> > +	}
> > +
> > +	return report_summary();
> > +}
> > diff --git a/arm/unittests.cfg b/arm/unittests.cfg
> > index ffd12e5794aa0..bb364675043f0 100644
> > --- a/arm/unittests.cfg
> > +++ b/arm/unittests.cfg
> > @@ -51,3 +51,10 @@ file = selftest.flat
> >  smp = $MAX_SMP
> >  extra_params = -append 'smp'
> >  groups = selftest
> > +
> > +# Test GIC emulation
> > +[gicv2-ipi]
> > +file = gic.flat
> > +smp = $((($MAX_SMP < 8)?$MAX_SMP:8))
> > +extra_params = -machine gic-version=2 -append 'ipi'
> > +groups = gic
> > 
> Aside the minor comments above,
> Reviewed-by: Eric Auger <eric.auger@redhat.com>

Thanks!
drew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 10/10] arm/arm64: gic: don't just use zero
  2016-09-02  9:43   ` Auger Eric
@ 2016-10-17 19:53       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 19:53 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm

On Fri, Sep 02, 2016 at 11:43:33AM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Allow user to select who sends ipis and with which irq,
> > rather than just always sending irq=0 from cpu0.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > 
> > ---
> > v2: actually check that the irq received was the irq sent,
> >     and (for gicv2) that the sender is the expected one.
> > ---
> >  arm/gic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
> >  1 file changed, 64 insertions(+), 16 deletions(-)
> > 
> > diff --git a/arm/gic.c b/arm/gic.c
> > index fc7ef241de3e2..d3ab97d4ae470 100644
> > --- a/arm/gic.c
> > +++ b/arm/gic.c
> > @@ -11,6 +11,7 @@
> >   * This work is licensed under the terms of the GNU LGPL, version 2.
> >   */
> >  #include <libcflat.h>
> > +#include <util.h>
> >  #include <asm/setup.h>
> >  #include <asm/processor.h>
> >  #include <asm/gic.h>
> > @@ -33,6 +34,8 @@ static struct gic *gic;
> >  static int gic_version;
> >  static int acked[NR_CPUS], spurious[NR_CPUS];
> >  static cpumask_t ready;
> > +static int sender;
> > +static u32 irq;
> >  
> >  static void nr_cpu_check(int nr)
> >  {
> > @@ -85,7 +88,16 @@ static void check_acked(cpumask_t *mask)
> >  
> >  static u32 gicv2_read_iar(void)
> >  {
> > -	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +	int src = (iar >> 10) & 7;
> > +
> > +	if (src != sender) {
> > +		report("cpu%d received IPI from unexpected source cpu%d "
> > +		       "(expected cpu%d)",
> > +		       false, smp_processor_id(), src, sender);
> > +	}
> > +
> > +	return iar & 0x3ff;
> you can use GICC_IAR_INT_ID_MASK instead

OK

> >  }
> >  
> >  static void gicv2_write_eoi(u32 irq)
> > @@ -99,9 +111,15 @@ static void ipi_handler(struct pt_regs *regs __unused)
> >  
> >  	if (iar != GICC_INT_SPURIOUS) {
> >  		gic->write_eoi(iar);
> > -		smp_rmb(); /* pairs with wmb in ipi_test functions */
> > -		++acked[smp_processor_id()];
> > -		smp_wmb(); /* pairs with rmb in check_acked */
> > +		if (iar == irq) {
> > +			smp_rmb(); /* pairs with wmb in ipi_test functions */
> > +			++acked[smp_processor_id()];
> > +			smp_wmb(); /* pairs with rmb in check_acked */
> > +		} else {
> > +			report("cpu%d received unexpected irq %u "
> > +			       "(expected %u)",
> > +			       false, smp_processor_id(), iar, irq);
> > +		}
> >  	} else {
> >  		++spurious[smp_processor_id()];
> >  		smp_wmb();
> > @@ -110,19 +128,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
> >  
> >  static void gicv2_ipi_send_self(void)
> >  {
> > -	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	writel(2 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
> >  }
> >  
> >  static void gicv2_ipi_send_tlist(cpumask_t *mask)
> >  {
> >  	u8 tlist = (u8)cpumask_bits(mask)[0];
> >  
> > -	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	writel(tlist << 16 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
> >  }
> >  
> >  static void gicv2_ipi_send_broadcast(void)
> >  {
> > -	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	writel(1 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
> >  }
> >  
> >  #define ICC_SGI1R_AFFINITY_1_SHIFT	16
> > @@ -165,7 +183,7 @@ static void gicv3_ipi_send_tlist(cpumask_t *mask)
> >  
> >  		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
> >  			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
> > -			 /* irq << 24				| */
> > +			 irq << 24				|
> >  			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
> >  			 tlist);
> >  
> > @@ -187,7 +205,7 @@ static void gicv3_ipi_send_self(void)
> >  
> >  static void gicv3_ipi_send_broadcast(void)
> >  {
> > -	gicv3_write_sgi1r(1ULL << 40);
> > +	gicv3_write_sgi1r(1ULL << 40 | irq << 24);
> >  	isb();
> >  }
> >  
> > @@ -199,7 +217,7 @@ static void ipi_test_self(void)
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> >  	cpumask_clear(&mask);
> > -	cpumask_set_cpu(0, &mask);
> > +	cpumask_set_cpu(smp_processor_id(), &mask);
> >  	gic->ipi.send_self();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> > @@ -214,7 +232,7 @@ static void ipi_test_smp(void)
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> >  	cpumask_copy(&mask, &cpu_present_mask);
> > -	for (i = 0; i < nr_cpus; i += 2)
> > +	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
> >  		cpumask_clear_cpu(i, &mask);
> >  	gic->ipi.send_tlist(&mask);
> >  	check_acked(&mask);
> > @@ -224,7 +242,7 @@ static void ipi_test_smp(void)
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> >  	cpumask_copy(&mask, &cpu_present_mask);
> > -	cpumask_clear_cpu(0, &mask);
> > +	cpumask_clear_cpu(smp_processor_id(), &mask);
> >  	gic->ipi.send_broadcast();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> > @@ -241,6 +259,15 @@ static void ipi_enable(void)
> >  	local_irq_enable();
> >  }
> >  
> > +static void ipi_send(void)
> > +{
> > +	ipi_enable();
> > +	wait_on_ready();
> > +	ipi_test_self();
> > +	ipi_test_smp();
> > +	exit(report_summary());
> > +}
> > +
> >  static void ipi_recv(void)
> >  {
> >  	ipi_enable();
> > @@ -300,19 +327,40 @@ int main(int argc, char **argv)
> >  		report_prefix_pop();
> >  
> >  	} else if (!strcmp(argv[1], "ipi")) {
> > +		int off, i = 1;
> > +		long val;
> >  
> >  		report_prefix_push(argv[1]);
> > +
> > +		while (--argc != 1) {
> > +			off = parse_keyval(argv[++i], &val);
> > +			if (off == -1)
> > +				continue;
> > +			argv[i][off] = '\0';
> > +			if (strcmp(argv[i], "sender") == 0)
> > +				sender = val;
> > +			else if (strcmp(argv[i], "irq") == 0)
> > +				irq = val;
> > +		}
> > +
> >  		nr_cpu_check(2);
> >  		ipi_enable();
> >  
> >  		for_each_present_cpu(cpu) {
> >  			if (cpu == 0)
> >  				continue;
> > -			smp_boot_secondary(cpu, ipi_recv);
> > +			if (cpu == sender)
> > +				smp_boot_secondary(cpu, ipi_send);
> > +			else
> > +				smp_boot_secondary(cpu, ipi_recv);
> > +		}
> > +		if (sender == 0)  {
> > +			wait_on_ready();
> > +			ipi_test_self();
> > +			ipi_test_smp();
> > +		} else {
> > +			ipi_recv();
> >  		}
> > -		wait_on_ready();
> > -		ipi_test_self();
> > -		ipi_test_smp();
> >  
> >  		smp_rmb();
> >  		for_each_present_cpu(cpu) {
> > 
> 
> I ran the tests on both Cavium & Seattle HW without noticing issues.
> 
> I guess the file organization & infra will need to change while adding
> some new tests, removing some globals ... but that's a good start to

Can you explain what you have in mind for removing some globals, changing
things? I can change it now :-)  As for adding new tests, though, while
I think we can extend arm/gic.c with more tests, anytime a unit test
differs too much from a framework of a current unit test (group of tests)
it should just create a new unit test file in arm/ and then do whatever
it likes. The common code lib/* is where changes should be made if the
framework doesn't work - but I should get that as close to right as
possible before merging the series.

> show how to write new tests. I am a bit concerned by the LOCs and
> redundancies with the kernel with possible out-of-sync macros but well I
> think there is no other way.

Me neither. We've debated using kernel headers straight from a kernel
source directory in the past, but opted against it. I don't think we'll
need to synch too much though. If somebody writes a test that needs new
defines, then that's when it can be synched.

> 
> I will spend some time writing some tests within the next weeks.

Awesome. Of course that was some weeks ago that you wrote that :-)

Thanks for the review of the series. I'll send a v4 soon.

drew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 10/10] arm/arm64: gic: don't just use zero
@ 2016-10-17 19:53       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-17 19:53 UTC (permalink / raw)
  To: Auger Eric
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, andre.przywara,
	peter.maydell, alex.bennee, marc.zyngier, wei, christoffer.dall

On Fri, Sep 02, 2016 at 11:43:33AM +0200, Auger Eric wrote:
> Hi Drew,
> 
> On 15/07/2016 15:00, Andrew Jones wrote:
> > Allow user to select who sends ipis and with which irq,
> > rather than just always sending irq=0 from cpu0.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > 
> > ---
> > v2: actually check that the irq received was the irq sent,
> >     and (for gicv2) that the sender is the expected one.
> > ---
> >  arm/gic.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++-------------
> >  1 file changed, 64 insertions(+), 16 deletions(-)
> > 
> > diff --git a/arm/gic.c b/arm/gic.c
> > index fc7ef241de3e2..d3ab97d4ae470 100644
> > --- a/arm/gic.c
> > +++ b/arm/gic.c
> > @@ -11,6 +11,7 @@
> >   * This work is licensed under the terms of the GNU LGPL, version 2.
> >   */
> >  #include <libcflat.h>
> > +#include <util.h>
> >  #include <asm/setup.h>
> >  #include <asm/processor.h>
> >  #include <asm/gic.h>
> > @@ -33,6 +34,8 @@ static struct gic *gic;
> >  static int gic_version;
> >  static int acked[NR_CPUS], spurious[NR_CPUS];
> >  static cpumask_t ready;
> > +static int sender;
> > +static u32 irq;
> >  
> >  static void nr_cpu_check(int nr)
> >  {
> > @@ -85,7 +88,16 @@ static void check_acked(cpumask_t *mask)
> >  
> >  static u32 gicv2_read_iar(void)
> >  {
> > -	return readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +	u32 iar = readl(gicv2_cpu_base() + GIC_CPU_INTACK);
> > +	int src = (iar >> 10) & 7;
> > +
> > +	if (src != sender) {
> > +		report("cpu%d received IPI from unexpected source cpu%d "
> > +		       "(expected cpu%d)",
> > +		       false, smp_processor_id(), src, sender);
> > +	}
> > +
> > +	return iar & 0x3ff;
> you can use GICC_IAR_INT_ID_MASK instead

OK

> >  }
> >  
> >  static void gicv2_write_eoi(u32 irq)
> > @@ -99,9 +111,15 @@ static void ipi_handler(struct pt_regs *regs __unused)
> >  
> >  	if (iar != GICC_INT_SPURIOUS) {
> >  		gic->write_eoi(iar);
> > -		smp_rmb(); /* pairs with wmb in ipi_test functions */
> > -		++acked[smp_processor_id()];
> > -		smp_wmb(); /* pairs with rmb in check_acked */
> > +		if (iar == irq) {
> > +			smp_rmb(); /* pairs with wmb in ipi_test functions */
> > +			++acked[smp_processor_id()];
> > +			smp_wmb(); /* pairs with rmb in check_acked */
> > +		} else {
> > +			report("cpu%d received unexpected irq %u "
> > +			       "(expected %u)",
> > +			       false, smp_processor_id(), iar, irq);
> > +		}
> >  	} else {
> >  		++spurious[smp_processor_id()];
> >  		smp_wmb();
> > @@ -110,19 +128,19 @@ static void ipi_handler(struct pt_regs *regs __unused)
> >  
> >  static void gicv2_ipi_send_self(void)
> >  {
> > -	writel(2 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	writel(2 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
> >  }
> >  
> >  static void gicv2_ipi_send_tlist(cpumask_t *mask)
> >  {
> >  	u8 tlist = (u8)cpumask_bits(mask)[0];
> >  
> > -	writel(tlist << 16, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	writel(tlist << 16 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
> >  }
> >  
> >  static void gicv2_ipi_send_broadcast(void)
> >  {
> > -	writel(1 << 24, gicv2_dist_base() + GIC_DIST_SOFTINT);
> > +	writel(1 << 24 | irq, gicv2_dist_base() + GIC_DIST_SOFTINT);
> >  }
> >  
> >  #define ICC_SGI1R_AFFINITY_1_SHIFT	16
> > @@ -165,7 +183,7 @@ static void gicv3_ipi_send_tlist(cpumask_t *mask)
> >  
> >  		sgi1r = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3)	|
> >  			 MPIDR_TO_SGI_AFFINITY(cluster_id, 2)	|
> > -			 /* irq << 24				| */
> > +			 irq << 24				|
> >  			 MPIDR_TO_SGI_AFFINITY(cluster_id, 1)	|
> >  			 tlist);
> >  
> > @@ -187,7 +205,7 @@ static void gicv3_ipi_send_self(void)
> >  
> >  static void gicv3_ipi_send_broadcast(void)
> >  {
> > -	gicv3_write_sgi1r(1ULL << 40);
> > +	gicv3_write_sgi1r(1ULL << 40 | irq << 24);
> >  	isb();
> >  }
> >  
> > @@ -199,7 +217,7 @@ static void ipi_test_self(void)
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> >  	cpumask_clear(&mask);
> > -	cpumask_set_cpu(0, &mask);
> > +	cpumask_set_cpu(smp_processor_id(), &mask);
> >  	gic->ipi.send_self();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> > @@ -214,7 +232,7 @@ static void ipi_test_smp(void)
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> >  	cpumask_copy(&mask, &cpu_present_mask);
> > -	for (i = 0; i < nr_cpus; i += 2)
> > +	for (i = smp_processor_id() & 1; i < nr_cpus; i += 2)
> >  		cpumask_clear_cpu(i, &mask);
> >  	gic->ipi.send_tlist(&mask);
> >  	check_acked(&mask);
> > @@ -224,7 +242,7 @@ static void ipi_test_smp(void)
> >  	memset(acked, 0, sizeof(acked));
> >  	smp_wmb();
> >  	cpumask_copy(&mask, &cpu_present_mask);
> > -	cpumask_clear_cpu(0, &mask);
> > +	cpumask_clear_cpu(smp_processor_id(), &mask);
> >  	gic->ipi.send_broadcast();
> >  	check_acked(&mask);
> >  	report_prefix_pop();
> > @@ -241,6 +259,15 @@ static void ipi_enable(void)
> >  	local_irq_enable();
> >  }
> >  
> > +static void ipi_send(void)
> > +{
> > +	ipi_enable();
> > +	wait_on_ready();
> > +	ipi_test_self();
> > +	ipi_test_smp();
> > +	exit(report_summary());
> > +}
> > +
> >  static void ipi_recv(void)
> >  {
> >  	ipi_enable();
> > @@ -300,19 +327,40 @@ int main(int argc, char **argv)
> >  		report_prefix_pop();
> >  
> >  	} else if (!strcmp(argv[1], "ipi")) {
> > +		int off, i = 1;
> > +		long val;
> >  
> >  		report_prefix_push(argv[1]);
> > +
> > +		while (--argc != 1) {
> > +			off = parse_keyval(argv[++i], &val);
> > +			if (off == -1)
> > +				continue;
> > +			argv[i][off] = '\0';
> > +			if (strcmp(argv[i], "sender") == 0)
> > +				sender = val;
> > +			else if (strcmp(argv[i], "irq") == 0)
> > +				irq = val;
> > +		}
> > +
> >  		nr_cpu_check(2);
> >  		ipi_enable();
> >  
> >  		for_each_present_cpu(cpu) {
> >  			if (cpu == 0)
> >  				continue;
> > -			smp_boot_secondary(cpu, ipi_recv);
> > +			if (cpu == sender)
> > +				smp_boot_secondary(cpu, ipi_send);
> > +			else
> > +				smp_boot_secondary(cpu, ipi_recv);
> > +		}
> > +		if (sender == 0)  {
> > +			wait_on_ready();
> > +			ipi_test_self();
> > +			ipi_test_smp();
> > +		} else {
> > +			ipi_recv();
> >  		}
> > -		wait_on_ready();
> > -		ipi_test_self();
> > -		ipi_test_smp();
> >  
> >  		smp_rmb();
> >  		for_each_present_cpu(cpu) {
> > 
> 
> I ran the tests on both Cavium & Seattle HW without noticing issues.
> 
> I guess the file organization & infra will need to change while adding
> some new tests, removing some globals ... but that's a good start to

Can you explain what you have in mind for removing some globals, changing
things? I can change it now :-)  As for adding new tests, though, while
I think we can extend arm/gic.c with more tests, anytime a unit test
differs too much from a framework of a current unit test (group of tests)
it should just create a new unit test file in arm/ and then do whatever
it likes. The common code lib/* is where changes should be made if the
framework doesn't work - but I should get that as close to right as
possible before merging the series.

> show how to write new tests. I am a bit concerned by the LOCs and
> redundancies with the kernel with possible out-of-sync macros but well I
> think there is no other way.

Me neither. We've debated using kernel headers straight from a kernel
source directory in the past, but opted against it. I don't think we'll
need to synch too much though. If somebody writes a test that needs new
defines, then that's when it can be synched.

> 
> I will spend some time writing some tests within the next weeks.

Awesome. Of course that was some weeks ago that you wrote that :-)

Thanks for the review of the series. I'll send a v4 soon.

drew

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
  2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
@ 2016-10-20 17:29     ` Andre Przywara
  -1 siblings, 0 replies; 51+ messages in thread
From: Andre Przywara @ 2016-10-20 17:29 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	peter.maydell, alex.bennee
  Cc: marc.zyngier

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;
> +}
> +

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
@ 2016-10-20 17:29     ` Andre Przywara
  0 siblings, 0 replies; 51+ messages in thread
From: Andre Przywara @ 2016-10-20 17:29 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, pbonzini, qemu-devel, qemu-arm,
	peter.maydell, alex.bennee
  Cc: christoffer.dall, marc.zyngier, eric.auger, wei

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;
> +}
> +

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
  2016-10-20 17:29     ` [Qemu-devel] " Andre Przywara
@ 2016-10-21 12:49       ` Andrew Jones
  -1 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-21 12:49 UTC (permalink / raw)
  To: Andre Przywara; +Cc: kvm, marc.zyngier, qemu-devel, qemu-arm, pbonzini, kvmarm


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

^ permalink raw reply	[flat|nested] 51+ messages in thread

* Re: [Qemu-devel] [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support
@ 2016-10-21 12:49       ` Andrew Jones
  0 siblings, 0 replies; 51+ messages in thread
From: Andrew Jones @ 2016-10-21 12:49 UTC (permalink / raw)
  To: Andre Przywara
  Cc: kvm, kvmarm, pbonzini, qemu-devel, qemu-arm, peter.maydell,
	alex.bennee, marc.zyngier, eric.auger, wei, christoffer.dall


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

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2016-10-21 12:49 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-15 13:00 [kvm-unit-tests PATCH v3 00/10] arm/arm64: add gic framework Andrew Jones
2016-07-15 13:00 ` [Qemu-devel] " Andrew Jones
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 01/10] lib: xstr: allow multiple args Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-08-30 14:28   ` Auger Eric
2016-08-30 14:28     ` Auger Eric
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 02/10] arm64: fix get_"sysreg32" and make MPIDR 64bit Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-08-30 14:28   ` Auger Eric
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 03/10] arm/arm64: smp: support more than 8 cpus Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-08-30 14:28   ` Auger Eric
2016-08-31 22:01     ` Auger Eric
2016-10-17 12:24     ` Andrew Jones
2016-10-17 12:24       ` Andrew Jones
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 04/10] arm/arm64: add some delay routines Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-01 10:19   ` Auger Eric
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 05/10] arm/arm64: irq enable/disable Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-01 10:19   ` Auger Eric
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 06/10] arm/arm64: add initial gicv2 support Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-01 10:20   ` Auger Eric
2016-09-01 10:20     ` Auger Eric
2016-10-17 13:14     ` Andrew Jones
2016-10-17 13:14       ` Andrew Jones
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 07/10] arm/arm64: add initial gicv3 support Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-01 10:19   ` Auger Eric
2016-09-01 10:19     ` Auger Eric
2016-10-17 13:30     ` Andrew Jones
2016-10-20 17:29   ` Andre Przywara
2016-10-20 17:29     ` [Qemu-devel] " Andre Przywara
2016-10-21 12:49     ` Andrew Jones
2016-10-21 12:49       ` Andrew Jones
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 08/10] arm/arm64: gicv2: add an IPI test Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-01 16:42   ` Auger Eric
2016-10-17 19:15     ` Andrew Jones
2016-10-17 19:15       ` Andrew Jones
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 09/10] arm/arm64: gicv3: " Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-01 16:42   ` Auger Eric
2016-10-17 13:36     ` Andrew Jones
2016-10-17 13:36       ` Andrew Jones
2016-07-15 13:00 ` [kvm-unit-tests PATCH v3 10/10] arm/arm64: gic: don't just use zero Andrew Jones
2016-07-15 13:00   ` [Qemu-devel] " Andrew Jones
2016-09-02  9:43   ` Auger Eric
2016-10-17 19:53     ` Andrew Jones
2016-10-17 19:53       ` Andrew Jones

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.