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


v8:
 - Main change is rebasing to Wei's sysreg framework, which is part
   of his PMU series, which I've applied to arm/next. That rebase
   leads to dropping the first two patches of the v7 series, expecting
   get_mpidr() to return u64 (with future patches), a rework of the
   delay routines (now based on sysreg framework), and changes to all
   sysreg asms
 - The delay routines also got their own files: delay.[ch]
 - Another bigger change was to now keep gic_common_ops local to
   lib/arm/gic.c, export the functions from the gic-v[23] instead
 - Yet another bigger change was dropping the sender and irq cmdline
   inputs, hard coding to '1' is sufficient and much less code
 - Other minor changes listed in individual patches   


v7:
 - biggest change is splitting lib/arm/gic.c into lib/arm/gic.c,
   lib/arm/gic-v2.c, lib/arm/gic-v3.c
 - second biggest change, which probably affects Alex, is that
   gic_ipi_send(cpu, irq) changed to gic_ipi_send_single(irq, cpu),
   note the swapping of cpu and irq!
 - other changes thanks to Eric are noted in individual patches
 - also rebased to latest master

v6:
 - rebased to latest master
 - several other changes thanks to Andre and Alex, changes in
   individual patch change logs
 - some code cleanups

v5:
 - fix arm32/gicv3 compile [drew]
 - use modern register names [Andre]
 - one Andre r-b

v4:
 - Eric's r-b's
 - Andre's suggestion to only take defines we need
 - several other changes listed in individual patches

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-04: fixes and functionality needed by the later gic patches
05-06: enable gicv2 and gicv2 IPI test
07-09: enable gicv3 and gicv3 IPI test
   10: extend the IPI tests to use cpu1 and irq1 instead of zero

Available here: https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic-v8
and based on https://github.com/rhdrjones/kvm-unit-tests/commits/arm/next


Andrew Jones (9):
  arm/arm64: yield on cpu_relax
  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: gicv2: add an IPI test
  arm/arm64: add initial gicv3 support
  arm/arm64: gicv3: add an IPI test
  arm/arm64: gic: don't just use zero

Peter Xu (1):
  libcflat: add IS_ALIGNED() macro, and page sizes

 arm/Makefile.common        |  12 +-
 arm/run                    |  19 +--
 arm/unittests.cfg          |  14 +++
 lib/arm/asm/arch_gicv3.h   |  65 ++++++++++
 lib/arm/asm/barrier.h      |   5 +-
 lib/arm/asm/delay.h        |  14 +++
 lib/arm/asm/gic-v2.h       |  42 +++++++
 lib/arm/asm/gic-v3.h       | 117 ++++++++++++++++++
 lib/arm/asm/gic.h          |  65 ++++++++++
 lib/arm/asm/processor.h    |  34 +++++-
 lib/arm/asm/setup.h        |   4 +-
 lib/arm64/asm/arch_gicv3.h |  64 ++++++++++
 lib/arm64/asm/barrier.h    |   3 +-
 lib/arm64/asm/delay.h      |   1 +
 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  |  31 ++++-
 lib/arm64/asm/sysreg.h     |  34 +++++-
 lib/libcflat.h             |   6 +
 arm/gic.c                  | 298 +++++++++++++++++++++++++++++++++++++++++++++
 arm/selftest.c             |   7 +-
 lib/arm/delay.c            |  29 +++++
 lib/arm/gic-v2.c           |  57 +++++++++
 lib/arm/gic-v3.c           | 145 ++++++++++++++++++++++
 lib/arm/gic.c              | 147 ++++++++++++++++++++++
 lib/arm/setup.c            |  10 ++
 27 files changed, 1202 insertions(+), 24 deletions(-)
 create mode 100644 lib/arm/asm/arch_gicv3.h
 create mode 100644 lib/arm/asm/delay.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/arm64/asm/arch_gicv3.h
 create mode 100644 lib/arm64/asm/delay.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 arm/gic.c
 create mode 100644 lib/arm/delay.c
 create mode 100644 lib/arm/gic-v2.c
 create mode 100644 lib/arm/gic-v3.c
 create mode 100644 lib/arm/gic.c

-- 
2.9.3


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

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


v8:
 - Main change is rebasing to Wei's sysreg framework, which is part
   of his PMU series, which I've applied to arm/next. That rebase
   leads to dropping the first two patches of the v7 series, expecting
   get_mpidr() to return u64 (with future patches), a rework of the
   delay routines (now based on sysreg framework), and changes to all
   sysreg asms
 - The delay routines also got their own files: delay.[ch]
 - Another bigger change was to now keep gic_common_ops local to
   lib/arm/gic.c, export the functions from the gic-v[23] instead
 - Yet another bigger change was dropping the sender and irq cmdline
   inputs, hard coding to '1' is sufficient and much less code
 - Other minor changes listed in individual patches   


v7:
 - biggest change is splitting lib/arm/gic.c into lib/arm/gic.c,
   lib/arm/gic-v2.c, lib/arm/gic-v3.c
 - second biggest change, which probably affects Alex, is that
   gic_ipi_send(cpu, irq) changed to gic_ipi_send_single(irq, cpu),
   note the swapping of cpu and irq!
 - other changes thanks to Eric are noted in individual patches
 - also rebased to latest master

v6:
 - rebased to latest master
 - several other changes thanks to Andre and Alex, changes in
   individual patch change logs
 - some code cleanups

v5:
 - fix arm32/gicv3 compile [drew]
 - use modern register names [Andre]
 - one Andre r-b

v4:
 - Eric's r-b's
 - Andre's suggestion to only take defines we need
 - several other changes listed in individual patches

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-04: fixes and functionality needed by the later gic patches
05-06: enable gicv2 and gicv2 IPI test
07-09: enable gicv3 and gicv3 IPI test
   10: extend the IPI tests to use cpu1 and irq1 instead of zero

Available here: https://github.com/rhdrjones/kvm-unit-tests/commits/arm/gic-v8
and based on https://github.com/rhdrjones/kvm-unit-tests/commits/arm/next


Andrew Jones (9):
  arm/arm64: yield on cpu_relax
  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: gicv2: add an IPI test
  arm/arm64: add initial gicv3 support
  arm/arm64: gicv3: add an IPI test
  arm/arm64: gic: don't just use zero

Peter Xu (1):
  libcflat: add IS_ALIGNED() macro, and page sizes

 arm/Makefile.common        |  12 +-
 arm/run                    |  19 +--
 arm/unittests.cfg          |  14 +++
 lib/arm/asm/arch_gicv3.h   |  65 ++++++++++
 lib/arm/asm/barrier.h      |   5 +-
 lib/arm/asm/delay.h        |  14 +++
 lib/arm/asm/gic-v2.h       |  42 +++++++
 lib/arm/asm/gic-v3.h       | 117 ++++++++++++++++++
 lib/arm/asm/gic.h          |  65 ++++++++++
 lib/arm/asm/processor.h    |  34 +++++-
 lib/arm/asm/setup.h        |   4 +-
 lib/arm64/asm/arch_gicv3.h |  64 ++++++++++
 lib/arm64/asm/barrier.h    |   3 +-
 lib/arm64/asm/delay.h      |   1 +
 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  |  31 ++++-
 lib/arm64/asm/sysreg.h     |  34 +++++-
 lib/libcflat.h             |   6 +
 arm/gic.c                  | 298 +++++++++++++++++++++++++++++++++++++++++++++
 arm/selftest.c             |   7 +-
 lib/arm/delay.c            |  29 +++++
 lib/arm/gic-v2.c           |  57 +++++++++
 lib/arm/gic-v3.c           | 145 ++++++++++++++++++++++
 lib/arm/gic.c              | 147 ++++++++++++++++++++++
 lib/arm/setup.c            |  10 ++
 27 files changed, 1202 insertions(+), 24 deletions(-)
 create mode 100644 lib/arm/asm/arch_gicv3.h
 create mode 100644 lib/arm/asm/delay.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/arm64/asm/arch_gicv3.h
 create mode 100644 lib/arm64/asm/delay.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 arm/gic.c
 create mode 100644 lib/arm/delay.c
 create mode 100644 lib/arm/gic-v2.c
 create mode 100644 lib/arm/gic-v3.c
 create mode 100644 lib/arm/gic.c

-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 01/10] arm/arm64: yield on cpu_relax
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

In many tests one or more cpus wait for events from other cpus. However,
with TCG, if the event triggering cpus then continue without first
informing TCG it should schedule other cpus, then those other cpus may
never get scheduled, and never see their events. This is because the
TCG scheduler relies on either the currently running cpu to invoke an
instruction that results in scheduling or for some I/O event to occur,
and then to do scheduling while handling the I/O. kvm-unit-tests do not
have external I/O events, so we must invoke a yielding instruction
wherever needed. cpu_relax() is almost always a place it's needed.

While this change is mostly for TCG, it's fine to do for KVM as well.
The Linux kernel made the same change with 1baa82f4803 for armv8. As
the yield instruction is also available on armv7, we make the change
for both.

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

---

v8: new patch that drastically speeds up the tests with tcg,
    actually allowing it to complete at all after adding
    -nodefaults to the qemu command line...
---
 lib/arm/asm/barrier.h   | 5 +++--
 lib/arm64/asm/barrier.h | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/arm/asm/barrier.h b/lib/arm/asm/barrier.h
index 394a4a2da26f..927cd3801dfb 100644
--- a/lib/arm/asm/barrier.h
+++ b/lib/arm/asm/barrier.h
@@ -1,13 +1,14 @@
 #ifndef _ASMARM_BARRIER_H_
 #define _ASMARM_BARRIER_H_
 /*
- * Adapted form arch/arm/include/asm/barrier.h
+ * Adapted from arch/arm/include/asm/barrier.h
  */
 
 #define sev()		asm volatile("sev" : : : "memory")
 #define wfe()		asm volatile("wfe" : : : "memory")
 #define wfi()		asm volatile("wfi" : : : "memory")
-#define cpu_relax()	asm volatile(""    : : : "memory")
+#define yield()		asm volatile("yield" : : : "memory")
+#define cpu_relax()	yield()
 
 #define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
 #define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
diff --git a/lib/arm64/asm/barrier.h b/lib/arm64/asm/barrier.h
index dbdac9d339c7..4f7bb97c2279 100644
--- a/lib/arm64/asm/barrier.h
+++ b/lib/arm64/asm/barrier.h
@@ -7,7 +7,8 @@
 #define sev()		asm volatile("sev" : : : "memory")
 #define wfe()		asm volatile("wfe" : : : "memory")
 #define wfi()		asm volatile("wfi" : : : "memory")
-#define cpu_relax()	asm volatile(""    : : : "memory")
+#define yield()		asm volatile("yield" : : : "memory")
+#define cpu_relax()	yield()
 
 #define isb()		asm volatile("isb" : : : "memory")
 #define dmb(opt)	asm volatile("dmb " #opt : : : "memory")
-- 
2.9.3


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

* [Qemu-devel] [PATCH kvm-unit-tests v8 01/10] arm/arm64: yield on cpu_relax
@ 2016-12-08 17:50   ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

In many tests one or more cpus wait for events from other cpus. However,
with TCG, if the event triggering cpus then continue without first
informing TCG it should schedule other cpus, then those other cpus may
never get scheduled, and never see their events. This is because the
TCG scheduler relies on either the currently running cpu to invoke an
instruction that results in scheduling or for some I/O event to occur,
and then to do scheduling while handling the I/O. kvm-unit-tests do not
have external I/O events, so we must invoke a yielding instruction
wherever needed. cpu_relax() is almost always a place it's needed.

While this change is mostly for TCG, it's fine to do for KVM as well.
The Linux kernel made the same change with 1baa82f4803 for armv8. As
the yield instruction is also available on armv7, we make the change
for both.

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

---

v8: new patch that drastically speeds up the tests with tcg,
    actually allowing it to complete at all after adding
    -nodefaults to the qemu command line...
---
 lib/arm/asm/barrier.h   | 5 +++--
 lib/arm64/asm/barrier.h | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/lib/arm/asm/barrier.h b/lib/arm/asm/barrier.h
index 394a4a2da26f..927cd3801dfb 100644
--- a/lib/arm/asm/barrier.h
+++ b/lib/arm/asm/barrier.h
@@ -1,13 +1,14 @@
 #ifndef _ASMARM_BARRIER_H_
 #define _ASMARM_BARRIER_H_
 /*
- * Adapted form arch/arm/include/asm/barrier.h
+ * Adapted from arch/arm/include/asm/barrier.h
  */
 
 #define sev()		asm volatile("sev" : : : "memory")
 #define wfe()		asm volatile("wfe" : : : "memory")
 #define wfi()		asm volatile("wfi" : : : "memory")
-#define cpu_relax()	asm volatile(""    : : : "memory")
+#define yield()		asm volatile("yield" : : : "memory")
+#define cpu_relax()	yield()
 
 #define isb(option) __asm__ __volatile__ ("isb " #option : : : "memory")
 #define dsb(option) __asm__ __volatile__ ("dsb " #option : : : "memory")
diff --git a/lib/arm64/asm/barrier.h b/lib/arm64/asm/barrier.h
index dbdac9d339c7..4f7bb97c2279 100644
--- a/lib/arm64/asm/barrier.h
+++ b/lib/arm64/asm/barrier.h
@@ -7,7 +7,8 @@
 #define sev()		asm volatile("sev" : : : "memory")
 #define wfe()		asm volatile("wfe" : : : "memory")
 #define wfi()		asm volatile("wfi" : : : "memory")
-#define cpu_relax()	asm volatile(""    : : : "memory")
+#define yield()		asm volatile("yield" : : : "memory")
+#define cpu_relax()	yield()
 
 #define isb()		asm volatile("isb" : : : "memory")
 #define dmb(opt)	asm volatile("dmb " #opt : : : "memory")
-- 
2.9.3

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

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

By adding support for launching with gicv3 we can break the 8 vcpu
limit. This patch adds support to smp code and also selects the
vgic model corresponding to the host. The vgic model may also be
manually selected by adding e.g. -machine gic-version=3 to
extra_params.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v8: in anticipation of get_mpidr() returning a u64 (patches will
    be in a future series), make sure we use that type everywhere
    get_mpidr is used
v5: left cpus a u32 for now. Changing to u64 requires a change to
    devicetree. Will do it later. [Andre]
v4: improved commit message
---
 arm/run                   | 19 ++++++++++++-------
 lib/arm/asm/processor.h   |  9 +++++++--
 lib/arm/asm/setup.h       |  4 ++--
 lib/arm64/asm/processor.h |  9 +++++++--
 arm/selftest.c            |  7 ++++++-
 lib/arm/setup.c           | 10 ++++++++++
 6 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/arm/run b/arm/run
index f1b04af614dc..1c40ab02eb57 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/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index c831749e04de..6b0d36b87817 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 read_sysreg(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(uint64_t 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 cb8fdbd38dd5..1de99dd184d1 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 u32 cpus[NR_CPUS];	/* per-cpu IDs (MPIDRs) */
 extern int nr_cpus;
 
 #define NR_MEM_REGIONS		8
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index ed59ad25007b..48abf2c9e358 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -72,8 +72,13 @@ static inline unsigned int get_mpidr(void)
 	return read_sysreg(mpidr_el1);
 }
 
-/* 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(uint64_t 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/arm/selftest.c b/arm/selftest.c
index 196164f5313d..750e90893141 100644
--- a/arm/selftest.c
+++ b/arm/selftest.c
@@ -312,9 +312,11 @@ static bool psci_check(void)
 static cpumask_t smp_reported;
 static void cpu_report(void)
 {
+	uint64_t mpidr = get_mpidr();
 	int cpu = smp_processor_id();
 
-	report("CPU%d online", true, cpu);
+	report("CPU(%3d) mpidr=%010" PRIx64,
+		mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
 	cpumask_set_cpu(cpu, &smp_reported);
 	halt();
 }
@@ -343,6 +345,7 @@ int main(int argc, char **argv)
 
 	} else if (strcmp(argv[1], "smp") == 0) {
 
+		uint64_t mpidr = get_mpidr();
 		int cpu;
 
 		report("PSCI version", psci_check());
@@ -353,6 +356,8 @@ int main(int argc, char **argv)
 			smp_boot_secondary(cpu, cpu_report);
 		}
 
+		report("CPU(%3d) mpidr=%010" PRIx64,
+			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/setup.c b/lib/arm/setup.c
index 7e7b39f11dde..e52a25abd722 100644
--- a/lib/arm/setup.c
+++ b/lib/arm/setup.c
@@ -30,6 +30,16 @@ int nr_cpus;
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __phys_offset, __phys_end;
 
+int mpidr_to_cpu(uint64_t 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++;
-- 
2.9.3


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

* [Qemu-devel] [PATCH kvm-unit-tests v8 02/10] arm/arm64: smp: support more than 8 cpus
@ 2016-12-08 17:50   ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

By adding support for launching with gicv3 we can break the 8 vcpu
limit. This patch adds support to smp code and also selects the
vgic model corresponding to the host. The vgic model may also be
manually selected by adding e.g. -machine gic-version=3 to
extra_params.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v8: in anticipation of get_mpidr() returning a u64 (patches will
    be in a future series), make sure we use that type everywhere
    get_mpidr is used
v5: left cpus a u32 for now. Changing to u64 requires a change to
    devicetree. Will do it later. [Andre]
v4: improved commit message
---
 arm/run                   | 19 ++++++++++++-------
 lib/arm/asm/processor.h   |  9 +++++++--
 lib/arm/asm/setup.h       |  4 ++--
 lib/arm64/asm/processor.h |  9 +++++++--
 arm/selftest.c            |  7 ++++++-
 lib/arm/setup.c           | 10 ++++++++++
 6 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/arm/run b/arm/run
index f1b04af614dc..1c40ab02eb57 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/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index c831749e04de..6b0d36b87817 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 read_sysreg(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(uint64_t 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 cb8fdbd38dd5..1de99dd184d1 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 u32 cpus[NR_CPUS];	/* per-cpu IDs (MPIDRs) */
 extern int nr_cpus;
 
 #define NR_MEM_REGIONS		8
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index ed59ad25007b..48abf2c9e358 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -72,8 +72,13 @@ static inline unsigned int get_mpidr(void)
 	return read_sysreg(mpidr_el1);
 }
 
-/* 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(uint64_t 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/arm/selftest.c b/arm/selftest.c
index 196164f5313d..750e90893141 100644
--- a/arm/selftest.c
+++ b/arm/selftest.c
@@ -312,9 +312,11 @@ static bool psci_check(void)
 static cpumask_t smp_reported;
 static void cpu_report(void)
 {
+	uint64_t mpidr = get_mpidr();
 	int cpu = smp_processor_id();
 
-	report("CPU%d online", true, cpu);
+	report("CPU(%3d) mpidr=%010" PRIx64,
+		mpidr_to_cpu(mpidr) == cpu, cpu, mpidr);
 	cpumask_set_cpu(cpu, &smp_reported);
 	halt();
 }
@@ -343,6 +345,7 @@ int main(int argc, char **argv)
 
 	} else if (strcmp(argv[1], "smp") == 0) {
 
+		uint64_t mpidr = get_mpidr();
 		int cpu;
 
 		report("PSCI version", psci_check());
@@ -353,6 +356,8 @@ int main(int argc, char **argv)
 			smp_boot_secondary(cpu, cpu_report);
 		}
 
+		report("CPU(%3d) mpidr=%010" PRIx64,
+			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/setup.c b/lib/arm/setup.c
index 7e7b39f11dde..e52a25abd722 100644
--- a/lib/arm/setup.c
+++ b/lib/arm/setup.c
@@ -30,6 +30,16 @@ int nr_cpus;
 struct mem_region mem_regions[NR_MEM_REGIONS];
 phys_addr_t __phys_offset, __phys_end;
 
+int mpidr_to_cpu(uint64_t 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++;
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

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

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

---
v8: rewrote basing on new sysreg framework. Also decided delay
    functions warrant their own files (delay.[ch])
---
 arm/Makefile.common       |  1 +
 lib/arm/asm/delay.h       | 14 ++++++++++++++
 lib/arm/asm/processor.h   | 15 +++++++++++++++
 lib/arm64/asm/delay.h     |  1 +
 lib/arm64/asm/processor.h | 12 ++++++++++++
 lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
 6 files changed, 72 insertions(+)
 create mode 100644 lib/arm/asm/delay.h
 create mode 100644 lib/arm64/asm/delay.h
 create mode 100644 lib/arm/delay.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index b2c0fc8a2fdc..89fe3f69eb44 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
 cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/delay.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
new file mode 100644
index 000000000000..2436b28c77ae
--- /dev/null
+++ b/lib/arm/asm/delay.h
@@ -0,0 +1,14 @@
+#ifndef _ASMARM_DELAY_H_
+#define _ASMARM_DELAY_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.
+ */
+#include <libcflat.h>
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+extern void mdelay(unsigned long msecs);
+
+#endif /* _ASMARM_DELAY_H_ */
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index 6b0d36b87817..857bdd96a3cc 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -7,6 +7,7 @@
  */
 #include <asm/ptrace.h>
 #include <asm/sysreg.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EXCPTN_RST,
@@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+#define CNTVCT		__ACCESS_CP15_64(1, c14)
+#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
+
+static inline u64 get_cntvct(void)
+{
+	isb();
+	return read_sysreg(CNTVCT);
+}
+
+static inline u32 get_cntfrq(void)
+{
+	return read_sysreg(CNTFRQ);
+}
+
 #endif /* _ASMARM_PROCESSOR_H_ */
diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
new file mode 100644
index 000000000000..288e4b3fe610
--- /dev/null
+++ b/lib/arm64/asm/delay.h
@@ -0,0 +1 @@
+#include "../../arm/asm/delay.h"
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 48abf2c9e358..0898d89f9761 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -20,6 +20,7 @@
 #include <asm/ptrace.h>
 #include <asm/esr.h>
 #include <asm/sysreg.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EL1T_SYNC,
@@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t 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)
+{
+	isb();
+	return read_sysreg(cntvct_el0);
+}
+
+static inline u32 get_cntfrq(void)
+{
+	return read_sysreg(cntfrq_el0);
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM64_PROCESSOR_H_ */
diff --git a/lib/arm/delay.c b/lib/arm/delay.c
new file mode 100644
index 000000000000..fa65e2dc9e35
--- /dev/null
+++ b/lib/arm/delay.c
@@ -0,0 +1,29 @@
+/*
+ * Delay loops
+ *
+ * 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/processor.h>
+#include <asm/barrier.h>
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	delay((u64)usec * get_cntfrq() / 1000000);
+}
+
+void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}
-- 
2.9.3


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

* [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
@ 2016-12-08 17:50   ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

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

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

---
v8: rewrote basing on new sysreg framework. Also decided delay
    functions warrant their own files (delay.[ch])
---
 arm/Makefile.common       |  1 +
 lib/arm/asm/delay.h       | 14 ++++++++++++++
 lib/arm/asm/processor.h   | 15 +++++++++++++++
 lib/arm64/asm/delay.h     |  1 +
 lib/arm64/asm/processor.h | 12 ++++++++++++
 lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
 6 files changed, 72 insertions(+)
 create mode 100644 lib/arm/asm/delay.h
 create mode 100644 lib/arm64/asm/delay.h
 create mode 100644 lib/arm/delay.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index b2c0fc8a2fdc..89fe3f69eb44 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
 cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
+cflatobjs += lib/arm/delay.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
new file mode 100644
index 000000000000..2436b28c77ae
--- /dev/null
+++ b/lib/arm/asm/delay.h
@@ -0,0 +1,14 @@
+#ifndef _ASMARM_DELAY_H_
+#define _ASMARM_DELAY_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.
+ */
+#include <libcflat.h>
+
+extern void delay(u64 cycles);
+extern void udelay(unsigned long usecs);
+extern void mdelay(unsigned long msecs);
+
+#endif /* _ASMARM_DELAY_H_ */
diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
index 6b0d36b87817..857bdd96a3cc 100644
--- a/lib/arm/asm/processor.h
+++ b/lib/arm/asm/processor.h
@@ -7,6 +7,7 @@
  */
 #include <asm/ptrace.h>
 #include <asm/sysreg.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EXCPTN_RST,
@@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);
 extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
 extern bool is_user(void);
 
+#define CNTVCT		__ACCESS_CP15_64(1, c14)
+#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
+
+static inline u64 get_cntvct(void)
+{
+	isb();
+	return read_sysreg(CNTVCT);
+}
+
+static inline u32 get_cntfrq(void)
+{
+	return read_sysreg(CNTFRQ);
+}
+
 #endif /* _ASMARM_PROCESSOR_H_ */
diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
new file mode 100644
index 000000000000..288e4b3fe610
--- /dev/null
+++ b/lib/arm64/asm/delay.h
@@ -0,0 +1 @@
+#include "../../arm/asm/delay.h"
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 48abf2c9e358..0898d89f9761 100644
--- a/lib/arm64/asm/processor.h
+++ b/lib/arm64/asm/processor.h
@@ -20,6 +20,7 @@
 #include <asm/ptrace.h>
 #include <asm/esr.h>
 #include <asm/sysreg.h>
+#include <asm/barrier.h>
 
 enum vector {
 	EL1T_SYNC,
@@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t 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)
+{
+	isb();
+	return read_sysreg(cntvct_el0);
+}
+
+static inline u32 get_cntfrq(void)
+{
+	return read_sysreg(cntfrq_el0);
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM64_PROCESSOR_H_ */
diff --git a/lib/arm/delay.c b/lib/arm/delay.c
new file mode 100644
index 000000000000..fa65e2dc9e35
--- /dev/null
+++ b/lib/arm/delay.c
@@ -0,0 +1,29 @@
+/*
+ * Delay loops
+ *
+ * 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/processor.h>
+#include <asm/barrier.h>
+
+void delay(u64 cycles)
+{
+	u64 start = get_cntvct();
+
+	while ((get_cntvct() - start) < cycles)
+		cpu_relax();
+}
+
+void udelay(unsigned long usec)
+{
+	delay((u64)usec * get_cntfrq() / 1000000);
+}
+
+void mdelay(unsigned long msecs)
+{
+	while (msecs--)
+		udelay(1000);
+}
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 04/10] arm/arm64: irq enable/disable
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
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 857bdd96a3cc..6dc1472468dd 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");
+}
+
 #define MPIDR __ACCESS_CP15(c0, 0, c0, 5)
 static inline unsigned int get_mpidr(void)
 {
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 0898d89f9761..f42f15c79d43 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");
+}
+
 static inline unsigned int get_mpidr(void)
 {
 	return read_sysreg(mpidr_el1);
-- 
2.9.3


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

* [Qemu-devel] [PATCH kvm-unit-tests v8 04/10] arm/arm64: irq enable/disable
@ 2016-12-08 17:50   ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
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 857bdd96a3cc..6dc1472468dd 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");
+}
+
 #define MPIDR __ACCESS_CP15(c0, 0, c0, 5)
 static inline unsigned int get_mpidr(void)
 {
diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
index 0898d89f9761..f42f15c79d43 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");
+}
+
 static inline unsigned int get_mpidr(void)
 {
 	return read_sysreg(mpidr_el1);
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 05/10] arm/arm64: add initial gicv2 support
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

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

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v6: added comments (register offset headers) [Alex]
v5: share/use only the modern register names [Andre]
v4:
 - only take defines from kernel we need now [Andre]
 - moved defines to asm/gic.h so they'll be shared with v3 [drew]
 - simplify enable by not caring if we reinit the distributor [drew]
 - init all GICD_INT_DEF_PRI_X4 registers [Eric]
---
 arm/Makefile.common    |  1 +
 lib/arm/asm/gic-v2.h   | 34 ++++++++++++++++++++++
 lib/arm/asm/gic.h      | 39 ++++++++++++++++++++++++++
 lib/arm64/asm/gic-v2.h |  1 +
 lib/arm64/asm/gic.h    |  1 +
 lib/arm/gic.c          | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+)
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic.h
 create mode 100644 lib/arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 89fe3f69eb44..0ccd6743a8fe 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -49,6 +49,7 @@ cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
 cflatobjs += lib/arm/delay.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 000000000000..c2d5fecd4886
--- /dev/null
+++ b/lib/arm/asm/gic-v2.h
@@ -0,0 +1,34 @@
+/*
+ * 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_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v2.h>. Include <asm/gic.h>
+#endif
+
+#define GICD_ENABLE			0x1
+#define GICC_ENABLE			0x1
+
+#ifndef __ASSEMBLY__
+
+struct gicv2_data {
+	void *dist_base;
+	void *cpu_base;
+	unsigned int irq_nr;
+};
+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 000000000000..e3580bd1d42d
--- /dev/null
+++ b/lib/arm/asm/gic.h
@@ -0,0 +1,39 @@
+/*
+ * 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>
+
+/* Distributor registers */
+#define GICD_CTLR			0x0000
+#define GICD_TYPER			0x0004
+#define GICD_ISENABLER			0x0100
+#define GICD_IPRIORITYR			0x0400
+
+#define GICD_TYPER_IRQS(typer)		((((typer) & 0x1f) + 1) * 32)
+#define GICD_INT_EN_SET_SGI		0x0000ffff
+#define GICD_INT_DEF_PRI_X4		0xa0a0a0a0
+
+/* CPU interface registers */
+#define GICC_CTLR			0x0000
+#define GICC_PMR			0x0004
+
+#define GICC_INT_PRI_THRESHOLD		0xf0
+
+#ifndef __ASSEMBLY__
+
+/*
+ * 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 /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
new file mode 100644
index 000000000000..52226624a209
--- /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 000000000000..e5eb302a31b4
--- /dev/null
+++ b/lib/arm64/asm/gic.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic.h"
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
new file mode 100644
index 000000000000..d655105e058b
--- /dev/null
+++ b/lib/arm/gic.c
@@ -0,0 +1,76 @@
+/*
+ * 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 <devicetree.h>
+#include <asm/gic.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)
+{
+	void *dist = gicv2_dist_base();
+	void *cpu_base = gicv2_cpu_base();
+	unsigned int i;
+
+	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv2_data.irq_nr > 1020)
+		gicv2_data.irq_nr = 1020;
+
+	for (i = 0; i < gicv2_data.irq_nr; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
+
+	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
+	writel(GICD_ENABLE, dist + GICD_CTLR);
+
+	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
+	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
+}
-- 
2.9.3


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

* [Qemu-devel] [PATCH kvm-unit-tests v8 05/10] arm/arm64: add initial gicv2 support
@ 2016-12-08 17:50   ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

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

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v6: added comments (register offset headers) [Alex]
v5: share/use only the modern register names [Andre]
v4:
 - only take defines from kernel we need now [Andre]
 - moved defines to asm/gic.h so they'll be shared with v3 [drew]
 - simplify enable by not caring if we reinit the distributor [drew]
 - init all GICD_INT_DEF_PRI_X4 registers [Eric]
---
 arm/Makefile.common    |  1 +
 lib/arm/asm/gic-v2.h   | 34 ++++++++++++++++++++++
 lib/arm/asm/gic.h      | 39 ++++++++++++++++++++++++++
 lib/arm64/asm/gic-v2.h |  1 +
 lib/arm64/asm/gic.h    |  1 +
 lib/arm/gic.c          | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+)
 create mode 100644 lib/arm/asm/gic-v2.h
 create mode 100644 lib/arm/asm/gic.h
 create mode 100644 lib/arm64/asm/gic-v2.h
 create mode 100644 lib/arm64/asm/gic.h
 create mode 100644 lib/arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 89fe3f69eb44..0ccd6743a8fe 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -49,6 +49,7 @@ cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
 cflatobjs += lib/arm/delay.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 000000000000..c2d5fecd4886
--- /dev/null
+++ b/lib/arm/asm/gic-v2.h
@@ -0,0 +1,34 @@
+/*
+ * 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_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v2.h>. Include <asm/gic.h>
+#endif
+
+#define GICD_ENABLE			0x1
+#define GICC_ENABLE			0x1
+
+#ifndef __ASSEMBLY__
+
+struct gicv2_data {
+	void *dist_base;
+	void *cpu_base;
+	unsigned int irq_nr;
+};
+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 000000000000..e3580bd1d42d
--- /dev/null
+++ b/lib/arm/asm/gic.h
@@ -0,0 +1,39 @@
+/*
+ * 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>
+
+/* Distributor registers */
+#define GICD_CTLR			0x0000
+#define GICD_TYPER			0x0004
+#define GICD_ISENABLER			0x0100
+#define GICD_IPRIORITYR			0x0400
+
+#define GICD_TYPER_IRQS(typer)		((((typer) & 0x1f) + 1) * 32)
+#define GICD_INT_EN_SET_SGI		0x0000ffff
+#define GICD_INT_DEF_PRI_X4		0xa0a0a0a0
+
+/* CPU interface registers */
+#define GICC_CTLR			0x0000
+#define GICC_PMR			0x0004
+
+#define GICC_INT_PRI_THRESHOLD		0xf0
+
+#ifndef __ASSEMBLY__
+
+/*
+ * 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 /* !__ASSEMBLY__ */
+#endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm64/asm/gic-v2.h b/lib/arm64/asm/gic-v2.h
new file mode 100644
index 000000000000..52226624a209
--- /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 000000000000..e5eb302a31b4
--- /dev/null
+++ b/lib/arm64/asm/gic.h
@@ -0,0 +1 @@
+#include "../../arm/asm/gic.h"
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
new file mode 100644
index 000000000000..d655105e058b
--- /dev/null
+++ b/lib/arm/gic.c
@@ -0,0 +1,76 @@
+/*
+ * 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 <devicetree.h>
+#include <asm/gic.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)
+{
+	void *dist = gicv2_dist_base();
+	void *cpu_base = gicv2_cpu_base();
+	unsigned int i;
+
+	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv2_data.irq_nr > 1020)
+		gicv2_data.irq_nr = 1020;
+
+	for (i = 0; i < gicv2_data.irq_nr; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
+
+	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
+	writel(GICD_ENABLE, dist + GICD_CTLR);
+
+	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
+	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
+}
-- 
2.9.3

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

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

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v8:
  - fix check_spurious print arguments and change the printf
    to a report_info
  - remove the self-ipi test issued when no subtest is given,
    i.e. require a subtest to be given
  - use report_summary for no supported gic present instead
    of report_abort, this will output nice SKIP message
v6: move the spurious check to its own check_ function [drew]
v5: use modern registers [Andre]
v4: properly mask irqnr in ipi_handler
v2: add more details in the output if a test fails,
    report spurious interrupts if we get them
---
 arm/Makefile.common  |  10 +--
 arm/unittests.cfg    |   8 +++
 lib/arm/asm/gic-v2.h |   2 +
 lib/arm/asm/gic.h    |   4 ++
 arm/gic.c            | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 214 insertions(+), 5 deletions(-)
 create mode 100644 arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 0ccd6743a8fe..275f8993012a 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,11 +9,11 @@ ifeq ($(LOADADDR),)
 	LOADADDR = 0x40000000
 endif
 
-tests-common = \
-	$(TEST_DIR)/selftest.flat \
-	$(TEST_DIR)/spinlock-test.flat \
-	$(TEST_DIR)/pci-test.flat \
-	$(TEST_DIR)/pmu.flat
+tests-common  = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/pci-test.flat
+tests-common += $(TEST_DIR)/pmu.flat
+tests-common += $(TEST_DIR)/gic.flat
 
 all: test_cases
 
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index 65f9c4c0b9eb..f61e30b8526d 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -55,6 +55,7 @@ smp = $MAX_SMP
 extra_params = -append 'smp'
 groups = selftest
 
+# Test PCI emulation
 [pci-test]
 file = pci-test.flat
 groups = pci
@@ -77,3 +78,10 @@ groups = pmu
 #extra_params = -icount 8 -append '256'
 #groups = pmu
 #accel = tcg
+
+# 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
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
index c2d5fecd4886..8b3f7ed6790c 100644
--- a/lib/arm/asm/gic-v2.h
+++ b/lib/arm/asm/gic-v2.h
@@ -13,7 +13,9 @@
 #endif
 
 #define GICD_ENABLE			0x1
+
 #define GICC_ENABLE			0x1
+#define GICC_IAR_INT_ID_MASK		0x3ff
 
 #ifndef __ASSEMBLY__
 
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index e3580bd1d42d..d816b96e46b4 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -13,6 +13,7 @@
 #define GICD_TYPER			0x0004
 #define GICD_ISENABLER			0x0100
 #define GICD_IPRIORITYR			0x0400
+#define GICD_SGIR			0x0f00
 
 #define GICD_TYPER_IRQS(typer)		((((typer) & 0x1f) + 1) * 32)
 #define GICD_INT_EN_SET_SGI		0x0000ffff
@@ -21,8 +22,11 @@
 /* CPU interface registers */
 #define GICC_CTLR			0x0000
 #define GICC_PMR			0x0004
+#define GICC_IAR			0x000c
+#define GICC_EOIR			0x0010
 
 #define GICC_INT_PRI_THRESHOLD		0xf0
+#define GICC_INT_SPURIOUS		0x3ff
 
 #ifndef __ASSEMBLY__
 
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 000000000000..744e227426bf
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,195 @@
+/*
+ * 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/delay.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 check_spurious(void)
+{
+	int cpu;
+
+	smp_rmb();
+	for_each_present_cpu(cpu) {
+		if (spurious[cpu])
+			report_info("WARN: cpu%d got %d spurious interrupts",
+				cpu, spurious[cpu]);
+	}
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+	u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+	if (irqnr != GICC_INT_SPURIOUS) {
+		writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+		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() + GICD_SGIR);
+	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() + GICD_SGIR);
+	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() + GICD_SGIR);
+	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) {
+		printf("No supported gic present, skipping tests...\n");
+		return report_summary();
+	}
+
+	snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+	report_prefix_push(pfx);
+
+	if (argc < 2)
+		report_abort("no test specified");
+
+	if (strcmp(argv[1], "ipi") == 0) {
+		report_prefix_push(argv[1]);
+		nr_cpu_check(2);
+
+		for_each_present_cpu(cpu) {
+			if (cpu == 0)
+				continue;
+			smp_boot_secondary(cpu, ipi_recv);
+		}
+		ipi_enable();
+		wait_on_ready();
+		ipi_test_self();
+		ipi_test_smp();
+		check_spurious();
+		report_prefix_pop();
+	} else {
+		report_abort("Unknown subtest '%s'", argv[1]);
+	}
+
+	return report_summary();
+}
-- 
2.9.3


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

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

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>
---
v8:
  - fix check_spurious print arguments and change the printf
    to a report_info
  - remove the self-ipi test issued when no subtest is given,
    i.e. require a subtest to be given
  - use report_summary for no supported gic present instead
    of report_abort, this will output nice SKIP message
v6: move the spurious check to its own check_ function [drew]
v5: use modern registers [Andre]
v4: properly mask irqnr in ipi_handler
v2: add more details in the output if a test fails,
    report spurious interrupts if we get them
---
 arm/Makefile.common  |  10 +--
 arm/unittests.cfg    |   8 +++
 lib/arm/asm/gic-v2.h |   2 +
 lib/arm/asm/gic.h    |   4 ++
 arm/gic.c            | 195 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 214 insertions(+), 5 deletions(-)
 create mode 100644 arm/gic.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 0ccd6743a8fe..275f8993012a 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -9,11 +9,11 @@ ifeq ($(LOADADDR),)
 	LOADADDR = 0x40000000
 endif
 
-tests-common = \
-	$(TEST_DIR)/selftest.flat \
-	$(TEST_DIR)/spinlock-test.flat \
-	$(TEST_DIR)/pci-test.flat \
-	$(TEST_DIR)/pmu.flat
+tests-common  = $(TEST_DIR)/selftest.flat
+tests-common += $(TEST_DIR)/spinlock-test.flat
+tests-common += $(TEST_DIR)/pci-test.flat
+tests-common += $(TEST_DIR)/pmu.flat
+tests-common += $(TEST_DIR)/gic.flat
 
 all: test_cases
 
diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index 65f9c4c0b9eb..f61e30b8526d 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -55,6 +55,7 @@ smp = $MAX_SMP
 extra_params = -append 'smp'
 groups = selftest
 
+# Test PCI emulation
 [pci-test]
 file = pci-test.flat
 groups = pci
@@ -77,3 +78,10 @@ groups = pmu
 #extra_params = -icount 8 -append '256'
 #groups = pmu
 #accel = tcg
+
+# 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
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
index c2d5fecd4886..8b3f7ed6790c 100644
--- a/lib/arm/asm/gic-v2.h
+++ b/lib/arm/asm/gic-v2.h
@@ -13,7 +13,9 @@
 #endif
 
 #define GICD_ENABLE			0x1
+
 #define GICC_ENABLE			0x1
+#define GICC_IAR_INT_ID_MASK		0x3ff
 
 #ifndef __ASSEMBLY__
 
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index e3580bd1d42d..d816b96e46b4 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -13,6 +13,7 @@
 #define GICD_TYPER			0x0004
 #define GICD_ISENABLER			0x0100
 #define GICD_IPRIORITYR			0x0400
+#define GICD_SGIR			0x0f00
 
 #define GICD_TYPER_IRQS(typer)		((((typer) & 0x1f) + 1) * 32)
 #define GICD_INT_EN_SET_SGI		0x0000ffff
@@ -21,8 +22,11 @@
 /* CPU interface registers */
 #define GICC_CTLR			0x0000
 #define GICC_PMR			0x0004
+#define GICC_IAR			0x000c
+#define GICC_EOIR			0x0010
 
 #define GICC_INT_PRI_THRESHOLD		0xf0
+#define GICC_INT_SPURIOUS		0x3ff
 
 #ifndef __ASSEMBLY__
 
diff --git a/arm/gic.c b/arm/gic.c
new file mode 100644
index 000000000000..744e227426bf
--- /dev/null
+++ b/arm/gic.c
@@ -0,0 +1,195 @@
+/*
+ * 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/delay.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 check_spurious(void)
+{
+	int cpu;
+
+	smp_rmb();
+	for_each_present_cpu(cpu) {
+		if (spurious[cpu])
+			report_info("WARN: cpu%d got %d spurious interrupts",
+				cpu, spurious[cpu]);
+	}
+}
+
+static void ipi_handler(struct pt_regs *regs __unused)
+{
+	u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
+	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+
+	if (irqnr != GICC_INT_SPURIOUS) {
+		writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+		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() + GICD_SGIR);
+	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() + GICD_SGIR);
+	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() + GICD_SGIR);
+	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) {
+		printf("No supported gic present, skipping tests...\n");
+		return report_summary();
+	}
+
+	snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+	report_prefix_push(pfx);
+
+	if (argc < 2)
+		report_abort("no test specified");
+
+	if (strcmp(argv[1], "ipi") == 0) {
+		report_prefix_push(argv[1]);
+		nr_cpu_check(2);
+
+		for_each_present_cpu(cpu) {
+			if (cpu == 0)
+				continue;
+			smp_boot_secondary(cpu, ipi_recv);
+		}
+		ipi_enable();
+		wait_on_ready();
+		ipi_test_self();
+		ipi_test_smp();
+		check_spurious();
+		report_prefix_pop();
+	} else {
+		report_abort("Unknown subtest '%s'", argv[1]);
+	}
+
+	return report_summary();
+}
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 07/10] libcflat: add IS_ALIGNED() macro, and page sizes
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall, Peter Xu

From: Peter Xu <peterx@redhat.com>

These macros will be useful to do page alignment checks.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
[drew: also added SZ_64K and changed to shifts]
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v6: change to shifts [Alex]
---
 lib/libcflat.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 15dbcadc6c7a..e636705e12b3 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -33,6 +33,12 @@
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
 #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
 #define ALIGN(x, a)		__ALIGN((x), (a))
+#define IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
+
+#define SZ_4K			(1 << 12)
+#define SZ_64K			(1 << 16)
+#define SZ_2M			(1 << 21)
+#define SZ_1G			(1 << 30)
 
 typedef uint8_t		u8;
 typedef int8_t		s8;
-- 
2.9.3


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

* [Qemu-devel] [PATCH kvm-unit-tests v8 07/10] libcflat: add IS_ALIGNED() macro, and page sizes
@ 2016-12-08 17:50   ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall, Peter Xu

From: Peter Xu <peterx@redhat.com>

These macros will be useful to do page alignment checks.

Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
[drew: also added SZ_64K and changed to shifts]
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v6: change to shifts [Alex]
---
 lib/libcflat.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/libcflat.h b/lib/libcflat.h
index 15dbcadc6c7a..e636705e12b3 100644
--- a/lib/libcflat.h
+++ b/lib/libcflat.h
@@ -33,6 +33,12 @@
 #define __ALIGN_MASK(x, mask)	(((x) + (mask)) & ~(mask))
 #define __ALIGN(x, a)		__ALIGN_MASK(x, (typeof(x))(a) - 1)
 #define ALIGN(x, a)		__ALIGN((x), (a))
+#define IS_ALIGNED(x, a)	(((x) & ((typeof(x))(a) - 1)) == 0)
+
+#define SZ_4K			(1 << 12)
+#define SZ_64K			(1 << 16)
+#define SZ_2M			(1 << 21)
+#define SZ_1G			(1 << 30)
 
 typedef uint8_t		u8;
 typedef int8_t		s8;
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 08/10] arm/arm64: add initial gicv3 support
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, andre.przywara, eric.auger,
	pbonzini, alex.bennee, christoffer.dall

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v8: few sysreg framework and new delay rebase changes
v7: split lib/arm/gic.c into gic-v2/3.c [Eric]
v6:
 - added comments [Alex]
 - added stride parameter to gicv3_set_redist_base [Andre]
 - redist-wait s/rwp/uwp/ and comment [Andre]
 - removed unnecessary wait-for-rwps [Andre]
v5: use modern register names [Andre]
v4:
 - only take defines from kernel we need now [Andre]
 - simplify enable by not caring if we reinit the distributor [drew]
v2:
 - configure irqs as NS GRP1
---
 arm/Makefile.common        |   2 +-
 lib/arm/asm/arch_gicv3.h   |  44 +++++++++++++++++++
 lib/arm/asm/gic-v3.h       | 105 +++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h          |   5 ++-
 lib/arm64/asm/arch_gicv3.h |  42 ++++++++++++++++++
 lib/arm64/asm/gic-v3.h     |   1 +
 lib/arm64/asm/sysreg.h     |  34 ++++++++++++++-
 lib/arm/gic-v2.c           |  27 ++++++++++++
 lib/arm/gic-v3.c           |  61 ++++++++++++++++++++++++++
 lib/arm/gic.c              |  30 +++++--------
 10 files changed, 327 insertions(+), 24 deletions(-)
 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/arm/gic-v2.c
 create mode 100644 lib/arm/gic-v3.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 275f8993012a..5b7d57e77aab 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -49,7 +49,7 @@ cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
 cflatobjs += lib/arm/delay.o
-cflatobjs += lib/arm/gic.o
+cflatobjs += lib/arm/gic.o lib/arm/gic-v2.o lib/arm/gic-v3.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
new file mode 100644
index 000000000000..f4388d057975
--- /dev/null
+++ b/lib/arm/asm/arch_gicv3.h
@@ -0,0 +1,44 @@
+/*
+ * 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/sysreg.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+#define ICC_PMR				__ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_IGRPEN1			__ACCESS_CP15(c12, 0, c12, 7)
+
+static inline void gicv3_write_pmr(u32 val)
+{
+	write_sysreg(val, ICC_PMR);
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+	write_sysreg(val, ICC_IGRPEN1);
+	isb();
+}
+
+/*
+ * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER
+ * offset and the following offset (+ 4) and then combining them to
+ * form a 64-bit address.
+ */
+static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
+{
+	u64 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 000000000000..65f148b8a265
--- /dev/null
+++ b/lib/arm/asm/gic-v3.h
@@ -0,0 +1,105 @@
+/*
+ * 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_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
+#endif
+
+/*
+ * Distributor registers
+ *
+ * We expect to be run in Non-secure mode, thus we define the
+ * group1 enable bits with respect to that view.
+ */
+#define GICD_CTLR_RWP			(1U << 31)
+#define GICD_CTLR_ARE_NS		(1U << 4)
+#define GICD_CTLR_ENABLE_G1A		(1U << 1)
+#define GICD_CTLR_ENABLE_G1		(1U << 0)
+
+/* Re-Distributor registers, offsets from RD_base */
+#define GICR_TYPER			0x0008
+
+#define GICR_TYPER_LAST			(1U << 4)
+
+/* Re-Distributor registers, offsets from SGI_base */
+#define GICR_IGROUPR0			GICD_IGROUPR
+#define GICR_ISENABLER0			GICD_ISENABLER
+#define GICR_IPRIORITYR0		GICD_IPRIORITYR
+
+#include <asm/arch_gicv3.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/delay.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);
+extern void gicv3_set_redist_base(size_t stride);
+
+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_uwp(void)
+{
+	/*
+	 * We can build on gic_do_wait_for_rwp, which uses GICD_ registers
+	 * because GICD_CTLR == GICR_CTLR and GICD_CTLR_RWP == GICR_CTLR_UWP
+	 */
+	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 d816b96e46b4..21511997f2a9 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -6,11 +6,11 @@
 #ifndef _ASMARM_GIC_H_
 #define _ASMARM_GIC_H_
 
-#include <asm/gic-v2.h>
 
 /* Distributor registers */
 #define GICD_CTLR			0x0000
 #define GICD_TYPER			0x0004
+#define GICD_IGROUPR			0x0080
 #define GICD_ISENABLER			0x0100
 #define GICD_IPRIORITYR			0x0400
 #define GICD_SGIR			0x0f00
@@ -28,6 +28,9 @@
 #define GICC_INT_PRI_THRESHOLD		0xf0
 #define GICC_INT_SPURIOUS		0x3ff
 
+#include <asm/gic-v2.h>
+#include <asm/gic-v3.h>
+
 #ifndef __ASSEMBLY__
 
 /*
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
new file mode 100644
index 000000000000..a6c153103547
--- /dev/null
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -0,0 +1,42 @@
+/*
+ * 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_PMR_EL1			sys_reg(3, 0, 4, 6, 0)
+#define ICC_GRPEN1_EL1			sys_reg(3, 0, 12, 12, 7)
+
+#ifndef __ASSEMBLY__
+
+#include <libcflat.h>
+#include <asm/barrier.h>
+
+/*
+ * 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_pmr(u32 val)
+{
+	asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+	asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
+	isb();
+}
+
+#define gicv3_read_typer(c) readq(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 000000000000..8ee5d4d9c181
--- /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
index 05b9fcb1bbf7..a03830bceb8f 100644
--- a/lib/arm64/asm/sysreg.h
+++ b/lib/arm64/asm/sysreg.h
@@ -8,7 +8,23 @@
 #ifndef _ASMARM64_SYSREG_H_
 #define _ASMARM64_SYSREG_H_
 
-#ifndef __ASSEMBLY__
+#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
 #include <libcflat.h>
 
 #define read_sysreg(r) ({					\
@@ -22,5 +38,19 @@
 	asm volatile("msr " xstr(r) ", %x0" : : "rZ" (__val));	\
 } while (0)
 
-#endif /* !__ASSEMBLY__ */
+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 /* __ASSEMBLY__ */
 #endif /* _ASMARM64_SYSREG_H_ */
diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
new file mode 100644
index 000000000000..e80eb8f29488
--- /dev/null
+++ b/lib/arm/gic-v2.c
@@ -0,0 +1,27 @@
+/*
+ * 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 <asm/gic.h>
+#include <asm/io.h>
+
+void gicv2_enable_defaults(void)
+{
+	void *dist = gicv2_dist_base();
+	void *cpu_base = gicv2_cpu_base();
+	unsigned int i;
+
+	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv2_data.irq_nr > 1020)
+		gicv2_data.irq_nr = 1020;
+
+	for (i = 0; i < gicv2_data.irq_nr; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
+
+	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
+	writel(GICD_ENABLE, dist + GICD_CTLR);
+
+	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
+	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
+}
diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c
new file mode 100644
index 000000000000..c46d16e11782
--- /dev/null
+++ b/lib/arm/gic-v3.c
@@ -0,0 +1,61 @@
+/*
+ * 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 <asm/gic.h>
+#include <asm/io.h>
+
+void gicv3_set_redist_base(size_t stride)
+{
+	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 += stride; /* skip RD_base, SGI_base, etc. */
+	} while (!(typer & GICR_TYPER_LAST));
+
+	/* should never reach here */
+	assert(0);
+}
+
+void gicv3_enable_defaults(void)
+{
+	void *dist = gicv3_dist_base();
+	void *sgi_base;
+	unsigned int i;
+
+	gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv3_data.irq_nr > 1020)
+		gicv3_data.irq_nr = 1020;
+
+	writel(0, dist + GICD_CTLR);
+	gicv3_dist_wait_for_rwp();
+
+	writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+	       dist + GICD_CTLR);
+	gicv3_dist_wait_for_rwp();
+
+	for (i = 0; i < gicv3_data.irq_nr; i += 4)
+		writel(~0, dist + GICD_IGROUPR + i);
+
+	if (!gicv3_redist_base())
+		gicv3_set_redist_base(SZ_64K * 2);
+	sgi_base = gicv3_sgi_base();
+
+	writel(~0, sgi_base + GICR_IGROUPR0);
+
+	for (i = 0; i < 16; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, sgi_base + GICR_IPRIORITYR0 + i);
+
+	writel(GICD_INT_EN_SET_SGI, sgi_base + GICR_ISENABLER0);
+
+	gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
+	gicv3_write_grpen1(1);
+}
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index d655105e058b..4d3ddd9722b1 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -8,9 +8,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)
@@ -48,29 +50,17 @@ 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;
 }
-
-void gicv2_enable_defaults(void)
-{
-	void *dist = gicv2_dist_base();
-	void *cpu_base = gicv2_cpu_base();
-	unsigned int i;
-
-	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
-	if (gicv2_data.irq_nr > 1020)
-		gicv2_data.irq_nr = 1020;
-
-	for (i = 0; i < gicv2_data.irq_nr; i += 4)
-		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
-
-	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
-	writel(GICD_ENABLE, dist + GICD_CTLR);
-
-	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
-	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
-}
-- 
2.9.3


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

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

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v8: few sysreg framework and new delay rebase changes
v7: split lib/arm/gic.c into gic-v2/3.c [Eric]
v6:
 - added comments [Alex]
 - added stride parameter to gicv3_set_redist_base [Andre]
 - redist-wait s/rwp/uwp/ and comment [Andre]
 - removed unnecessary wait-for-rwps [Andre]
v5: use modern register names [Andre]
v4:
 - only take defines from kernel we need now [Andre]
 - simplify enable by not caring if we reinit the distributor [drew]
v2:
 - configure irqs as NS GRP1
---
 arm/Makefile.common        |   2 +-
 lib/arm/asm/arch_gicv3.h   |  44 +++++++++++++++++++
 lib/arm/asm/gic-v3.h       | 105 +++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/asm/gic.h          |   5 ++-
 lib/arm64/asm/arch_gicv3.h |  42 ++++++++++++++++++
 lib/arm64/asm/gic-v3.h     |   1 +
 lib/arm64/asm/sysreg.h     |  34 ++++++++++++++-
 lib/arm/gic-v2.c           |  27 ++++++++++++
 lib/arm/gic-v3.c           |  61 ++++++++++++++++++++++++++
 lib/arm/gic.c              |  30 +++++--------
 10 files changed, 327 insertions(+), 24 deletions(-)
 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/arm/gic-v2.c
 create mode 100644 lib/arm/gic-v3.c

diff --git a/arm/Makefile.common b/arm/Makefile.common
index 275f8993012a..5b7d57e77aab 100644
--- a/arm/Makefile.common
+++ b/arm/Makefile.common
@@ -49,7 +49,7 @@ cflatobjs += lib/arm/bitops.o
 cflatobjs += lib/arm/psci.o
 cflatobjs += lib/arm/smp.o
 cflatobjs += lib/arm/delay.o
-cflatobjs += lib/arm/gic.o
+cflatobjs += lib/arm/gic.o lib/arm/gic-v2.o lib/arm/gic-v3.o
 
 libeabi = lib/arm/libeabi.a
 eabiobjs = lib/arm/eabi_compat.o
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
new file mode 100644
index 000000000000..f4388d057975
--- /dev/null
+++ b/lib/arm/asm/arch_gicv3.h
@@ -0,0 +1,44 @@
+/*
+ * 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/sysreg.h>
+#include <asm/barrier.h>
+#include <asm/io.h>
+
+#define ICC_PMR				__ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_IGRPEN1			__ACCESS_CP15(c12, 0, c12, 7)
+
+static inline void gicv3_write_pmr(u32 val)
+{
+	write_sysreg(val, ICC_PMR);
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+	write_sysreg(val, ICC_IGRPEN1);
+	isb();
+}
+
+/*
+ * We may access GICR_TYPER and GITS_TYPER by reading both the TYPER
+ * offset and the following offset (+ 4) and then combining them to
+ * form a 64-bit address.
+ */
+static inline u64 gicv3_read_typer(const volatile void __iomem *addr)
+{
+	u64 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 000000000000..65f148b8a265
--- /dev/null
+++ b/lib/arm/asm/gic-v3.h
@@ -0,0 +1,105 @@
+/*
+ * 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_
+
+#ifndef _ASMARM_GIC_H_
+#error Do not directly include <asm/gic-v3.h>. Include <asm/gic.h>
+#endif
+
+/*
+ * Distributor registers
+ *
+ * We expect to be run in Non-secure mode, thus we define the
+ * group1 enable bits with respect to that view.
+ */
+#define GICD_CTLR_RWP			(1U << 31)
+#define GICD_CTLR_ARE_NS		(1U << 4)
+#define GICD_CTLR_ENABLE_G1A		(1U << 1)
+#define GICD_CTLR_ENABLE_G1		(1U << 0)
+
+/* Re-Distributor registers, offsets from RD_base */
+#define GICR_TYPER			0x0008
+
+#define GICR_TYPER_LAST			(1U << 4)
+
+/* Re-Distributor registers, offsets from SGI_base */
+#define GICR_IGROUPR0			GICD_IGROUPR
+#define GICR_ISENABLER0			GICD_ISENABLER
+#define GICR_IPRIORITYR0		GICD_IPRIORITYR
+
+#include <asm/arch_gicv3.h>
+
+#ifndef __ASSEMBLY__
+#include <asm/setup.h>
+#include <asm/processor.h>
+#include <asm/delay.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);
+extern void gicv3_set_redist_base(size_t stride);
+
+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_uwp(void)
+{
+	/*
+	 * We can build on gic_do_wait_for_rwp, which uses GICD_ registers
+	 * because GICD_CTLR == GICR_CTLR and GICD_CTLR_RWP == GICR_CTLR_UWP
+	 */
+	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 d816b96e46b4..21511997f2a9 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -6,11 +6,11 @@
 #ifndef _ASMARM_GIC_H_
 #define _ASMARM_GIC_H_
 
-#include <asm/gic-v2.h>
 
 /* Distributor registers */
 #define GICD_CTLR			0x0000
 #define GICD_TYPER			0x0004
+#define GICD_IGROUPR			0x0080
 #define GICD_ISENABLER			0x0100
 #define GICD_IPRIORITYR			0x0400
 #define GICD_SGIR			0x0f00
@@ -28,6 +28,9 @@
 #define GICC_INT_PRI_THRESHOLD		0xf0
 #define GICC_INT_SPURIOUS		0x3ff
 
+#include <asm/gic-v2.h>
+#include <asm/gic-v3.h>
+
 #ifndef __ASSEMBLY__
 
 /*
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
new file mode 100644
index 000000000000..a6c153103547
--- /dev/null
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -0,0 +1,42 @@
+/*
+ * 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_PMR_EL1			sys_reg(3, 0, 4, 6, 0)
+#define ICC_GRPEN1_EL1			sys_reg(3, 0, 12, 12, 7)
+
+#ifndef __ASSEMBLY__
+
+#include <libcflat.h>
+#include <asm/barrier.h>
+
+/*
+ * 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_pmr(u32 val)
+{
+	asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
+}
+
+static inline void gicv3_write_grpen1(u32 val)
+{
+	asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
+	isb();
+}
+
+#define gicv3_read_typer(c) readq(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 000000000000..8ee5d4d9c181
--- /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
index 05b9fcb1bbf7..a03830bceb8f 100644
--- a/lib/arm64/asm/sysreg.h
+++ b/lib/arm64/asm/sysreg.h
@@ -8,7 +8,23 @@
 #ifndef _ASMARM64_SYSREG_H_
 #define _ASMARM64_SYSREG_H_
 
-#ifndef __ASSEMBLY__
+#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
 #include <libcflat.h>
 
 #define read_sysreg(r) ({					\
@@ -22,5 +38,19 @@
 	asm volatile("msr " xstr(r) ", %x0" : : "rZ" (__val));	\
 } while (0)
 
-#endif /* !__ASSEMBLY__ */
+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 /* __ASSEMBLY__ */
 #endif /* _ASMARM64_SYSREG_H_ */
diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
new file mode 100644
index 000000000000..e80eb8f29488
--- /dev/null
+++ b/lib/arm/gic-v2.c
@@ -0,0 +1,27 @@
+/*
+ * 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 <asm/gic.h>
+#include <asm/io.h>
+
+void gicv2_enable_defaults(void)
+{
+	void *dist = gicv2_dist_base();
+	void *cpu_base = gicv2_cpu_base();
+	unsigned int i;
+
+	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv2_data.irq_nr > 1020)
+		gicv2_data.irq_nr = 1020;
+
+	for (i = 0; i < gicv2_data.irq_nr; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
+
+	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
+	writel(GICD_ENABLE, dist + GICD_CTLR);
+
+	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
+	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
+}
diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c
new file mode 100644
index 000000000000..c46d16e11782
--- /dev/null
+++ b/lib/arm/gic-v3.c
@@ -0,0 +1,61 @@
+/*
+ * 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 <asm/gic.h>
+#include <asm/io.h>
+
+void gicv3_set_redist_base(size_t stride)
+{
+	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 += stride; /* skip RD_base, SGI_base, etc. */
+	} while (!(typer & GICR_TYPER_LAST));
+
+	/* should never reach here */
+	assert(0);
+}
+
+void gicv3_enable_defaults(void)
+{
+	void *dist = gicv3_dist_base();
+	void *sgi_base;
+	unsigned int i;
+
+	gicv3_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
+	if (gicv3_data.irq_nr > 1020)
+		gicv3_data.irq_nr = 1020;
+
+	writel(0, dist + GICD_CTLR);
+	gicv3_dist_wait_for_rwp();
+
+	writel(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+	       dist + GICD_CTLR);
+	gicv3_dist_wait_for_rwp();
+
+	for (i = 0; i < gicv3_data.irq_nr; i += 4)
+		writel(~0, dist + GICD_IGROUPR + i);
+
+	if (!gicv3_redist_base())
+		gicv3_set_redist_base(SZ_64K * 2);
+	sgi_base = gicv3_sgi_base();
+
+	writel(~0, sgi_base + GICR_IGROUPR0);
+
+	for (i = 0; i < 16; i += 4)
+		writel(GICD_INT_DEF_PRI_X4, sgi_base + GICR_IPRIORITYR0 + i);
+
+	writel(GICD_INT_EN_SET_SGI, sgi_base + GICR_ISENABLER0);
+
+	gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
+	gicv3_write_grpen1(1);
+}
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index d655105e058b..4d3ddd9722b1 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -8,9 +8,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)
@@ -48,29 +50,17 @@ 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;
 }
-
-void gicv2_enable_defaults(void)
-{
-	void *dist = gicv2_dist_base();
-	void *cpu_base = gicv2_cpu_base();
-	unsigned int i;
-
-	gicv2_data.irq_nr = GICD_TYPER_IRQS(readl(dist + GICD_TYPER));
-	if (gicv2_data.irq_nr > 1020)
-		gicv2_data.irq_nr = 1020;
-
-	for (i = 0; i < gicv2_data.irq_nr; i += 4)
-		writel(GICD_INT_DEF_PRI_X4, dist + GICD_IPRIORITYR + i);
-
-	writel(GICD_INT_EN_SET_SGI, dist + GICD_ISENABLER + 0);
-	writel(GICD_ENABLE, dist + GICD_CTLR);
-
-	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
-	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
-}
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 09/10] arm/arm64: gicv3: add an IPI test
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm; +Cc: marc.zyngier, andre.przywara, pbonzini

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

---
v8:
 - keep the gic_common_ops concept completely local to
   lib/arm/gic.c by instead exposing the more useful
   concept of gic-specific functions
 - sysreg rebase changes
 - ordered ICC registers in spec-order (OCD kicked in...)
v7:
 - add common ipi_send_single/mask (replacing ipi_send).
   Note, the arg order irq,cpu got swapped. [Eric]
 - comment rewording [Eric]
 - make enable_defaults a common op [Eric]
 - gic_enable_defaults() will now invoke gic_init if
   necessary [drew]
 - split lib/arm/gic.c into gic-v2/3.c [Eric]
v6: move most gicv2/gicv3 wrappers to common code [Alex]
v5:
 - fix copy+paste error in gicv3_write_eoir [drew]
 - use modern register names [Andre]
v4:
 - heavily comment gicv3_ipi_send_tlist() [Eric]
 - changes needed for gicv2 iar/irqstat fix to other patch
v2:
 - use IRM for gicv3 broadcast
---
 arm/unittests.cfg          |  6 ++++
 lib/arm/asm/arch_gicv3.h   | 21 ++++++++++++
 lib/arm/asm/gic-v2.h       |  6 ++++
 lib/arm/asm/gic-v3.h       | 12 +++++++
 lib/arm/asm/gic.h          | 19 +++++++++++
 lib/arm64/asm/arch_gicv3.h | 22 ++++++++++++
 arm/gic.c                  | 81 +++++++++++++++++++++++++++++++++++--------
 lib/arm/gic-v2.c           | 30 ++++++++++++++++
 lib/arm/gic-v3.c           | 84 +++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/gic.c              | 85 ++++++++++++++++++++++++++++++++++++++++++++--
 10 files changed, 350 insertions(+), 16 deletions(-)

diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index f61e30b8526d..8cf94729d86e 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -85,3 +85,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
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
index f4388d057975..45b609684460 100644
--- a/lib/arm/asm/arch_gicv3.h
+++ b/lib/arm/asm/arch_gicv3.h
@@ -15,6 +15,9 @@
 #include <asm/io.h>
 
 #define ICC_PMR				__ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_SGI1R			__ACCESS_CP15_64(0, c12)
+#define ICC_IAR1			__ACCESS_CP15(c12, 0, c12, 0)
+#define ICC_EOIR1			__ACCESS_CP15(c12, 0, c12, 1)
 #define ICC_IGRPEN1			__ACCESS_CP15(c12, 0, c12, 7)
 
 static inline void gicv3_write_pmr(u32 val)
@@ -22,6 +25,24 @@ static inline void gicv3_write_pmr(u32 val)
 	write_sysreg(val, ICC_PMR);
 }
 
+static inline void gicv3_write_sgi1r(u64 val)
+{
+	write_sysreg(val, ICC_SGI1R);
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+	u32 irqstat = read_sysreg(ICC_IAR1);
+	dsb(sy);
+	return irqstat;
+}
+
+static inline void gicv3_write_eoir(u32 irq)
+{
+	write_sysreg(irq, ICC_EOIR1);
+	isb();
+}
+
 static inline void gicv3_write_grpen1(u32 val)
 {
 	write_sysreg(val, ICC_IGRPEN1);
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
index 8b3f7ed6790c..1fcfd43c8075 100644
--- a/lib/arm/asm/gic-v2.h
+++ b/lib/arm/asm/gic-v2.h
@@ -18,6 +18,7 @@
 #define GICC_IAR_INT_ID_MASK		0x3ff
 
 #ifndef __ASSEMBLY__
+#include <asm/cpumask.h>
 
 struct gicv2_data {
 	void *dist_base;
@@ -31,6 +32,11 @@ extern struct gicv2_data gicv2_data;
 
 extern int gicv2_init(void);
 extern void gicv2_enable_defaults(void);
+extern u32 gicv2_read_iar(void);
+extern u32 gicv2_iar_irqnr(u32 iar);
+extern void gicv2_write_eoir(u32 irqstat);
+extern void gicv2_ipi_send_single(int irq, int cpu);
+extern void gicv2_ipi_send_mask(int irq, const cpumask_t *dest);
 
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM_GIC_V2_H_ */
diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
index 65f148b8a265..1dceb9541f62 100644
--- a/lib/arm/asm/gic-v3.h
+++ b/lib/arm/asm/gic-v3.h
@@ -33,12 +33,19 @@
 #define GICR_ISENABLER0			GICD_ISENABLER
 #define GICR_IPRIORITYR0		GICD_IPRIORITYR
 
+#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)
+
 #include <asm/arch_gicv3.h>
 
 #ifndef __ASSEMBLY__
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/delay.h>
+#include <asm/cpumask.h>
 #include <asm/smp.h>
 #include <asm/io.h>
 
@@ -55,6 +62,11 @@ extern struct gicv3_data gicv3_data;
 
 extern int gicv3_init(void);
 extern void gicv3_enable_defaults(void);
+extern u32 gicv3_read_iar(void);
+extern u32 gicv3_iar_irqnr(u32 iar);
+extern void gicv3_write_eoir(u32 irqstat);
+extern void gicv3_ipi_send_single(int irq, int cpu);
+extern void gicv3_ipi_send_mask(int irq, const cpumask_t *dest);
 extern void gicv3_set_redist_base(size_t stride);
 
 static inline void gicv3_do_wait_for_rwp(void *base)
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index 21511997f2a9..c8186f25aa6b 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -32,6 +32,7 @@
 #include <asm/gic-v3.h>
 
 #ifndef __ASSEMBLY__
+#include <asm/cpumask.h>
 
 /*
  * gic_init will try to find all known gics, and then
@@ -42,5 +43,23 @@
  */
 extern int gic_init(void);
 
+/*
+ * gic_enable_defaults enables the gic with basic but useful
+ * settings. gic_enable_defaults will call gic_init if it has
+ * not yet been invoked.
+ */
+extern void gic_enable_defaults(void);
+
+/*
+ * After enabling the gic with gic_enable_defaults the functions
+ * below will work with any supported gic version.
+ */
+extern int gic_version(void);
+extern u32 gic_read_iar(void);
+extern u32 gic_iar_irqnr(u32 iar);
+extern void gic_write_eoir(u32 irqstat);
+extern void gic_ipi_send_single(int irq, int cpu);
+extern void gic_ipi_send_mask(int irq, const cpumask_t *dest);
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
index a6c153103547..a7994ec2fbbe 100644
--- a/lib/arm64/asm/arch_gicv3.h
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -11,6 +11,9 @@
 #include <asm/sysreg.h>
 
 #define ICC_PMR_EL1			sys_reg(3, 0, 4, 6, 0)
+#define ICC_SGI1R_EL1			sys_reg(3, 0, 12, 11, 5)
+#define ICC_IAR1_EL1			sys_reg(3, 0, 12, 12, 0)
+#define ICC_EOIR1_EL1			sys_reg(3, 0, 12, 12, 1)
 #define ICC_GRPEN1_EL1			sys_reg(3, 0, 12, 12, 7)
 
 #ifndef __ASSEMBLY__
@@ -30,6 +33,25 @@ static inline void gicv3_write_pmr(u32 val)
 	asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
 }
 
+static inline void gicv3_write_sgi1r(u64 val)
+{
+	asm volatile("msr_s " xstr(ICC_SGI1R_EL1) ", %0" : : "r" (val));
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+	u64 irqstat;
+	asm volatile("mrs_s %0, " xstr(ICC_IAR1_EL1) : "=r" (irqstat));
+	dsb(sy);
+	return (u64)irqstat;
+}
+
+static inline void gicv3_write_eoir(u32 irq)
+{
+	asm volatile("msr_s " xstr(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq));
+	isb();
+}
+
 static inline void gicv3_write_grpen1(u32 val)
 {
 	asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
diff --git a/arm/gic.c b/arm/gic.c
index 744e227426bf..d0d3be0fa36e 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>
  *
@@ -17,7 +19,14 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
-static int gic_version;
+struct gic {
+	struct {
+		void (*send_self)(void);
+		void (*send_broadcast)(void);
+	} ipi;
+};
+
+static struct gic *gic;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
 
@@ -84,11 +93,11 @@ static void check_spurious(void)
 
 static void ipi_handler(struct pt_regs *regs __unused)
 {
-	u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
-	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	u32 irqstat = gic_read_iar();
+	u32 irqnr = gic_iar_irqnr(irqstat);
 
 	if (irqnr != GICC_INT_SPURIOUS) {
-		writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+		gic_write_eoir(irqstat);
 		smp_rmb(); /* pairs with wmb in ipi_test functions */
 		++acked[smp_processor_id()];
 		smp_wmb(); /* pairs with rmb in check_acked */
@@ -98,6 +107,27 @@ static void ipi_handler(struct pt_regs *regs __unused)
 	}
 }
 
+static void gicv2_ipi_send_self(void)
+{
+	writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv2_ipi_send_broadcast(void)
+{
+	writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv3_ipi_send_self(void)
+{
+	gic_ipi_send_single(0, smp_processor_id());
+}
+
+static void gicv3_ipi_send_broadcast(void)
+{
+	gicv3_write_sgi1r(1ULL << 40);
+	isb();
+}
+
 static void ipi_test_self(void)
 {
 	cpumask_t mask;
@@ -107,7 +137,7 @@ static void ipi_test_self(void)
 	smp_wmb();
 	cpumask_clear(&mask);
 	cpumask_set_cpu(0, &mask);
-	writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
 }
@@ -115,14 +145,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() + GICD_SGIR);
+	cpumask_copy(&mask, &cpu_present_mask);
+	for (i = 0; i < nr_cpus; i += 2)
+		cpumask_clear_cpu(i, &mask);
+	gic_ipi_send_mask(0, &mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
@@ -131,14 +162,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() + GICD_SGIR);
+	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
 }
 
 static void ipi_enable(void)
 {
-	gicv2_enable_defaults();
+	gic_enable_defaults();
 #ifdef __arm__
 	install_exception_handler(EXCPTN_IRQ, ipi_handler);
 #else
@@ -155,20 +186,42 @@ static void ipi_recv(void)
 		wfi();
 }
 
+static struct gic gicv2 = {
+	.ipi = {
+		.send_self = gicv2_ipi_send_self,
+		.send_broadcast = gicv2_ipi_send_broadcast,
+	},
+};
+
+static struct gic gicv3 = {
+	.ipi = {
+		.send_self = gicv3_ipi_send_self,
+		.send_broadcast = gicv3_ipi_send_broadcast,
+	},
+};
+
 int main(int argc, char **argv)
 {
 	char pfx[8];
 	int cpu;
 
-	gic_version = gic_init();
-	if (!gic_version) {
+	if (!gic_init()) {
 		printf("No supported gic present, skipping tests...\n");
 		return report_summary();
 	}
 
-	snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+	snprintf(pfx, sizeof(pfx), "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_abort("no test specified");
 
diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
index e80eb8f29488..dc6a97c600ec 100644
--- a/lib/arm/gic-v2.c
+++ b/lib/arm/gic-v2.c
@@ -25,3 +25,33 @@ void gicv2_enable_defaults(void)
 	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
 	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
 }
+
+u32 gicv2_read_iar(void)
+{
+	return readl(gicv2_cpu_base() + GICC_IAR);
+}
+
+u32 gicv2_iar_irqnr(u32 iar)
+{
+	return iar & GICC_IAR_INT_ID_MASK;
+}
+
+void gicv2_write_eoir(u32 irqstat)
+{
+	writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+}
+
+void gicv2_ipi_send_single(int irq, int cpu)
+{
+	assert(cpu < 8);
+	assert(irq < 16);
+	writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR);
+}
+
+void gicv2_ipi_send_mask(int irq, const cpumask_t *dest)
+{
+	u8 tlist = (u8)cpumask_bits(dest)[0];
+
+	assert(irq < 16);
+	writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
+}
diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c
index c46d16e11782..9682fc96b631 100644
--- a/lib/arm/gic-v3.c
+++ b/lib/arm/gic-v3.c
@@ -59,3 +59,87 @@ void gicv3_enable_defaults(void)
 	gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
 	gicv3_write_grpen1(1);
 }
+
+u32 gicv3_iar_irqnr(u32 iar)
+{
+	return iar;
+}
+
+void gicv3_ipi_send_mask(int irq, const cpumask_t *dest)
+{
+	u16 tlist;
+	int cpu;
+
+	assert(irq < 16);
+
+	/*
+	 * For each cpu in the mask collect its peers, which are also in
+	 * the mask, in order to form target lists.
+	 */
+	for_each_cpu(cpu, dest) {
+		u64 mpidr = cpus[cpu], sgi1r;
+		u64 cluster_id;
+
+		/*
+		 * GICv3 can send IPIs to up 16 peer cpus with a single
+		 * write to ICC_SGI1R_EL1 (using the target list). Peers
+		 * are cpus that have nearly identical MPIDRs, the only
+		 * difference being Aff0. The matching upper affinity
+		 * levels form the cluster ID.
+		 */
+		cluster_id = mpidr & ~0xffUL;
+		tlist = 0;
+
+		/*
+		 * Sort of open code for_each_cpu in order to have a
+		 * nested for_each_cpu loop.
+		 */
+		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, dest);
+			if (cpu >= nr_cpus)
+				break;
+
+			mpidr = cpus[cpu];
+
+			if (cluster_id != (mpidr & ~0xffUL)) {
+				/*
+				 * The next cpu isn't in our cluster. Roll
+				 * back the cpu index allowing the outer
+				 * for_each_cpu to find it again with
+				 * cpumask_next
+				 */
+				--cpu;
+				break;
+			}
+		}
+
+		/* Send the IPIs for the target list of this cluster */
+		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();
+}
+
+void gicv3_ipi_send_single(int irq, int cpu)
+{
+	cpumask_t dest;
+
+	cpumask_clear(&dest);
+	cpumask_set_cpu(cpu, &dest);
+	gicv3_ipi_send_mask(irq, &dest);
+}
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index 4d3ddd9722b1..3ed539727f8c 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -10,6 +10,38 @@
 struct gicv2_data gicv2_data;
 struct gicv3_data gicv3_data;
 
+struct gic_common_ops {
+	int gic_version;
+	void (*enable_defaults)(void);
+	u32 (*read_iar)(void);
+	u32 (*iar_irqnr)(u32 iar);
+	void (*write_eoir)(u32 irqstat);
+	void (*ipi_send_single)(int irq, int cpu);
+	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
+};
+
+static const struct gic_common_ops *gic_common_ops;
+
+static const struct gic_common_ops gicv2_common_ops = {
+	.gic_version = 2,
+	.enable_defaults = gicv2_enable_defaults,
+	.read_iar = gicv2_read_iar,
+	.iar_irqnr = gicv2_iar_irqnr,
+	.write_eoir = gicv2_write_eoir,
+	.ipi_send_single = gicv2_ipi_send_single,
+	.ipi_send_mask = gicv2_ipi_send_mask,
+};
+
+static const struct gic_common_ops gicv3_common_ops = {
+	.gic_version = 3,
+	.enable_defaults = gicv3_enable_defaults,
+	.read_iar = gicv3_read_iar,
+	.iar_irqnr = gicv3_iar_irqnr,
+	.write_eoir = gicv3_write_eoir,
+	.ipi_send_single = gicv3_ipi_send_single,
+	.ipi_send_mask = gicv3_ipi_send_mask,
+};
+
 /*
  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
  * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
@@ -58,9 +90,58 @@ int gicv3_init(void)
 
 int gic_init(void)
 {
-	if (gicv2_init())
+	if (gicv2_init()) {
+		gic_common_ops = &gicv2_common_ops;
 		return 2;
-	else if (gicv3_init())
+	} else if (gicv3_init()) {
+		gic_common_ops = &gicv3_common_ops;
 		return 3;
+	}
 	return 0;
 }
+
+void gic_enable_defaults(void)
+{
+	if (!gic_common_ops) {
+		int ret = gic_init();
+		assert(ret != 0);
+	} else
+		assert(gic_common_ops->enable_defaults);
+	gic_common_ops->enable_defaults();
+}
+
+int gic_version(void)
+{
+	assert(gic_common_ops);
+	return gic_common_ops->gic_version;
+}
+
+u32 gic_read_iar(void)
+{
+	assert(gic_common_ops && gic_common_ops->read_iar);
+	return gic_common_ops->read_iar();
+}
+
+u32 gic_iar_irqnr(u32 iar)
+{
+	assert(gic_common_ops && gic_common_ops->iar_irqnr);
+	return gic_common_ops->iar_irqnr(iar);
+}
+
+void gic_write_eoir(u32 irqstat)
+{
+	assert(gic_common_ops && gic_common_ops->write_eoir);
+	gic_common_ops->write_eoir(irqstat);
+}
+
+void gic_ipi_send_single(int irq, int cpu)
+{
+	assert(gic_common_ops && gic_common_ops->ipi_send_single);
+	gic_common_ops->ipi_send_single(irq, cpu);
+}
+
+void gic_ipi_send_mask(int irq, const cpumask_t *dest)
+{
+	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
+	gic_common_ops->ipi_send_mask(irq, dest);
+}
-- 
2.9.3

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

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

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

---
v8:
 - keep the gic_common_ops concept completely local to
   lib/arm/gic.c by instead exposing the more useful
   concept of gic-specific functions
 - sysreg rebase changes
 - ordered ICC registers in spec-order (OCD kicked in...)
v7:
 - add common ipi_send_single/mask (replacing ipi_send).
   Note, the arg order irq,cpu got swapped. [Eric]
 - comment rewording [Eric]
 - make enable_defaults a common op [Eric]
 - gic_enable_defaults() will now invoke gic_init if
   necessary [drew]
 - split lib/arm/gic.c into gic-v2/3.c [Eric]
v6: move most gicv2/gicv3 wrappers to common code [Alex]
v5:
 - fix copy+paste error in gicv3_write_eoir [drew]
 - use modern register names [Andre]
v4:
 - heavily comment gicv3_ipi_send_tlist() [Eric]
 - changes needed for gicv2 iar/irqstat fix to other patch
v2:
 - use IRM for gicv3 broadcast
---
 arm/unittests.cfg          |  6 ++++
 lib/arm/asm/arch_gicv3.h   | 21 ++++++++++++
 lib/arm/asm/gic-v2.h       |  6 ++++
 lib/arm/asm/gic-v3.h       | 12 +++++++
 lib/arm/asm/gic.h          | 19 +++++++++++
 lib/arm64/asm/arch_gicv3.h | 22 ++++++++++++
 arm/gic.c                  | 81 +++++++++++++++++++++++++++++++++++--------
 lib/arm/gic-v2.c           | 30 ++++++++++++++++
 lib/arm/gic-v3.c           | 84 +++++++++++++++++++++++++++++++++++++++++++++
 lib/arm/gic.c              | 85 ++++++++++++++++++++++++++++++++++++++++++++--
 10 files changed, 350 insertions(+), 16 deletions(-)

diff --git a/arm/unittests.cfg b/arm/unittests.cfg
index f61e30b8526d..8cf94729d86e 100644
--- a/arm/unittests.cfg
+++ b/arm/unittests.cfg
@@ -85,3 +85,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
diff --git a/lib/arm/asm/arch_gicv3.h b/lib/arm/asm/arch_gicv3.h
index f4388d057975..45b609684460 100644
--- a/lib/arm/asm/arch_gicv3.h
+++ b/lib/arm/asm/arch_gicv3.h
@@ -15,6 +15,9 @@
 #include <asm/io.h>
 
 #define ICC_PMR				__ACCESS_CP15(c4, 0, c6, 0)
+#define ICC_SGI1R			__ACCESS_CP15_64(0, c12)
+#define ICC_IAR1			__ACCESS_CP15(c12, 0, c12, 0)
+#define ICC_EOIR1			__ACCESS_CP15(c12, 0, c12, 1)
 #define ICC_IGRPEN1			__ACCESS_CP15(c12, 0, c12, 7)
 
 static inline void gicv3_write_pmr(u32 val)
@@ -22,6 +25,24 @@ static inline void gicv3_write_pmr(u32 val)
 	write_sysreg(val, ICC_PMR);
 }
 
+static inline void gicv3_write_sgi1r(u64 val)
+{
+	write_sysreg(val, ICC_SGI1R);
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+	u32 irqstat = read_sysreg(ICC_IAR1);
+	dsb(sy);
+	return irqstat;
+}
+
+static inline void gicv3_write_eoir(u32 irq)
+{
+	write_sysreg(irq, ICC_EOIR1);
+	isb();
+}
+
 static inline void gicv3_write_grpen1(u32 val)
 {
 	write_sysreg(val, ICC_IGRPEN1);
diff --git a/lib/arm/asm/gic-v2.h b/lib/arm/asm/gic-v2.h
index 8b3f7ed6790c..1fcfd43c8075 100644
--- a/lib/arm/asm/gic-v2.h
+++ b/lib/arm/asm/gic-v2.h
@@ -18,6 +18,7 @@
 #define GICC_IAR_INT_ID_MASK		0x3ff
 
 #ifndef __ASSEMBLY__
+#include <asm/cpumask.h>
 
 struct gicv2_data {
 	void *dist_base;
@@ -31,6 +32,11 @@ extern struct gicv2_data gicv2_data;
 
 extern int gicv2_init(void);
 extern void gicv2_enable_defaults(void);
+extern u32 gicv2_read_iar(void);
+extern u32 gicv2_iar_irqnr(u32 iar);
+extern void gicv2_write_eoir(u32 irqstat);
+extern void gicv2_ipi_send_single(int irq, int cpu);
+extern void gicv2_ipi_send_mask(int irq, const cpumask_t *dest);
 
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM_GIC_V2_H_ */
diff --git a/lib/arm/asm/gic-v3.h b/lib/arm/asm/gic-v3.h
index 65f148b8a265..1dceb9541f62 100644
--- a/lib/arm/asm/gic-v3.h
+++ b/lib/arm/asm/gic-v3.h
@@ -33,12 +33,19 @@
 #define GICR_ISENABLER0			GICD_ISENABLER
 #define GICR_IPRIORITYR0		GICD_IPRIORITYR
 
+#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)
+
 #include <asm/arch_gicv3.h>
 
 #ifndef __ASSEMBLY__
 #include <asm/setup.h>
 #include <asm/processor.h>
 #include <asm/delay.h>
+#include <asm/cpumask.h>
 #include <asm/smp.h>
 #include <asm/io.h>
 
@@ -55,6 +62,11 @@ extern struct gicv3_data gicv3_data;
 
 extern int gicv3_init(void);
 extern void gicv3_enable_defaults(void);
+extern u32 gicv3_read_iar(void);
+extern u32 gicv3_iar_irqnr(u32 iar);
+extern void gicv3_write_eoir(u32 irqstat);
+extern void gicv3_ipi_send_single(int irq, int cpu);
+extern void gicv3_ipi_send_mask(int irq, const cpumask_t *dest);
 extern void gicv3_set_redist_base(size_t stride);
 
 static inline void gicv3_do_wait_for_rwp(void *base)
diff --git a/lib/arm/asm/gic.h b/lib/arm/asm/gic.h
index 21511997f2a9..c8186f25aa6b 100644
--- a/lib/arm/asm/gic.h
+++ b/lib/arm/asm/gic.h
@@ -32,6 +32,7 @@
 #include <asm/gic-v3.h>
 
 #ifndef __ASSEMBLY__
+#include <asm/cpumask.h>
 
 /*
  * gic_init will try to find all known gics, and then
@@ -42,5 +43,23 @@
  */
 extern int gic_init(void);
 
+/*
+ * gic_enable_defaults enables the gic with basic but useful
+ * settings. gic_enable_defaults will call gic_init if it has
+ * not yet been invoked.
+ */
+extern void gic_enable_defaults(void);
+
+/*
+ * After enabling the gic with gic_enable_defaults the functions
+ * below will work with any supported gic version.
+ */
+extern int gic_version(void);
+extern u32 gic_read_iar(void);
+extern u32 gic_iar_irqnr(u32 iar);
+extern void gic_write_eoir(u32 irqstat);
+extern void gic_ipi_send_single(int irq, int cpu);
+extern void gic_ipi_send_mask(int irq, const cpumask_t *dest);
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASMARM_GIC_H_ */
diff --git a/lib/arm64/asm/arch_gicv3.h b/lib/arm64/asm/arch_gicv3.h
index a6c153103547..a7994ec2fbbe 100644
--- a/lib/arm64/asm/arch_gicv3.h
+++ b/lib/arm64/asm/arch_gicv3.h
@@ -11,6 +11,9 @@
 #include <asm/sysreg.h>
 
 #define ICC_PMR_EL1			sys_reg(3, 0, 4, 6, 0)
+#define ICC_SGI1R_EL1			sys_reg(3, 0, 12, 11, 5)
+#define ICC_IAR1_EL1			sys_reg(3, 0, 12, 12, 0)
+#define ICC_EOIR1_EL1			sys_reg(3, 0, 12, 12, 1)
 #define ICC_GRPEN1_EL1			sys_reg(3, 0, 12, 12, 7)
 
 #ifndef __ASSEMBLY__
@@ -30,6 +33,25 @@ static inline void gicv3_write_pmr(u32 val)
 	asm volatile("msr_s " xstr(ICC_PMR_EL1) ", %0" : : "r" ((u64)val));
 }
 
+static inline void gicv3_write_sgi1r(u64 val)
+{
+	asm volatile("msr_s " xstr(ICC_SGI1R_EL1) ", %0" : : "r" (val));
+}
+
+static inline u32 gicv3_read_iar(void)
+{
+	u64 irqstat;
+	asm volatile("mrs_s %0, " xstr(ICC_IAR1_EL1) : "=r" (irqstat));
+	dsb(sy);
+	return (u64)irqstat;
+}
+
+static inline void gicv3_write_eoir(u32 irq)
+{
+	asm volatile("msr_s " xstr(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq));
+	isb();
+}
+
 static inline void gicv3_write_grpen1(u32 val)
 {
 	asm volatile("msr_s " xstr(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val));
diff --git a/arm/gic.c b/arm/gic.c
index 744e227426bf..d0d3be0fa36e 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>
  *
@@ -17,7 +19,14 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
-static int gic_version;
+struct gic {
+	struct {
+		void (*send_self)(void);
+		void (*send_broadcast)(void);
+	} ipi;
+};
+
+static struct gic *gic;
 static int acked[NR_CPUS], spurious[NR_CPUS];
 static cpumask_t ready;
 
@@ -84,11 +93,11 @@ static void check_spurious(void)
 
 static void ipi_handler(struct pt_regs *regs __unused)
 {
-	u32 irqstat = readl(gicv2_cpu_base() + GICC_IAR);
-	u32 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
+	u32 irqstat = gic_read_iar();
+	u32 irqnr = gic_iar_irqnr(irqstat);
 
 	if (irqnr != GICC_INT_SPURIOUS) {
-		writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+		gic_write_eoir(irqstat);
 		smp_rmb(); /* pairs with wmb in ipi_test functions */
 		++acked[smp_processor_id()];
 		smp_wmb(); /* pairs with rmb in check_acked */
@@ -98,6 +107,27 @@ static void ipi_handler(struct pt_regs *regs __unused)
 	}
 }
 
+static void gicv2_ipi_send_self(void)
+{
+	writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv2_ipi_send_broadcast(void)
+{
+	writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+}
+
+static void gicv3_ipi_send_self(void)
+{
+	gic_ipi_send_single(0, smp_processor_id());
+}
+
+static void gicv3_ipi_send_broadcast(void)
+{
+	gicv3_write_sgi1r(1ULL << 40);
+	isb();
+}
+
 static void ipi_test_self(void)
 {
 	cpumask_t mask;
@@ -107,7 +137,7 @@ static void ipi_test_self(void)
 	smp_wmb();
 	cpumask_clear(&mask);
 	cpumask_set_cpu(0, &mask);
-	writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+	gic->ipi.send_self();
 	check_acked(&mask);
 	report_prefix_pop();
 }
@@ -115,14 +145,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() + GICD_SGIR);
+	cpumask_copy(&mask, &cpu_present_mask);
+	for (i = 0; i < nr_cpus; i += 2)
+		cpumask_clear_cpu(i, &mask);
+	gic_ipi_send_mask(0, &mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
@@ -131,14 +162,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() + GICD_SGIR);
+	gic->ipi.send_broadcast();
 	check_acked(&mask);
 	report_prefix_pop();
 }
 
 static void ipi_enable(void)
 {
-	gicv2_enable_defaults();
+	gic_enable_defaults();
 #ifdef __arm__
 	install_exception_handler(EXCPTN_IRQ, ipi_handler);
 #else
@@ -155,20 +186,42 @@ static void ipi_recv(void)
 		wfi();
 }
 
+static struct gic gicv2 = {
+	.ipi = {
+		.send_self = gicv2_ipi_send_self,
+		.send_broadcast = gicv2_ipi_send_broadcast,
+	},
+};
+
+static struct gic gicv3 = {
+	.ipi = {
+		.send_self = gicv3_ipi_send_self,
+		.send_broadcast = gicv3_ipi_send_broadcast,
+	},
+};
+
 int main(int argc, char **argv)
 {
 	char pfx[8];
 	int cpu;
 
-	gic_version = gic_init();
-	if (!gic_version) {
+	if (!gic_init()) {
 		printf("No supported gic present, skipping tests...\n");
 		return report_summary();
 	}
 
-	snprintf(pfx, sizeof(pfx), "gicv%d", gic_version);
+	snprintf(pfx, sizeof(pfx), "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_abort("no test specified");
 
diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
index e80eb8f29488..dc6a97c600ec 100644
--- a/lib/arm/gic-v2.c
+++ b/lib/arm/gic-v2.c
@@ -25,3 +25,33 @@ void gicv2_enable_defaults(void)
 	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
 	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
 }
+
+u32 gicv2_read_iar(void)
+{
+	return readl(gicv2_cpu_base() + GICC_IAR);
+}
+
+u32 gicv2_iar_irqnr(u32 iar)
+{
+	return iar & GICC_IAR_INT_ID_MASK;
+}
+
+void gicv2_write_eoir(u32 irqstat)
+{
+	writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
+}
+
+void gicv2_ipi_send_single(int irq, int cpu)
+{
+	assert(cpu < 8);
+	assert(irq < 16);
+	writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR);
+}
+
+void gicv2_ipi_send_mask(int irq, const cpumask_t *dest)
+{
+	u8 tlist = (u8)cpumask_bits(dest)[0];
+
+	assert(irq < 16);
+	writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
+}
diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c
index c46d16e11782..9682fc96b631 100644
--- a/lib/arm/gic-v3.c
+++ b/lib/arm/gic-v3.c
@@ -59,3 +59,87 @@ void gicv3_enable_defaults(void)
 	gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
 	gicv3_write_grpen1(1);
 }
+
+u32 gicv3_iar_irqnr(u32 iar)
+{
+	return iar;
+}
+
+void gicv3_ipi_send_mask(int irq, const cpumask_t *dest)
+{
+	u16 tlist;
+	int cpu;
+
+	assert(irq < 16);
+
+	/*
+	 * For each cpu in the mask collect its peers, which are also in
+	 * the mask, in order to form target lists.
+	 */
+	for_each_cpu(cpu, dest) {
+		u64 mpidr = cpus[cpu], sgi1r;
+		u64 cluster_id;
+
+		/*
+		 * GICv3 can send IPIs to up 16 peer cpus with a single
+		 * write to ICC_SGI1R_EL1 (using the target list). Peers
+		 * are cpus that have nearly identical MPIDRs, the only
+		 * difference being Aff0. The matching upper affinity
+		 * levels form the cluster ID.
+		 */
+		cluster_id = mpidr & ~0xffUL;
+		tlist = 0;
+
+		/*
+		 * Sort of open code for_each_cpu in order to have a
+		 * nested for_each_cpu loop.
+		 */
+		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, dest);
+			if (cpu >= nr_cpus)
+				break;
+
+			mpidr = cpus[cpu];
+
+			if (cluster_id != (mpidr & ~0xffUL)) {
+				/*
+				 * The next cpu isn't in our cluster. Roll
+				 * back the cpu index allowing the outer
+				 * for_each_cpu to find it again with
+				 * cpumask_next
+				 */
+				--cpu;
+				break;
+			}
+		}
+
+		/* Send the IPIs for the target list of this cluster */
+		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();
+}
+
+void gicv3_ipi_send_single(int irq, int cpu)
+{
+	cpumask_t dest;
+
+	cpumask_clear(&dest);
+	cpumask_set_cpu(cpu, &dest);
+	gicv3_ipi_send_mask(irq, &dest);
+}
diff --git a/lib/arm/gic.c b/lib/arm/gic.c
index 4d3ddd9722b1..3ed539727f8c 100644
--- a/lib/arm/gic.c
+++ b/lib/arm/gic.c
@@ -10,6 +10,38 @@
 struct gicv2_data gicv2_data;
 struct gicv3_data gicv3_data;
 
+struct gic_common_ops {
+	int gic_version;
+	void (*enable_defaults)(void);
+	u32 (*read_iar)(void);
+	u32 (*iar_irqnr)(u32 iar);
+	void (*write_eoir)(u32 irqstat);
+	void (*ipi_send_single)(int irq, int cpu);
+	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
+};
+
+static const struct gic_common_ops *gic_common_ops;
+
+static const struct gic_common_ops gicv2_common_ops = {
+	.gic_version = 2,
+	.enable_defaults = gicv2_enable_defaults,
+	.read_iar = gicv2_read_iar,
+	.iar_irqnr = gicv2_iar_irqnr,
+	.write_eoir = gicv2_write_eoir,
+	.ipi_send_single = gicv2_ipi_send_single,
+	.ipi_send_mask = gicv2_ipi_send_mask,
+};
+
+static const struct gic_common_ops gicv3_common_ops = {
+	.gic_version = 3,
+	.enable_defaults = gicv3_enable_defaults,
+	.read_iar = gicv3_read_iar,
+	.iar_irqnr = gicv3_iar_irqnr,
+	.write_eoir = gicv3_write_eoir,
+	.ipi_send_single = gicv3_ipi_send_single,
+	.ipi_send_mask = gicv3_ipi_send_mask,
+};
+
 /*
  * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
  * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
@@ -58,9 +90,58 @@ int gicv3_init(void)
 
 int gic_init(void)
 {
-	if (gicv2_init())
+	if (gicv2_init()) {
+		gic_common_ops = &gicv2_common_ops;
 		return 2;
-	else if (gicv3_init())
+	} else if (gicv3_init()) {
+		gic_common_ops = &gicv3_common_ops;
 		return 3;
+	}
 	return 0;
 }
+
+void gic_enable_defaults(void)
+{
+	if (!gic_common_ops) {
+		int ret = gic_init();
+		assert(ret != 0);
+	} else
+		assert(gic_common_ops->enable_defaults);
+	gic_common_ops->enable_defaults();
+}
+
+int gic_version(void)
+{
+	assert(gic_common_ops);
+	return gic_common_ops->gic_version;
+}
+
+u32 gic_read_iar(void)
+{
+	assert(gic_common_ops && gic_common_ops->read_iar);
+	return gic_common_ops->read_iar();
+}
+
+u32 gic_iar_irqnr(u32 iar)
+{
+	assert(gic_common_ops && gic_common_ops->iar_irqnr);
+	return gic_common_ops->iar_irqnr(iar);
+}
+
+void gic_write_eoir(u32 irqstat)
+{
+	assert(gic_common_ops && gic_common_ops->write_eoir);
+	gic_common_ops->write_eoir(irqstat);
+}
+
+void gic_ipi_send_single(int irq, int cpu)
+{
+	assert(gic_common_ops && gic_common_ops->ipi_send_single);
+	gic_common_ops->ipi_send_single(irq, cpu);
+}
+
+void gic_ipi_send_mask(int irq, const cpumask_t *dest)
+{
+	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
+	gic_common_ops->ipi_send_mask(irq, dest);
+}
-- 
2.9.3

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

* [PATCH kvm-unit-tests v8 10/10] arm/arm64: gic: don't just use zero
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-08 17:50   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-08 17:50 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm; +Cc: marc.zyngier, andre.przywara, pbonzini

Instead of using cpu0 and irq=0 for the IPI test, use something
a bit more interesting. To make sure we can still run the test
with the minimal number of cpus (2), we need to use sender=1. As
the irq in the test (an SGI) can only be 0 to 15 and there's really
no difference, then use irq=1. sender=1 is a bit limited for the
long term, as we may want to test IPIs across host sockets with
pinned vcpus. But we can improve on this later, possibly with the
introduction of a command line parameter.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v8:
 - remove crufy command line parsing. No need for sender or irq
   to be input right now.
v7:
 - cleanup cmdline parsing and add complain on bad args [Eric]
v6:
 - make sender/irq names more future-proof [drew]
 - sanity check inputs [drew]
 - introduce check_sender/irq and bad_sender/irq to more
   cleanly do checks [drew]
 - default sender and irq to 1, instead of still zero [drew]
v4: improve structure and make sure spurious checking is
    done even when the sender isn't cpu0
v2: actually check that the irq received was the irq sent,
    and (for gicv2) that the sender is the expected one.
---
 arm/gic.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 73 insertions(+), 23 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index d0d3be0fa36e..3054d45f7387 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -19,6 +19,9 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
+#define IPI_SENDER	1
+#define IPI_IRQ		1
+
 struct gic {
 	struct {
 		void (*send_self)(void);
@@ -28,6 +31,7 @@ struct gic {
 
 static struct gic *gic;
 static int acked[NR_CPUS], spurious[NR_CPUS];
+static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
 static cpumask_t ready;
 
 static void nr_cpu_check(int nr)
@@ -43,10 +47,23 @@ static void wait_on_ready(void)
 		cpu_relax();
 }
 
+static void stats_reset(void)
+{
+	int i;
+
+	for (i = 0; i < nr_cpus; ++i) {
+		acked[i] = 0;
+		bad_sender[i] = -1;
+		bad_irq[i] = -1;
+	}
+	smp_wmb();
+}
+
 static void check_acked(cpumask_t *mask)
 {
 	int missing = 0, extra = 0, unexpected = 0;
 	int nr_pass, cpu, i;
+	bool bad = false;
 
 	/* Wait up to 5s for all interrupts to be delivered */
 	for (i = 0; i < 50; ++i) {
@@ -56,9 +73,21 @@ static void check_acked(cpumask_t *mask)
 			smp_rmb();
 			nr_pass += cpumask_test_cpu(cpu, mask) ?
 				acked[cpu] == 1 : acked[cpu] == 0;
+
+			if (bad_sender[cpu] != -1) {
+				printf("cpu%d received IPI from wrong sender %d\n",
+					cpu, bad_sender[cpu]);
+				bad = true;
+			}
+
+			if (bad_irq[cpu] != -1) {
+				printf("cpu%d received wrong irq %d\n",
+					cpu, bad_irq[cpu]);
+				bad = true;
+			}
 		}
 		if (nr_pass == nr_cpus) {
-			report("Completed in %d ms", true, ++i * 100);
+			report("Completed in %d ms", !bad, ++i * 100);
 			return;
 		}
 	}
@@ -91,6 +120,22 @@ static void check_spurious(void)
 	}
 }
 
+static void check_ipi_sender(u32 irqstat)
+{
+	if (gic_version() == 2) {
+		int src = (irqstat >> 10) & 7;
+
+		if (src != IPI_SENDER)
+			bad_sender[smp_processor_id()] = src;
+	}
+}
+
+static void check_irqnr(u32 irqnr)
+{
+	if (irqnr != IPI_IRQ)
+		bad_irq[smp_processor_id()] = irqnr;
+}
+
 static void ipi_handler(struct pt_regs *regs __unused)
 {
 	u32 irqstat = gic_read_iar();
@@ -98,8 +143,10 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 	if (irqnr != GICC_INT_SPURIOUS) {
 		gic_write_eoir(irqstat);
-		smp_rmb(); /* pairs with wmb in ipi_test functions */
+		smp_rmb(); /* pairs with wmb in stats_reset */
 		++acked[smp_processor_id()];
+		check_ipi_sender(irqstat);
+		check_irqnr(irqnr);
 		smp_wmb(); /* pairs with rmb in check_acked */
 	} else {
 		++spurious[smp_processor_id()];
@@ -109,22 +156,22 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 static void gicv2_ipi_send_self(void)
 {
-	writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+	writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
 }
 
 static void gicv2_ipi_send_broadcast(void)
 {
-	writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+	writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
 }
 
 static void gicv3_ipi_send_self(void)
 {
-	gic_ipi_send_single(0, smp_processor_id());
+	gic_ipi_send_single(IPI_IRQ, smp_processor_id());
 }
 
 static void gicv3_ipi_send_broadcast(void)
 {
-	gicv3_write_sgi1r(1ULL << 40);
+	gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24);
 	isb();
 }
 
@@ -133,10 +180,9 @@ static void ipi_test_self(void)
 	cpumask_t mask;
 
 	report_prefix_push("self");
-	memset(acked, 0, sizeof(acked));
-	smp_wmb();
+	stats_reset();
 	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();
@@ -148,20 +194,18 @@ static void ipi_test_smp(void)
 	int i;
 
 	report_prefix_push("target-list");
-	memset(acked, 0, sizeof(acked));
-	smp_wmb();
+	stats_reset();
 	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_mask(0, &mask);
+	gic_ipi_send_mask(IPI_IRQ, &mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
 	report_prefix_push("broadcast");
-	memset(acked, 0, sizeof(acked));
-	smp_wmb();
+	stats_reset();
 	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();
@@ -178,6 +222,16 @@ static void ipi_enable(void)
 	local_irq_enable();
 }
 
+static void ipi_send(void)
+{
+	ipi_enable();
+	wait_on_ready();
+	ipi_test_self();
+	ipi_test_smp();
+	check_spurious();
+	exit(report_summary());
+}
+
 static void ipi_recv(void)
 {
 	ipi_enable();
@@ -232,14 +286,10 @@ int main(int argc, char **argv)
 		for_each_present_cpu(cpu) {
 			if (cpu == 0)
 				continue;
-			smp_boot_secondary(cpu, ipi_recv);
+			smp_boot_secondary(cpu,
+				cpu == IPI_SENDER ? ipi_send : ipi_recv);
 		}
-		ipi_enable();
-		wait_on_ready();
-		ipi_test_self();
-		ipi_test_smp();
-		check_spurious();
-		report_prefix_pop();
+		ipi_recv();
 	} else {
 		report_abort("Unknown subtest '%s'", argv[1]);
 	}
-- 
2.9.3

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

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

Instead of using cpu0 and irq=0 for the IPI test, use something
a bit more interesting. To make sure we can still run the test
with the minimal number of cpus (2), we need to use sender=1. As
the irq in the test (an SGI) can only be 0 to 15 and there's really
no difference, then use irq=1. sender=1 is a bit limited for the
long term, as we may want to test IPIs across host sockets with
pinned vcpus. But we can improve on this later, possibly with the
introduction of a command line parameter.

Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Andrew Jones <drjones@redhat.com>

---
v8:
 - remove crufy command line parsing. No need for sender or irq
   to be input right now.
v7:
 - cleanup cmdline parsing and add complain on bad args [Eric]
v6:
 - make sender/irq names more future-proof [drew]
 - sanity check inputs [drew]
 - introduce check_sender/irq and bad_sender/irq to more
   cleanly do checks [drew]
 - default sender and irq to 1, instead of still zero [drew]
v4: improve structure and make sure spurious checking is
    done even when the sender isn't cpu0
v2: actually check that the irq received was the irq sent,
    and (for gicv2) that the sender is the expected one.
---
 arm/gic.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 73 insertions(+), 23 deletions(-)

diff --git a/arm/gic.c b/arm/gic.c
index d0d3be0fa36e..3054d45f7387 100644
--- a/arm/gic.c
+++ b/arm/gic.c
@@ -19,6 +19,9 @@
 #include <asm/barrier.h>
 #include <asm/io.h>
 
+#define IPI_SENDER	1
+#define IPI_IRQ		1
+
 struct gic {
 	struct {
 		void (*send_self)(void);
@@ -28,6 +31,7 @@ struct gic {
 
 static struct gic *gic;
 static int acked[NR_CPUS], spurious[NR_CPUS];
+static int bad_sender[NR_CPUS], bad_irq[NR_CPUS];
 static cpumask_t ready;
 
 static void nr_cpu_check(int nr)
@@ -43,10 +47,23 @@ static void wait_on_ready(void)
 		cpu_relax();
 }
 
+static void stats_reset(void)
+{
+	int i;
+
+	for (i = 0; i < nr_cpus; ++i) {
+		acked[i] = 0;
+		bad_sender[i] = -1;
+		bad_irq[i] = -1;
+	}
+	smp_wmb();
+}
+
 static void check_acked(cpumask_t *mask)
 {
 	int missing = 0, extra = 0, unexpected = 0;
 	int nr_pass, cpu, i;
+	bool bad = false;
 
 	/* Wait up to 5s for all interrupts to be delivered */
 	for (i = 0; i < 50; ++i) {
@@ -56,9 +73,21 @@ static void check_acked(cpumask_t *mask)
 			smp_rmb();
 			nr_pass += cpumask_test_cpu(cpu, mask) ?
 				acked[cpu] == 1 : acked[cpu] == 0;
+
+			if (bad_sender[cpu] != -1) {
+				printf("cpu%d received IPI from wrong sender %d\n",
+					cpu, bad_sender[cpu]);
+				bad = true;
+			}
+
+			if (bad_irq[cpu] != -1) {
+				printf("cpu%d received wrong irq %d\n",
+					cpu, bad_irq[cpu]);
+				bad = true;
+			}
 		}
 		if (nr_pass == nr_cpus) {
-			report("Completed in %d ms", true, ++i * 100);
+			report("Completed in %d ms", !bad, ++i * 100);
 			return;
 		}
 	}
@@ -91,6 +120,22 @@ static void check_spurious(void)
 	}
 }
 
+static void check_ipi_sender(u32 irqstat)
+{
+	if (gic_version() == 2) {
+		int src = (irqstat >> 10) & 7;
+
+		if (src != IPI_SENDER)
+			bad_sender[smp_processor_id()] = src;
+	}
+}
+
+static void check_irqnr(u32 irqnr)
+{
+	if (irqnr != IPI_IRQ)
+		bad_irq[smp_processor_id()] = irqnr;
+}
+
 static void ipi_handler(struct pt_regs *regs __unused)
 {
 	u32 irqstat = gic_read_iar();
@@ -98,8 +143,10 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 	if (irqnr != GICC_INT_SPURIOUS) {
 		gic_write_eoir(irqstat);
-		smp_rmb(); /* pairs with wmb in ipi_test functions */
+		smp_rmb(); /* pairs with wmb in stats_reset */
 		++acked[smp_processor_id()];
+		check_ipi_sender(irqstat);
+		check_irqnr(irqnr);
 		smp_wmb(); /* pairs with rmb in check_acked */
 	} else {
 		++spurious[smp_processor_id()];
@@ -109,22 +156,22 @@ static void ipi_handler(struct pt_regs *regs __unused)
 
 static void gicv2_ipi_send_self(void)
 {
-	writel(2 << 24, gicv2_dist_base() + GICD_SGIR);
+	writel(2 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
 }
 
 static void gicv2_ipi_send_broadcast(void)
 {
-	writel(1 << 24, gicv2_dist_base() + GICD_SGIR);
+	writel(1 << 24 | IPI_IRQ, gicv2_dist_base() + GICD_SGIR);
 }
 
 static void gicv3_ipi_send_self(void)
 {
-	gic_ipi_send_single(0, smp_processor_id());
+	gic_ipi_send_single(IPI_IRQ, smp_processor_id());
 }
 
 static void gicv3_ipi_send_broadcast(void)
 {
-	gicv3_write_sgi1r(1ULL << 40);
+	gicv3_write_sgi1r(1ULL << 40 | IPI_IRQ << 24);
 	isb();
 }
 
@@ -133,10 +180,9 @@ static void ipi_test_self(void)
 	cpumask_t mask;
 
 	report_prefix_push("self");
-	memset(acked, 0, sizeof(acked));
-	smp_wmb();
+	stats_reset();
 	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();
@@ -148,20 +194,18 @@ static void ipi_test_smp(void)
 	int i;
 
 	report_prefix_push("target-list");
-	memset(acked, 0, sizeof(acked));
-	smp_wmb();
+	stats_reset();
 	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_mask(0, &mask);
+	gic_ipi_send_mask(IPI_IRQ, &mask);
 	check_acked(&mask);
 	report_prefix_pop();
 
 	report_prefix_push("broadcast");
-	memset(acked, 0, sizeof(acked));
-	smp_wmb();
+	stats_reset();
 	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();
@@ -178,6 +222,16 @@ static void ipi_enable(void)
 	local_irq_enable();
 }
 
+static void ipi_send(void)
+{
+	ipi_enable();
+	wait_on_ready();
+	ipi_test_self();
+	ipi_test_smp();
+	check_spurious();
+	exit(report_summary());
+}
+
 static void ipi_recv(void)
 {
 	ipi_enable();
@@ -232,14 +286,10 @@ int main(int argc, char **argv)
 		for_each_present_cpu(cpu) {
 			if (cpu == 0)
 				continue;
-			smp_boot_secondary(cpu, ipi_recv);
+			smp_boot_secondary(cpu,
+				cpu == IPI_SENDER ? ipi_send : ipi_recv);
 		}
-		ipi_enable();
-		wait_on_ready();
-		ipi_test_self();
-		ipi_test_smp();
-		check_spurious();
-		report_prefix_pop();
+		ipi_recv();
 	} else {
 		report_abort("Unknown subtest '%s'", argv[1]);
 	}
-- 
2.9.3

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

* Re: [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
@ 2016-12-09 11:41     ` Andre Przywara
  -1 siblings, 0 replies; 39+ messages in thread
From: Andre Przywara @ 2016-12-09 11:41 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, eric.auger, pbonzini, alex.bennee,
	christoffer.dall

Hi,

On 08/12/16 17:50, Andrew Jones wrote:
> Allow a thread to wait some specified amount of time. Can
> specify in cycles, usecs, and msecs.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v8: rewrote basing on new sysreg framework. Also decided delay
>     functions warrant their own files (delay.[ch])
> ---
>  arm/Makefile.common       |  1 +
>  lib/arm/asm/delay.h       | 14 ++++++++++++++
>  lib/arm/asm/processor.h   | 15 +++++++++++++++
>  lib/arm64/asm/delay.h     |  1 +
>  lib/arm64/asm/processor.h | 12 ++++++++++++
>  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
>  6 files changed, 72 insertions(+)
>  create mode 100644 lib/arm/asm/delay.h
>  create mode 100644 lib/arm64/asm/delay.h
>  create mode 100644 lib/arm/delay.c
> 
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index b2c0fc8a2fdc..89fe3f69eb44 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/delay.o
>  
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
> new file mode 100644
> index 000000000000..2436b28c77ae
> --- /dev/null
> +++ b/lib/arm/asm/delay.h
> @@ -0,0 +1,14 @@
> +#ifndef _ASMARM_DELAY_H_
> +#define _ASMARM_DELAY_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.
> + */
> +#include <libcflat.h>
> +
> +extern void delay(u64 cycles);

Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
misleading, especially since this prototype is the only documentation on
this. You might just want to fix this when applying the patches.

That notwithstanding:
Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> +extern void udelay(unsigned long usecs);
> +extern void mdelay(unsigned long msecs);
> +
> +#endif /* _ASMARM_DELAY_H_ */
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index 6b0d36b87817..857bdd96a3cc 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -7,6 +7,7 @@
>   */
>  #include <asm/ptrace.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>
>  
>  enum vector {
>  	EXCPTN_RST,
> @@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
>  
> +#define CNTVCT		__ACCESS_CP15_64(1, c14)
> +#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
> +
> +static inline u64 get_cntvct(void)
> +{
> +	isb();
> +	return read_sysreg(CNTVCT);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(CNTFRQ);
> +}
> +
>  #endif /* _ASMARM_PROCESSOR_H_ */
> diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
> new file mode 100644
> index 000000000000..288e4b3fe610
> --- /dev/null
> +++ b/lib/arm64/asm/delay.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/delay.h"
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 48abf2c9e358..0898d89f9761 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -20,6 +20,7 @@
>  #include <asm/ptrace.h>
>  #include <asm/esr.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>
>  
>  enum vector {
>  	EL1T_SYNC,
> @@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t 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)
> +{
> +	isb();
> +	return read_sysreg(cntvct_el0);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(cntfrq_el0);
> +}
> +
>  #endif /* !__ASSEMBLY__ */
>  #endif /* _ASMARM64_PROCESSOR_H_ */
> diff --git a/lib/arm/delay.c b/lib/arm/delay.c
> new file mode 100644
> index 000000000000..fa65e2dc9e35
> --- /dev/null
> +++ b/lib/arm/delay.c
> @@ -0,0 +1,29 @@
> +/*
> + * Delay loops
> + *
> + * 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/processor.h>
> +#include <asm/barrier.h>
> +
> +void delay(u64 cycles)
> +{
> +	u64 start = get_cntvct();
> +
> +	while ((get_cntvct() - start) < cycles)
> +		cpu_relax();
> +}
> +
> +void udelay(unsigned long usec)
> +{
> +	delay((u64)usec * get_cntfrq() / 1000000);
> +}
> +
> +void mdelay(unsigned long msecs)
> +{
> +	while (msecs--)
> +		udelay(1000);
> +}
> 

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
@ 2016-12-09 11:41     ` Andre Przywara
  0 siblings, 0 replies; 39+ messages in thread
From: Andre Przywara @ 2016-12-09 11:41 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, eric.auger, pbonzini, alex.bennee,
	christoffer.dall

Hi,

On 08/12/16 17:50, Andrew Jones wrote:
> Allow a thread to wait some specified amount of time. Can
> specify in cycles, usecs, and msecs.
> 
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v8: rewrote basing on new sysreg framework. Also decided delay
>     functions warrant their own files (delay.[ch])
> ---
>  arm/Makefile.common       |  1 +
>  lib/arm/asm/delay.h       | 14 ++++++++++++++
>  lib/arm/asm/processor.h   | 15 +++++++++++++++
>  lib/arm64/asm/delay.h     |  1 +
>  lib/arm64/asm/processor.h | 12 ++++++++++++
>  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
>  6 files changed, 72 insertions(+)
>  create mode 100644 lib/arm/asm/delay.h
>  create mode 100644 lib/arm64/asm/delay.h
>  create mode 100644 lib/arm/delay.c
> 
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index b2c0fc8a2fdc..89fe3f69eb44 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/delay.o
>  
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
> new file mode 100644
> index 000000000000..2436b28c77ae
> --- /dev/null
> +++ b/lib/arm/asm/delay.h
> @@ -0,0 +1,14 @@
> +#ifndef _ASMARM_DELAY_H_
> +#define _ASMARM_DELAY_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.
> + */
> +#include <libcflat.h>
> +
> +extern void delay(u64 cycles);

Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
misleading, especially since this prototype is the only documentation on
this. You might just want to fix this when applying the patches.

That notwithstanding:
Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> +extern void udelay(unsigned long usecs);
> +extern void mdelay(unsigned long msecs);
> +
> +#endif /* _ASMARM_DELAY_H_ */
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index 6b0d36b87817..857bdd96a3cc 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -7,6 +7,7 @@
>   */
>  #include <asm/ptrace.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>
>  
>  enum vector {
>  	EXCPTN_RST,
> @@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
>  
> +#define CNTVCT		__ACCESS_CP15_64(1, c14)
> +#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
> +
> +static inline u64 get_cntvct(void)
> +{
> +	isb();
> +	return read_sysreg(CNTVCT);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(CNTFRQ);
> +}
> +
>  #endif /* _ASMARM_PROCESSOR_H_ */
> diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
> new file mode 100644
> index 000000000000..288e4b3fe610
> --- /dev/null
> +++ b/lib/arm64/asm/delay.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/delay.h"
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 48abf2c9e358..0898d89f9761 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -20,6 +20,7 @@
>  #include <asm/ptrace.h>
>  #include <asm/esr.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>
>  
>  enum vector {
>  	EL1T_SYNC,
> @@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t 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)
> +{
> +	isb();
> +	return read_sysreg(cntvct_el0);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(cntfrq_el0);
> +}
> +
>  #endif /* !__ASSEMBLY__ */
>  #endif /* _ASMARM64_PROCESSOR_H_ */
> diff --git a/lib/arm/delay.c b/lib/arm/delay.c
> new file mode 100644
> index 000000000000..fa65e2dc9e35
> --- /dev/null
> +++ b/lib/arm/delay.c
> @@ -0,0 +1,29 @@
> +/*
> + * Delay loops
> + *
> + * 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/processor.h>
> +#include <asm/barrier.h>
> +
> +void delay(u64 cycles)
> +{
> +	u64 start = get_cntvct();
> +
> +	while ((get_cntvct() - start) < cycles)
> +		cpu_relax();
> +}
> +
> +void udelay(unsigned long usec)
> +{
> +	delay((u64)usec * get_cntfrq() / 1000000);
> +}
> +
> +void mdelay(unsigned long msecs)
> +{
> +	while (msecs--)
> +		udelay(1000);
> +}
> 

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-09 11:41     ` [Qemu-devel] " Andre Przywara
  (?)
@ 2016-12-09 12:15     ` Andrew Jones
  2016-12-27 15:27       ` Christopher Covington
  -1 siblings, 1 reply; 39+ messages in thread
From: Andrew Jones @ 2016-12-09 12:15 UTC (permalink / raw)
  To: Andre Przywara
  Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
	eric.auger, pbonzini, alex.bennee, christoffer.dall

On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:
> Hi,
> 
> On 08/12/16 17:50, Andrew Jones wrote:
> > Allow a thread to wait some specified amount of time. Can
> > specify in cycles, usecs, and msecs.
> > 
> > Signed-off-by: Andrew Jones <drjones@redhat.com>
> > 
> > ---
> > v8: rewrote basing on new sysreg framework. Also decided delay
> >     functions warrant their own files (delay.[ch])
> > ---
> >  arm/Makefile.common       |  1 +
> >  lib/arm/asm/delay.h       | 14 ++++++++++++++
> >  lib/arm/asm/processor.h   | 15 +++++++++++++++
> >  lib/arm64/asm/delay.h     |  1 +
> >  lib/arm64/asm/processor.h | 12 ++++++++++++
> >  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
> >  6 files changed, 72 insertions(+)
> >  create mode 100644 lib/arm/asm/delay.h
> >  create mode 100644 lib/arm64/asm/delay.h
> >  create mode 100644 lib/arm/delay.c
> > 
> > diff --git a/arm/Makefile.common b/arm/Makefile.common
> > index b2c0fc8a2fdc..89fe3f69eb44 100644
> > --- a/arm/Makefile.common
> > +++ b/arm/Makefile.common
> > @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
> >  cflatobjs += lib/arm/bitops.o
> >  cflatobjs += lib/arm/psci.o
> >  cflatobjs += lib/arm/smp.o
> > +cflatobjs += lib/arm/delay.o
> >  
> >  libeabi = lib/arm/libeabi.a
> >  eabiobjs = lib/arm/eabi_compat.o
> > diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
> > new file mode 100644
> > index 000000000000..2436b28c77ae
> > --- /dev/null
> > +++ b/lib/arm/asm/delay.h
> > @@ -0,0 +1,14 @@
> > +#ifndef _ASMARM_DELAY_H_
> > +#define _ASMARM_DELAY_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.
> > + */
> > +#include <libcflat.h>
> > +
> > +extern void delay(u64 cycles);
> 
> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
> misleading, especially since this prototype is the only documentation on
> this. You might just want to fix this when applying the patches.

Right or wrong the kernel uses 'cycles' for this function, named
__timer_delay for arm and __delay for arm64. I guess I prefer
consistency here.

> 
> That notwithstanding:
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!

drew

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

* Re: [PATCH kvm-unit-tests v8 09/10] arm/arm64: gicv3: add an IPI test
  2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
@ 2016-12-09 16:08     ` Andre Przywara
  -1 siblings, 0 replies; 39+ messages in thread
From: Andre Przywara @ 2016-12-09 16:08 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, qemu-devel, qemu-arm; +Cc: marc.zyngier, pbonzini

Hi,

On 08/12/16 17:50, Andrew Jones wrote:
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v8:
>  - keep the gic_common_ops concept completely local to
>    lib/arm/gic.c by instead exposing the more useful
>    concept of gic-specific functions
>  - sysreg rebase changes
>  - ordered ICC registers in spec-order (OCD kicked in...)
> v7:
>  - add common ipi_send_single/mask (replacing ipi_send).
>    Note, the arg order irq,cpu got swapped. [Eric]
>  - comment rewording [Eric]
>  - make enable_defaults a common op [Eric]
>  - gic_enable_defaults() will now invoke gic_init if
>    necessary [drew]
>  - split lib/arm/gic.c into gic-v2/3.c [Eric]
> v6: move most gicv2/gicv3 wrappers to common code [Alex]
> v5:
>  - fix copy+paste error in gicv3_write_eoir [drew]
>  - use modern register names [Andre]
> v4:
>  - heavily comment gicv3_ipi_send_tlist() [Eric]
>  - changes needed for gicv2 iar/irqstat fix to other patch
> v2:
>  - use IRM for gicv3 broadcast
> ---
>  arm/unittests.cfg          |  6 ++++
>  lib/arm/asm/arch_gicv3.h   | 21 ++++++++++++
>  lib/arm/asm/gic-v2.h       |  6 ++++
>  lib/arm/asm/gic-v3.h       | 12 +++++++
>  lib/arm/asm/gic.h          | 19 +++++++++++
>  lib/arm64/asm/arch_gicv3.h | 22 ++++++++++++
>  arm/gic.c                  | 81 +++++++++++++++++++++++++++++++++++--------
>  lib/arm/gic-v2.c           | 30 ++++++++++++++++
>  lib/arm/gic-v3.c           | 84 +++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm/gic.c              | 85 ++++++++++++++++++++++++++++++++++++++++++++--
>  10 files changed, 350 insertions(+), 16 deletions(-)

....

> diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
> index e80eb8f29488..dc6a97c600ec 100644
> --- a/lib/arm/gic-v2.c
> +++ b/lib/arm/gic-v2.c
> @@ -25,3 +25,33 @@ void gicv2_enable_defaults(void)
>  	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
>  	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
>  }
> +
> +u32 gicv2_read_iar(void)
> +{
> +	return readl(gicv2_cpu_base() + GICC_IAR);
> +}
> +
> +u32 gicv2_iar_irqnr(u32 iar)
> +{
> +	return iar & GICC_IAR_INT_ID_MASK;
> +}
> +
> +void gicv2_write_eoir(u32 irqstat)
> +{
> +	writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
> +}
> +
> +void gicv2_ipi_send_single(int irq, int cpu)
> +{
> +	assert(cpu < 8);
> +	assert(irq < 16);
> +	writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR);
> +}
> +
> +void gicv2_ipi_send_mask(int irq, const cpumask_t *dest)
> +{
> +	u8 tlist = (u8)cpumask_bits(dest)[0];
> +
> +	assert(irq < 16);
> +	writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
> +}
> diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c
> index c46d16e11782..9682fc96b631 100644
> --- a/lib/arm/gic-v3.c
> +++ b/lib/arm/gic-v3.c
> @@ -59,3 +59,87 @@ void gicv3_enable_defaults(void)
>  	gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
>  	gicv3_write_grpen1(1);
>  }
> +
> +u32 gicv3_iar_irqnr(u32 iar)
> +{
> +	return iar;

I am probably a bit paranoid here, but the spec says that the interrupt
ID is in bits[23:0] only (at most).

> +}
> +
> +void gicv3_ipi_send_mask(int irq, const cpumask_t *dest)
> +{
> +	u16 tlist;
> +	int cpu;
> +
> +	assert(irq < 16);
> +
> +	/*
> +	 * For each cpu in the mask collect its peers, which are also in
> +	 * the mask, in order to form target lists.
> +	 */
> +	for_each_cpu(cpu, dest) {
> +		u64 mpidr = cpus[cpu], sgi1r;
> +		u64 cluster_id;
> +
> +		/*
> +		 * GICv3 can send IPIs to up 16 peer cpus with a single
> +		 * write to ICC_SGI1R_EL1 (using the target list). Peers
> +		 * are cpus that have nearly identical MPIDRs, the only
> +		 * difference being Aff0. The matching upper affinity
> +		 * levels form the cluster ID.
> +		 */
> +		cluster_id = mpidr & ~0xffUL;
> +		tlist = 0;
> +
> +		/*
> +		 * Sort of open code for_each_cpu in order to have a
> +		 * nested for_each_cpu loop.
> +		 */
> +		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, dest);
> +			if (cpu >= nr_cpus)
> +				break;
> +
> +			mpidr = cpus[cpu];
> +
> +			if (cluster_id != (mpidr & ~0xffUL)) {
> +				/*
> +				 * The next cpu isn't in our cluster. Roll
> +				 * back the cpu index allowing the outer
> +				 * for_each_cpu to find it again with
> +				 * cpumask_next
> +				 */
> +				--cpu;
> +				break;
> +			}
> +		}
> +
> +		/* Send the IPIs for the target list of this cluster */
> +		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();
> +}

Wow, this is really heavy stuff, especially for a Friday afternoon ;-)
But I convinced myself that it's correct. The only issue is that it's
sub-optimal if the MPIDRs of the VCPUs are not in order, say: 0x000,
0x100, 0x001.
In this case we do three register writes instead of the minimal two.
But it's still correct, so it's actually a minor nit just to prove that
I checked the algorithm ;-)

So apart from the minor comment above:

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> +
> +void gicv3_ipi_send_single(int irq, int cpu)
> +{
> +	cpumask_t dest;
> +
> +	cpumask_clear(&dest);
> +	cpumask_set_cpu(cpu, &dest);
> +	gicv3_ipi_send_mask(irq, &dest);
> +}
> diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> index 4d3ddd9722b1..3ed539727f8c 100644
> --- a/lib/arm/gic.c
> +++ b/lib/arm/gic.c
> @@ -10,6 +10,38 @@
>  struct gicv2_data gicv2_data;
>  struct gicv3_data gicv3_data;
>  
> +struct gic_common_ops {
> +	int gic_version;
> +	void (*enable_defaults)(void);
> +	u32 (*read_iar)(void);
> +	u32 (*iar_irqnr)(u32 iar);
> +	void (*write_eoir)(u32 irqstat);
> +	void (*ipi_send_single)(int irq, int cpu);
> +	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
> +};
> +
> +static const struct gic_common_ops *gic_common_ops;
> +
> +static const struct gic_common_ops gicv2_common_ops = {
> +	.gic_version = 2,
> +	.enable_defaults = gicv2_enable_defaults,
> +	.read_iar = gicv2_read_iar,
> +	.iar_irqnr = gicv2_iar_irqnr,
> +	.write_eoir = gicv2_write_eoir,
> +	.ipi_send_single = gicv2_ipi_send_single,
> +	.ipi_send_mask = gicv2_ipi_send_mask,
> +};
> +
> +static const struct gic_common_ops gicv3_common_ops = {
> +	.gic_version = 3,
> +	.enable_defaults = gicv3_enable_defaults,
> +	.read_iar = gicv3_read_iar,
> +	.iar_irqnr = gicv3_iar_irqnr,
> +	.write_eoir = gicv3_write_eoir,
> +	.ipi_send_single = gicv3_ipi_send_single,
> +	.ipi_send_mask = gicv3_ipi_send_mask,
> +};
> +
>  /*
>   * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
>   * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
> @@ -58,9 +90,58 @@ int gicv3_init(void)
>  
>  int gic_init(void)
>  {
> -	if (gicv2_init())
> +	if (gicv2_init()) {
> +		gic_common_ops = &gicv2_common_ops;
>  		return 2;
> -	else if (gicv3_init())
> +	} else if (gicv3_init()) {
> +		gic_common_ops = &gicv3_common_ops;
>  		return 3;
> +	}
>  	return 0;
>  }
> +
> +void gic_enable_defaults(void)
> +{
> +	if (!gic_common_ops) {
> +		int ret = gic_init();
> +		assert(ret != 0);
> +	} else
> +		assert(gic_common_ops->enable_defaults);
> +	gic_common_ops->enable_defaults();
> +}
> +
> +int gic_version(void)
> +{
> +	assert(gic_common_ops);
> +	return gic_common_ops->gic_version;
> +}
> +
> +u32 gic_read_iar(void)
> +{
> +	assert(gic_common_ops && gic_common_ops->read_iar);
> +	return gic_common_ops->read_iar();
> +}
> +
> +u32 gic_iar_irqnr(u32 iar)
> +{
> +	assert(gic_common_ops && gic_common_ops->iar_irqnr);
> +	return gic_common_ops->iar_irqnr(iar);
> +}
> +
> +void gic_write_eoir(u32 irqstat)
> +{
> +	assert(gic_common_ops && gic_common_ops->write_eoir);
> +	gic_common_ops->write_eoir(irqstat);
> +}
> +
> +void gic_ipi_send_single(int irq, int cpu)
> +{
> +	assert(gic_common_ops && gic_common_ops->ipi_send_single);
> +	gic_common_ops->ipi_send_single(irq, cpu);
> +}
> +
> +void gic_ipi_send_mask(int irq, const cpumask_t *dest)
> +{
> +	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
> +	gic_common_ops->ipi_send_mask(irq, dest);
> +}
> 

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 09/10] arm/arm64: gicv3: add an IPI test
@ 2016-12-09 16:08     ` Andre Przywara
  0 siblings, 0 replies; 39+ messages in thread
From: Andre Przywara @ 2016-12-09 16:08 UTC (permalink / raw)
  To: Andrew Jones, kvm, kvmarm, qemu-devel, qemu-arm
  Cc: peter.maydell, marc.zyngier, eric.auger, pbonzini, alex.bennee,
	christoffer.dall

Hi,

On 08/12/16 17:50, Andrew Jones wrote:
> Signed-off-by: Andrew Jones <drjones@redhat.com>
> 
> ---
> v8:
>  - keep the gic_common_ops concept completely local to
>    lib/arm/gic.c by instead exposing the more useful
>    concept of gic-specific functions
>  - sysreg rebase changes
>  - ordered ICC registers in spec-order (OCD kicked in...)
> v7:
>  - add common ipi_send_single/mask (replacing ipi_send).
>    Note, the arg order irq,cpu got swapped. [Eric]
>  - comment rewording [Eric]
>  - make enable_defaults a common op [Eric]
>  - gic_enable_defaults() will now invoke gic_init if
>    necessary [drew]
>  - split lib/arm/gic.c into gic-v2/3.c [Eric]
> v6: move most gicv2/gicv3 wrappers to common code [Alex]
> v5:
>  - fix copy+paste error in gicv3_write_eoir [drew]
>  - use modern register names [Andre]
> v4:
>  - heavily comment gicv3_ipi_send_tlist() [Eric]
>  - changes needed for gicv2 iar/irqstat fix to other patch
> v2:
>  - use IRM for gicv3 broadcast
> ---
>  arm/unittests.cfg          |  6 ++++
>  lib/arm/asm/arch_gicv3.h   | 21 ++++++++++++
>  lib/arm/asm/gic-v2.h       |  6 ++++
>  lib/arm/asm/gic-v3.h       | 12 +++++++
>  lib/arm/asm/gic.h          | 19 +++++++++++
>  lib/arm64/asm/arch_gicv3.h | 22 ++++++++++++
>  arm/gic.c                  | 81 +++++++++++++++++++++++++++++++++++--------
>  lib/arm/gic-v2.c           | 30 ++++++++++++++++
>  lib/arm/gic-v3.c           | 84 +++++++++++++++++++++++++++++++++++++++++++++
>  lib/arm/gic.c              | 85 ++++++++++++++++++++++++++++++++++++++++++++--
>  10 files changed, 350 insertions(+), 16 deletions(-)

....

> diff --git a/lib/arm/gic-v2.c b/lib/arm/gic-v2.c
> index e80eb8f29488..dc6a97c600ec 100644
> --- a/lib/arm/gic-v2.c
> +++ b/lib/arm/gic-v2.c
> @@ -25,3 +25,33 @@ void gicv2_enable_defaults(void)
>  	writel(GICC_INT_PRI_THRESHOLD, cpu_base + GICC_PMR);
>  	writel(GICC_ENABLE, cpu_base + GICC_CTLR);
>  }
> +
> +u32 gicv2_read_iar(void)
> +{
> +	return readl(gicv2_cpu_base() + GICC_IAR);
> +}
> +
> +u32 gicv2_iar_irqnr(u32 iar)
> +{
> +	return iar & GICC_IAR_INT_ID_MASK;
> +}
> +
> +void gicv2_write_eoir(u32 irqstat)
> +{
> +	writel(irqstat, gicv2_cpu_base() + GICC_EOIR);
> +}
> +
> +void gicv2_ipi_send_single(int irq, int cpu)
> +{
> +	assert(cpu < 8);
> +	assert(irq < 16);
> +	writel(1 << (cpu + 16) | irq, gicv2_dist_base() + GICD_SGIR);
> +}
> +
> +void gicv2_ipi_send_mask(int irq, const cpumask_t *dest)
> +{
> +	u8 tlist = (u8)cpumask_bits(dest)[0];
> +
> +	assert(irq < 16);
> +	writel(tlist << 16 | irq, gicv2_dist_base() + GICD_SGIR);
> +}
> diff --git a/lib/arm/gic-v3.c b/lib/arm/gic-v3.c
> index c46d16e11782..9682fc96b631 100644
> --- a/lib/arm/gic-v3.c
> +++ b/lib/arm/gic-v3.c
> @@ -59,3 +59,87 @@ void gicv3_enable_defaults(void)
>  	gicv3_write_pmr(GICC_INT_PRI_THRESHOLD);
>  	gicv3_write_grpen1(1);
>  }
> +
> +u32 gicv3_iar_irqnr(u32 iar)
> +{
> +	return iar;

I am probably a bit paranoid here, but the spec says that the interrupt
ID is in bits[23:0] only (at most).

> +}
> +
> +void gicv3_ipi_send_mask(int irq, const cpumask_t *dest)
> +{
> +	u16 tlist;
> +	int cpu;
> +
> +	assert(irq < 16);
> +
> +	/*
> +	 * For each cpu in the mask collect its peers, which are also in
> +	 * the mask, in order to form target lists.
> +	 */
> +	for_each_cpu(cpu, dest) {
> +		u64 mpidr = cpus[cpu], sgi1r;
> +		u64 cluster_id;
> +
> +		/*
> +		 * GICv3 can send IPIs to up 16 peer cpus with a single
> +		 * write to ICC_SGI1R_EL1 (using the target list). Peers
> +		 * are cpus that have nearly identical MPIDRs, the only
> +		 * difference being Aff0. The matching upper affinity
> +		 * levels form the cluster ID.
> +		 */
> +		cluster_id = mpidr & ~0xffUL;
> +		tlist = 0;
> +
> +		/*
> +		 * Sort of open code for_each_cpu in order to have a
> +		 * nested for_each_cpu loop.
> +		 */
> +		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, dest);
> +			if (cpu >= nr_cpus)
> +				break;
> +
> +			mpidr = cpus[cpu];
> +
> +			if (cluster_id != (mpidr & ~0xffUL)) {
> +				/*
> +				 * The next cpu isn't in our cluster. Roll
> +				 * back the cpu index allowing the outer
> +				 * for_each_cpu to find it again with
> +				 * cpumask_next
> +				 */
> +				--cpu;
> +				break;
> +			}
> +		}
> +
> +		/* Send the IPIs for the target list of this cluster */
> +		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();
> +}

Wow, this is really heavy stuff, especially for a Friday afternoon ;-)
But I convinced myself that it's correct. The only issue is that it's
sub-optimal if the MPIDRs of the VCPUs are not in order, say: 0x000,
0x100, 0x001.
In this case we do three register writes instead of the minimal two.
But it's still correct, so it's actually a minor nit just to prove that
I checked the algorithm ;-)

So apart from the minor comment above:

Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Cheers,
Andre.

> +
> +void gicv3_ipi_send_single(int irq, int cpu)
> +{
> +	cpumask_t dest;
> +
> +	cpumask_clear(&dest);
> +	cpumask_set_cpu(cpu, &dest);
> +	gicv3_ipi_send_mask(irq, &dest);
> +}
> diff --git a/lib/arm/gic.c b/lib/arm/gic.c
> index 4d3ddd9722b1..3ed539727f8c 100644
> --- a/lib/arm/gic.c
> +++ b/lib/arm/gic.c
> @@ -10,6 +10,38 @@
>  struct gicv2_data gicv2_data;
>  struct gicv3_data gicv3_data;
>  
> +struct gic_common_ops {
> +	int gic_version;
> +	void (*enable_defaults)(void);
> +	u32 (*read_iar)(void);
> +	u32 (*iar_irqnr)(u32 iar);
> +	void (*write_eoir)(u32 irqstat);
> +	void (*ipi_send_single)(int irq, int cpu);
> +	void (*ipi_send_mask)(int irq, const cpumask_t *dest);
> +};
> +
> +static const struct gic_common_ops *gic_common_ops;
> +
> +static const struct gic_common_ops gicv2_common_ops = {
> +	.gic_version = 2,
> +	.enable_defaults = gicv2_enable_defaults,
> +	.read_iar = gicv2_read_iar,
> +	.iar_irqnr = gicv2_iar_irqnr,
> +	.write_eoir = gicv2_write_eoir,
> +	.ipi_send_single = gicv2_ipi_send_single,
> +	.ipi_send_mask = gicv2_ipi_send_mask,
> +};
> +
> +static const struct gic_common_ops gicv3_common_ops = {
> +	.gic_version = 3,
> +	.enable_defaults = gicv3_enable_defaults,
> +	.read_iar = gicv3_read_iar,
> +	.iar_irqnr = gicv3_iar_irqnr,
> +	.write_eoir = gicv3_write_eoir,
> +	.ipi_send_single = gicv3_ipi_send_single,
> +	.ipi_send_mask = gicv3_ipi_send_mask,
> +};
> +
>  /*
>   * Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
>   * Documentation/devicetree/bindings/interrupt-controller/arm,gic-v3.txt
> @@ -58,9 +90,58 @@ int gicv3_init(void)
>  
>  int gic_init(void)
>  {
> -	if (gicv2_init())
> +	if (gicv2_init()) {
> +		gic_common_ops = &gicv2_common_ops;
>  		return 2;
> -	else if (gicv3_init())
> +	} else if (gicv3_init()) {
> +		gic_common_ops = &gicv3_common_ops;
>  		return 3;
> +	}
>  	return 0;
>  }
> +
> +void gic_enable_defaults(void)
> +{
> +	if (!gic_common_ops) {
> +		int ret = gic_init();
> +		assert(ret != 0);
> +	} else
> +		assert(gic_common_ops->enable_defaults);
> +	gic_common_ops->enable_defaults();
> +}
> +
> +int gic_version(void)
> +{
> +	assert(gic_common_ops);
> +	return gic_common_ops->gic_version;
> +}
> +
> +u32 gic_read_iar(void)
> +{
> +	assert(gic_common_ops && gic_common_ops->read_iar);
> +	return gic_common_ops->read_iar();
> +}
> +
> +u32 gic_iar_irqnr(u32 iar)
> +{
> +	assert(gic_common_ops && gic_common_ops->iar_irqnr);
> +	return gic_common_ops->iar_irqnr(iar);
> +}
> +
> +void gic_write_eoir(u32 irqstat)
> +{
> +	assert(gic_common_ops && gic_common_ops->write_eoir);
> +	gic_common_ops->write_eoir(irqstat);
> +}
> +
> +void gic_ipi_send_single(int irq, int cpu)
> +{
> +	assert(gic_common_ops && gic_common_ops->ipi_send_single);
> +	gic_common_ops->ipi_send_single(irq, cpu);
> +}
> +
> +void gic_ipi_send_mask(int irq, const cpumask_t *dest)
> +{
> +	assert(gic_common_ops && gic_common_ops->ipi_send_mask);
> +	gic_common_ops->ipi_send_mask(irq, dest);
> +}
> 

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

* Re: [PATCH kvm-unit-tests v8 09/10] arm/arm64: gicv3: add an IPI test
  2016-12-09 16:08     ` [Qemu-devel] " Andre Przywara
@ 2016-12-09 17:28       ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-09 17:28 UTC (permalink / raw)
  To: Andre Przywara
  Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
	eric.auger, pbonzini, alex.bennee, christoffer.dall

On Fri, Dec 09, 2016 at 04:08:00PM +0000, Andre Przywara wrote:
> On 08/12/16 17:50, Andrew Jones wrote:
> > +u32 gicv3_iar_irqnr(u32 iar)
> > +{
> > +	return iar;
> 
> I am probably a bit paranoid here, but the spec says that the interrupt
> ID is in bits[23:0] only (at most).

Indeed, I'll add '& ((1 << 24) - 1' here.

> 
> > +}
> > +
> > +void gicv3_ipi_send_mask(int irq, const cpumask_t *dest)
> > +{
> > +	u16 tlist;
> > +	int cpu;
> > +
> > +	assert(irq < 16);
> > +
> > +	/*
> > +	 * For each cpu in the mask collect its peers, which are also in
> > +	 * the mask, in order to form target lists.
> > +	 */
> > +	for_each_cpu(cpu, dest) {
> > +		u64 mpidr = cpus[cpu], sgi1r;
> > +		u64 cluster_id;
> > +
> > +		/*
> > +		 * GICv3 can send IPIs to up 16 peer cpus with a single
> > +		 * write to ICC_SGI1R_EL1 (using the target list). Peers
> > +		 * are cpus that have nearly identical MPIDRs, the only
> > +		 * difference being Aff0. The matching upper affinity
> > +		 * levels form the cluster ID.
> > +		 */
> > +		cluster_id = mpidr & ~0xffUL;
> > +		tlist = 0;
> > +
> > +		/*
> > +		 * Sort of open code for_each_cpu in order to have a
> > +		 * nested for_each_cpu loop.
> > +		 */
> > +		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, dest);
> > +			if (cpu >= nr_cpus)
> > +				break;
> > +
> > +			mpidr = cpus[cpu];
> > +
> > +			if (cluster_id != (mpidr & ~0xffUL)) {
> > +				/*
> > +				 * The next cpu isn't in our cluster. Roll
> > +				 * back the cpu index allowing the outer
> > +				 * for_each_cpu to find it again with
> > +				 * cpumask_next
> > +				 */
> > +				--cpu;
> > +				break;
> > +			}
> > +		}
> > +
> > +		/* Send the IPIs for the target list of this cluster */
> > +		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();
> > +}
> 
> Wow, this is really heavy stuff, especially for a Friday afternoon ;-)
> But I convinced myself that it's correct. The only issue is that it's
> sub-optimal if the MPIDRs of the VCPUs are not in order, say: 0x000,
> 0x100, 0x001.
> In this case we do three register writes instead of the minimal two.
> But it's still correct, so it's actually a minor nit just to prove that
> I checked the algorithm ;-)
> 
> So apart from the minor comment above:
> 
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!
drew

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 09/10] arm/arm64: gicv3: add an IPI test
@ 2016-12-09 17:28       ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-09 17:28 UTC (permalink / raw)
  To: Andre Przywara
  Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
	eric.auger, pbonzini, alex.bennee, christoffer.dall

On Fri, Dec 09, 2016 at 04:08:00PM +0000, Andre Przywara wrote:
> On 08/12/16 17:50, Andrew Jones wrote:
> > +u32 gicv3_iar_irqnr(u32 iar)
> > +{
> > +	return iar;
> 
> I am probably a bit paranoid here, but the spec says that the interrupt
> ID is in bits[23:0] only (at most).

Indeed, I'll add '& ((1 << 24) - 1' here.

> 
> > +}
> > +
> > +void gicv3_ipi_send_mask(int irq, const cpumask_t *dest)
> > +{
> > +	u16 tlist;
> > +	int cpu;
> > +
> > +	assert(irq < 16);
> > +
> > +	/*
> > +	 * For each cpu in the mask collect its peers, which are also in
> > +	 * the mask, in order to form target lists.
> > +	 */
> > +	for_each_cpu(cpu, dest) {
> > +		u64 mpidr = cpus[cpu], sgi1r;
> > +		u64 cluster_id;
> > +
> > +		/*
> > +		 * GICv3 can send IPIs to up 16 peer cpus with a single
> > +		 * write to ICC_SGI1R_EL1 (using the target list). Peers
> > +		 * are cpus that have nearly identical MPIDRs, the only
> > +		 * difference being Aff0. The matching upper affinity
> > +		 * levels form the cluster ID.
> > +		 */
> > +		cluster_id = mpidr & ~0xffUL;
> > +		tlist = 0;
> > +
> > +		/*
> > +		 * Sort of open code for_each_cpu in order to have a
> > +		 * nested for_each_cpu loop.
> > +		 */
> > +		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, dest);
> > +			if (cpu >= nr_cpus)
> > +				break;
> > +
> > +			mpidr = cpus[cpu];
> > +
> > +			if (cluster_id != (mpidr & ~0xffUL)) {
> > +				/*
> > +				 * The next cpu isn't in our cluster. Roll
> > +				 * back the cpu index allowing the outer
> > +				 * for_each_cpu to find it again with
> > +				 * cpumask_next
> > +				 */
> > +				--cpu;
> > +				break;
> > +			}
> > +		}
> > +
> > +		/* Send the IPIs for the target list of this cluster */
> > +		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();
> > +}
> 
> Wow, this is really heavy stuff, especially for a Friday afternoon ;-)
> But I convinced myself that it's correct. The only issue is that it's
> sub-optimal if the MPIDRs of the VCPUs are not in order, say: 0x000,
> 0x100, 0x001.
> In this case we do three register writes instead of the minimal two.
> But it's still correct, so it's actually a minor nit just to prove that
> I checked the algorithm ;-)
> 
> So apart from the minor comment above:
> 
> Reviewed-by: Andre Przywara <andre.przywara@arm.com>

Thanks!
drew

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

* Re: [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
@ 2016-12-13 16:41     ` Alex Bennée
  -1 siblings, 0 replies; 39+ messages in thread
From: Alex Bennée @ 2016-12-13 16:41 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm


Andrew Jones <drjones@redhat.com> writes:

> Allow a thread to wait some specified amount of time. Can
> specify in cycles, usecs, and msecs.
>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
>
> ---
> v8: rewrote basing on new sysreg framework. Also decided delay
>     functions warrant their own files (delay.[ch])
> ---
>  arm/Makefile.common       |  1 +
>  lib/arm/asm/delay.h       | 14 ++++++++++++++
>  lib/arm/asm/processor.h   | 15 +++++++++++++++
>  lib/arm64/asm/delay.h     |  1 +
>  lib/arm64/asm/processor.h | 12 ++++++++++++
>  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
>  6 files changed, 72 insertions(+)
>  create mode 100644 lib/arm/asm/delay.h
>  create mode 100644 lib/arm64/asm/delay.h
>  create mode 100644 lib/arm/delay.c
>
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index b2c0fc8a2fdc..89fe3f69eb44 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/delay.o
>
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
> new file mode 100644
> index 000000000000..2436b28c77ae
> --- /dev/null
> +++ b/lib/arm/asm/delay.h
> @@ -0,0 +1,14 @@
> +#ifndef _ASMARM_DELAY_H_
> +#define _ASMARM_DELAY_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.
> + */
> +#include <libcflat.h>
> +
> +extern void delay(u64 cycles);
> +extern void udelay(unsigned long usecs);
> +extern void mdelay(unsigned long msecs);
> +
> +#endif /* _ASMARM_DELAY_H_ */
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index 6b0d36b87817..857bdd96a3cc 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -7,6 +7,7 @@
>   */
>  #include <asm/ptrace.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>

Hmm this fails to apply cleanly to master and doesn't build as sysreg.h
isn't in my tree. What happened to it?

>
>  enum vector {
>  	EXCPTN_RST,
> @@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
>
> +#define CNTVCT		__ACCESS_CP15_64(1, c14)
> +#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
> +
> +static inline u64 get_cntvct(void)
> +{
> +	isb();
> +	return read_sysreg(CNTVCT);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(CNTFRQ);
> +}
> +
>  #endif /* _ASMARM_PROCESSOR_H_ */
> diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
> new file mode 100644
> index 000000000000..288e4b3fe610
> --- /dev/null
> +++ b/lib/arm64/asm/delay.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/delay.h"
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 48abf2c9e358..0898d89f9761 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -20,6 +20,7 @@
>  #include <asm/ptrace.h>
>  #include <asm/esr.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>
>
>  enum vector {
>  	EL1T_SYNC,
> @@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t 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)
> +{
> +	isb();
> +	return read_sysreg(cntvct_el0);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(cntfrq_el0);
> +}
> +
>  #endif /* !__ASSEMBLY__ */
>  #endif /* _ASMARM64_PROCESSOR_H_ */
> diff --git a/lib/arm/delay.c b/lib/arm/delay.c
> new file mode 100644
> index 000000000000..fa65e2dc9e35
> --- /dev/null
> +++ b/lib/arm/delay.c
> @@ -0,0 +1,29 @@
> +/*
> + * Delay loops
> + *
> + * 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/processor.h>
> +#include <asm/barrier.h>
> +
> +void delay(u64 cycles)
> +{
> +	u64 start = get_cntvct();
> +
> +	while ((get_cntvct() - start) < cycles)
> +		cpu_relax();
> +}
> +
> +void udelay(unsigned long usec)
> +{
> +	delay((u64)usec * get_cntfrq() / 1000000);
> +}
> +
> +void mdelay(unsigned long msecs)
> +{
> +	while (msecs--)
> +		udelay(1000);
> +}


--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
@ 2016-12-13 16:41     ` Alex Bennée
  0 siblings, 0 replies; 39+ messages in thread
From: Alex Bennée @ 2016-12-13 16:41 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
	andre.przywara, eric.auger, pbonzini, christoffer.dall


Andrew Jones <drjones@redhat.com> writes:

> Allow a thread to wait some specified amount of time. Can
> specify in cycles, usecs, and msecs.
>
> Signed-off-by: Andrew Jones <drjones@redhat.com>
>
> ---
> v8: rewrote basing on new sysreg framework. Also decided delay
>     functions warrant their own files (delay.[ch])
> ---
>  arm/Makefile.common       |  1 +
>  lib/arm/asm/delay.h       | 14 ++++++++++++++
>  lib/arm/asm/processor.h   | 15 +++++++++++++++
>  lib/arm64/asm/delay.h     |  1 +
>  lib/arm64/asm/processor.h | 12 ++++++++++++
>  lib/arm/delay.c           | 29 +++++++++++++++++++++++++++++
>  6 files changed, 72 insertions(+)
>  create mode 100644 lib/arm/asm/delay.h
>  create mode 100644 lib/arm64/asm/delay.h
>  create mode 100644 lib/arm/delay.c
>
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index b2c0fc8a2fdc..89fe3f69eb44 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -48,6 +48,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/delay.o
>
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/asm/delay.h b/lib/arm/asm/delay.h
> new file mode 100644
> index 000000000000..2436b28c77ae
> --- /dev/null
> +++ b/lib/arm/asm/delay.h
> @@ -0,0 +1,14 @@
> +#ifndef _ASMARM_DELAY_H_
> +#define _ASMARM_DELAY_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.
> + */
> +#include <libcflat.h>
> +
> +extern void delay(u64 cycles);
> +extern void udelay(unsigned long usecs);
> +extern void mdelay(unsigned long msecs);
> +
> +#endif /* _ASMARM_DELAY_H_ */
> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
> index 6b0d36b87817..857bdd96a3cc 100644
> --- a/lib/arm/asm/processor.h
> +++ b/lib/arm/asm/processor.h
> @@ -7,6 +7,7 @@
>   */
>  #include <asm/ptrace.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>

Hmm this fails to apply cleanly to master and doesn't build as sysreg.h
isn't in my tree. What happened to it?

>
>  enum vector {
>  	EXCPTN_RST,
> @@ -51,4 +52,18 @@ extern int mpidr_to_cpu(uint64_t mpidr);
>  extern void start_usr(void (*func)(void *arg), void *arg, unsigned long sp_usr);
>  extern bool is_user(void);
>
> +#define CNTVCT		__ACCESS_CP15_64(1, c14)
> +#define CNTFRQ		__ACCESS_CP15(c14, 0, c0, 0)
> +
> +static inline u64 get_cntvct(void)
> +{
> +	isb();
> +	return read_sysreg(CNTVCT);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(CNTFRQ);
> +}
> +
>  #endif /* _ASMARM_PROCESSOR_H_ */
> diff --git a/lib/arm64/asm/delay.h b/lib/arm64/asm/delay.h
> new file mode 100644
> index 000000000000..288e4b3fe610
> --- /dev/null
> +++ b/lib/arm64/asm/delay.h
> @@ -0,0 +1 @@
> +#include "../../arm/asm/delay.h"
> diff --git a/lib/arm64/asm/processor.h b/lib/arm64/asm/processor.h
> index 48abf2c9e358..0898d89f9761 100644
> --- a/lib/arm64/asm/processor.h
> +++ b/lib/arm64/asm/processor.h
> @@ -20,6 +20,7 @@
>  #include <asm/ptrace.h>
>  #include <asm/esr.h>
>  #include <asm/sysreg.h>
> +#include <asm/barrier.h>
>
>  enum vector {
>  	EL1T_SYNC,
> @@ -83,5 +84,16 @@ extern int mpidr_to_cpu(uint64_t 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)
> +{
> +	isb();
> +	return read_sysreg(cntvct_el0);
> +}
> +
> +static inline u32 get_cntfrq(void)
> +{
> +	return read_sysreg(cntfrq_el0);
> +}
> +
>  #endif /* !__ASSEMBLY__ */
>  #endif /* _ASMARM64_PROCESSOR_H_ */
> diff --git a/lib/arm/delay.c b/lib/arm/delay.c
> new file mode 100644
> index 000000000000..fa65e2dc9e35
> --- /dev/null
> +++ b/lib/arm/delay.c
> @@ -0,0 +1,29 @@
> +/*
> + * Delay loops
> + *
> + * 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/processor.h>
> +#include <asm/barrier.h>
> +
> +void delay(u64 cycles)
> +{
> +	u64 start = get_cntvct();
> +
> +	while ((get_cntvct() - start) < cycles)
> +		cpu_relax();
> +}
> +
> +void udelay(unsigned long usec)
> +{
> +	delay((u64)usec * get_cntfrq() / 1000000);
> +}
> +
> +void mdelay(unsigned long msecs)
> +{
> +	while (msecs--)
> +		udelay(1000);
> +}


--
Alex Bennée

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

* Re: [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-13 16:41     ` [Qemu-devel] " Alex Bennée
@ 2016-12-13 17:09       ` Alex Bennée
  -1 siblings, 0 replies; 39+ messages in thread
From: Alex Bennée @ 2016-12-13 17:09 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, marc.zyngier, andre.przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm


Alex Bennée <alex.bennee@linaro.org> writes:

> Andrew Jones <drjones@redhat.com> writes:
>
>> Allow a thread to wait some specified amount of time. Can
>> specify in cycles, usecs, and msecs.
<snip>
>> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
>> index 6b0d36b87817..857bdd96a3cc 100644
>> --- a/lib/arm/asm/processor.h
>> +++ b/lib/arm/asm/processor.h
>> @@ -7,6 +7,7 @@
>>   */
>>  #include <asm/ptrace.h>
>>  #include <asm/sysreg.h>
>> +#include <asm/barrier.h>
>
> Hmm this fails to apply cleanly to master and doesn't build as sysreg.h
> isn't in my tree. What happened to it?
<snip>

Ahh I missed this is based on arm/next

--
Alex Bennée
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
@ 2016-12-13 17:09       ` Alex Bennée
  0 siblings, 0 replies; 39+ messages in thread
From: Alex Bennée @ 2016-12-13 17:09 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
	andre.przywara, eric.auger, pbonzini, christoffer.dall


Alex Bennée <alex.bennee@linaro.org> writes:

> Andrew Jones <drjones@redhat.com> writes:
>
>> Allow a thread to wait some specified amount of time. Can
>> specify in cycles, usecs, and msecs.
<snip>
>> diff --git a/lib/arm/asm/processor.h b/lib/arm/asm/processor.h
>> index 6b0d36b87817..857bdd96a3cc 100644
>> --- a/lib/arm/asm/processor.h
>> +++ b/lib/arm/asm/processor.h
>> @@ -7,6 +7,7 @@
>>   */
>>  #include <asm/ptrace.h>
>>  #include <asm/sysreg.h>
>> +#include <asm/barrier.h>
>
> Hmm this fails to apply cleanly to master and doesn't build as sysreg.h
> isn't in my tree. What happened to it?
<snip>

Ahh I missed this is based on arm/next

--
Alex Bennée

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 00/10] arm/arm64: add gic framework
  2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
@ 2016-12-14 13:46   ` Andrew Jones
  -1 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-14 13:46 UTC (permalink / raw)
  To: kvm, kvmarm, qemu-devel, qemu-arm; +Cc: marc.zyngier, andre.przywara, pbonzini

On Thu, Dec 08, 2016 at 06:50:20PM +0100, Andrew Jones wrote:
> 
> v8:
>  - Main change is rebasing to Wei's sysreg framework, which is part
>    of his PMU series, which I've applied to arm/next. That rebase
>    leads to dropping the first two patches of the v7 series, expecting
>    get_mpidr() to return u64 (with future patches), a rework of the
>    delay routines (now based on sysreg framework), and changes to all
>    sysreg asms
>  - The delay routines also got their own files: delay.[ch]
>  - Another bigger change was to now keep gic_common_ops local to
>    lib/arm/gic.c, export the functions from the gic-v[23] instead
>  - Yet another bigger change was dropping the sender and irq cmdline
>    inputs, hard coding to '1' is sufficient and much less code
>  - Other minor changes listed in individual patches   
>

OK, I'm going to go ahead and apply this to arm/next. Before making
the pull request I'll post another series that includes the 64-bit
MPIDR fix that Andre pointed out we need, and a couple other fixes,
though. Assuming nobody complains about that series, then I'll fold
those patches into arm/next too and make the pull request.

Thanks,
drew

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

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

On Thu, Dec 08, 2016 at 06:50:20PM +0100, Andrew Jones wrote:
> 
> v8:
>  - Main change is rebasing to Wei's sysreg framework, which is part
>    of his PMU series, which I've applied to arm/next. That rebase
>    leads to dropping the first two patches of the v7 series, expecting
>    get_mpidr() to return u64 (with future patches), a rework of the
>    delay routines (now based on sysreg framework), and changes to all
>    sysreg asms
>  - The delay routines also got their own files: delay.[ch]
>  - Another bigger change was to now keep gic_common_ops local to
>    lib/arm/gic.c, export the functions from the gic-v[23] instead
>  - Yet another bigger change was dropping the sender and irq cmdline
>    inputs, hard coding to '1' is sufficient and much less code
>  - Other minor changes listed in individual patches   
>

OK, I'm going to go ahead and apply this to arm/next. Before making
the pull request I'll post another series that includes the 64-bit
MPIDR fix that Andre pointed out we need, and a couple other fixes,
though. Assuming nobody complains about that series, then I'll fold
those patches into arm/next too and make the pull request.

Thanks,
drew

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 00/10] arm/arm64: add gic framework
  2016-12-14 13:46   ` Andrew Jones
  (?)
@ 2016-12-14 15:36   ` Alex Bennée
  -1 siblings, 0 replies; 39+ messages in thread
From: Alex Bennée @ 2016-12-14 15:36 UTC (permalink / raw)
  To: Andrew Jones
  Cc: kvm, kvmarm, qemu-devel, qemu-arm, peter.maydell, marc.zyngier,
	andre.przywara, eric.auger, pbonzini, christoffer.dall


Andrew Jones <drjones@redhat.com> writes:

> On Thu, Dec 08, 2016 at 06:50:20PM +0100, Andrew Jones wrote:
>>
>> v8:
>>  - Main change is rebasing to Wei's sysreg framework, which is part
>>    of his PMU series, which I've applied to arm/next. That rebase
>>    leads to dropping the first two patches of the v7 series, expecting
>>    get_mpidr() to return u64 (with future patches), a rework of the
>>    delay routines (now based on sysreg framework), and changes to all
>>    sysreg asms
>>  - The delay routines also got their own files: delay.[ch]
>>  - Another bigger change was to now keep gic_common_ops local to
>>    lib/arm/gic.c, export the functions from the gic-v[23] instead
>>  - Yet another bigger change was dropping the sender and irq cmdline
>>    inputs, hard coding to '1' is sufficient and much less code
>>  - Other minor changes listed in individual patches
>>
>
> OK, I'm going to go ahead and apply this to arm/next. Before making
> the pull request I'll post another series that includes the 64-bit
> MPIDR fix that Andre pointed out we need, and a couple other fixes,
> though. Assuming nobody complains about that series, then I'll fold
> those patches into arm/next too and make the pull request.

All looks good for me. I'll be re-basing my TCG tests once upstream has
these changes merged.

--
Alex Bennée

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-09 12:15     ` Andrew Jones
@ 2016-12-27 15:27       ` Christopher Covington
  2016-12-27 16:27           ` Andrew Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Christopher Covington @ 2016-12-27 15:27 UTC (permalink / raw)
  To: Andrew Jones, Andre Przywara
  Cc: peter.maydell, kvm, marc.zyngier, qemu-devel, eric.auger,
	qemu-arm, pbonzini, alex.bennee, kvmarm, christoffer.dall

On 12/09/2016 07:15 AM, Andrew Jones wrote:
> On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:
>> Hi,
>>
>> On 08/12/16 17:50, Andrew Jones wrote:
>>> Allow a thread to wait some specified amount of time. Can
>>> specify in cycles, usecs, and msecs.

>>> +++ b/lib/arm/asm/delay.h
>>> @@ -0,0 +1,14 @@
>>> +#ifndef _ASMARM_DELAY_H_
>>> +#define _ASMARM_DELAY_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.
>>> + */
>>> +#include <libcflat.h>
>>> +
>>> +extern void delay(u64 cycles);
>>
>> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
>> misleading, especially since this prototype is the only documentation on
>> this. You might just want to fix this when applying the patches.
> 
> Right or wrong the kernel uses 'cycles' for this function, named
> __timer_delay for arm and __delay for arm64. I guess I prefer
> consistency here.

I too expect timers to tick and CPUs to cycle. The benefit of
parameter-name-precise consistency with the Linux source is not
obvious to me.

Cov

-- 
Qualcomm Datacenter Technologies, Inc. as an affiliate of Qualcomm
Technologies, Inc. Qualcomm Technologies, Inc. is a member of the Code
Aurora Forum, a Linux Foundation Collaborative Project.

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
  2016-12-27 15:27       ` Christopher Covington
@ 2016-12-27 16:27           ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-27 16:27 UTC (permalink / raw)
  To: Christopher Covington
  Cc: kvm, marc.zyngier, Andre Przywara, qemu-devel, qemu-arm,
	pbonzini, kvmarm

On Tue, Dec 27, 2016 at 10:27:25AM -0500, Christopher Covington wrote:
> On 12/09/2016 07:15 AM, Andrew Jones wrote:
> > On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 08/12/16 17:50, Andrew Jones wrote:
> >>> Allow a thread to wait some specified amount of time. Can
> >>> specify in cycles, usecs, and msecs.
> 
> >>> +++ b/lib/arm/asm/delay.h
> >>> @@ -0,0 +1,14 @@
> >>> +#ifndef _ASMARM_DELAY_H_
> >>> +#define _ASMARM_DELAY_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.
> >>> + */
> >>> +#include <libcflat.h>
> >>> +
> >>> +extern void delay(u64 cycles);
> >>
> >> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
> >> misleading, especially since this prototype is the only documentation on
> >> this. You might just want to fix this when applying the patches.
> > 
> > Right or wrong the kernel uses 'cycles' for this function, named
> > __timer_delay for arm and __delay for arm64. I guess I prefer
> > consistency here.
> 
> I too expect timers to tick and CPUs to cycle. The benefit of
> parameter-name-precise consistency with the Linux source is not
> obvious to me.
>

I just didn't have a strong enough opinion on it to change it. It appears
I'm in a minority though. As this is in master already, patches welcome :)

Thanks,
drew

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

* Re: [Qemu-devel] [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines
@ 2016-12-27 16:27           ` Andrew Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Andrew Jones @ 2016-12-27 16:27 UTC (permalink / raw)
  To: Christopher Covington
  Cc: Andre Przywara, peter.maydell, kvm, marc.zyngier, qemu-devel,
	eric.auger, qemu-arm, pbonzini, alex.bennee, kvmarm,
	christoffer.dall

On Tue, Dec 27, 2016 at 10:27:25AM -0500, Christopher Covington wrote:
> On 12/09/2016 07:15 AM, Andrew Jones wrote:
> > On Fri, Dec 09, 2016 at 11:41:06AM +0000, Andre Przywara wrote:
> >> Hi,
> >>
> >> On 08/12/16 17:50, Andrew Jones wrote:
> >>> Allow a thread to wait some specified amount of time. Can
> >>> specify in cycles, usecs, and msecs.
> 
> >>> +++ b/lib/arm/asm/delay.h
> >>> @@ -0,0 +1,14 @@
> >>> +#ifndef _ASMARM_DELAY_H_
> >>> +#define _ASMARM_DELAY_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.
> >>> + */
> >>> +#include <libcflat.h>
> >>> +
> >>> +extern void delay(u64 cycles);
> >>
> >> Nit: Shouldn't this parameter be called "ticks"? Cycles might be a bit
> >> misleading, especially since this prototype is the only documentation on
> >> this. You might just want to fix this when applying the patches.
> > 
> > Right or wrong the kernel uses 'cycles' for this function, named
> > __timer_delay for arm and __delay for arm64. I guess I prefer
> > consistency here.
> 
> I too expect timers to tick and CPUs to cycle. The benefit of
> parameter-name-precise consistency with the Linux source is not
> obvious to me.
>

I just didn't have a strong enough opinion on it to change it. It appears
I'm in a minority though. As this is in master already, patches welcome :)

Thanks,
drew

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

end of thread, other threads:[~2016-12-27 16:27 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-12-08 17:50 [PATCH kvm-unit-tests v8 00/10] arm/arm64: add gic framework Andrew Jones
2016-12-08 17:50 ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 01/10] arm/arm64: yield on cpu_relax Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 02/10] arm/arm64: smp: support more than 8 cpus Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 03/10] arm/arm64: add some delay routines Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-09 11:41   ` Andre Przywara
2016-12-09 11:41     ` [Qemu-devel] " Andre Przywara
2016-12-09 12:15     ` Andrew Jones
2016-12-27 15:27       ` Christopher Covington
2016-12-27 16:27         ` Andrew Jones
2016-12-27 16:27           ` Andrew Jones
2016-12-13 16:41   ` Alex Bennée
2016-12-13 16:41     ` [Qemu-devel] " Alex Bennée
2016-12-13 17:09     ` Alex Bennée
2016-12-13 17:09       ` [Qemu-devel] " Alex Bennée
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 04/10] arm/arm64: irq enable/disable Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 05/10] arm/arm64: add initial gicv2 support Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 06/10] arm/arm64: gicv2: add an IPI test Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 07/10] libcflat: add IS_ALIGNED() macro, and page sizes Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 08/10] arm/arm64: add initial gicv3 support Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 09/10] arm/arm64: gicv3: add an IPI test Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-09 16:08   ` Andre Przywara
2016-12-09 16:08     ` [Qemu-devel] " Andre Przywara
2016-12-09 17:28     ` Andrew Jones
2016-12-09 17:28       ` [Qemu-devel] " Andrew Jones
2016-12-08 17:50 ` [PATCH kvm-unit-tests v8 10/10] arm/arm64: gic: don't just use zero Andrew Jones
2016-12-08 17:50   ` [Qemu-devel] " Andrew Jones
2016-12-14 13:46 ` [Qemu-devel] [PATCH kvm-unit-tests v8 00/10] arm/arm64: add gic framework Andrew Jones
2016-12-14 13:46   ` Andrew Jones
2016-12-14 15:36   ` Alex Bennée

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.