Skip to contentSkip to conversation

arm64: GICv3 support

PATCH Superseded Marc Zyngier 8 participants 49 messages May 15, 2014 – Jun 11, 2014

Subsystems (7)

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v4 cover arm64: GICv3 support

GICv3 is the base for a new generation of interrupt controllers designed to overcome some of the most glaring limitations of GICv2.

Some of the features are:
- Support for more than 8 CPUs (a lot more...)
- System registers for CPU interface access (instead of the memory mapped GICC, GICV, GICH)
- Message based interrupts

This patch series currently support:
- Affinity Routing
- System Registers
- Non-Secure Group-1 interrupts only
- KVM support (GICv3 host, GICv2 guest)

What is *not yet* supported in this series (WIP):
- LPI/ITS/MSI
- KVM GICv3 guest support
- Any form of power management
- 32bit systems

To be built, this code requires a fairly recent compiler/binutils combo. Linaro 13.06 seems to do the trick. This has been tested on the ARM FVP and Foundation models, with non-regressions run on a VExpress TC-2 and another Cortex-A57 based platform.

So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for being the only ones to review it). While the documentation is unfortunately not public yet, it is available to those actively implementing GICv3 in their hardware, and I'm really eager to see reviews and test reports.

Without that kind of engagement, it is unlikely that this code will get merged any time soon.

Individuals without access to documentation and/or hardware can still review the code (it shares a lot of concepts with GICv2) and test in on the freely available Foundation model (see
http://releases.linaro.org/latest/openembedded/aarch64/ for details on how to use the Foundation model).

The code is also available at the following location (warning, unstable branch!):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv3

* From v3 [3]
- Fixed a lot of issues found by Christoffer (too many to report here, see the email thread)
- New .sync_lr_elrsr backend
- New probing method
- New irqchip_in_kernel implementation
- Checked full bisectability of the series (hopefully got it right

    this time...)

- rebased on top of 3.15-rc5

* From v2 [2]
- removed sharing of the xlate method with GICv2 (TI crossbar is now getting in the way...)
- Switched to a tree domain to accomodate for the LPI space
- Fixed more bisectability

* From the initial revision [1]
- Some code sharing with GICv2
- Barrier cleanup/clarification
- Revised boot protocol update
- Consistent use of the MPIDR access macros
- Fixed a number of embarassing bugs
- Fixed DT examples
- Fixed bisectability of the series

[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229959.html
[2]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241972.html
[3]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/248008.html

Marc Zyngier (20):
ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3
KVM: arm/arm64: vgic: move GICv2 registers to their own structure
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
KVM: ARM: vgic: abstract access to the ELRSR bitmap
KVM: ARM: vgic: abstract EISR bitmap access
KVM: ARM: vgic: abstract MISR decoding
KVM: ARM: vgic: move underflow handling to vgic_ops
KVM: ARM: vgic: abstract VMCR access
KVM: ARM: vgic: introduce vgic_enable
KVM: ARM: introduce vgic_params structure
KVM: ARM: vgic: split GICv2 backend from the main vgic code
KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S
arm64: KVM: split GICv2 world switch from hyp code
arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch
code
KVM: ARM: vgic: add the GICv3 backend
arm64: KVM: vgic: add GICv3 world switch

 Documentation/arm64/booting.txt                  |   6 +
 Documentation/devicetree/bindings/arm/gic-v3.txt |  79 +++
 arch/arm/include/asm/kvm_host.h                  |   5 +
 arch/arm/kernel/asm-offsets.c                    |  14 +-
 arch/arm/kvm/Makefile                            |   1 +
 arch/arm/kvm/interrupts_head.S                   |  26 +-
 arch/arm64/Kconfig                               |   1 +
 arch/arm64/include/asm/kvm_arm.h                 |   5 +-
 arch/arm64/include/asm/kvm_asm.h                 |  14 +-
 arch/arm64/include/asm/kvm_host.h                |  28 +
 arch/arm64/include/asm/virt.h                    |   4 +
 arch/arm64/kernel/asm-offsets.c                  |  25 +-
 arch/arm64/kernel/head.S                         |  18 +
 arch/arm64/kernel/hyp-stub.S                     |   1 +
 arch/arm64/kvm/Makefile                          |   4 +
 arch/arm64/kvm/hyp.S                             | 127 +----
 arch/arm64/kvm/vgic-v2-switch.S                  | 133 +++++
 arch/arm64/kvm/vgic-v3-switch.S                  | 271 +++++++++
 drivers/irqchip/Kconfig                          |   5 +
 drivers/irqchip/Makefile                         |   3 +-
 drivers/irqchip/irq-gic-common.c                 | 115 ++++
 drivers/irqchip/irq-gic-common.h                 |  29 +
 drivers/irqchip/irq-gic-v3.c                     | 684 +++++++++++++++++++++++
 drivers/irqchip/irq-gic.c                        |  59 +-
 include/kvm/arm_vgic.h                           | 115 +++-
 include/linux/irqchip/arm-gic-v3.h               | 190 +++++++
 virt/kvm/arm/vgic-v2.c                           | 236 ++++++++
 virt/kvm/arm/vgic-v3.c                           | 225 ++++++++
 virt/kvm/arm/vgic.c                              | 345 ++++++------
 29 files changed, 2415 insertions(+), 353 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
 create mode 100644 arch/arm64/kvm/vgic-v2-switch.S
 create mode 100644 arch/arm64/kvm/vgic-v3-switch.S
 create mode 100644 drivers/irqchip/irq-gic-common.c
 create mode 100644 drivers/irqchip/irq-gic-common.h
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h
 create mode 100644 virt/kvm/arm/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic-v3.c
Signature · 1 line
1.8.3.4
#1 lore raw

PATCH v4 1/20 ARM: GIC: move some bits of GICv2 to a library-type file

A few GICv2 low-level function are actually very useful to GICv3, and it makes some sense to share them across the two drivers. They end-up in their own file, with an additional parameter used to ensure an optional synchronization (unused on GICv2).

---
 drivers/irqchip/Makefile         |   2 +-
 drivers/irqchip/irq-gic-common.c | 115 +++++++++++++++++++++++++++++++++++++++
 drivers/irqchip/irq-gic-common.h |  29 ++++++++++
 drivers/irqchip/irq-gic.c        |  59 ++------------------
 4 files changed, 149 insertions(+), 56 deletions(-)
 create mode 100644 drivers/irqchip/irq-gic-common.c
 create mode 100644 drivers/irqchip/irq-gic-common.h
drivers/irqchip/Makefile +1 -1
index f180f8d..880eb66 100644
@@ -15,7 +15,7 @@ obj-$(CONFIG_ORION_IRQCHIP)		+= irq-orion.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
-obj-$(CONFIG_ARM_GIC)			+= irq-gic.o
+obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_IMGPDC_IRQ)		+= irq-imgpdc.o
drivers/irqchip/irq-gic-common.c new file +115 -0

115 lines not on this page · raw message

drivers/irqchip/irq-gic-common.h new file +29 -0
new file mode 100644
index 0000000..b41f024
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2002 ARM Limited, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _IRQ_GIC_COMMON_H
+#define _IRQ_GIC_COMMON_H
+
+#include <linux/of.h>
+#include <linux/irqdomain.h>
+
+void gic_configure_irq(unsigned int irq, unsigned int type,
+                       void __iomem *base, void (*sync_access)(void));
+void gic_dist_config(void __iomem *base, int gic_irqs,
+		     void (*sync_access)(void));
+void gic_cpu_config(void __iomem *base, void (*sync_access)(void));
+
+#endif /* _IRQ_GIC_COMMON_H */
drivers/irqchip/irq-gic.c +4 -55

95 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#2 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

In reply to Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

---
 arch/arm64/Kconfig                 |   1 +
 arch/arm64/kernel/head.S           |  18 +
 arch/arm64/kernel/hyp-stub.S       |   1 +
 drivers/irqchip/Kconfig            |   5 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-gic-v3.c       | 684 +++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-v3.h | 190 +++++++++++
 7 files changed, 900 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h
arch/arm64/Kconfig +1 -0
index 6635183..7f993b3 100644
@@ -9,6 +9,7 @@ config ARM64
 	select ARM_AMBA
 	select ARM_ARCH_TIMER
 	select ARM_GIC
+	select ARM_GIC_V3
 	select BUILDTIME_EXTABLE_SORT
 	select CLONE_BACKWARDS
 	select COMMON_CLK
arch/arm64/kernel/head.S +18 -0
index 0fd5650..d6894a4 100644
@@ -22,6 +22,7 @@
 
 #include <linux/linkage.h>
 #include <linux/init.h>
+#include <linux/irqchip/arm-gic-v3.h>
 
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
@@ -184,6 +185,23 @@ CPU_LE(	bic	x0, x0, #(3 << 24)	)	// Clear the EE and E0E bits for EL1
 	msr	cnthctl_el2, x0
 	msr	cntvoff_el2, xzr		// Clear virtual offset
 
+#ifdef CONFIG_ARM_GIC_V3
+	/* GICv3 system register access */
+	mrs	x0, id_aa64pfr0_el1
+	ubfx	x0, x0, #24, #4
+	cmp	x0, #1
+	b.ne	3f
+
+	mrs	x0, ICC_SRE_EL2
+	orr	x0, x0, #1			// Set ICC_SRE_EL2.SRE==1
+	orr	x0, x0, #(1 << 3)		// Set ICC_SRE_EL2.Enable==1
+	msr	ICC_SRE_EL2, x0
+	isb					// Make sure SRE is now 1
+	msr	ICH_HCR_EL2, xzr		// Reset ICC_HCR_EL2 to defaults
+
+3:
+#endif
+
 	/* Populate ID registers. */
 	mrs	x0, midr_el1
 	mrs	x1, mpidr_el1
arch/arm64/kernel/hyp-stub.S +1 -0
index 0959611..a272f33 100644
@@ -19,6 +19,7 @@
 
 #include <linux/init.h>
 #include <linux/linkage.h>
+#include <linux/irqchip/arm-gic-v3.h>
 
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
drivers/irqchip/Kconfig +5 -0
index d770f74..32e68b4 100644
@@ -10,6 +10,11 @@ config ARM_GIC
 config GIC_NON_BANKED
 	bool
 
+config ARM_GIC_V3
+	bool
+	select IRQ_DOMAIN
+	select MULTI_IRQ_HANDLER
+
 config ARM_NVIC
 	bool
 	select IRQ_DOMAIN
drivers/irqchip/Makefile +1 -0
index 880eb66..bd8c1a3 100644
@@ -16,6 +16,7 @@ obj-$(CONFIG_ARCH_SUNXI)		+= irq-sun4i.o
 obj-$(CONFIG_ARCH_SUNXI)		+= irq-sunxi-nmi.o
 obj-$(CONFIG_ARCH_SPEAR3XX)		+= spear-shirq.o
 obj-$(CONFIG_ARM_GIC)			+= irq-gic.o irq-gic-common.o
+obj-$(CONFIG_ARM_GIC_V3)		+= irq-gic-v3.o irq-gic-common.o
 obj-$(CONFIG_ARM_NVIC)			+= irq-nvic.o
 obj-$(CONFIG_ARM_VIC)			+= irq-vic.o
 obj-$(CONFIG_IMGPDC_IRQ)		+= irq-imgpdc.o
drivers/irqchip/irq-gic-v3.c new file +684 -0

684 lines not on this page · raw message

include/linux/irqchip/arm-gic-v3.h new file +190 -0

190 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#3 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Hi Marc,

Quoted 14 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

[...]

include/linux/irqchip/arm-gic-v3.h line 110

Quoted 11 lines
include/linux/irqchip/arm-gic-v3.h new file +11 -0
+/*
+ * Hypervisor interface registers (SRE only)
+ */
+#define GICH_LR_VIRTUAL_ID_MASK                ((1UL << 32) - 1)
+
+#define GICH_LR_EOI                    (1UL << 41)
+#define GICH_LR_GROUP                  (1UL << 60)
+#define GICH_LR_STATE                  (3UL << 62)
+#define GICH_LR_PENDING_BIT            (1UL << 62)
+#define GICH_LR_ACTIVE_BIT             (1UL << 63)
+

Minor nit:
I think these names can be misleading, since the GICH_LR in GICv3 is the same as in GICv2, and is 32bit.
Since AArch32 splits the LR into two system registers, it may be clearer to name these bits ICH_LR* on arm64, and ICH_LRC* on arm.

Cheers,
Jean-Philippe

#4 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Quoted 18 lines · Jean-Philippe Brucker

Hi Marc,

Quoted 14 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

[...]

Quoted 16 lines

include/linux/irqchip/arm-gic-v3.h line 110

Quoted 11 lines
include/linux/irqchip/arm-gic-v3.h new file +11 -0
+/*
+ * Hypervisor interface registers (SRE only)
+ */
+#define GICH_LR_VIRTUAL_ID_MASK                ((1UL << 32) - 1)
+
+#define GICH_LR_EOI                    (1UL << 41)
+#define GICH_LR_GROUP                  (1UL << 60)
+#define GICH_LR_STATE                  (3UL << 62)
+#define GICH_LR_PENDING_BIT            (1UL << 62)
+#define GICH_LR_ACTIVE_BIT             (1UL << 63)
+

Minor nit:
I think these names can be misleading, since the GICH_LR in GICv3 is the same as in GICv2, and is 32bit.
Since AArch32 splits the LR into two system registers, it may be clearer to name these bits ICH_LR* on arm64, and ICH_LRC* on arm.

Good point, worth the change.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
#5 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

In reply to Marc Zyngier

Hi Marc,

Quoted 31 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

---
 arch/arm64/Kconfig                 |   1 +
 arch/arm64/kernel/head.S           |  18 +
 arch/arm64/kernel/hyp-stub.S       |   1 +
 drivers/irqchip/Kconfig            |   5 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-gic-v3.c       | 684 +++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-v3.h | 190 +++++++++++
 7 files changed, 900 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h

[...]

Quoted 245 lines
drivers/irqchip/irq-gic-v3.c new file +239 -0
new file mode 100644
index 0000000..6570e7b
@@ -0,0 +1,684 @@
+/*
+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
+
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/cputype.h>
+#include <asm/exception.h>
+#include <asm/smp_plat.h>
+
+#include "irq-gic-common.h"
+#include "irqchip.h"
+
+struct gic_chip_data {
+	void __iomem		*dist_base;
+	void __iomem		**redist_base;
+	void __percpu __iomem	**rdist;
+	struct irq_domain	*domain;
+	u64			redist_stride;
+	u32			redist_regions;
+	unsigned int		irq_nr;
+};
+
+static struct gic_chip_data gic_data __read_mostly;
+
+#define gic_data_rdist()		(this_cpu_ptr(gic_data.rdist))
+#define gic_data_rdist_rd_base()	(*gic_data_rdist())
+#define gic_data_rdist_sgi_base()	(gic_data_rdist_rd_base() + SZ_64K)
+
+#define DEFAULT_PMR_VALUE	0xf0
+
+static inline unsigned int gic_irq(struct irq_data *d)
+{
+	return d->hwirq;
+}
+
+static inline int gic_irq_in_rdist(struct irq_data *d)
+{
+	return gic_irq(d) < 32;
+}
+
+static inline void __iomem *gic_dist_base(struct irq_data *d)
+{
+	if (gic_irq_in_rdist(d))	/* SGI+PPI -> SGI_base for this CPU */
+		return gic_data_rdist_sgi_base();
+
+	if (d->hwirq <= 1023)		/* SPI -> dist_base */
+		return gic_data.dist_base;
+
+	if (d->hwirq >= 8192)
+		BUG();		/* LPI Detected!!! */
+
+	return NULL;
+}
+
+static void gic_do_wait_for_rwp(void __iomem *base)
+{
+	u32 count = 1000000;	/* 1s! */
+
+	while (readl_relaxed(base + GICD_CTLR) & GICD_CTLR_RWP) {
+		count--;
+		if (!count) {
+			pr_err_ratelimited("RWP timeout, gone fishing\n");
+			return;
+		}
+		cpu_relax();
+		udelay(1);
+	};
+}
+
+/* Wait for completion of a distributor change */
+static void gic_dist_wait_for_rwp(void)
+{
+	gic_do_wait_for_rwp(gic_data.dist_base);
+}
+
+/* Wait for completion of a redistributor change */
+static void gic_redist_wait_for_rwp(void)
+{
+	gic_do_wait_for_rwp(gic_data_rdist_rd_base());
+}
+
+/* Low level accessors */
+static u64 gic_read_iar(void)
+{
+	u64 irqstat;
+
+	asm volatile("mrs %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat));
+	return irqstat;
+}
+
+static void gic_write_pmr(u64 val)
+{
+	asm volatile("msr " __stringify(ICC_PMR_EL1) ", %0" : : "r" (val));
+}
+
+static void gic_write_ctlr(u64 val)
+{
+	asm volatile("msr " __stringify(ICC_CTLR_EL1) ", %0" : : "r" (val));
+	isb();
+}
+
+static void gic_write_grpen1(u64 val)
+{
+	asm volatile("msr " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" (val));
+	isb();
+}
+
+static void gic_write_sgi1r(u64 val)
+{
+	asm volatile("msr " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val));
+}
+
+static void gic_enable_sre(void)
+{
+	u64 val;
+
+	asm volatile("mrs %0, " __stringify(ICC_SRE_EL1) : "=r" (val));
+	val |= GICC_SRE_EL1_SRE;
+	asm volatile("msr " __stringify(ICC_SRE_EL1) ", %0" : : "r" (val));
+	isb();
+
+	/*
+	 * Need to check that the SRE bit has actually been set. If
+	 * not, it means that SRE is disabled at EL2. We're going to
+	 * die painfully, and there is nothing we can do about it.
+	 *
+	 * Kindly inform the luser.
+	 */
+	asm volatile("mrs %0, " __stringify(ICC_SRE_EL1) : "=r" (val));
+	if (!(val & GICC_SRE_EL1_SRE))
+		pr_err("GIC: unable to set SRE (disabled at EL2), panic ahead\n");
+}
+
+static void gic_enable_redist(void)
+{
+	void __iomem *rbase;
+	u32 count = 1000000;	/* 1s! */
+	u32 val;
+
+	rbase = gic_data_rdist_rd_base();
+
+	/* Wake up this CPU redistributor */
+	val = readl_relaxed(rbase + GICR_WAKER);
+	val &= ~GICR_WAKER_ProcessorSleep;
+	writel_relaxed(val, rbase + GICR_WAKER);
+
+	while (readl_relaxed(rbase + GICR_WAKER) & GICR_WAKER_ChildrenAsleep) {
+		count--;
+		if (!count) {
+			pr_err_ratelimited("redist didn't wake up...\n");
+			return;
+		}
+		cpu_relax();
+		udelay(1);
+	};
+}
+
+/*
+ * Routines to acknowledge, disable and enable interrupts
+ */
+static void gic_poke_irq(struct irq_data *d, u32 offset)
+{
+	u32 mask = 1 << (gic_irq(d) % 32);
+	void (*rwp_wait)(void);
+	void __iomem *base;
+
+	if (gic_irq_in_rdist(d)) {
+		base = gic_data_rdist_sgi_base();
+		rwp_wait = gic_redist_wait_for_rwp;
+	} else {
+		base = gic_data.dist_base;
+		rwp_wait = gic_dist_wait_for_rwp;
+	}
+
+	writel_relaxed(mask, base + offset + (gic_irq(d) / 32) * 4);
+	rwp_wait();
+}
+
+static int gic_peek_irq(struct irq_data *d, u32 offset)
+{
+	u32 mask = 1 << (gic_irq(d) % 32);
+	void __iomem *base;
+
+	if (gic_irq_in_rdist(d))
+		base = gic_data_rdist_sgi_base();
+	else
+		base = gic_data.dist_base;
+
+	return !!(readl_relaxed(base + offset + (gic_irq(d) / 32) * 4) & mask);
+}
+
+static void gic_mask_irq(struct irq_data *d)
+{
+	gic_poke_irq(d, GICD_ICENABLER);
+}
+
+static void gic_unmask_irq(struct irq_data *d)
+{
+	gic_poke_irq(d, GICD_ISENABLER);
+}
+
+static void gic_eoi_irq(struct irq_data *d)
+{
+	gic_write_eoir(gic_irq(d));
+}
+
+static int gic_set_type(struct irq_data *d, unsigned int type)
+{
+	unsigned int irq = gic_irq(d);
+	void (*rwp_wait)(void);
+	void __iomem *base;
+
+	if (gic_irq_in_rdist(d)) {
+		base = gic_data_rdist_sgi_base();
+		rwp_wait = gic_redist_wait_for_rwp;
+	} else {

drivers/irqchip/irq-gic-v3.c line 249

Quoted 10 lines
drivers/irqchip/irq-gic-v3.c new file +10 -0
+		base = gic_data.dist_base;
+		rwp_wait = gic_dist_wait_for_rwp;
+	}
+
+	/* Interrupt configuration for SGIs can't be changed */
+	if (irq < 16)
+		return -EINVAL;
+
+	if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+		return -EINVAL;

It would be better if checking the two conditions right after variable declaration.

Quoted 16 lines
drivers/irqchip/irq-gic-v3.c new file +16 -0
+
+	gic_configure_irq(irq, type, base, rwp_wait);
+
+	return 0;
+}
+
+static u64 gic_mpidr_to_affinity(u64 mpidr)
+{
+	u64 aff;
+
+	aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
+	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
+	       MPIDR_AFFINITY_LEVEL(mpidr, 0)) & ~GICD_IROUTER_SPI_MODE_ANY;
+
+	return aff;

drivers/irqchip/irq-gic-v3.c line 275

Quoted 10 lines
drivers/irqchip/irq-gic-v3.c new file +10 -0
+}
+
+static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+{
+	u64 irqnr;
+
+	do {
+		irqnr = gic_read_iar();
+
+		if (likely(irqnr > 15 && irqnr < 1021)) {

I prefer to use gic_data.irq_nr instead of '1021'.
The ranges here should be consistent with the ones in domain.map.

Quoted 14 lines
drivers/irqchip/irq-gic-v3.c new file +14 -0
+			irqnr = irq_find_mapping(gic_data.domain, irqnr);
+			handle_IRQ(irqnr, regs);
+			continue;
+		}
+		if (irqnr < 16) {
+			gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+			handle_IPI(irqnr, regs);
+#else
+			WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+			continue;
+		}
+	} while (irqnr != 0x3ff);

drivers/irqchip/irq-gic-v3.c line 299

Quoted 10 lines
drivers/irqchip/irq-gic-v3.c new file +10 -0
+}
+
+static void __init gic_dist_init(void)
+{
+	unsigned int i;
+	u64 affinity;
+	void __iomem *base = gic_data.dist_base;
+
+	/* Disable the distributor */
+	writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Quoted 248 lines
drivers/irqchip/irq-gic-v3.c new file +246 -0
+
+	gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
+
+	/* Enable distributor with ARE, Group1 */
+	writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+		       base + GICD_CTLR);
+
+	/*
+	 * Set all global interrupts to the boot CPU only. ARE must be
+	 * enabled.
+	 */
+	affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
+	for (i = 32; i < gic_data.irq_nr; i++)
+		writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
+}
+
+static int gic_populate_rdist(void)
+{
+	u64 mpidr = cpu_logical_map(smp_processor_id());
+	u64 typer;
+	u32 aff;
+	int i;
+
+	/*
+	 * Convert affinity to a 32bit value that can be matched to
+	 * GICR_TYPER bits [63:32].
+	 */
+	aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 24 |
+	       MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+	       MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8 |
+	       MPIDR_AFFINITY_LEVEL(mpidr, 0));
+
+	for (i = 0; i < gic_data.redist_regions; i++) {
+		void __iomem *ptr = gic_data.redist_base[i];
+		u32 reg;
+
+		reg = readl_relaxed(ptr + GICR_PIDR2) & GIC_PIDR2_ARCH_MASK;
+		if (reg != 0x30 && reg != 0x40) { /* We're in trouble... */
+			pr_warn("No redistributor present @%p\n", ptr);
+			break;
+		}
+
+		do {
+			typer = readq_relaxed(ptr + GICR_TYPER);
+			if ((typer >> 32) == aff) {
+				gic_data_rdist_rd_base() = ptr;
+				pr_info("CPU%d: found redistributor %llx @%p\n",
+					smp_processor_id(),
+					(unsigned long long)mpidr, ptr);
+				return 0;
+			}
+
+			if (gic_data.redist_stride) {
+				ptr += gic_data.redist_stride;
+			} else {
+				ptr += SZ_64K * 2; /* Skip RD_base + SGI_base */
+				if (typer & GICR_TYPER_VLPIS)
+					ptr += SZ_64K * 2; /* Skip VLPI_base + reserved page */
+			}
+		} while (!(typer & GICR_TYPER_LAST));
+	}
+
+	/* We couldn't even deal with ourselves... */
+	WARN(true, "CPU%d: mpidr %llx has no re-distributor!\n",
+	     smp_processor_id(), (unsigned long long)mpidr);
+	return -ENODEV;
+}
+
+static void gic_cpu_init(void)
+{
+	void __iomem *rbase;
+
+	/* Register ourselves with the rest of the world */
+	if (gic_populate_rdist())
+		return;
+
+	gic_enable_redist();
+
+	rbase = gic_data_rdist_sgi_base();
+
+	gic_cpu_config(rbase, gic_redist_wait_for_rwp);
+
+	/* Enable system registers */
+	gic_enable_sre();
+
+	/* Set priority mask register */
+	gic_write_pmr(DEFAULT_PMR_VALUE);
+
+	/* EOI deactivates interrupt too (mode 0) */
+	gic_write_ctlr(GICC_CTLR_EL1_EOImode_drop_dir);
+
+	/* ... and let's hit the road... */
+	gic_write_grpen1(1);
+}
+
+#ifdef CONFIG_SMP
+static int gic_secondary_init(struct notifier_block *nfb,
+			      unsigned long action, void *hcpu)
+{
+	if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+		gic_cpu_init();
+	return NOTIFY_OK;
+}
+
+/*
+ * Notifier for enabling the GIC CPU interface. Set an arbitrarily high
+ * priority because the GIC needs to be up before the ARM generic timers.
+ */
+static struct notifier_block gic_cpu_notifier = {
+	.notifier_call = gic_secondary_init,
+	.priority = 100,
+};
+
+static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
+				   u64 cluster_id)
+{
+	int cpu = *base_cpu;
+	u64 mpidr = cpu_logical_map(cpu);
+	u16 tlist = 0;
+
+	while (cpu < nr_cpu_ids) {
+		/*
+		 * If we ever get a cluster of more than 16 CPUs, just
+		 * scream and skip that CPU.
+		 */
+		if (WARN_ON((mpidr & 0xff) >= 16))
+			goto out;
+
+		tlist |= 1 << (mpidr & 0xf);
+
+		cpu = cpumask_next(cpu, mask);
+		if (cpu == nr_cpu_ids)
+			goto out;
+
+		mpidr = cpu_logical_map(cpu);
+
+		if (cluster_id != (mpidr & ~0xffUL)) {
+			cpu--;
+			goto out;
+		}
+	}
+out:
+	*base_cpu = cpu;
+	return tlist;
+}
+
+static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
+{
+	u64 val;
+
+	val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48	|
+	       MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32	|
+	       irq << 24			    		|
+	       MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16	|
+	       tlist);
+
+	pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
+	gic_write_sgi1r(val);
+}
+
+static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
+{
+	int cpu;
+
+	if (WARN_ON(irq >= 16))
+		return;
+
+	/*
+	 * Ensure that stores to Normal memory are visible to the
+	 * other CPUs before issuing the IPI.
+	 */
+	smp_wmb();
+
+	for_each_cpu_mask(cpu, *mask) {
+		u64 cluster_id = cpu_logical_map(cpu) & ~0xffUL;
+		u16 tlist;
+
+		tlist = gic_compute_target_list(&cpu, mask, cluster_id);
+		gic_send_sgi(cluster_id, tlist, irq);
+	}
+
+	/* Force the above writes to ICC_SGI1R_EL1 to be executed */
+	isb();
+}
+
+static void gic_smp_init(void)
+{
+	set_smp_cross_call(gic_raise_softirq);
+	register_cpu_notifier(&gic_cpu_notifier);
+}
+
+static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
+			    bool force)
+{
+	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
+	void __iomem *reg;
+	int enabled;
+	u64 val;
+
+	if (gic_irq_in_rdist(d))
+		return -EINVAL;
+
+	/* If interrupt was enabled, disable it first */
+	enabled = gic_peek_irq(d, GICD_ISENABLER);
+	if (enabled)
+		gic_mask_irq(d);
+
+	reg = gic_dist_base(d) + GICD_IROUTER + (gic_irq(d) * 8);
+	val = gic_mpidr_to_affinity(cpu_logical_map(cpu));
+
+	writeq_relaxed(val, reg);
+
+	/*
+	 * If the interrupt was enabled, enabled it again. Otherwise,
+	 * just wait for the distributor to have digested our changes.
+	 */
+	if (enabled)
+		gic_unmask_irq(d);
+	else
+		gic_dist_wait_for_rwp();
 
+
 
+	return IRQ_SET_MASK_OK;
+}
+#else
+#define gic_set_affinity	NULL
+#define gic_smp_init()		do { } while(0)
+#endif
+
+static struct irq_chip gic_chip = {
+	.name			= "GICv3",
+	.irq_mask		= gic_mask_irq,
+	.irq_unmask		= gic_unmask_irq,
+	.irq_eoi		= gic_eoi_irq,
+	.irq_set_type		= gic_set_type,
+	.irq_set_affinity	= gic_set_affinity,
+};
+
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+			      irq_hw_number_t hw)
+{
+	/* SGIs are private to the core kernel */
+	if (hw < 16)
+		return -EPERM;
+	/* PPIs */
+	if (hw < 32) {
+		irq_set_percpu_devid(irq);

drivers/irqchip/irq-gic-v3.c line 555

Quoted 10 lines
drivers/irqchip/irq-gic-v3.c new file +10 -0
+		irq_set_chip_and_handler(irq, &gic_chip,
+					 handle_percpu_devid_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+	}
+	/* SPIs */
+	if (hw >= 32 && hw < gic_data.irq_nr) {
+		irq_set_chip_and_handler(irq, &gic_chip,
+					 handle_fasteoi_irq);
+		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+	}

Use 'else' here, since the conditions are non-overlapping.

Regards,
Abel.

Quoted 325 lines
drivers/irqchip/irq-gic-v3.c new file +129 -0
+	irq_set_chip_data(irq, d->host_data);
+	return 0;
+}
+
+static int gic_irq_domain_xlate(struct irq_domain *d,
+				struct device_node *controller,
+				const u32 *intspec, unsigned int intsize,
+				unsigned long *out_hwirq, unsigned int *out_type)
+{
+	if (d->of_node != controller)
+		return -EINVAL;
+	if (intsize < 3)
+		return -EINVAL;
+
+	switch(intspec[0]) {
+	case 0:			/* SPI */
+		*out_hwirq = intspec[1] + 32;
+		break;
+	case 1:			/* PPI */
+		*out_hwirq = intspec[1] + 16;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
+	return 0;
+}
+
+static const struct irq_domain_ops gic_irq_domain_ops = {
+	.map = gic_irq_domain_map,
+	.xlate = gic_irq_domain_xlate,
+};
+
+static int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+	void __iomem *dist_base;
+	void __iomem **redist_base;
+	u64 redist_stride;
+	u32 redist_regions;
+	u32 reg;
+	int gic_irqs;
+	int err;
+	int i;
+
+	dist_base = of_iomap(node, 0);
+	if (!dist_base) {
+		pr_err("%s: unable to map gic dist registers\n",
+			node->full_name);
+		return -ENXIO;
+	}
+
+	reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+	if (reg != 0x30 && reg != 0x40) {
+		pr_err("%s: no distributor detected, giving up\n",
+			node->full_name);
+		err = -ENODEV;
+		goto out_unmap_dist;
+	}
+
+	if (of_property_read_u32(node, "#redistributor-regions", &redist_regions))
+		redist_regions = 1;
+
+	redist_base = kzalloc(sizeof(*redist_base) * redist_regions, GFP_KERNEL);
+	if (!redist_base) {
+		err = -ENOMEM;
+		goto out_unmap_dist;
+	}
+
+	for (i = 0; i < redist_regions; i++) {
+		redist_base[i] = of_iomap(node, 1 + i);
+		if (!redist_base[i]) {
+			pr_err("%s: couldn't map region %d\n",
+			       node->full_name, i);
+			err = -ENODEV;
+			goto out_unmap_rdist;
+		}
+	}
+
+	if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
+		redist_stride = 0;
+
+	gic_data.dist_base = dist_base;
+	gic_data.redist_base = redist_base;
+	gic_data.redist_regions = redist_regions;
+	gic_data.redist_stride = redist_stride;
+
+	/*
+	 * Find out how many interrupts are supported.
+	 * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI)
+	 */
+	gic_irqs = readl_relaxed(gic_data.dist_base + GICD_TYPER) & 0x1f;
+	gic_irqs = (gic_irqs + 1) * 32;
+	if (gic_irqs > 1020)
+		gic_irqs = 1020;
+	gic_data.irq_nr = gic_irqs;
+
+	gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
+					      &gic_data);
+	gic_data.rdist = alloc_percpu(typeof(*gic_data.rdist));
+
+	if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdist)) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	set_handle_irq(gic_handle_irq);
+
+	gic_smp_init();
+	gic_dist_init();
+	gic_cpu_init();
+
+	return 0;
+
+out_free:
+	if (gic_data.domain)
+		irq_domain_remove(gic_data.domain);
+	free_percpu(gic_data.rdist);
+out_unmap_rdist:
+	for (i = 0; i < redist_regions; i++)
+		if (redist_base[i])
+			iounmap(redist_base[i]);
+	kfree(redist_base);
+out_unmap_dist:
+	iounmap(dist_base);
+	return err;
+}
+
+IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
include/linux/irqchip/arm-gic-v3.h new file +190 -0
new file mode 100644
index 0000000..752cbef
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2013, 2014 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <[email protected]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __LINUX_IRQCHIP_ARM_GIC_V3_H
+#define __LINUX_IRQCHIP_ARM_GIC_V3_H
+
+/*
+ * Distributor registers. We assume we're running non-secure, with ARE
+ * being set. Secure-only and non-ARE registers are not described.
+ */
+#define GICD_CTLR			0x0000
+#define GICD_TYPER			0x0004
+#define GICD_IIDR			0x0008
+#define GICD_STATUSR			0x0010
+#define GICD_SETSPI_NSR			0x0040
+#define GICD_CLRSPI_NSR			0x0048
+#define GICD_SETSPI_SR			0x0050
+#define GICD_CLRSPI_SR			0x0058
+#define GICD_SEIR			0x0068
+#define GICD_ISENABLER			0x0100
+#define GICD_ICENABLER			0x0180
+#define GICD_ISPENDR			0x0200
+#define GICD_ICPENDR			0x0280
+#define GICD_ISACTIVER			0x0300
+#define GICD_ICACTIVER			0x0380
+#define GICD_IPRIORITYR			0x0400
+#define GICD_ICFGR			0x0C00
+#define GICD_IROUTER			0x6000
+#define GICD_PIDR2			0xFFE8
+
+#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)
+
+#define GICD_IROUTER_SPI_MODE_ONE	(0U << 31)
+#define GICD_IROUTER_SPI_MODE_ANY	(1U << 31)
+
+#define GIC_PIDR2_ARCH_MASK		0xf0
+
+/*
+ * Re-Distributor registers, offsets from RD_base
+ */
+#define GICR_CTLR			GICD_CTLR
+#define GICR_IIDR			0x0004
+#define GICR_TYPER			0x0008
+#define GICR_STATUSR			GICD_STATUSR
+#define GICR_WAKER			0x0014
+#define GICR_SETLPIR			0x0040
+#define GICR_CLRLPIR			0x0048
+#define GICR_SEIR			GICD_SEIR
+#define GICR_PROPBASER			0x0070
+#define GICR_PENDBASER			0x0078
+#define GICR_INVLPIR			0x00A0
+#define GICR_INVALLR			0x00B0
+#define GICR_SYNCR			0x00C0
+#define GICR_MOVLPIR			0x0100
+#define GICR_MOVALLR			0x0110
+#define GICR_PIDR2			GICD_PIDR2
+
+#define GICR_WAKER_ProcessorSleep	(1U << 1)
+#define GICR_WAKER_ChildrenAsleep	(1U << 2)
+
+/*
+ * Re-Distributor registers, offsets from SGI_base
+ */
+#define GICR_ISENABLER0			GICD_ISENABLER
+#define GICR_ICENABLER0			GICD_ICENABLER
+#define GICR_ISPENDR0			GICD_ISPENDR
+#define GICR_ICPENDR0			GICD_ICPENDR
+#define GICR_ISACTIVER0			GICD_ISACTIVER
+#define GICR_ICACTIVER0			GICD_ICACTIVER
+#define GICR_IPRIORITYR0		GICD_IPRIORITYR
+#define GICR_ICFGR0			GICD_ICFGR
+
+#define GICR_TYPER_VLPIS		(1U << 1)
+#define GICR_TYPER_LAST			(1U << 4)
+
+/*
+ * CPU interface registers
+ */
+#define GICC_CTLR_EL1_EOImode_drop_dir	(0U << 1)
+#define GICC_CTLR_EL1_EOImode_drop	(1U << 1)
+#define GICC_SRE_EL1_SRE		(1U << 0)
+
+/*
+ * Hypervisor interface registers (SRE only)
+ */
+#define GICH_LR_VIRTUAL_ID_MASK		((1UL << 32) - 1)
+
+#define GICH_LR_EOI			(1UL << 41)
+#define GICH_LR_GROUP			(1UL << 60)
+#define GICH_LR_STATE			(3UL << 62)
+#define GICH_LR_PENDING_BIT		(1UL << 62)
+#define GICH_LR_ACTIVE_BIT		(1UL << 63)
+
+#define GICH_MISR_EOI			(1 << 0)
+#define GICH_MISR_U			(1 << 1)
+
+#define GICH_HCR_EN			(1 << 0)
+#define GICH_HCR_UIE			(1 << 1)
+
+#define GICH_VMCR_CTLR_SHIFT		0
+#define GICH_VMCR_CTLR_MASK		(0x21f << GICH_VMCR_CTLR_SHIFT)
+#define GICH_VMCR_BPR1_SHIFT		18
+#define GICH_VMCR_BPR1_MASK		(7 << GICH_VMCR_BPR1_SHIFT)
+#define GICH_VMCR_BPR0_SHIFT		21
+#define GICH_VMCR_BPR0_MASK		(7 << GICH_VMCR_BPR0_SHIFT)
+#define GICH_VMCR_PMR_SHIFT		24
+#define GICH_VMCR_PMR_MASK		(0xffUL << GICH_VMCR_PMR_SHIFT)
+
+#define ICC_EOIR1_EL1			S3_0_C12_C12_1
+#define ICC_IAR1_EL1			S3_0_C12_C12_0
+#define ICC_SGI1R_EL1			S3_0_C12_C11_5
+#define ICC_PMR_EL1			S3_0_C4_C6_0
+#define ICC_CTLR_EL1			S3_0_C12_C12_4
+#define ICC_SRE_EL1			S3_0_C12_C12_5
+#define ICC_GRPEN1_EL1			S3_0_C12_C12_7
+
+#define ICC_SRE_EL2			S3_4_C12_C9_5
+
+#define ICC_SRE_EL2_ENABLE		(1 << 3)
+
+#define ICH_VSEIR_EL2			S3_4_C12_C9_4
+#define ICH_HCR_EL2			S3_4_C12_C11_0
+#define ICH_VTR_EL2			S3_4_C12_C11_1
+#define ICH_MISR_EL2			S3_4_C12_C11_2
+#define ICH_EISR_EL2			S3_4_C12_C11_3
+#define ICH_ELSR_EL2			S3_4_C12_C11_5
+#define ICH_VMCR_EL2			S3_4_C12_C11_7
+
+#define __LR0_EL2(x)			S3_4_C12_C12_ ## x
+#define __LR8_EL2(x)			S3_4_C12_C13_ ## x
+
+#define ICH_LR0_EL2			__LR0_EL2(0)
+#define ICH_LR1_EL2			__LR0_EL2(1)
+#define ICH_LR2_EL2			__LR0_EL2(2)
+#define ICH_LR3_EL2			__LR0_EL2(3)
+#define ICH_LR4_EL2			__LR0_EL2(4)
+#define ICH_LR5_EL2			__LR0_EL2(5)
+#define ICH_LR6_EL2			__LR0_EL2(6)
+#define ICH_LR7_EL2			__LR0_EL2(7)
+#define ICH_LR8_EL2			__LR8_EL2(0)
+#define ICH_LR9_EL2			__LR8_EL2(1)
+#define ICH_LR10_EL2			__LR8_EL2(2)
+#define ICH_LR11_EL2			__LR8_EL2(3)
+#define ICH_LR12_EL2			__LR8_EL2(4)
+#define ICH_LR13_EL2			__LR8_EL2(5)
+#define ICH_LR14_EL2			__LR8_EL2(6)
+#define ICH_LR15_EL2			__LR8_EL2(7)
+
+#define __AP0Rx_EL2(x)			S3_4_C12_C8_ ## x
+#define ICH_AP0R0_EL2			__AP0Rx_EL2(0)
+#define ICH_AP0R1_EL2			__AP0Rx_EL2(1)
+#define ICH_AP0R2_EL2			__AP0Rx_EL2(2)
+#define ICH_AP0R3_EL2			__AP0Rx_EL2(3)
+
+#define __AP1Rx_EL2(x)			S3_4_C12_C9_ ## x
+#define ICH_AP1R0_EL2			__AP1Rx_EL2(0)
+#define ICH_AP1R1_EL2			__AP1Rx_EL2(1)
+#define ICH_AP1R2_EL2			__AP1Rx_EL2(2)
+#define ICH_AP1R3_EL2			__AP1Rx_EL2(3)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/stringify.h>
+
+static inline void gic_write_eoir(u64 irq)
+{
+	asm volatile("msr " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" (irq));
+	isb();
+}
+
+#endif
+
+#endif
#6 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Hi Abel,

Quoted 44 lines · Abel

Hi Marc,

Quoted 31 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

---
 arch/arm64/Kconfig                 |   1 +
 arch/arm64/kernel/head.S           |  18 +
 arch/arm64/kernel/hyp-stub.S       |   1 +
 drivers/irqchip/Kconfig            |   5 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-gic-v3.c       | 684 +++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-v3.h | 190 +++++++++++
 7 files changed, 900 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h

[...]

Quoted 6 lines
drivers/irqchip/irq-gic-v3.c new file +0 -0
new file mode 100644
index 0000000..6570e7b
@@ -0,0 +1,684 @@

[...]

Quoted 15 lines
Quoted 15 lines
drivers/irqchip/irq-gic-v3.c new file +15 -0
+static int gic_set_type(struct irq_data *d, unsigned int type)
+{
+     unsigned int irq = gic_irq(d);
+     void (*rwp_wait)(void);
+     void __iomem *base;
+
+     if (gic_irq_in_rdist(d)) {
+             base = gic_data_rdist_sgi_base();
+             rwp_wait = gic_redist_wait_for_rwp;
+     } else {
+             base = gic_data.dist_base;
+             rwp_wait = gic_dist_wait_for_rwp;
+     }
+
+     /* Interrupt configuration for SGIs can't be changed */
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 249

Quoted 5 lines
drivers/irqchip/irq-gic-v3.c new file +5 -0
+     if (irq < 16)
+             return -EINVAL;
+
+     if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+             return -EINVAL;

It would be better if checking the two conditions right after variable declaration.

Sure, why not.

Quoted 22 lines
Quoted 22 lines
drivers/irqchip/irq-gic-v3.c new file +22 -0
+
+     gic_configure_irq(irq, type, base, rwp_wait);
+
+     return 0;
+}
+
+static u64 gic_mpidr_to_affinity(u64 mpidr)
+{
+     u64 aff;
+
+     aff = (MPIDR_AFFINITY_LEVEL(mpidr, 3) << 32 |
+            MPIDR_AFFINITY_LEVEL(mpidr, 2) << 16 |
+            MPIDR_AFFINITY_LEVEL(mpidr, 1) << 8  |
+            MPIDR_AFFINITY_LEVEL(mpidr, 0)) & ~GICD_IROUTER_SPI_MODE_ANY;
+
+     return aff;
+}
+
+static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+{
+     u64 irqnr;
+
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 275

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     do {
+             irqnr = gic_read_iar();
+
+             if (likely(irqnr > 15 && irqnr < 1021)) {

I prefer to use gic_data.irq_nr instead of '1021'.
The ranges here should be consistent with the ones in domain.map.

That's debatable. gic_data.irq_nr is used as a guard for the rest of the kernel, so that we don't map an out-of-range interrupt number. But here, we read the interrupt that has been generated by the actual HW. If such thing happen, we need to know about it, handle it as a spurious interrupt, and EOI it. Otherwise, we're stuck forever (with your proposed change, nothing EOIs the interrupt).

Quoted 19 lines
Quoted 19 lines
drivers/irqchip/irq-gic-v3.c new file +19 -0
+                     irqnr = irq_find_mapping(gic_data.domain, irqnr);
+                     handle_IRQ(irqnr, regs);
+                     continue;
+             }
+             if (irqnr < 16) {
+                     gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+                     handle_IPI(irqnr, regs);
+#else
+                     WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+                     continue;
+             }
+     } while (irqnr != 0x3ff);
+}
+
+static void __init gic_dist_init(void)
+{
+     unsigned int i;
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 299

Quoted 5 lines
drivers/irqchip/irq-gic-v3.c new file +5 -0
+     u64 affinity;
+     void __iomem *base = gic_data.dist_base;
+
+     /* Disable the distributor */
+     writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Hmmm. That's a good point. The spec says the RWP tracks the completion of writes that change (among other things) the state of an interrupt group enable. But the next line will perform a wait_for_rwp anyway after having disabled all SPIs. So no, I don't think we need to wait. We guaranteed to get a consistent state after the call to gic_dist_config.

Quoted 16 lines
Quoted 16 lines
drivers/irqchip/irq-gic-v3.c new file +16 -0
+
+     gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
+
+     /* Enable distributor with ARE, Group1 */
+     writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+                    base + GICD_CTLR);
+
+     /*
+      * Set all global interrupts to the boot CPU only. ARE must be
+      * enabled.
+      */
+     affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
+     for (i = 32; i < gic_data.irq_nr; i++)
+             writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
+}
+

[...]

Quoted 14 lines
Quoted 14 lines
drivers/irqchip/irq-gic-v3.c new file +14 -0
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                           irq_hw_number_t hw)
+{
+     /* SGIs are private to the core kernel */
+     if (hw < 16)
+             return -EPERM;
+     /* PPIs */
+     if (hw < 32) {
+             irq_set_percpu_devid(irq);
+             irq_set_chip_and_handler(irq, &gic_chip,
+                                      handle_percpu_devid_irq);
+             set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+     }
+     /* SPIs */
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 555

Quoted 5 lines
drivers/irqchip/irq-gic-v3.c new file +5 -0
+     if (hw >= 32 && hw < gic_data.irq_nr) {
+             irq_set_chip_and_handler(irq, &gic_chip,
+                                      handle_fasteoi_irq);
+             set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+     }

Use 'else' here, since the conditions are non-overlapping.

For the code as it is now, I'd agree. But I'm also looking at the ITS code that will follow as soon as this one is on its way to mainline, and I then have this:

@@ -553,6 +571,19 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,

                                         handle_fasteoi_irq);
                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
        }

+ /* Nothing */
+ if (hw >= gic_data.irq_nr && hw < 8192)
+ return -EPERM;
+ /* LPIs */
+ if (hw >= 8192 && hw < GIC_ID_NR) {
+ if (!its_chip)
+ return -EPERM;
+ irq_set_chip_and_handler(irq, its_chip, handle_fasteoi_irq);
+ set_irq_flags(irq, IRQF_VALID);

+       }
+       /* Off limits */
+       if (hw >= GIC_ID_NR)
+               return -EPERM;
        irq_set_chip_data(irq, d->host_data);
        return 0;

}

Having a bunch of else clauses looks pretty awful in this context, and I've decided to try and keep it readable instead. This is not on the hot path anyway, so it doesn't really matter if we test an extra variable.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#7 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Quoted 38 lines · Marc Zyngier

Hi Abel,

Quoted 35 lines · Abel

Hi Marc,

Quoted 31 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

---
 arch/arm64/Kconfig                 |   1 +
 arch/arm64/kernel/head.S           |  18 +
 arch/arm64/kernel/hyp-stub.S       |   1 +
 drivers/irqchip/Kconfig            |   5 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-gic-v3.c       | 684 +++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-v3.h | 190 +++++++++++
 7 files changed, 900 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h

[...]

Quoted 13 lines
Quoted 4 lines
Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
+{
+     u64 irqnr;
+
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 275

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     do {
+             irqnr = gic_read_iar();
+
+             if (likely(irqnr > 15 && irqnr < 1021)) {

I prefer to use gic_data.irq_nr instead of '1021'.
The ranges here should be consistent with the ones in domain.map.

Quoted 6 lines

That's debatable. gic_data.irq_nr is used as a guard for the rest of the kernel, so that we don't map an out-of-range interrupt number. But here, we read the interrupt that has been generated by the actual HW. If such thing happen, we need to know about it, handle it as a spurious interrupt, and EOI it. Otherwise, we're stuck forever (with your proposed change, nothing EOIs the interrupt).

I don't think it's necessary to EOI the spurious interrupts, since EOIing a spurious interrupt won't cause any effect.
As for the interrupts here, the ones entered into this 'if' clause, I think they are expected already been mapped into this irq_domain.

Quoted 29 lines
Quoted 20 lines
Quoted 20 lines
drivers/irqchip/irq-gic-v3.c new file +19 -0
+                     irqnr = irq_find_mapping(gic_data.domain, irqnr);
+                     handle_IRQ(irqnr, regs);
+                     continue;
+             }
+             if (irqnr < 16) {
+                     gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+                     handle_IPI(irqnr, regs);
+#else
+                     WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+                     continue;
+             }
+     } while (irqnr != 0x3ff);
+}
+
+static void __init gic_dist_init(void)
+{
+     unsigned int i;
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 299

Quoted 5 lines
drivers/irqchip/irq-gic-v3.c new file +5 -0
+     u64 affinity;
+     void __iomem *base = gic_data.dist_base;
+
+     /* Disable the distributor */
+     writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Quoted 5 lines

Hmmm. That's a good point. The spec says the RWP tracks the completion of writes that change (among other things) the state of an interrupt group enable. But the next line will perform a wait_for_rwp anyway after having disabled all SPIs. So no, I don't think we need to wait. We guaranteed to get a consistent state after the call to gic_dist_config.

The spec also says that software must ensure the interrupt is disabled before changing its routing/priority/group information, see chapter 4.5.5 in v18.

Quoted 68 lines
Quoted 17 lines
Quoted 17 lines
drivers/irqchip/irq-gic-v3.c new file +16 -0
+
+     gic_dist_config(base, gic_data.irq_nr, gic_dist_wait_for_rwp);
+
+     /* Enable distributor with ARE, Group1 */
+     writel_relaxed(GICD_CTLR_ARE_NS | GICD_CTLR_ENABLE_G1A | GICD_CTLR_ENABLE_G1,
+                    base + GICD_CTLR);
+
+     /*
+      * Set all global interrupts to the boot CPU only. ARE must be
+      * enabled.
+      */
+     affinity = gic_mpidr_to_affinity(cpu_logical_map(smp_processor_id()));
+     for (i = 32; i < gic_data.irq_nr; i++)
+             writeq_relaxed(affinity, base + GICD_IROUTER + i * 8);
+}
+

[...]

Quoted 14 lines
Quoted 14 lines
drivers/irqchip/irq-gic-v3.c new file +14 -0
+static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                           irq_hw_number_t hw)
+{
+     /* SGIs are private to the core kernel */
+     if (hw < 16)
+             return -EPERM;
+     /* PPIs */
+     if (hw < 32) {
+             irq_set_percpu_devid(irq);
+             irq_set_chip_and_handler(irq, &gic_chip,
+                                      handle_percpu_devid_irq);
+             set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
+     }
+     /* SPIs */
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 555

Quoted 5 lines
drivers/irqchip/irq-gic-v3.c new file +5 -0
+     if (hw >= 32 && hw < gic_data.irq_nr) {
+             irq_set_chip_and_handler(irq, &gic_chip,
+                                      handle_fasteoi_irq);
+             set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+     }

Use 'else' here, since the conditions are non-overlapping.

For the code as it is now, I'd agree. But I'm also looking at the ITS code that will follow as soon as this one is on its way to mainline, and I then have this:

(quoted diff) +13 -0
@@ -553,6 +571,19 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                                         handle_fasteoi_irq);
                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
        }
+       /* Nothing */
+       if (hw >= gic_data.irq_nr && hw < 8192)
+               return -EPERM;
+       /* LPIs */
+       if (hw >= 8192 && hw < GIC_ID_NR) {
+               if (!its_chip)
+                       return -EPERM;
+               irq_set_chip_and_handler(irq, its_chip, handle_fasteoi_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+       /* Off limits */
+       if (hw >= GIC_ID_NR)
+               return -EPERM;
        irq_set_chip_data(irq, d->host_data);
        return 0;
 }
Quoted 3 lines

Having a bunch of else clauses looks pretty awful in this context, and I've decided to try and keep it readable instead. This is not on the hot path anyway, so it doesn't really matter if we test an extra variable.

OK, it makes sense.

Regards,
Abel.

#8 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Quoted 64 lines · Abel
Quoted 39 lines · Marc Zyngier

Hi Abel,

Quoted 36 lines · Abel

Hi Marc,

Quoted 32 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

---
 arch/arm64/Kconfig                 |   1 +
 arch/arm64/kernel/head.S           |  18 +
 arch/arm64/kernel/hyp-stub.S       |   1 +
 drivers/irqchip/Kconfig            |   5 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-gic-v3.c | 684
+++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-v3.h | 190 +++++++++++
 7 files changed, 900 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h

[...]

Quoted 14 lines
Quoted 5 lines
Quoted 5 lines

+static asmlinkage void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs)

drivers/irqchip/irq-gic-v3.c new file +3 -0
+{
+     u64 irqnr;
+
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 275

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     do {
+             irqnr = gic_read_iar();
+
+             if (likely(irqnr > 15 && irqnr < 1021)) {

I prefer to use gic_data.irq_nr instead of '1021'.
The ranges here should be consistent with the ones in domain.map.

Quoted 6 lines

That's debatable. gic_data.irq_nr is used as a guard for the rest of the kernel, so that we don't map an out-of-range interrupt number. But here, we read the interrupt that has been generated by the actual HW. If such thing happen, we need to know about it, handle it as a spurious interrupt, and EOI it. Otherwise, we're stuck forever (with your proposed change, nothing EOIs the interrupt).

Quoted 2 lines

I don't think it's necessary to EOI the spurious interrupts, since EOIing a spurious interrupt won't cause any effect.

My choice of word was rather poor in this context. I wasn't thinking of a spurious interrupt", as defined in the GIC architecture (where ICC_IAR_EL1 returns 0x3ff), but rather of a valid interrupt number (between irq_nr and 1021).

Quoted 2 lines

As for the interrupts here, the ones entered into this 'if' clause, I think they are expected already been mapped into this irq_domain.

Mapped or not is not the problem. Think of a (broken) implementation that would generate random IDs in the irq_nr..1021 range. You'd end up with the deadlock situation I've outlined above.

And actually, irq_find_mapping can fail, and I should handle this.

Quoted 37 lines
Quoted 30 lines
Quoted 21 lines
Quoted 21 lines
drivers/irqchip/irq-gic-v3.c new file +20 -0
+                     irqnr = irq_find_mapping(gic_data.domain, irqnr);
+                     handle_IRQ(irqnr, regs);
+                     continue;
+             }
+             if (irqnr < 16) {
+                     gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+                     handle_IPI(irqnr, regs);
+#else
+                     WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+                     continue;
+             }
+     } while (irqnr != 0x3ff);
+}
+
+static void __init gic_dist_init(void)
+{
+     unsigned int i;
+     u64 affinity;
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 299

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     void __iomem *base = gic_data.dist_base;
+
+     /* Disable the distributor */
+     writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Quoted 5 lines

Hmmm. That's a good point. The spec says the RWP tracks the completion of writes that change (among other things) the state of an interrupt group enable. But the next line will perform a wait_for_rwp anyway after having disabled all SPIs. So no, I don't think we need to wait. We guaranteed to get a consistent state after the call to gic_dist_config.

Quoted 2 lines

The spec also says that software must ensure the interrupt is disabled before changing its routing/priority/group information, see chapter 4.5.5 in v18.

That's only to ensure consistency when a single interrupt is being reconfigured, and that's what the code already does. In this particular context, waiting for RWP looks completely superfluous.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#9 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Quoted 65 lines · Marc Zyngier
Quoted 64 lines · Abel
Quoted 39 lines · Marc Zyngier

Hi Abel,

Quoted 36 lines · Abel

Hi Marc,

Quoted 32 lines · Marc Zyngier

The Generic Interrupt Controller (version 3) offers services that are similar to GICv2, with a number of additional features:
- Affinity routing based on the CPU MPIDR (ARE)
- System register for the CPU interfaces (SRE)
- Support for more that 8 CPUs
- Locality-specific Peripheral Interrupts (LPIs)
- Interrupt Translation Services (ITS)

This patch adds preliminary support for GICv3 with ARE and SRE, non-secure mode only. It relies on higher exception levels to grant ARE and SRE access.

Support for LPI and ITS will be added at a later time.

---
 arch/arm64/Kconfig                 |   1 +
 arch/arm64/kernel/head.S           |  18 +
 arch/arm64/kernel/hyp-stub.S       |   1 +
 drivers/irqchip/Kconfig            |   5 +
 drivers/irqchip/Makefile           |   1 +
 drivers/irqchip/irq-gic-v3.c | 684
+++++++++++++++++++++++++++++++++++++
 include/linux/irqchip/arm-gic-v3.h | 190 +++++++++++
 7 files changed, 900 insertions(+)
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h

[...]

Quoted 20 lines
Quoted 5 lines
Quoted 5 lines

+static asmlinkage void __exception_irq_entry
gic_handle_irq(struct pt_regs *regs)

drivers/irqchip/irq-gic-v3.c new file +3 -0
+{
+     u64 irqnr;
+
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 275

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     do {
+             irqnr = gic_read_iar();
+
+             if (likely(irqnr > 15 && irqnr < 1021)) {

I prefer to use gic_data.irq_nr instead of '1021'.
The ranges here should be consistent with the ones in domain.map.

That's debatable. gic_data.irq_nr is used as a guard for the rest of the kernel, so that we don't map an out-of-range interrupt number. But here, we read the interrupt that has been generated by the actual HW. If such thing happen, we need to know about it, handle it as a spurious interrupt, and EOI it. Otherwise, we're stuck forever (with your proposed change, nothing EOIs the interrupt).

Quoted 7 lines
Quoted 2 lines

I don't think it's necessary to EOI the spurious interrupts, since EOIing a spurious interrupt won't cause any effect.

My choice of word was rather poor in this context. I wasn't thinking of a spurious interrupt", as defined in the GIC architecture (where ICC_IAR_EL1 returns 0x3ff), but rather of a valid interrupt number (between irq_nr and 1021).

Understood.

Quoted 8 lines
Quoted 2 lines

As for the interrupts here, the ones entered into this 'if' clause, I think they are expected already been mapped into this irq_domain.

Mapped or not is not the problem. Think of a (broken) implementation that would generate random IDs in the irq_nr..1021 range. You'd end up with the deadlock situation I've outlined above.

And actually, irq_find_mapping can fail, and I should handle this.

Yes, makes sense. This case should be properly handled.
And I still have two questions.
a) Does this scenario really exist or necessary? I mean, part of interrupts mapped while others which belongs to the same interrupt controller are not.
b) Why 1021?

Quoted 37 lines
Quoted 37 lines
Quoted 35 lines
Quoted 21 lines
Quoted 21 lines
drivers/irqchip/irq-gic-v3.c new file +20 -0
+                     irqnr = irq_find_mapping(gic_data.domain, irqnr);
+                     handle_IRQ(irqnr, regs);
+                     continue;
+             }
+             if (irqnr < 16) {
+                     gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+                     handle_IPI(irqnr, regs);
+#else
+                     WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+                     continue;
+             }
+     } while (irqnr != 0x3ff);
+}
+
+static void __init gic_dist_init(void)
+{
+     unsigned int i;
+     u64 affinity;
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 299

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     void __iomem *base = gic_data.dist_base;
+
+     /* Disable the distributor */
+     writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Hmmm. That's a good point. The spec says the RWP tracks the completion of writes that change (among other things) the state of an interrupt group enable. But the next line will perform a wait_for_rwp anyway after having disabled all SPIs. So no, I don't think we need to wait. We guaranteed to get a consistent state after the call to gic_dist_config.

Quoted 6 lines
Quoted 2 lines

The spec also says that software must ensure the interrupt is disabled before changing its routing/priority/group information, see chapter 4.5.5 in v18.

That's only to ensure consistency when a single interrupt is being reconfigured, and that's what the code already does. In this particular context, waiting for RWP looks completely superfluous.

It's reasonable to think GIC having been enabled by boot loader or something else in the boot procedure. And here not waiting for RWP may cause hardware implementation defined behavior, that is configuring an enabled interrupt. It's beyond the scope of the GIC architecture, and vendors also don't want to see this happen.

Thanks,
Abel.

#10 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Quoted 10 lines · Abel
Quoted 8 lines · Marc Zyngier
Quoted 2 lines · Abel

As for the interrupts here, the ones entered into this 'if' clause, I think they are expected already been mapped into this irq_domain.

Mapped or not is not the problem. Think of a (broken) implementation that would generate random IDs in the irq_nr..1021 range. You'd end up with the deadlock situation I've outlined above.

Quoted 7 lines
Quoted 1 line

And actually, irq_find_mapping can fail, and I should handle this.

Yes, makes sense. This case should be properly handled.
And I still have two questions.
a) Does this scenario really exist or necessary? I mean, part of interrupts mapped while others which belongs to the same interrupt controller are not.

Not that I know of. But consider this cheap defensive programming. It is actually cheaper to check against a constant boundary than do a load and check against a variable. Safer, faster.

Quoted 1 line

b) Why 1021?

The maximum SPI ID is 1020.

Quoted 45 lines
Quoted 38 lines
Quoted 38 lines
Quoted 36 lines
Quoted 22 lines
Quoted 22 lines
drivers/irqchip/irq-gic-v3.c new file +20 -0
+                     irqnr = irq_find_mapping(gic_data.domain, irqnr);
+                     handle_IRQ(irqnr, regs);
+                     continue;
+             }
+             if (irqnr < 16) {
+                     gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+                     handle_IPI(irqnr, regs);
+#else
+                     WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+                     continue;
+             }
+     } while (irqnr != 0x3ff);
+}
+
+static void __init gic_dist_init(void)
+{
+     unsigned int i;
+     u64 affinity;
Quoted 8 lines

drivers/irqchip/irq-gic-v3.c line 299

Quoted 4 lines
drivers/irqchip/irq-gic-v3.c new file +4 -0
+     void __iomem *base = gic_data.dist_base;
+
+     /* Disable the distributor */
+     writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Hmmm. That's a good point. The spec says the RWP tracks the completion of writes that change (among other things) the state of an interrupt group enable. But the next line will perform a wait_for_rwp anyway after having disabled all SPIs. So no, I don't think we need to wait. We guaranteed to get a consistent state after the call to gic_dist_config.

Quoted 6 lines
Quoted 2 lines

The spec also says that software must ensure the interrupt is disabled before changing its routing/priority/group information, see chapter 4.5.5 in v18.

That's only to ensure consistency when a single interrupt is being reconfigured, and that's what the code already does. In this particular context, waiting for RWP looks completely superfluous.

Quoted 5 lines

It's reasonable to think GIC having been enabled by boot loader or something else in the boot procedure. And here not waiting for RWP may cause hardware implementation defined behavior, that is configuring an enabled interrupt. It's beyond the scope of the GIC architecture, and vendors also don't want to see this happen.

Well, I guess that since this is a one-off thing, it doesn't really add an extra synchronization. As long as it gives you peace of mind... ;-)

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#11 lore raw

PATCH v4 2/20 arm64: initial support for GICv3

Quoted 14 lines · Marc Zyngier
Quoted 13 lines · Abel
Quoted 9 lines · Marc Zyngier
Quoted 2 lines · Abel

As for the interrupts here, the ones entered into this 'if' clause, I think they are expected already been mapped into this irq_domain.

Mapped or not is not the problem. Think of a (broken) implementation that would generate random IDs in the irq_nr..1021 range. You'd end up with the deadlock situation I've outlined above.

And actually, irq_find_mapping can fail, and I should handle this.

Quoted 8 lines
Quoted 4 lines

Yes, makes sense. This case should be properly handled.
And I still have two questions.
a) Does this scenario really exist or necessary? I mean, part of interrupts mapped while others which belongs to the same interrupt controller are not.

Not that I know of. But consider this cheap defensive programming. It is actually cheaper to check against a constant boundary than do a load and check against a variable. Safer, faster.

Yes, sure.

Quoted 4 lines
Quoted 2 lines

b) Why 1021?

The maximum SPI ID is 1020.

Oooh.. SPI ends at 1019, and 1020 is for special purpose.

Quoted 46 lines
Quoted 46 lines
Quoted 45 lines
Quoted 39 lines
Quoted 32 lines
Quoted 23 lines
Quoted 23 lines
(quoted diff) +20 -0
+                     irqnr = irq_find_mapping(gic_data.domain, irqnr);
+                     handle_IRQ(irqnr, regs);
+                     continue;
+             }
+             if (irqnr < 16) {
+                     gic_write_eoir(irqnr);
+#ifdef CONFIG_SMP
+                     handle_IPI(irqnr, regs);
+#else
+                     WARN_ONCE(true, "Unexpected SGI received!\n");
+#endif
+                     continue;
+             }
+     } while (irqnr != 0x3ff);
+}
+
+static void __init gic_dist_init(void)
+{
+     unsigned int i;
+     u64 affinity;
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +4 -0
+     void __iomem *base = gic_data.dist_base;
+
+     /* Disable the distributor */
+     writel_relaxed(0, base + GICD_CTLR);

I'm not sure whether waiting for write pending here is necessary. What do you think?

Quoted 5 lines

Hmmm. That's a good point. The spec says the RWP tracks the completion of writes that change (among other things) the state of an interrupt group enable. But the next line will perform a wait_for_rwp anyway after having disabled all SPIs. So no, I don't think we need to wait. We guaranteed to get a consistent state after the call to gic_dist_config.

Quoted 2 lines

The spec also says that software must ensure the interrupt is disabled before changing its routing/priority/group information, see chapter 4.5.5 in v18.

That's only to ensure consistency when a single interrupt is being reconfigured, and that's what the code already does. In this particular context, waiting for RWP looks completely superfluous.

Quoted 9 lines
Quoted 5 lines

It's reasonable to think GIC having been enabled by boot loader or something else in the boot procedure. And here not waiting for RWP may cause hardware implementation defined behavior, that is configuring an enabled interrupt. It's beyond the scope of the GIC architecture, and vendors also don't want to see this happen.

Well, I guess that since this is a one-off thing, it doesn't really add an extra synchronization. As long as it gives you peace of mind... ;-)

OK, then let's keep it what it was. :)

Thanks,
Abel.

#12 lore raw

PATCH v4 3/20 arm64: GICv3 device tree binding documentation

In reply to Marc Zyngier

Add the necessary documentation to support GICv3.

---
 Documentation/devicetree/bindings/arm/gic-v3.txt | 79 ++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
Documentation/devicetree/bindings/arm/gic-v3.txt new file +79 -0
new file mode 100644
index 0000000..33cd05e
@@ -0,0 +1,79 @@
+* ARM Generic Interrupt Controller, version 3
+
+AArch64 SMP cores are often associated with a GICv3, providing Private
+Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
+Software Generated Interrupts (SGI), and Locality-specific Peripheral
+Interrupts (LPI).
+
+Main node required properties:
+
+- compatible : should at least contain  "arm,gic-v3".
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. Must be a single cell with a value of at least 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts. Other values are reserved for future use.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987]. PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+	bits[3:0] trigger type and level flags.
+		1 = edge triggered
+		4 = level triggered
+
+  Cells 4 and beyond are reserved for future use. When the 1st cell
+  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
+  ignored. It is recommended that padding cells have a value of 0.
+
+- reg : Specifies base physical address(s) and size of the GIC
+  registers, in the following order:
+  - GIC Distributor interface (GICD)
+  - GIC Redistributors (GICR), one range per redistributor region
+  - GIC CPU interface (GICC)
+  - GIC Hypervisor interface (GICH)
+  - GIC Virtual CPU interface (GICV)
+
+  GICC, GICH and GICV are optional.
+
+- interrupts : Interrupt source of the VGIC maintenance interrupt.
+
+Optional
+
+- redistributor-stride : If using padding pages, specifies the stride
+  of consecutive redistributors. Must be a multiple of 64kB.
+
+- #redistributor-regions: The number of independent contiguous regions
+  occupied by the redistributors. Required if more than one such
+  region is present.
+
+Examples:
+
+	gic: interrupt-controller at 2cf00000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-controller;
+		reg = <0x0 0x2f000000 0 0x10000>,	// GICD
+		      <0x0 0x2f100000 0 0x200000>,	// GICR
+		      <0x0 0x2c000000 0 0x2000>,	// GICC
+		      <0x0 0x2c010000 0 0x2000>,	// GICH
+		      <0x0 0x2c020000 0 0x2000>;	// GICV
+		interrupts = <1 9 4>;
+	};
+
+	gic: interrupt-controller at 2c010000 {
+		compatible = "arm,gic-v3";
+		#interrupt-cells = <3>;
+		interrupt-controller;
+		redistributor-stride = <0x0 0x40000>;	// 256kB stride
+		#redistributor-regions = <2>;
+		reg = <0x0 0x2c010000 0 0x10000>,	// GICD
+		      <0x0 0x2d000000 0 0x800000>,	// GICR 1: CPUs 0-31
+		      <0x0 0x2e000000 0 0x800000>;	// GICR 2: CPUs 32-63
+		      <0x0 0x2c040000 0 0x2000>,	// GICC
+		      <0x0 0x2c060000 0 0x2000>,	// GICH
+		      <0x0 0x2c080000 0 0x2000>;	// GICV
+		interrupts = <1 9 4>;
+	};
Signature · 1 line
1.8.3.4
#13 lore raw

PATCH v4 3/20 arm64: GICv3 device tree binding documentation

Quoted 48 lines · Marc Zyngier

Add the necessary documentation to support GICv3.

---
 Documentation/devicetree/bindings/arm/gic-v3.txt | 79 ++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
Documentation/devicetree/bindings/arm/gic-v3.txt new file +29 -0
new file mode 100644
index 0000000..33cd05e
@@ -0,0 +1,79 @@
+* ARM Generic Interrupt Controller, version 3
+
+AArch64 SMP cores are often associated with a GICv3, providing Private
+Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
+Software Generated Interrupts (SGI), and Locality-specific Peripheral
+Interrupts (LPI).
+
+Main node required properties:
+
+- compatible : should at least contain  "arm,gic-v3".
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. Must be a single cell with a value of at least 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts. Other values are reserved for future use.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987]. PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+     bits[3:0] trigger type and level flags.
+             1 = edge triggered
+             4 = level triggered
+
+  Cells 4 and beyond are reserved for future use. When the 1st cell
+  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
+  ignored. It is recommended that padding cells have a value of 0.

Documentation/devicetree/bindings/arm/gic-v3.txt line 39

Quoted 10 lines
Documentation/devicetree/bindings/arm/gic-v3.txt new file +10 -0
+
+- reg : Specifies base physical address(s) and size of the GIC
+  registers, in the following order:
+  - GIC Distributor interface (GICD)
+  - GIC Redistributors (GICR), one range per redistributor region
+  - GIC CPU interface (GICC)
+  - GIC Hypervisor interface (GICH)
+  - GIC Virtual CPU interface (GICV)
+
+  GICC, GICH and GICV are optional.

I wonder if it should be noted here that a lack of these last three regions denies GICv2 emulation support for KVM guests. It's probably not worth to introduce a special property for this v2 compat support, but if the lack of these registers is indicating that fact, it should be added here.

Regards,
Andre.

Quoted 31 lines
Documentation/devicetree/bindings/arm/gic-v3.txt new file +30 -0
+
+- interrupts : Interrupt source of the VGIC maintenance interrupt.
+
+Optional
+
+- redistributor-stride : If using padding pages, specifies the stride
+  of consecutive redistributors. Must be a multiple of 64kB.
+
+- #redistributor-regions: The number of independent contiguous regions
+  occupied by the redistributors. Required if more than one such
+  region is present.
+
+Examples:
+
+     gic: interrupt-controller at 2cf00000 {
+             compatible = "arm,gic-v3";
+             #interrupt-cells = <3>;
+             interrupt-controller;
+             reg = <0x0 0x2f000000 0 0x10000>,       // GICD
+                   <0x0 0x2f100000 0 0x200000>,      // GICR
+                   <0x0 0x2c000000 0 0x2000>,        // GICC
+                   <0x0 0x2c010000 0 0x2000>,        // GICH
+                   <0x0 0x2c020000 0 0x2000>;        // GICV
+             interrupts = <1 9 4>;
+     };
+
+     gic: interrupt-controller at 2c010000 {
+             compatible = "arm,gic-v3";
+             #interrupt-cells = <3>;
+             interrupt-controller;

Documentation/devicetree/bindings/arm/gic-v3.txt line 79

Quoted 10 lines
Documentation/devicetree/bindings/arm/gic-v3.txt new file +10 -0
+             redistributor-stride = <0x0 0x40000>;   // 256kB stride
+             #redistributor-regions = <2>;
+             reg = <0x0 0x2c010000 0 0x10000>,       // GICD
+                   <0x0 0x2d000000 0 0x800000>,      // GICR 1: CPUs 0-31
+                   <0x0 0x2e000000 0 0x800000>;      // GICR 2: CPUs 32-63
+                   <0x0 0x2c040000 0 0x2000>,        // GICC
+                   <0x0 0x2c060000 0 0x2000>,        // GICH
+                   <0x0 0x2c080000 0 0x2000>;        // GICV
+             interrupts = <1 9 4>;
+     };

-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590 ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782

#14 lore raw

PATCH v4 3/20 arm64: GICv3 device tree binding documentation

Hi Andre,

Quoted 56 lines · Andre Przywara
Quoted 55 lines · Marc Zyngier

Add the necessary documentation to support GICv3.

---
 Documentation/devicetree/bindings/arm/gic-v3.txt | 79
++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
Documentation/devicetree/bindings/arm/gic-v3.txt new file +34 -0
new file mode 100644
index 0000000..33cd05e
@@ -0,0 +1,79 @@
+* ARM Generic Interrupt Controller, version 3
+
+AArch64 SMP cores are often associated with a GICv3, providing Private
+Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
+Software Generated Interrupts (SGI), and Locality-specific Peripheral
+Interrupts (LPI).
+
+Main node required properties:
+
+- compatible : should at least contain  "arm,gic-v3".
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. Must be a single cell with a value of at least 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts. Other values are reserved for future use.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987]. PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+	bits[3:0] trigger type and level flags.
+		1 = edge triggered
+		4 = level triggered
+
+  Cells 4 and beyond are reserved for future use. When the 1st cell
+  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
+  ignored. It is recommended that padding cells have a value of 0.
+
+- reg : Specifies base physical address(s) and size of the GIC
+  registers, in the following order:
+  - GIC Distributor interface (GICD)
+  - GIC Redistributors (GICR), one range per redistributor region
Quoted 8 lines

Documentation/devicetree/bindings/arm/gic-v3.txt line 39

Quoted 5 lines
Documentation/devicetree/bindings/arm/gic-v3.txt new file +5 -0
+  - GIC CPU interface (GICC)
+  - GIC Hypervisor interface (GICH)
+  - GIC Virtual CPU interface (GICV)
+
+  GICC, GICH and GICV are optional.

I wonder if it should be noted here that a lack of these last three regions denies GICv2 emulation support for KVM guests.

Only the lack of the last one prevents KVM from emulating a GICv2. But that's a software support issue, and does not impact the hardware description (which is what we're doing in this patch).

KVM can still use software emulation of GICv2 (just like we did back in the days...).

Quoted 3 lines

It's probably not worth to introduce a special property for this v2 compat support, but if the lack of these registers is indicating that fact, it should be added here.

Absence of these ranges just indicates that the OS must be GICv3 aware to boot (i.e can't be GICv2 only). I don't think that how this information is used for guests is relevant to the DT documentation.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#15 lore raw

PATCH v4 3/20 arm64: GICv3 device tree binding documentation

On 05/20/2014 05:32 PM, Marc Zyngier wrote:

Hi Marc,

Quoted 67 lines · Andre Przywara
Quoted 56 lines · Marc Zyngier
Quoted 55 lines

Add the necessary documentation to support GICv3.

---
 Documentation/devicetree/bindings/arm/gic-v3.txt | 79
++++++++++++++++++++++++
 1 file changed, 79 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
Documentation/devicetree/bindings/arm/gic-v3.txt new file +34 -0
new file mode 100644
index 0000000..33cd05e
@@ -0,0 +1,79 @@
+* ARM Generic Interrupt Controller, version 3
+
+AArch64 SMP cores are often associated with a GICv3, providing Private
+Peripheral Interrupts (PPI), Shared Peripheral Interrupts (SPI),
+Software Generated Interrupts (SGI), and Locality-specific Peripheral
+Interrupts (LPI).
+
+Main node required properties:
+
+- compatible : should at least contain  "arm,gic-v3".
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. Must be a single cell with a value of at least 3.
+
+  The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
+  interrupts. Other values are reserved for future use.
+
+  The 2nd cell contains the interrupt number for the interrupt type.
+  SPI interrupts are in the range [0-987]. PPI interrupts are in the
+  range [0-15].
+
+  The 3rd cell is the flags, encoded as follows:
+   bits[3:0] trigger type and level flags.
+           1 = edge triggered
+           4 = level triggered
+
+  Cells 4 and beyond are reserved for future use. When the 1st cell
+  has a value of 0 or 1, cells 4 and beyond act as padding, and may be
+  ignored. It is recommended that padding cells have a value of 0.
+
+- reg : Specifies base physical address(s) and size of the GIC
+  registers, in the following order:
+  - GIC Distributor interface (GICD)
+  - GIC Redistributors (GICR), one range per redistributor region
Quoted 8 lines

Documentation/devicetree/bindings/arm/gic-v3.txt line 39

Quoted 5 lines
Documentation/devicetree/bindings/arm/gic-v3.txt new file +5 -0
+  - GIC CPU interface (GICC)
+  - GIC Hypervisor interface (GICH)
+  - GIC Virtual CPU interface (GICV)
+
+  GICC, GICH and GICV are optional.

I wonder if it should be noted here that a lack of these last three regions denies GICv2 emulation support for KVM guests.

Quoted 3 lines

Only the lack of the last one prevents KVM from emulating a GICv2. But that's a software support issue, and does not impact the hardware description (which is what we're doing in this patch).

But the lack of hardware vGICv2 compat support is a hardware feature. Either the GIC(v3) hardware supports it or not. Currently I am "guessing" this in my patch series based on the existence of these addresses in the DT. Based on this bit I allow an instantiation of a virtual GICv2 in the guest or require a GICv3.
I'd just like to see this documented.

Quoted 2 lines

KVM can still use software emulation of GICv2 (just like we did back in the days...).

But KVM would need to know whether it can use the hardware emulation bits or not. I am fine with deducing this from the existence of some registers, but would like to see this officially stated here.

Cheers,
Andre.

Quoted 4 lines
Quoted 3 lines

It's probably not worth to introduce a special property for this v2 compat support, but if the lack of these registers is indicating that fact, it should be added here.

Quoted 9 lines

Absence of these ranges just indicates that the OS must be GICv3 aware to boot (i.e can't be GICv2 only).
I don't think that how this
information is used for guests is relevant to the DT documentation.

Thanks,

      M.

-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2557590 ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England & Wales, Company No: 2548782

#16 lore raw

PATCH v4 4/20 arm64: boot protocol documentation update for GICv3

In reply to Marc Zyngier

Linux has some requirements that must be satisfied in order to boot on a system built with a GICv3.

---
 Documentation/arm64/booting.txt | 6 ++++++
 1 file changed, 6 insertions(+)
Documentation/arm64/booting.txt +6 -0
index beb754e..fb9f772 100644
@@ -137,6 +137,12 @@ Before jumping into the kernel, the following conditions must be met:
   the kernel image will be entered must be initialised by software at a
   higher exception level to prevent execution in an UNKNOWN state.
 
+  For systems with a GICv3 interrupt controller, it is expected that:
+  - If EL3 is present, it must program ICC_SRE_EL3.Enable (bit 3) to
+    0b1 and ICC_SRE_EL3.SRE (bit 0) to 0b1.
+  - If the kernel is entered at EL1, EL2 must set ICC_SRE_EL2.Enable
+    (bit 3) to 0b1 and ICC_SRE_EL2.SRE (bit 0) to 0b1.
+
 The requirements described above for CPU mode, caches, MMUs, architected
 timers, coherency and system registers apply to all CPUs.  All CPUs must
 enter the kernel in the same exception level.
Signature · 1 line
1.8.3.4
#17 lore raw

PATCH v4 5/20 KVM: arm/arm64: vgic: move GICv2 registers to their own structure

In reply to Marc Zyngier

In order to make way for the GICv3 registers, move the v2-specific registers to their own structure.

---
 arch/arm/kernel/asm-offsets.c   | 14 +++++------
 arch/arm/kvm/interrupts_head.S  | 26 +++++++++----------
 arch/arm64/kernel/asm-offsets.c | 14 +++++------
 arch/arm64/kvm/hyp.S            | 26 +++++++++----------
 include/kvm/arm_vgic.h          | 20 +++++++++------
 virt/kvm/arm/vgic.c             | 56 ++++++++++++++++++++---------------------
 6 files changed, 81 insertions(+), 75 deletions(-)
arch/arm/kernel/asm-offsets.c +7 -7
index 85598b5..713e807 100644
@@ -182,13 +182,13 @@ int main(void)
   DEFINE(VCPU_HYP_PC,		offsetof(struct kvm_vcpu, arch.fault.hyp_pc));
 #ifdef CONFIG_KVM_ARM_VGIC
   DEFINE(VCPU_VGIC_CPU,		offsetof(struct kvm_vcpu, arch.vgic_cpu));
-  DEFINE(VGIC_CPU_HCR,		offsetof(struct vgic_cpu, vgic_hcr));
-  DEFINE(VGIC_CPU_VMCR,		offsetof(struct vgic_cpu, vgic_vmcr));
-  DEFINE(VGIC_CPU_MISR,		offsetof(struct vgic_cpu, vgic_misr));
-  DEFINE(VGIC_CPU_EISR,		offsetof(struct vgic_cpu, vgic_eisr));
-  DEFINE(VGIC_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_elrsr));
-  DEFINE(VGIC_CPU_APR,		offsetof(struct vgic_cpu, vgic_apr));
-  DEFINE(VGIC_CPU_LR,		offsetof(struct vgic_cpu, vgic_lr));
+  DEFINE(VGIC_V2_CPU_HCR,	offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
+  DEFINE(VGIC_V2_CPU_VMCR,	offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
+  DEFINE(VGIC_V2_CPU_MISR,	offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
+  DEFINE(VGIC_V2_CPU_EISR,	offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
+  DEFINE(VGIC_V2_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
+  DEFINE(VGIC_V2_CPU_APR,	offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
+  DEFINE(VGIC_V2_CPU_LR,	offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
   DEFINE(VGIC_CPU_NR_LR,	offsetof(struct vgic_cpu, nr_lr));
 #ifdef CONFIG_KVM_ARM_TIMER
   DEFINE(VCPU_TIMER_CNTV_CTL,	offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
arch/arm/kvm/interrupts_head.S +13 -13
index 76af9302..e4eaf30 100644
@@ -421,14 +421,14 @@ vcpu	.req	r0		@ vcpu pointer always in r0
 	ldr	r9, [r2, #GICH_ELRSR1]
 	ldr	r10, [r2, #GICH_APR]
 
-	str	r3, [r11, #VGIC_CPU_HCR]
-	str	r4, [r11, #VGIC_CPU_VMCR]
-	str	r5, [r11, #VGIC_CPU_MISR]
-	str	r6, [r11, #VGIC_CPU_EISR]
-	str	r7, [r11, #(VGIC_CPU_EISR + 4)]
-	str	r8, [r11, #VGIC_CPU_ELRSR]
-	str	r9, [r11, #(VGIC_CPU_ELRSR + 4)]
-	str	r10, [r11, #VGIC_CPU_APR]
+	str	r3, [r11, #VGIC_V2_CPU_HCR]
+	str	r4, [r11, #VGIC_V2_CPU_VMCR]
+	str	r5, [r11, #VGIC_V2_CPU_MISR]
+	str	r6, [r11, #VGIC_V2_CPU_EISR]
+	str	r7, [r11, #(VGIC_V2_CPU_EISR + 4)]
+	str	r8, [r11, #VGIC_V2_CPU_ELRSR]
+	str	r9, [r11, #(VGIC_V2_CPU_ELRSR + 4)]
+	str	r10, [r11, #VGIC_V2_CPU_APR]
 
 	/* Clear GICH_HCR */
 	mov	r5, #0
@@ -436,7 +436,7 @@ vcpu	.req	r0		@ vcpu pointer always in r0
 
 	/* Save list registers */
 	add	r2, r2, #GICH_LR0
-	add	r3, r11, #VGIC_CPU_LR
+	add	r3, r11, #VGIC_V2_CPU_LR
 	ldr	r4, [r11, #VGIC_CPU_NR_LR]
 1:	ldr	r6, [r2], #4
 	str	r6, [r3], #4
@@ -463,9 +463,9 @@ vcpu	.req	r0		@ vcpu pointer always in r0
 	add	r11, vcpu, #VCPU_VGIC_CPU
 
 	/* We only restore a minimal set of registers */
-	ldr	r3, [r11, #VGIC_CPU_HCR]
-	ldr	r4, [r11, #VGIC_CPU_VMCR]
-	ldr	r8, [r11, #VGIC_CPU_APR]
+	ldr	r3, [r11, #VGIC_V2_CPU_HCR]
+	ldr	r4, [r11, #VGIC_V2_CPU_VMCR]
+	ldr	r8, [r11, #VGIC_V2_CPU_APR]
 
 	str	r3, [r2, #GICH_HCR]
 	str	r4, [r2, #GICH_VMCR]
@@ -473,7 +473,7 @@ vcpu	.req	r0		@ vcpu pointer always in r0
 
 	/* Restore list registers */
 	add	r2, r2, #GICH_LR0
-	add	r3, r11, #VGIC_CPU_LR
+	add	r3, r11, #VGIC_V2_CPU_LR
 	ldr	r4, [r11, #VGIC_CPU_NR_LR]
 1:	ldr	r6, [r3], #4
 	str	r6, [r2], #4
arch/arm64/kernel/asm-offsets.c +7 -7
index 646f888..20fd488 100644
@@ -129,13 +129,13 @@ int main(void)
   DEFINE(KVM_TIMER_ENABLED,	offsetof(struct kvm, arch.timer.enabled));
   DEFINE(VCPU_KVM,		offsetof(struct kvm_vcpu, kvm));
   DEFINE(VCPU_VGIC_CPU,		offsetof(struct kvm_vcpu, arch.vgic_cpu));
-  DEFINE(VGIC_CPU_HCR,		offsetof(struct vgic_cpu, vgic_hcr));
-  DEFINE(VGIC_CPU_VMCR,		offsetof(struct vgic_cpu, vgic_vmcr));
-  DEFINE(VGIC_CPU_MISR,		offsetof(struct vgic_cpu, vgic_misr));
-  DEFINE(VGIC_CPU_EISR,		offsetof(struct vgic_cpu, vgic_eisr));
-  DEFINE(VGIC_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_elrsr));
-  DEFINE(VGIC_CPU_APR,		offsetof(struct vgic_cpu, vgic_apr));
-  DEFINE(VGIC_CPU_LR,		offsetof(struct vgic_cpu, vgic_lr));
+  DEFINE(VGIC_V2_CPU_HCR,	offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
+  DEFINE(VGIC_V2_CPU_VMCR,	offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
+  DEFINE(VGIC_V2_CPU_MISR,	offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
+  DEFINE(VGIC_V2_CPU_EISR,	offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
+  DEFINE(VGIC_V2_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
+  DEFINE(VGIC_V2_CPU_APR,	offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
+  DEFINE(VGIC_V2_CPU_LR,	offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
   DEFINE(VGIC_CPU_NR_LR,	offsetof(struct vgic_cpu, nr_lr));
   DEFINE(KVM_VTTBR,		offsetof(struct kvm, arch.vttbr));
   DEFINE(KVM_VGIC_VCTRL,	offsetof(struct kvm, arch.vgic.vctrl_base));
arch/arm64/kvm/hyp.S +13 -13
index 2c56012..cc1b471 100644
@@ -412,14 +412,14 @@ CPU_BE(	rev	w9,  w9  )
 CPU_BE(	rev	w10, w10 )
 CPU_BE(	rev	w11, w11 )
 
-	str	w4, [x3, #VGIC_CPU_HCR]
-	str	w5, [x3, #VGIC_CPU_VMCR]
-	str	w6, [x3, #VGIC_CPU_MISR]
-	str	w7, [x3, #VGIC_CPU_EISR]
-	str	w8, [x3, #(VGIC_CPU_EISR + 4)]
-	str	w9, [x3, #VGIC_CPU_ELRSR]
-	str	w10, [x3, #(VGIC_CPU_ELRSR + 4)]
-	str	w11, [x3, #VGIC_CPU_APR]
+	str	w4, [x3, #VGIC_V2_CPU_HCR]
+	str	w5, [x3, #VGIC_V2_CPU_VMCR]
+	str	w6, [x3, #VGIC_V2_CPU_MISR]
+	str	w7, [x3, #VGIC_V2_CPU_EISR]
+	str	w8, [x3, #(VGIC_V2_CPU_EISR + 4)]
+	str	w9, [x3, #VGIC_V2_CPU_ELRSR]
+	str	w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)]
+	str	w11, [x3, #VGIC_V2_CPU_APR]
 
 	/* Clear GICH_HCR */
 	str	wzr, [x2, #GICH_HCR]
@@ -427,7 +427,7 @@ CPU_BE(	rev	w11, w11 )
 	/* Save list registers */
 	add	x2, x2, #GICH_LR0
 	ldr	w4, [x3, #VGIC_CPU_NR_LR]
-	add	x3, x3, #VGIC_CPU_LR
+	add	x3, x3, #VGIC_V2_CPU_LR
 1:	ldr	w5, [x2], #4
 CPU_BE(	rev	w5, w5 )
 	str	w5, [x3], #4
@@ -452,9 +452,9 @@ CPU_BE(	rev	w5, w5 )
 	add	x3, x0, #VCPU_VGIC_CPU
 
 	/* We only restore a minimal set of registers */
-	ldr	w4, [x3, #VGIC_CPU_HCR]
-	ldr	w5, [x3, #VGIC_CPU_VMCR]
-	ldr	w6, [x3, #VGIC_CPU_APR]
+	ldr	w4, [x3, #VGIC_V2_CPU_HCR]
+	ldr	w5, [x3, #VGIC_V2_CPU_VMCR]
+	ldr	w6, [x3, #VGIC_V2_CPU_APR]
 CPU_BE(	rev	w4, w4 )
 CPU_BE(	rev	w5, w5 )
 CPU_BE(	rev	w6, w6 )
@@ -466,7 +466,7 @@ CPU_BE(	rev	w6, w6 )
 	/* Restore list registers */
 	add	x2, x2, #GICH_LR0
 	ldr	w4, [x3, #VGIC_CPU_NR_LR]
-	add	x3, x3, #VGIC_CPU_LR
+	add	x3, x3, #VGIC_V2_CPU_LR
 1:	ldr	w5, [x3], #4
 CPU_BE(	rev	w5, w5 )
 	str	w5, [x2], #4
include/kvm/arm_vgic.h +13 -7
index f27000f..f738e5a 100644
@@ -110,6 +110,16 @@ struct vgic_dist {
 #endif
 };
 
+struct vgic_v2_cpu_if {
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr[2];	/* Saved only */
+	u32		vgic_elrsr[2];	/* Saved only */
+	u32		vgic_apr;
+	u32		vgic_lr[VGIC_MAX_LRS];
+};
+
 struct vgic_cpu {
 #ifdef CONFIG_KVM_ARM_VGIC
 	/* per IRQ to LR mapping */
@@ -126,13 +136,9 @@ struct vgic_cpu {
 	int		nr_lr;
 
 	/* CPU vif control registers for world switch */
-	u32		vgic_hcr;
-	u32		vgic_vmcr;
-	u32		vgic_misr;	/* Saved only */
-	u32		vgic_eisr[2];	/* Saved only */
-	u32		vgic_elrsr[2];	/* Saved only */
-	u32		vgic_apr;
-	u32		vgic_lr[VGIC_MAX_LRS];
+	union {
+		struct vgic_v2_cpu_if	vgic_v2;
+	};
 #endif
 };
 
virt/kvm/arm/vgic.c +28 -28

161 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#18 lore raw

PATCH v4 6/20 KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives

In reply to Marc Zyngier

In order to split the various register manipulation from the main vgic code, introduce a vgic_ops structure, and start by abstracting the LR manipulation code with a couple of accessors.

---
 include/kvm/arm_vgic.h |  18 ++++++
 virt/kvm/arm/vgic.c    | 162 +++++++++++++++++++++++++++++++++----------------
 2 files changed, 128 insertions(+), 52 deletions(-)
include/kvm/arm_vgic.h +18 -0
index f738e5a..17bbe51 100644
@@ -68,6 +68,24 @@ struct vgic_bytemap {
 	u32 shared[VGIC_NR_SHARED_IRQS  / 4];
 };
 
+struct kvm_vcpu;
+
+#define LR_STATE_PENDING	(1 << 0)
+#define LR_STATE_ACTIVE		(1 << 1)
+#define LR_STATE_MASK		(3 << 0)
+#define LR_EOI_INT		(1 << 2)
+
+struct vgic_lr {
+	u16	irq;
+	u8	source;
+	u8	state;
+};
+
+struct vgic_ops {
+	struct vgic_lr	(*get_lr)(const struct kvm_vcpu *, int);
+	void	(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
+};
+
 struct vgic_dist {
 #ifdef CONFIG_KVM_ARM_VGIC
 	spinlock_t		lock;
virt/kvm/arm/vgic.c +110 -52

269 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#20 lore raw

PATCH v4 7/20 KVM: ARM: vgic: abstract access to the ELRSR bitmap

In reply to Marc Zyngier

Move the GICH_ELRSR access to its own functions, and add them to the vgic_ops structure.

---
 include/kvm/arm_vgic.h |  2 ++
 virt/kvm/arm/vgic.c    | 38 +++++++++++++++++++++++++++++++++-----
 2 files changed, 35 insertions(+), 5 deletions(-)
include/kvm/arm_vgic.h +2 -0
index 17bbe51..38864f5 100644
@@ -84,6 +84,8 @@ struct vgic_lr {
 struct vgic_ops {
 	struct vgic_lr	(*get_lr)(const struct kvm_vcpu *, int);
 	void	(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
+	void	(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
+	u64	(*get_elrsr)(const struct kvm_vcpu *vcpu);
 };
 
 struct vgic_dist {
virt/kvm/arm/vgic.c +33 -5
index 11408fe..8b73cd6 100644
@@ -1015,9 +1015,24 @@ static void vgic_v2_set_lr(struct kvm_vcpu *vcpu, int lr,
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_lr[lr] = lr_val;
 }
 
+static void vgic_v2_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
+				  struct vgic_lr lr_desc)
+{
+	if (!(lr_desc.state & LR_STATE_MASK))
+		set_bit(lr, (unsigned long *)vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr);
+}
+
+static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
+{
+	const u32 *elrsr = vcpu->arch.vgic_cpu.vgic_v2.vgic_elrsr;
+	return *(u64 *)elrsr;
+}
+
 static const struct vgic_ops vgic_ops = {
 	.get_lr			= vgic_v2_get_lr,
 	.set_lr			= vgic_v2_set_lr,
+	.sync_lr_elrsr		= vgic_v2_sync_lr_elrsr,
+	.get_elrsr		= vgic_v2_get_elrsr,
 };
 
 static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -1031,6 +1046,17 @@ static void vgic_set_lr(struct kvm_vcpu *vcpu, int lr,
 	vgic_ops.set_lr(vcpu, lr, vlr);
 }
 
+static void vgic_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
+			       struct vgic_lr vlr)
+{
+	vgic_ops.sync_lr_elrsr(vcpu, lr, vlr);
+}
+
+static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
+{
+	return vgic_ops.get_elrsr(vcpu);
+}
+
 static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
@@ -1260,7 +1286,7 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 			 * Despite being EOIed, the LR may not have
 			 * been marked as empty.
 			 */
-			set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr);
+			vgic_sync_lr_elrsr(vcpu, lr, vlr);
 		}
 	}
 
@@ -1278,14 +1304,17 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+	u64 elrsr;
+	unsigned long *elrsr_ptr;
 	int lr, pending;
 	bool level_pending;
 
 	level_pending = vgic_process_maintenance(vcpu);
+	elrsr = vgic_get_elrsr(vcpu);
+	elrsr_ptr = (unsigned long *)&elrsr;
 
 	/* Clear mappings for empty LRs */
-	for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr,
-			 vgic_cpu->nr_lr) {
+	for_each_set_bit(lr, elrsr_ptr, vgic_cpu->nr_lr) {
 		struct vgic_lr vlr;
 
 		if (!test_and_clear_bit(lr, vgic_cpu->lr_used))
@@ -1298,8 +1327,7 @@ static void __kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu)
 	}
 
 	/* Check if we still have something up our sleeve... */
-	pending = find_first_zero_bit((unsigned long *)vgic_cpu->vgic_v2.vgic_elrsr,
-				      vgic_cpu->nr_lr);
+	pending = find_first_zero_bit(elrsr_ptr, vgic_cpu->nr_lr);
 	if (level_pending || pending < vgic_cpu->nr_lr)
 		set_bit(vcpu->vcpu_id, &dist->irq_pending_on_cpu);
 }
Signature · 1 line
1.8.3.4
#22 lore raw

PATCH v4 8/20 KVM: ARM: vgic: abstract EISR bitmap access

In reply to Marc Zyngier

Move the GICH_EISR access to its own function.

---
 include/kvm/arm_vgic.h |  1 +
 virt/kvm/arm/vgic.c    | 17 +++++++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)
include/kvm/arm_vgic.h +1 -0
index 38864f5..ccb9b59 100644
@@ -86,6 +86,7 @@ struct vgic_ops {
 	void	(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
 	void	(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
 	u64	(*get_elrsr)(const struct kvm_vcpu *vcpu);
+	u64	(*get_eisr)(const struct kvm_vcpu *vcpu);
 };
 
 struct vgic_dist {
virt/kvm/arm/vgic.c +15 -2
index 8b73cd6..0d9701c 100644
@@ -1028,11 +1028,18 @@ static u64 vgic_v2_get_elrsr(const struct kvm_vcpu *vcpu)
 	return *(u64 *)elrsr;
 }
 
+static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
+{
+	const u32 *eisr = vcpu->arch.vgic_cpu.vgic_v2.vgic_eisr;
+	return *(u64 *)eisr;
+}
+
 static const struct vgic_ops vgic_ops = {
 	.get_lr			= vgic_v2_get_lr,
 	.set_lr			= vgic_v2_set_lr,
 	.sync_lr_elrsr		= vgic_v2_sync_lr_elrsr,
 	.get_elrsr		= vgic_v2_get_elrsr,
+	.get_eisr		= vgic_v2_get_eisr,
 };
 
 static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -1057,6 +1064,11 @@ static inline u64 vgic_get_elrsr(struct kvm_vcpu *vcpu)
 	return vgic_ops.get_elrsr(vcpu);
 }
 
+static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
+{
+	return vgic_ops.get_eisr(vcpu);
+}
+
 static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
@@ -1263,10 +1275,11 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 		 * Some level interrupts have been EOIed. Clear their
 		 * active bit.
 		 */
+		u64 eisr = vgic_get_eisr(vcpu);
+		unsigned long *eisr_ptr = (unsigned long *)&eisr;
 		int lr;
 
-		for_each_set_bit(lr, (unsigned long *)vgic_cpu->vgic_v2.vgic_eisr,
-				 vgic_cpu->nr_lr) {
+		for_each_set_bit(lr, eisr_ptr, vgic_cpu->nr_lr) {
 			struct vgic_lr vlr = vgic_get_lr(vcpu, lr);
 
 			vgic_irq_clear_active(vcpu, vlr.irq);
Signature · 1 line
1.8.3.4
#23 lore raw

PATCH v4 9/20 KVM: ARM: vgic: abstract MISR decoding

In reply to Marc Zyngier

Instead of directly dealing with the GICH_MISR bits, move the code to its own function and use a couple of public flags to represent the actual state.

---
 include/kvm/arm_vgic.h |  4 ++++
 virt/kvm/arm/vgic.c    | 26 +++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)
include/kvm/arm_vgic.h +4 -0
index ccb9b59..4857508 100644
@@ -87,6 +87,7 @@ struct vgic_ops {
 	void	(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr);
 	u64	(*get_elrsr)(const struct kvm_vcpu *vcpu);
 	u64	(*get_eisr)(const struct kvm_vcpu *vcpu);
+	u32	(*get_interrupt_status)(const struct kvm_vcpu *vcpu);
 };
 
 struct vgic_dist {
@@ -165,6 +166,9 @@ struct vgic_cpu {
 
 #define LR_EMPTY	0xff
 
+#define INT_STATUS_EOI		(1 << 0)
+#define INT_STATUS_UNDERFLOW	(1 << 1)
+
 struct kvm;
 struct kvm_vcpu;
 struct kvm_run;
virt/kvm/arm/vgic.c +23 -3
index 0d9701c..9491c22 100644
@@ -1034,12 +1034,26 @@ static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu)
 	return *(u64 *)eisr;
 }
 
+static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
+{
+	u32 misr = vcpu->arch.vgic_cpu.vgic_v2.vgic_misr;
+	u32 ret = 0;
+
+	if (misr & GICH_MISR_EOI)
+		ret |= INT_STATUS_EOI;
+	if (misr & GICH_MISR_U)
+		ret |= INT_STATUS_UNDERFLOW;
+
+	return ret;
+}
+
 static const struct vgic_ops vgic_ops = {
 	.get_lr			= vgic_v2_get_lr,
 	.set_lr			= vgic_v2_set_lr,
 	.sync_lr_elrsr		= vgic_v2_sync_lr_elrsr,
 	.get_elrsr		= vgic_v2_get_elrsr,
 	.get_eisr		= vgic_v2_get_eisr,
+	.get_interrupt_status	= vgic_v2_get_interrupt_status,
 };
 
 static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -1069,6 +1083,11 @@ static inline u64 vgic_get_eisr(struct kvm_vcpu *vcpu)
 	return vgic_ops.get_eisr(vcpu);
 }
 
+static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
+{
+	return vgic_ops.get_interrupt_status(vcpu);
+}
+
 static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
@@ -1266,11 +1285,12 @@ epilog:
 static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+	u32 status = vgic_get_interrupt_status(vcpu);
 	bool level_pending = false;
 
-	kvm_debug("MISR = %08x\n", vgic_cpu->vgic_v2.vgic_misr);
+	kvm_debug("STATUS = %08x\n", status);
 
-	if (vgic_cpu->vgic_v2.vgic_misr & GICH_MISR_EOI) {
+	if (status & INT_STATUS_EOI) {
 		/*
 		 * Some level interrupts have been EOIed. Clear their
 		 * active bit.
@@ -1303,7 +1323,7 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 		}
 	}
 
-	if (vgic_cpu->vgic_v2.vgic_misr & GICH_MISR_U)
+	if (status & INT_STATUS_UNDERFLOW)
 		vgic_cpu->vgic_v2.vgic_hcr &= ~GICH_HCR_UIE;
 
 	return level_pending;
Signature · 1 line
1.8.3.4
#24 lore raw

PATCH v4 10/20 KVM: ARM: vgic: move underflow handling to vgic_ops

In reply to Marc Zyngier

Move the code dealing with LR underflow handling to its own functions, and make them accessible through vgic_ops.

---
 include/kvm/arm_vgic.h |  2 ++
 virt/kvm/arm/vgic.c    | 28 +++++++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)
include/kvm/arm_vgic.h +2 -0
index 4857508..cdfa5d9 100644
@@ -88,6 +88,8 @@ struct vgic_ops {
 	u64	(*get_elrsr)(const struct kvm_vcpu *vcpu);
 	u64	(*get_eisr)(const struct kvm_vcpu *vcpu);
 	u32	(*get_interrupt_status)(const struct kvm_vcpu *vcpu);
+	void	(*enable_underflow)(struct kvm_vcpu *vcpu);
+	void	(*disable_underflow)(struct kvm_vcpu *vcpu);
 };
 
 struct vgic_dist {
virt/kvm/arm/vgic.c +25 -3
index 9491c22..369016c 100644
@@ -1047,6 +1047,16 @@ static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)
 	return ret;
 }
 
+static void vgic_v2_enable_underflow(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr |= GICH_HCR_UIE;
+}
+
+static void vgic_v2_disable_underflow(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr &= ~GICH_HCR_UIE;
+}
+
 static const struct vgic_ops vgic_ops = {
 	.get_lr			= vgic_v2_get_lr,
 	.set_lr			= vgic_v2_set_lr,
@@ -1054,6 +1064,8 @@ static const struct vgic_ops vgic_ops = {
 	.get_elrsr		= vgic_v2_get_elrsr,
 	.get_eisr		= vgic_v2_get_eisr,
 	.get_interrupt_status	= vgic_v2_get_interrupt_status,
+	.enable_underflow	= vgic_v2_enable_underflow,
+	.disable_underflow	= vgic_v2_disable_underflow,
 };
 
 static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -1088,6 +1100,16 @@ static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)
 	return vgic_ops.get_interrupt_status(vcpu);
 }
 
+static inline void vgic_enable_underflow(struct kvm_vcpu *vcpu)
+{
+	vgic_ops.enable_underflow(vcpu);
+}
+
+static inline void vgic_disable_underflow(struct kvm_vcpu *vcpu)
+{
+	vgic_ops.disable_underflow(vcpu);
+}
+
 static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
@@ -1269,9 +1291,9 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 
 epilog:
 	if (overflow) {
-		vgic_cpu->vgic_v2.vgic_hcr |= GICH_HCR_UIE;
+		vgic_enable_underflow(vcpu);
 	} else {
-		vgic_cpu->vgic_v2.vgic_hcr &= ~GICH_HCR_UIE;
+		vgic_disable_underflow(vcpu);
 		/*
 		 * We're about to run this VCPU, and we've consumed
 		 * everything the distributor had in store for
@@ -1324,7 +1346,7 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
 	}
 
 	if (status & INT_STATUS_UNDERFLOW)
-		vgic_cpu->vgic_v2.vgic_hcr &= ~GICH_HCR_UIE;
+		vgic_disable_underflow(vcpu);
 
 	return level_pending;
 }
Signature · 1 line
1.8.3.4
#25 lore raw

PATCH v4 11/20 KVM: ARM: vgic: abstract VMCR access

In reply to Marc Zyngier

Instead of directly messing with with the GICH_VMCR bits for the CPU interface save/restore code, add accessors that encode/decode the entire set of registers exposed by VMCR.

Not the most efficient thing, but given that this code is only used by the save/restore code, performance is far from being critical.

---
 include/kvm/arm_vgic.h |  9 +++++++
 virt/kvm/arm/vgic.c    | 69 ++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 62 insertions(+), 16 deletions(-)
include/kvm/arm_vgic.h +9 -0
index cdfa5d9..f515800 100644
@@ -81,6 +81,13 @@ struct vgic_lr {
 	u8	state;
 };
 
+struct vgic_vmcr {
+	u32	ctlr;
+	u32	abpr;
+	u32	bpr;
+	u32	pmr;
+};
+
 struct vgic_ops {
 	struct vgic_lr	(*get_lr)(const struct kvm_vcpu *, int);
 	void	(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr);
@@ -90,6 +97,8 @@ struct vgic_ops {
 	u32	(*get_interrupt_status)(const struct kvm_vcpu *vcpu);
 	void	(*enable_underflow)(struct kvm_vcpu *vcpu);
 	void	(*disable_underflow)(struct kvm_vcpu *vcpu);
+	void	(*get_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+	void	(*set_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 };
 
 struct vgic_dist {
virt/kvm/arm/vgic.c +53 -16

118 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#26 lore raw

PATCH v4 11/20 KVM: ARM: vgic: abstract VMCR access

Quoted 8 lines · Marc Zyngier

Instead of directly messing with with the GICH_VMCR bits for the CPU interface save/restore code, add accessors that encode/decode the entire set of registers exposed by VMCR.

Not the most efficient thing, but given that this code is only used by the save/restore code, performance is far from being critical.

#27 lore raw

PATCH v4 12/20 KVM: ARM: vgic: introduce vgic_enable

In reply to Marc Zyngier

Move the code dealing with enabling the VGIC on to vgic_ops.

---
 include/kvm/arm_vgic.h |  1 +
 virt/kvm/arm/vgic.c    | 29 +++++++++++++++++++++--------
 2 files changed, 22 insertions(+), 8 deletions(-)
include/kvm/arm_vgic.h +1 -0
index f515800..2228973 100644
@@ -99,6 +99,7 @@ struct vgic_ops {
 	void	(*disable_underflow)(struct kvm_vcpu *vcpu);
 	void	(*get_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 	void	(*set_vmcr)(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
+	void	(*enable)(struct kvm_vcpu *vcpu);
 };
 
 struct vgic_dist {
virt/kvm/arm/vgic.c +21 -8
index b097a2c..383db29 100644
@@ -1081,6 +1081,19 @@ static void vgic_v2_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
 	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = vmcr;
 }
 
+static void vgic_v2_enable(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_vmcr = 0;
+
+	/* Get the show on the road... */
+	vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr = GICH_HCR_EN;
+}
+
 static const struct vgic_ops vgic_ops = {
 	.get_lr			= vgic_v2_get_lr,
 	.set_lr			= vgic_v2_set_lr,
@@ -1092,6 +1105,7 @@ static const struct vgic_ops vgic_ops = {
 	.disable_underflow	= vgic_v2_disable_underflow,
 	.get_vmcr		= vgic_v2_get_vmcr,
 	.set_vmcr		= vgic_v2_set_vmcr,
+	.enable			= vgic_v2_enable,
 };
 
 static struct vgic_lr vgic_get_lr(const struct kvm_vcpu *vcpu, int lr)
@@ -1146,6 +1160,11 @@ static void vgic_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr)
 	vgic_ops.set_vmcr(vcpu, vmcr);
 }
 
+static inline void vgic_enable(struct kvm_vcpu *vcpu)
+{
+	vgic_ops.enable(vcpu);
+}
+
 static void vgic_retire_lr(int lr_nr, int irq, struct kvm_vcpu *vcpu)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
@@ -1608,15 +1627,9 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 		vgic_cpu->vgic_irq_lr_map[i] = LR_EMPTY;
 	}
 
-	/*
-	 * By forcing VMCR to zero, the GIC will restore the binary
-	 * points to their reset values. Anything else resets to zero
-	 * anyway.
-	 */
-	vgic_cpu->vgic_v2.vgic_vmcr = 0;
-
 	vgic_cpu->nr_lr = vgic_nr_lr;
-	vgic_cpu->vgic_v2.vgic_hcr = GICH_HCR_EN; /* Get the show on the road... */
+
+	vgic_enable(vcpu);
 
 	return 0;
 }
Signature · 1 line
1.8.3.4
#28 lore raw

PATCH v4 13/20 KVM: ARM: introduce vgic_params structure

In reply to Marc Zyngier

Move all the data specific to a given GIC implementation into its own little structure.

---
 include/kvm/arm_vgic.h | 11 ++++++++
 virt/kvm/arm/vgic.c    | 70 ++++++++++++++++++++++++--------------------------
 2 files changed, 44 insertions(+), 37 deletions(-)
include/kvm/arm_vgic.h +11 -0
index 2228973..ce2e142 100644
@@ -102,6 +102,17 @@ struct vgic_ops {
 	void	(*enable)(struct kvm_vcpu *vcpu);
 };
 
+struct vgic_params {
+	/* Physical address of vgic virtual cpu interface */
+	phys_addr_t	vcpu_base;
+	/* Number of list registers */
+	u32		nr_lr;
+	/* Interrupt number */
+	unsigned int	maint_irq;
+	/* Virtual control interface base address */
+	void __iomem	*vctrl_base;
+};
+
 struct vgic_dist {
 #ifdef CONFIG_KVM_ARM_VGIC
 	spinlock_t		lock;
virt/kvm/arm/vgic.c +33 -37

196 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#29 lore raw

PATCH v4 14/20 KVM: ARM: vgic: split GICv2 backend from the main vgic code

In reply to Marc Zyngier

Brutally hack the innocent vgic code, and move the GICv2 specific code to its own file, using vgic_ops and vgic_params as a way to pass information between the two blocks.

---
 arch/arm/kvm/Makefile   |   1 +
 arch/arm64/kvm/Makefile |   2 +-
 include/kvm/arm_vgic.h  |  11 ++-
 virt/kvm/arm/vgic-v2.c  | 235 +++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.c     | 251 +++++++++---------------------------------------
 5 files changed, 291 insertions(+), 209 deletions(-)
 create mode 100644 virt/kvm/arm/vgic-v2.c
arch/arm/kvm/Makefile +1 -0
index 789bca9..f7057ed 100644
@@ -21,4 +21,5 @@ obj-y += kvm-arm.o init.o interrupts.o
 obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o
 obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o
 obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
 obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
arch/arm64/kvm/Makefile +1 -1
index 72a9fd5..7e92952 100644
@@ -19,5 +19,5 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
 
-kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
include/kvm/arm_vgic.h +8 -3
index ce2e142..d8d52a9 100644
@@ -32,7 +32,8 @@
 #define VGIC_NR_PRIVATE_IRQS	(VGIC_NR_SGIS + VGIC_NR_PPIS)
 #define VGIC_NR_SHARED_IRQS	(VGIC_NR_IRQS - VGIC_NR_PRIVATE_IRQS)
 #define VGIC_MAX_CPUS		KVM_MAX_VCPUS
-#define VGIC_MAX_LRS		(1 << 6)
+
+#define VGIC_V2_MAX_LRS		(1 << 6)
 
 /* Sanity checks... */
 #if (VGIC_MAX_CPUS > 8)
@@ -162,7 +163,7 @@ struct vgic_v2_cpu_if {
 	u32		vgic_eisr[2];	/* Saved only */
 	u32		vgic_elrsr[2];	/* Saved only */
 	u32		vgic_apr;
-	u32		vgic_lr[VGIC_MAX_LRS];
+	u32		vgic_lr[VGIC_V2_MAX_LRS];
 };
 
 struct vgic_cpu {
@@ -175,7 +176,7 @@ struct vgic_cpu {
 	DECLARE_BITMAP(	pending_shared, VGIC_NR_SHARED_IRQS);
 
 	/* Bitmap of used/free list registers */
-	DECLARE_BITMAP(	lr_used, VGIC_MAX_LRS);
+	DECLARE_BITMAP(	lr_used, VGIC_V2_MAX_LRS);
 
 	/* Number of list registers on this CPU */
 	int		nr_lr;
@@ -214,6 +215,10 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
 #define irqchip_in_kernel(k)	(!!((k)->arch.vgic.vctrl_base))
 #define vgic_initialized(k)	((k)->arch.vgic.ready)
 
+int vgic_v2_probe(struct device_node *vgic_node,
+		  const struct vgic_ops **ops,
+		  const struct vgic_params **params);
+
 #else
 static inline int kvm_vgic_hyp_init(void)
 {
virt/kvm/arm/vgic-v2.c new file +235 -0

235 lines not on this page · raw message

virt/kvm/arm/vgic.c +46 -205

394 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#30 lore raw

PATCH v4 15/20 KVM: ARM: vgic: revisit implementation of irqchip_in_kernel

In reply to Marc Zyngier

So far, irqchip_in_kernel() was implemented by testing the value of vctrl_base, which worked fine with GICv2.

With GICv3, this field is useless, as we're using system registers instead of a emmory mapped interface. To solve this, add a boolean flag indicating if the we're using a vgic or not.

---
 include/kvm/arm_vgic.h | 3 ++-
 virt/kvm/arm/vgic.c    | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)
include/kvm/arm_vgic.h +2 -1
index d8d52a9..f6b9fec 100644
@@ -117,6 +117,7 @@ struct vgic_params {
 struct vgic_dist {
 #ifdef CONFIG_KVM_ARM_VGIC
 	spinlock_t		lock;
+	bool			in_kernel;
 	bool			ready;
 
 	/* Virtual control interface mapping */
@@ -212,7 +213,7 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
 bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		      struct kvm_exit_mmio *mmio);
 
-#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.vctrl_base))
+#define irqchip_in_kernel(k)	(!!((k)->arch.vgic.in_kernel))
 #define vgic_initialized(k)	((k)->arch.vgic.ready)
 
 int vgic_v2_probe(struct device_node *vgic_node,
virt/kvm/arm/vgic.c +1 -0
index e4b9cbb..1348e74 100644
@@ -1650,6 +1650,7 @@ int kvm_vgic_create(struct kvm *kvm)
 	}
 
 	spin_lock_init(&kvm->arch.vgic.lock);
+	kvm->arch.vgic.in_kernel = true;
 	kvm->arch.vgic.vctrl_base = vgic->vctrl_base;
 	kvm->arch.vgic.vgic_dist_base = VGIC_ADDR_UNDEF;
 	kvm->arch.vgic.vgic_cpu_base = VGIC_ADDR_UNDEF;
Signature · 1 line
1.8.3.4
#31 lore raw

PATCH v4 15/20 KVM: ARM: vgic: revisit implementation of irqchip_in_kernel

Quoted 8 lines · Marc Zyngier

So far, irqchip_in_kernel() was implemented by testing the value of vctrl_base, which worked fine with GICv2.

With GICv3, this field is useless, as we're using system registers instead of a emmory mapped interface. To solve this, add a boolean flag indicating if the we're using a vgic or not.

#32 lore raw

PATCH v4 16/20 arm64: KVM: remove __kvm_hyp_code_{start, end} from hyp.S

In reply to Marc Zyngier

We already have __hyp_text_{start,end} to express the boundaries of the HYP text section, and __kvm_hyp_code_{start,end} are getting in the way of a more modular world switch code.

Just turn __kvm_hyp_code_{start,end} into #defines mapping the linker-emited symbols.

---
 arch/arm64/include/asm/kvm_asm.h | 6 ++++--
 arch/arm64/include/asm/virt.h    | 4 ++++
 arch/arm64/kvm/hyp.S             | 6 ------
 3 files changed, 8 insertions(+), 8 deletions(-)
arch/arm64/include/asm/kvm_asm.h +4 -2
index 9fcd54b..d0bfc4b 100644
@@ -18,6 +18,8 @@
 #ifndef __ARM_KVM_ASM_H__
 #define __ARM_KVM_ASM_H__
 
+#include <asm/virt.h>
+
 /*
  * 0 is reserved as an invalid value.
  * Order *must* be kept in sync with the hyp switch code.
@@ -96,8 +98,8 @@ extern char __kvm_hyp_init_end[];
 
 extern char __kvm_hyp_vector[];
 
-extern char __kvm_hyp_code_start[];
-extern char __kvm_hyp_code_end[];
+#define	__kvm_hyp_code_start	__hyp_text_start
+#define	__kvm_hyp_code_end	__hyp_text_end
 
 extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
arch/arm64/include/asm/virt.h +4 -0
index 215ad46..7a5df52 100644
@@ -50,6 +50,10 @@ static inline bool is_hyp_mode_mismatched(void)
 	return __boot_cpu_mode[0] != __boot_cpu_mode[1];
 }
 
+/* The section containing the hypervisor text */
+extern char __hyp_text_start[];
+extern char __hyp_text_end[];
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* ! __ASM__VIRT_H */
arch/arm64/kvm/hyp.S +0 -6
index cc1b471..9e3364b 100644
@@ -36,9 +36,6 @@
 	.pushsection	.hyp.text, "ax"
 	.align	PAGE_SHIFT
 
-__kvm_hyp_code_start:
-	.globl __kvm_hyp_code_start
-
 .macro save_common_regs
 	// x2: base address for cpu context
 	// x3: tmp register
@@ -874,7 +871,4 @@ ENTRY(__kvm_hyp_vector)
 	ventry	el1_error_invalid		// Error 32-bit EL1
 ENDPROC(__kvm_hyp_vector)
 
-__kvm_hyp_code_end:
-	.globl	__kvm_hyp_code_end
-
 	.popsection
Signature · 1 line
1.8.3.4
#33 lore raw

PATCH v4 17/20 arm64: KVM: split GICv2 world switch from hyp code

In reply to Marc Zyngier

Move the GICv2 world switch code into its own file, and add the necessary indirection to the arm64 switch code.

Also introduce a new type field to the vgic_params structure.

---
 arch/arm/include/asm/kvm_host.h   |   5 ++
 arch/arm64/include/asm/kvm_asm.h  |   4 ++
 arch/arm64/include/asm/kvm_host.h |  21 ++++++
 arch/arm64/kernel/asm-offsets.c   |   3 +
 arch/arm64/kvm/Makefile           |   4 +-
 arch/arm64/kvm/hyp.S              | 104 +++++------------------------
 arch/arm64/kvm/vgic-v2-switch.S   | 133 ++++++++++++++++++++++++++++++++++++++
 include/kvm/arm_vgic.h            |   7 +-
 virt/kvm/arm/vgic-v2.c            |   1 +
 virt/kvm/arm/vgic.c               |   3 +
 10 files changed, 195 insertions(+), 90 deletions(-)
 create mode 100644 arch/arm64/kvm/vgic-v2-switch.S
arch/arm/include/asm/kvm_host.h +5 -0
index 09af149..86be18c 100644
@@ -225,6 +225,11 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext)
 	return 0;
 }
 
+static inline void vgic_arch_setup(const struct vgic_params *vgic)
+{
+	BUG_ON(vgic->type != VGIC_V2);
+}
+
 int kvm_perf_init(void);
 int kvm_perf_teardown(void);
 
arch/arm64/include/asm/kvm_asm.h +4 -0
index d0bfc4b..6252264 100644
@@ -105,6 +105,10 @@ extern void __kvm_flush_vm_context(void);
 extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+
+extern char __save_vgic_v2_state[];
+extern char __restore_vgic_v2_state[];
+
 #endif
 
 #endif /* __ARM_KVM_ASM_H__ */
arch/arm64/include/asm/kvm_host.h +21 -0
index 0a1d697..65f0c43 100644
@@ -200,4 +200,25 @@ static inline void __cpu_init_hyp_mode(phys_addr_t boot_pgd_ptr,
 		     hyp_stack_ptr, vector_ptr);
 }
 
+struct vgic_sr_vectors {
+	void	*save_vgic;
+	void	*restore_vgic;
+};
+
+static inline void vgic_arch_setup(const struct vgic_params *vgic)
+{
+	extern struct vgic_sr_vectors __vgic_sr_vectors;
+
+	switch(vgic->type)
+	{
+	case VGIC_V2:
+		__vgic_sr_vectors.save_vgic	= __save_vgic_v2_state;
+		__vgic_sr_vectors.restore_vgic	= __restore_vgic_v2_state;
+		break;
+
+	default:
+		BUG();
+	}
+}
+
 #endif /* __ARM64_KVM_HOST_H__ */
arch/arm64/kernel/asm-offsets.c +3 -0
index 20fd488..dafc415 100644
@@ -129,6 +129,9 @@ int main(void)
   DEFINE(KVM_TIMER_ENABLED,	offsetof(struct kvm, arch.timer.enabled));
   DEFINE(VCPU_KVM,		offsetof(struct kvm_vcpu, kvm));
   DEFINE(VCPU_VGIC_CPU,		offsetof(struct kvm_vcpu, arch.vgic_cpu));
+  DEFINE(VGIC_SAVE_FN,		offsetof(struct vgic_sr_vectors, save_vgic));
+  DEFINE(VGIC_RESTORE_FN,	offsetof(struct vgic_sr_vectors, restore_vgic));
+  DEFINE(VGIC_SR_VECTOR_SZ,	sizeof(struct vgic_sr_vectors));
   DEFINE(VGIC_V2_CPU_HCR,	offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
   DEFINE(VGIC_V2_CPU_VMCR,	offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
   DEFINE(VGIC_V2_CPU_MISR,	offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
arch/arm64/kvm/Makefile +3 -1
index 7e92952..daf24dc 100644
@@ -19,5 +19,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o
 kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
 kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
 
-kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o $(KVM)/arm/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
+kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o
 kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
arch/arm64/kvm/hyp.S +16 -88

129 lines not on this page · raw message

arch/arm64/kvm/vgic-v2-switch.S new file +133 -0

133 lines not on this page · raw message

include/kvm/arm_vgic.h +6 -1
index f6b9fec..65f1121 100644
@@ -24,7 +24,6 @@
 #include <linux/irqreturn.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
-#include <linux/irqchip/arm-gic.h>
 
 #define VGIC_NR_IRQS		256
 #define VGIC_NR_SGIS		16
@@ -71,6 +70,10 @@ struct vgic_bytemap {
 
 struct kvm_vcpu;
 
+enum vgic_type {
+	VGIC_V2,		/* Good ol' GICv2 */
+};
+
 #define LR_STATE_PENDING	(1 << 0)
 #define LR_STATE_ACTIVE		(1 << 1)
 #define LR_STATE_MASK		(3 << 0)
@@ -104,6 +107,8 @@ struct vgic_ops {
 };
 
 struct vgic_params {
+	/* vgic type */
+	enum vgic_type	type;
 	/* Physical address of vgic virtual cpu interface */
 	phys_addr_t	vcpu_base;
 	/* Number of list registers */
virt/kvm/arm/vgic-v2.c +1 -0
index bf2ea86..a55a9a4 100644
@@ -223,6 +223,7 @@ int vgic_v2_probe(struct device_node *vgic_node,
 	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
 		 vctrl_res.start, vgic->maint_irq);
 
+	vgic->type = VGIC_V2;
 	*ops = &vgic_v2_ops;
 	*params = vgic;
 	goto out;
virt/kvm/arm/vgic.c +3 -0
index 1348e74..7867b9a 100644
@@ -1568,6 +1568,9 @@ int kvm_vgic_hyp_init(void)
 
 	on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
 
+	/* Callback into for arch code for setup */
+	vgic_arch_setup(vgic);
+
 	return 0;
 
 out_free_irq:
Signature · 1 line
1.8.3.4
#35 lore raw

PATCH v4 18/20 arm64: KVM: move HCR_EL2.{IMO, FMO} manipulation into the vgic switch code

In reply to Marc Zyngier

GICv3 requires the IMO and FMO bits to be tightly coupled with some of the interrupt controller's register switch.

In order to have similar code paths, move the manipulation of these bits to the GICv2 switch code.

---
 arch/arm64/include/asm/kvm_arm.h |  5 +++--
 arch/arm64/kvm/hyp.S             | 17 ++++++++++++-----
 2 files changed, 15 insertions(+), 7 deletions(-)
arch/arm64/include/asm/kvm_arm.h +3 -2
index 3d69030..cc83520 100644
@@ -76,9 +76,10 @@
  */
 #define HCR_GUEST_FLAGS (HCR_TSC | HCR_TSW | HCR_TWE | HCR_TWI | HCR_VM | \
 			 HCR_TVM | HCR_BSU_IS | HCR_FB | HCR_TAC | \
-			 HCR_AMO | HCR_IMO | HCR_FMO | \
-			 HCR_SWIO | HCR_TIDCP | HCR_RW)
+			 HCR_AMO | HCR_SWIO | HCR_TIDCP | HCR_RW)
 #define HCR_VIRT_EXCP_MASK (HCR_VA | HCR_VI | HCR_VF)
+#define HCR_INT_OVERRIDE   (HCR_FMO | HCR_IMO)
+
 
 /* Hyp System Control Register (SCTLR_EL2) bits */
 #define SCTLR_EL2_EE	(1 << 25)
arch/arm64/kvm/hyp.S +12 -5
index 1757e78..646409a 100644
@@ -335,11 +335,8 @@
 .endm
 
 .macro activate_traps
-	ldr	x2, [x0, #VCPU_IRQ_LINES]
-	ldr	x1, [x0, #VCPU_HCR_EL2]
-	orr	x2, x2, x1
-	msr	hcr_el2, x2
-
+	ldr     x2, [x0, #VCPU_HCR_EL2]
+	msr     hcr_el2, x2
 	ldr	x2, =(CPTR_EL2_TTA)
 	msr	cptr_el2, x2
 
@@ -382,12 +379,22 @@
 	ldr	x24, [x24, VGIC_SAVE_FN]
 	kern_hyp_va	x24
 	blr	x24
+	mrs	x24, hcr_el2
+	mov	x25, #HCR_INT_OVERRIDE
+	neg	x25, x25
+	and	x24, x24, x25
+	msr	hcr_el2, x24
 .endm
 
 /*
  * Call into the vgic backend for state restoring
  */
 .macro restore_vgic_state
+	mrs	x24, hcr_el2
+	ldr	x25, [x0, #VCPU_IRQ_LINES]
+	orr	x24, x24, #HCR_INT_OVERRIDE
+	orr	x24, x24, x25
+	msr	hcr_el2, x24
 	adr	x24, __vgic_sr_vectors
 	ldr	x24, [x24, #VGIC_RESTORE_FN]
 	kern_hyp_va	x24
Signature · 1 line
1.8.3.4
#36 lore raw

PATCH v4 18/20 arm64: KVM: move HCR_EL2.{IMO, FMO} manipulation into the vgic switch code

Quoted 8 lines · Marc Zyngier

GICv3 requires the IMO and FMO bits to be tightly coupled with some of the interrupt controller's register switch.

In order to have similar code paths, move the manipulation of these bits to the GICv2 switch code.

#37 lore raw

PATCH v4 19/20 KVM: ARM: vgic: add the GICv3 backend

In reply to Marc Zyngier

Introduce the support code for emulating a GICv2 on top of GICv3 hardware.

---
 include/kvm/arm_vgic.h |  28 ++++++
 virt/kvm/arm/vgic-v3.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 virt/kvm/arm/vgic-v3.c
include/kvm/arm_vgic.h +28 -0
index 65f1121..35b0c12 100644
@@ -33,6 +33,7 @@
 #define VGIC_MAX_CPUS		KVM_MAX_VCPUS
 
 #define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
 
 /* Sanity checks... */
 #if (VGIC_MAX_CPUS > 8)
@@ -72,6 +73,7 @@ struct kvm_vcpu;
 
 enum vgic_type {
 	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
 };
 
 #define LR_STATE_PENDING	(1 << 0)
@@ -172,6 +174,19 @@ struct vgic_v2_cpu_if {
 	u32		vgic_lr[VGIC_V2_MAX_LRS];
 };
 
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_ARM_GIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
 struct vgic_cpu {
 #ifdef CONFIG_KVM_ARM_VGIC
 	/* per IRQ to LR mapping */
@@ -190,6 +205,7 @@ struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
 	};
 #endif
 };
@@ -224,6 +240,18 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
 		  const struct vgic_params **params);
+#ifdef CONFIG_ARM_GIC_V3
+int vgic_v3_probe(struct device_node *vgic_node,
+		  const struct vgic_ops **ops,
+		  const struct vgic_params **params);
+#else
+static inline int vgic_v3_probe(struct device_node *vgic_node,
+				const struct vgic_ops **ops,
+				const struct vgic_params **params)
+{
+	return -ENODEV;
+}
+#endif
 
 #else
 static inline int kvm_vgic_hyp_init(void)
virt/kvm/arm/vgic-v3.c new file +225 -0

225 lines not on this page · raw message

Signature · 1 line
1.8.3.4
#38 lore raw

PATCH v4 19/20 KVM: ARM: vgic: add the GICv3 backend

Quoted 269 lines · Marc Zyngier

Introduce the support code for emulating a GICv2 on top of GICv3 hardware.

---
 include/kvm/arm_vgic.h |  28 ++++++
 virt/kvm/arm/vgic-v3.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 virt/kvm/arm/vgic-v3.c
include/kvm/arm_vgic.h +28 -0
index 65f1121..35b0c12 100644
@@ -33,6 +33,7 @@
 #define VGIC_MAX_CPUS		KVM_MAX_VCPUS
 
 #define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
 
 /* Sanity checks... */
 #if (VGIC_MAX_CPUS > 8)
@@ -72,6 +73,7 @@ struct kvm_vcpu;
 
 enum vgic_type {
 	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
 };
 
 #define LR_STATE_PENDING	(1 << 0)
@@ -172,6 +174,19 @@ struct vgic_v2_cpu_if {
 	u32		vgic_lr[VGIC_V2_MAX_LRS];
 };
 
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_ARM_GIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
 struct vgic_cpu {
 #ifdef CONFIG_KVM_ARM_VGIC
 	/* per IRQ to LR mapping */
@@ -190,6 +205,7 @@ struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
 	};
 #endif
 };
@@ -224,6 +240,18 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
 		  const struct vgic_params **params);
+#ifdef CONFIG_ARM_GIC_V3
+int vgic_v3_probe(struct device_node *vgic_node,
+		  const struct vgic_ops **ops,
+		  const struct vgic_params **params);
+#else
+static inline int vgic_v3_probe(struct device_node *vgic_node,
+				const struct vgic_ops **ops,
+				const struct vgic_params **params)
+{
+	return -ENODEV;
+}
+#endif
 
 #else
 static inline int kvm_vgic_hyp_init(void)
virt/kvm/arm/vgic-v3.c new file +185 -0
new file mode 100644
index 0000000..ecdec34
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2013 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+/* These are for GICv2 emulation only */
+#define GICH_LR_VIRTUALID		(0x3ffUL << 0)
+#define GICH_LR_PHYSID_CPUID_SHIFT	(10)
+#define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
+
+static u32 ich_vtr_el2;
+
+static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
+{
+	struct vgic_lr lr_desc;
+	u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
+
+	lr_desc.irq	= val & GICH_LR_VIRTUALID;
+	if (lr_desc.irq <= 15)
+		lr_desc.source	= (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
+	else
+		lr_desc.source = 0;
+	lr_desc.state	= 0;
+
+	if (val & GICH_LR_PENDING_BIT)
+		lr_desc.state |= LR_STATE_PENDING;
+	if (val & GICH_LR_ACTIVE_BIT)
+		lr_desc.state |= LR_STATE_ACTIVE;
+	if (val & GICH_LR_EOI)
+		lr_desc.state |= LR_EOI_INT;
+
+	return lr_desc;
+}
+
+static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
+			   struct vgic_lr lr_desc)
+{
+	u64 lr_val = (((u32)lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT) |
+		      lr_desc.irq);
+
+	if (lr_desc.state & LR_STATE_PENDING)
+		lr_val |= GICH_LR_PENDING_BIT;
+	if (lr_desc.state & LR_STATE_ACTIVE)
+		lr_val |= GICH_LR_ACTIVE_BIT;
+	if (lr_desc.state & LR_EOI_INT)
+		lr_val |= GICH_LR_EOI;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = lr_val;
+}
+
+static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
+				  struct vgic_lr lr_desc)
+{
+	if (!(lr_desc.state & LR_STATE_MASK))
+		vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
+}
+
+static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr;
+}
+
+static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
+}
+
+static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
+{
+	u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
+	u32 ret = 0;
+
+	if (misr & GICH_MISR_EOI)
+		ret |= INT_STATUS_EOI;
+	if (misr & GICH_MISR_U)
+		ret |= INT_STATUS_UNDERFLOW;
+
+	return ret;
+}
+
+static void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & GICH_VMCR_CTLR_MASK) >> GICH_VMCR_CTLR_SHIFT;
+	vmcrp->abpr = (vmcr & GICH_VMCR_BPR1_MASK) >> GICH_VMCR_BPR1_SHIFT;
+	vmcrp->bpr  = (vmcr & GICH_VMCR_BPR0_MASK) >> GICH_VMCR_BPR0_SHIFT;
+	vmcrp->pmr  = (vmcr & GICH_VMCR_PMR_MASK) >> GICH_VMCR_PMR_SHIFT;
+}
+
+static void vgic_v3_enable_underflow(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr |= GICH_HCR_UIE;
+}
+
+static void vgic_v3_disable_underflow(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &= ~GICH_HCR_UIE;
+}
+
+static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTLR_SHIFT) & GICH_VMCR_CTLR_MASK;
+	vmcr |= (vmcrp->abpr << GICH_VMCR_BPR1_SHIFT) & GICH_VMCR_BPR1_MASK;
+	vmcr |= (vmcrp->bpr << GICH_VMCR_BPR0_SHIFT) & GICH_VMCR_BPR0_MASK;
+	vmcr |= (vmcrp->pmr << GICH_VMCR_PMR_SHIFT) & GICH_VMCR_PMR_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+}
+
+static void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = 0;
+
+	/* Get the show on the road... */
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr = GICH_HCR_EN;
+}
+
+static const struct vgic_ops vgic_v3_ops = {
+	.get_lr			= vgic_v3_get_lr,
+	.set_lr			= vgic_v3_set_lr,
+	.sync_lr_elrsr		= vgic_v3_sync_lr_elrsr,
+	.get_elrsr		= vgic_v3_get_elrsr,
+	.get_eisr		= vgic_v3_get_eisr,
+	.get_interrupt_status	= vgic_v3_get_interrupt_status,
+	.enable_underflow	= vgic_v3_enable_underflow,
+	.disable_underflow	= vgic_v3_disable_underflow,
+	.get_vmcr		= vgic_v3_get_vmcr,
+	.set_vmcr		= vgic_v3_set_vmcr,
+	.enable			= vgic_v3_enable,
+};
+
+static struct vgic_params vgic_v3_params;
+
+/**
+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ * @ops: 	address of a pointer to the GICv3 operations
+ * @params:	address of a pointer to HW-specific parameters
+ *
+ * Returns 0 if a GICv3 has been found, with the low level operations
+ * in *ops and the HW parameters in *params. Returns an error code
+ * otherwise.
+ */
+int vgic_v3_probe(struct device_node *vgic_node,
+		  const struct vgic_ops **ops,
+		  const struct vgic_params **params)
+{
+	int ret = 0;
+	u32 gicv_idx;
+	struct resource vcpu_res;

virt/kvm/arm/vgic-v3.c line 195

Quoted 10 lines
virt/kvm/arm/vgic-v3.c new file +10 -0
+	struct vgic_params *vgic = &vgic_v3_params;
+
+	vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!vgic->maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);

it builds, but the function is still not here :(

I think it would be nicer to move that little function into this patch.

Quoted 33 lines
virt/kvm/arm/vgic-v3.c new file +30 -0
+
+	/*
+	 * The ListRegs field is 5 bits, but there is a architectural
+	 * maximum of 16 list registers. Just ignore bit 4...
+	 */
+	vgic->nr_lr = (ich_vtr_el2 & 0xf) + 1;
+
+	if (of_property_read_u32(vgic_node, "#redistributor-regions", &gicv_idx))
+		gicv_idx = 1;
+
+	gicv_idx += 3; /* Also skip GICD, GICC, GICH */
+	if (of_address_to_resource(vgic_node, gicv_idx, &vcpu_res)) {
+		kvm_err("Cannot obtain GICV region\n");
+		ret = -ENXIO;
+		goto out;
+	}
+	vgic->vcpu_base = vcpu_res.start;
+	vgic->vctrl_base = NULL;
+	vgic->type = VGIC_V3;
+
+	kvm_info("%s@%llx IRQ%d\n", vgic_node->name,
+		 vcpu_res.start, vgic->maint_irq);
+
+	*ops = &vgic_v3_ops;
+	*params = vgic;
+
+out:
+	of_node_put(vgic_node);
+	return ret;
+}
Signature · 1 line
1.8.3.4

Besides the small patch-grouping issue above:

#39 lore raw

PATCH v4 19/20 KVM: ARM: vgic: add the GICv3 backend

Quoted 283 lines · Christoffer Dall
Quoted 269 lines · Marc Zyngier

Introduce the support code for emulating a GICv2 on top of GICv3 hardware.

---
 include/kvm/arm_vgic.h |  28 ++++++
 virt/kvm/arm/vgic-v3.c | 225 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+)
 create mode 100644 virt/kvm/arm/vgic-v3.c
include/kvm/arm_vgic.h +28 -0
index 65f1121..35b0c12 100644
@@ -33,6 +33,7 @@
 #define VGIC_MAX_CPUS		KVM_MAX_VCPUS
 
 #define VGIC_V2_MAX_LRS		(1 << 6)
+#define VGIC_V3_MAX_LRS		16
 
 /* Sanity checks... */
 #if (VGIC_MAX_CPUS > 8)
@@ -72,6 +73,7 @@ struct kvm_vcpu;
 
 enum vgic_type {
 	VGIC_V2,		/* Good ol' GICv2 */
+	VGIC_V3,		/* New fancy GICv3 */
 };
 
 #define LR_STATE_PENDING	(1 << 0)
@@ -172,6 +174,19 @@ struct vgic_v2_cpu_if {
 	u32		vgic_lr[VGIC_V2_MAX_LRS];
 };
 
+struct vgic_v3_cpu_if {
+#ifdef CONFIG_ARM_GIC_V3
+	u32		vgic_hcr;
+	u32		vgic_vmcr;
+	u32		vgic_misr;	/* Saved only */
+	u32		vgic_eisr;	/* Saved only */
+	u32		vgic_elrsr;	/* Saved only */
+	u32		vgic_ap0r[4];
+	u32		vgic_ap1r[4];
+	u64		vgic_lr[VGIC_V3_MAX_LRS];
+#endif
+};
+
 struct vgic_cpu {
 #ifdef CONFIG_KVM_ARM_VGIC
 	/* per IRQ to LR mapping */
@@ -190,6 +205,7 @@ struct vgic_cpu {
 	/* CPU vif control registers for world switch */
 	union {
 		struct vgic_v2_cpu_if	vgic_v2;
+		struct vgic_v3_cpu_if	vgic_v3;
 	};
 #endif
 };
@@ -224,6 +240,18 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
 int vgic_v2_probe(struct device_node *vgic_node,
 		  const struct vgic_ops **ops,
 		  const struct vgic_params **params);
+#ifdef CONFIG_ARM_GIC_V3
+int vgic_v3_probe(struct device_node *vgic_node,
+		  const struct vgic_ops **ops,
+		  const struct vgic_params **params);
+#else
+static inline int vgic_v3_probe(struct device_node *vgic_node,
+				const struct vgic_ops **ops,
+				const struct vgic_params **params)
+{
+	return -ENODEV;
+}
+#endif
 
 #else
 static inline int kvm_vgic_hyp_init(void)
virt/kvm/arm/vgic-v3.c new file +185 -0
new file mode 100644
index 0000000..ecdec34
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2013 ARM Limited, All Rights Reserved.
+ * Author: Marc Zyngier <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/cpu.h>
+#include <linux/kvm.h>
+#include <linux/kvm_host.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/kvm_emulate.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_mmu.h>
+
+/* These are for GICv2 emulation only */
+#define GICH_LR_VIRTUALID		(0x3ffUL << 0)
+#define GICH_LR_PHYSID_CPUID_SHIFT	(10)
+#define GICH_LR_PHYSID_CPUID		(7UL << GICH_LR_PHYSID_CPUID_SHIFT)
+
+static u32 ich_vtr_el2;
+
+static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
+{
+	struct vgic_lr lr_desc;
+	u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr];
+
+	lr_desc.irq	= val & GICH_LR_VIRTUALID;
+	if (lr_desc.irq <= 15)
+		lr_desc.source	= (val >> GICH_LR_PHYSID_CPUID_SHIFT) & 0x7;
+	else
+		lr_desc.source = 0;
+	lr_desc.state	= 0;
+
+	if (val & GICH_LR_PENDING_BIT)
+		lr_desc.state |= LR_STATE_PENDING;
+	if (val & GICH_LR_ACTIVE_BIT)
+		lr_desc.state |= LR_STATE_ACTIVE;
+	if (val & GICH_LR_EOI)
+		lr_desc.state |= LR_EOI_INT;
+
+	return lr_desc;
+}
+
+static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
+			   struct vgic_lr lr_desc)
+{
+	u64 lr_val = (((u32)lr_desc.source << GICH_LR_PHYSID_CPUID_SHIFT) |
+		      lr_desc.irq);
+
+	if (lr_desc.state & LR_STATE_PENDING)
+		lr_val |= GICH_LR_PENDING_BIT;
+	if (lr_desc.state & LR_STATE_ACTIVE)
+		lr_val |= GICH_LR_ACTIVE_BIT;
+	if (lr_desc.state & LR_EOI_INT)
+		lr_val |= GICH_LR_EOI;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[lr] = lr_val;
+}
+
+static void vgic_v3_sync_lr_elrsr(struct kvm_vcpu *vcpu, int lr,
+				  struct vgic_lr lr_desc)
+{
+	if (!(lr_desc.state & LR_STATE_MASK))
+		vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
+}
+
+static u64 vgic_v3_get_elrsr(const struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr;
+}
+
+static u64 vgic_v3_get_eisr(const struct kvm_vcpu *vcpu)
+{
+	return vcpu->arch.vgic_cpu.vgic_v3.vgic_eisr;
+}
+
+static u32 vgic_v3_get_interrupt_status(const struct kvm_vcpu *vcpu)
+{
+	u32 misr = vcpu->arch.vgic_cpu.vgic_v3.vgic_misr;
+	u32 ret = 0;
+
+	if (misr & GICH_MISR_EOI)
+		ret |= INT_STATUS_EOI;
+	if (misr & GICH_MISR_U)
+		ret |= INT_STATUS_UNDERFLOW;
+
+	return ret;
+}
+
+static void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr = vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr;
+
+	vmcrp->ctlr = (vmcr & GICH_VMCR_CTLR_MASK) >> GICH_VMCR_CTLR_SHIFT;
+	vmcrp->abpr = (vmcr & GICH_VMCR_BPR1_MASK) >> GICH_VMCR_BPR1_SHIFT;
+	vmcrp->bpr  = (vmcr & GICH_VMCR_BPR0_MASK) >> GICH_VMCR_BPR0_SHIFT;
+	vmcrp->pmr  = (vmcr & GICH_VMCR_PMR_MASK) >> GICH_VMCR_PMR_SHIFT;
+}
+
+static void vgic_v3_enable_underflow(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr |= GICH_HCR_UIE;
+}
+
+static void vgic_v3_disable_underflow(struct kvm_vcpu *vcpu)
+{
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr &= ~GICH_HCR_UIE;
+}
+
+static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp)
+{
+	u32 vmcr;
+
+	vmcr  = (vmcrp->ctlr << GICH_VMCR_CTLR_SHIFT) & GICH_VMCR_CTLR_MASK;
+	vmcr |= (vmcrp->abpr << GICH_VMCR_BPR1_SHIFT) & GICH_VMCR_BPR1_MASK;
+	vmcr |= (vmcrp->bpr << GICH_VMCR_BPR0_SHIFT) & GICH_VMCR_BPR0_MASK;
+	vmcr |= (vmcrp->pmr << GICH_VMCR_PMR_SHIFT) & GICH_VMCR_PMR_MASK;
+
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = vmcr;
+}
+
+static void vgic_v3_enable(struct kvm_vcpu *vcpu)
+{
+	/*
+	 * By forcing VMCR to zero, the GIC will restore the binary
+	 * points to their reset values. Anything else resets to zero
+	 * anyway.
+	 */
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_vmcr = 0;
+
+	/* Get the show on the road... */
+	vcpu->arch.vgic_cpu.vgic_v3.vgic_hcr = GICH_HCR_EN;
+}
+
+static const struct vgic_ops vgic_v3_ops = {
+	.get_lr			= vgic_v3_get_lr,
+	.set_lr			= vgic_v3_set_lr,
+	.sync_lr_elrsr		= vgic_v3_sync_lr_elrsr,
+	.get_elrsr		= vgic_v3_get_elrsr,
+	.get_eisr		= vgic_v3_get_eisr,
+	.get_interrupt_status	= vgic_v3_get_interrupt_status,
+	.enable_underflow	= vgic_v3_enable_underflow,
+	.disable_underflow	= vgic_v3_disable_underflow,
+	.get_vmcr		= vgic_v3_get_vmcr,
+	.set_vmcr		= vgic_v3_set_vmcr,
+	.enable			= vgic_v3_enable,
+};
+
+static struct vgic_params vgic_v3_params;
+
+/**
+ * vgic_v3_probe - probe for a GICv3 compatible interrupt controller in DT
+ * @node:	pointer to the DT node
+ * @ops: 	address of a pointer to the GICv3 operations
+ * @params:	address of a pointer to HW-specific parameters
+ *
+ * Returns 0 if a GICv3 has been found, with the low level operations
+ * in *ops and the HW parameters in *params. Returns an error code
+ * otherwise.
+ */
+int vgic_v3_probe(struct device_node *vgic_node,
+		  const struct vgic_ops **ops,
+		  const struct vgic_params **params)
+{
+	int ret = 0;
+	u32 gicv_idx;
+	struct resource vcpu_res;

virt/kvm/arm/vgic-v3.c line 195

Quoted 10 lines
virt/kvm/arm/vgic-v3.c new file +10 -0
+	struct vgic_params *vgic = &vgic_v3_params;
+
+	vgic->maint_irq = irq_of_parse_and_map(vgic_node, 0);
+	if (!vgic->maint_irq) {
+		kvm_err("error getting vgic maintenance irq from DT\n");
+		ret = -ENXIO;
+		goto out;
+	}
+
+	ich_vtr_el2 = kvm_call_hyp(__vgic_v3_get_ich_vtr_el2);

it builds, but the function is still not here :(

Quoted 1 line

I think it would be nicer to move that little function into this patch.

Ah, good point. I was bound to mess something up. I'll move the little sod over.

Thanks for the additionnal review!

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#40 lore raw

PATCH v4 20/20 arm64: KVM: vgic: add GICv3 world switch

In reply to Marc Zyngier

Introduce the GICv3 world switch code and helper functions, enabling GICv2 emulation on GICv3 hardware.

---
 arch/arm64/include/asm/kvm_asm.h  |   4 +
 arch/arm64/include/asm/kvm_host.h |   7 +
 arch/arm64/kernel/asm-offsets.c   |   8 ++
 arch/arm64/kvm/Makefile           |   2 +
 arch/arm64/kvm/vgic-v3-switch.S   | 271 ++++++++++++++++++++++++++++++++++++++
 virt/kvm/arm/vgic.c               |   1 +
 6 files changed, 293 insertions(+)
 create mode 100644 arch/arm64/kvm/vgic-v3-switch.S
arch/arm64/include/asm/kvm_asm.h +4 -0
index 6252264..a28c35b 100644
@@ -106,8 +106,12 @@ extern void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
 
 extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
 
+extern u64 __vgic_v3_get_ich_vtr_el2(void);
+
 extern char __save_vgic_v2_state[];
 extern char __restore_vgic_v2_state[];
+extern char __save_vgic_v3_state[];
+extern char __restore_vgic_v3_state[];
 
 #endif
 
arch/arm64/include/asm/kvm_host.h +7 -0
index 65f0c43..a10803c 100644
@@ -216,6 +216,13 @@ static inline void vgic_arch_setup(const struct vgic_params *vgic)
 		__vgic_sr_vectors.restore_vgic	= __restore_vgic_v2_state;
 		break;
 
+#ifdef CONFIG_ARM_GIC_V3
+	case VGIC_V3:
+		__vgic_sr_vectors.save_vgic	= __save_vgic_v3_state;
+		__vgic_sr_vectors.restore_vgic	= __restore_vgic_v3_state;
+		break;
+#endif
+
 	default:
 		BUG();
 	}
arch/arm64/kernel/asm-offsets.c +8 -0
index dafc415..e74654c 100644
@@ -139,6 +139,14 @@ int main(void)
   DEFINE(VGIC_V2_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
   DEFINE(VGIC_V2_CPU_APR,	offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
   DEFINE(VGIC_V2_CPU_LR,	offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
+  DEFINE(VGIC_V3_CPU_HCR,	offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
+  DEFINE(VGIC_V3_CPU_VMCR,	offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
+  DEFINE(VGIC_V3_CPU_MISR,	offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
+  DEFINE(VGIC_V3_CPU_EISR,	offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
+  DEFINE(VGIC_V3_CPU_ELRSR,	offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
+  DEFINE(VGIC_V3_CPU_AP0R,	offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
+  DEFINE(VGIC_V3_CPU_AP1R,	offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
+  DEFINE(VGIC_V3_CPU_LR,	offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
   DEFINE(VGIC_CPU_NR_LR,	offsetof(struct vgic_cpu, nr_lr));
   DEFINE(KVM_VTTBR,		offsetof(struct kvm, arch.vttbr));
   DEFINE(KVM_VGIC_VCTRL,	offsetof(struct kvm, arch.vgic.vctrl_base));
arch/arm64/kvm/Makefile +2 -0
index daf24dc..32a0961 100644
@@ -22,4 +22,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o
 kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o
 kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o
 kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o
+kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o
+kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o
 kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o
arch/arm64/kvm/vgic-v3-switch.S new file +271 -0

271 lines not on this page · raw message

virt/kvm/arm/vgic.c +1 -0
index 7867b9a..795ab48 100644
@@ -1530,6 +1530,7 @@ static struct notifier_block vgic_cpu_nb = {
 
 static const struct of_device_id vgic_ids[] = {
 	{ .compatible = "arm,cortex-a15-gic", .data = vgic_v2_probe, },
+	{ .compatible = "arm,gic-v3", .data = vgic_v3_probe, },
 	{},
 };
 
Signature · 1 line
1.8.3.4
#41 lore raw

PATCH v4 20/20 arm64: KVM: vgic: add GICv3 world switch

Quoted 6 lines · Marc Zyngier

Introduce the GICv3 world switch code and helper functions, enabling GICv2 emulation on GICv3 hardware.

[...]

Quoted 38 lines
arch/arm64/kvm/vgic-v3-switch.S new file +32 -0
new file mode 100644
index 0000000..791a9ab
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/asm-offsets.h>
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+	.text
+	.pushsection	.hyp.text, "ax"
+
+/*
+ * Save the VGIC CPU state into memory

arch/arm64/kvm/vgic-v3-switch.S line 42

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+ * x0: Register pointing to VCPU struct
+ * Do not corrupt x1!!!
+ */
+.macro	save_vgic_v3_state
+	// Compute the address of struct vgic_cpu
+	add	x3, x0, #VCPU_VGIC_CPU
+
+	// Make sure stores to the GIC via the memory mapped interface
+	// are now visible to the system register interface
+	dsb	sy

Stores you say? There's an option for that (-st).

Quoted 9 lines
arch/arm64/kvm/vgic-v3-switch.S new file +9 -0
+	// Save all interesting registers
+	mrs	x4, ICH_HCR_EL2
+	mrs	x5, ICH_VMCR_EL2
+	mrs	x6, ICH_MISR_EL2
+	mrs	x7, ICH_EISR_EL2
+	mrs	x8, ICH_ELSR_EL2
+
+	str	w4, [x3, #VGIC_V3_CPU_HCR]
+	str	w5, [x3, #VGIC_V3_CPU_VMCR]

arch/arm64/kvm/vgic-v3-switch.S line 62

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+	str	w6, [x3, #VGIC_V3_CPU_MISR]
+	str	w7, [x3, #VGIC_V3_CPU_EISR]
+	str	w8, [x3, #VGIC_V3_CPU_ELRSR]
+
+	msr	ICH_HCR_EL2, xzr
+
+	mrs	x21, ICH_VTR_EL2
+	and	w22, w21, #0xf
+	mov	w23, #0xf
+	sub	w23, w23, w22	// How many regs we have to skip
	mvn	w22, w21
	ubfiz	w23, w22, 2, 4

arch/arm64/kvm/vgic-v3-switch.S line 63

Quoted 2 lines
arch/arm64/kvm/vgic-v3-switch.S new file +2 -0
+	adr	x24, 1f
+	add	x24, x24, x23, lsl #2

... then you don't need this lsl.

Quoted 12 lines
arch/arm64/kvm/vgic-v3-switch.S new file +12 -0
+	br	x24
+
+1:
+	mrs	x20, ICH_LR15_EL2
+	mrs	x19, ICH_LR14_EL2
+	mrs	x18, ICH_LR13_EL2
+	mrs	x17, ICH_LR12_EL2
+	mrs	x16, ICH_LR11_EL2
+	mrs	x15, ICH_LR10_EL2
+	mrs	x14, ICH_LR9_EL2
+	mrs	x13, ICH_LR8_EL2
+	mrs	x12, ICH_LR7_EL2

arch/arm64/kvm/vgic-v3-switch.S line 87

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+	mrs	x11, ICH_LR6_EL2
+	mrs	x10, ICH_LR5_EL2
+	mrs	x9, ICH_LR4_EL2
+	mrs	x8, ICH_LR3_EL2
+	mrs	x7, ICH_LR2_EL2
+	mrs	x6, ICH_LR1_EL2
+	mrs	x5, ICH_LR0_EL2
+
+	adr	x24, 1f
+	add	x24, x24, x23, lsl #2	// adr(1f) + unimp_nr*4

Same here (you can drop the shift with the above)

Quoted 9 lines
arch/arm64/kvm/vgic-v3-switch.S new file +9 -0
+	br	x24
+
+1:
+	str	x20, [x3, #(VGIC_V3_CPU_LR + 15*8)]
+	str	x19, [x3, #(VGIC_V3_CPU_LR + 14*8)]
+	str	x18, [x3, #(VGIC_V3_CPU_LR + 13*8)]
+	str	x17, [x3, #(VGIC_V3_CPU_LR + 12*8)]
+	str	x16, [x3, #(VGIC_V3_CPU_LR + 11*8)]
+	str	x15, [x3, #(VGIC_V3_CPU_LR + 10*8)]

arch/arm64/kvm/vgic-v3-switch.S line 106

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+	str	x14, [x3, #(VGIC_V3_CPU_LR + 9*8)]
+	str	x13, [x3, #(VGIC_V3_CPU_LR + 8*8)]
+	str	x12, [x3, #(VGIC_V3_CPU_LR + 7*8)]
+	str	x11, [x3, #(VGIC_V3_CPU_LR + 6*8)]
+	str	x10, [x3, #(VGIC_V3_CPU_LR + 5*8)]
+	str	x9, [x3, #(VGIC_V3_CPU_LR + 4*8)]
+	str	x8, [x3, #(VGIC_V3_CPU_LR + 3*8)]
+	str	x7, [x3, #(VGIC_V3_CPU_LR + 2*8)]
+	str	x6, [x3, #(VGIC_V3_CPU_LR + 1*8)]
+	str	x5, [x3, #VGIC_V3_CPU_LR]

Do you have to store these backwards? I worry that it could defect some CPU optimisations detecting streaming stores.

arch/arm64/kvm/vgic-v3-switch.S line 110

Quoted 4 lines
arch/arm64/kvm/vgic-v3-switch.S new file +4 -0
+
+	lsr	w22, w21, #29	// Get PRIbits
+	cmp	w22, #4		// 5 bits
+	b.eq	5f

Can you lsr by 33 and use cbz for the 5 bits case?

arch/arm64/kvm/vgic-v3-switch.S line 117

Quoted 7 lines
arch/arm64/kvm/vgic-v3-switch.S new file +7 -0
+	cmp	w22, #5		// 6 bits
+	b.eq	6f
+				// 7 bits
+	mrs	x20, ICH_AP0R3_EL2
+	str	w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
+	mrs	x19, ICH_AP0R2_EL2
+	str	w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]

I'm slightly confused here... Why do we access ICH_AP0R3_EL2 when we have 7 bits of priority? Shouldn't we have a check for 8 bits?

Quoted 12 lines
arch/arm64/kvm/vgic-v3-switch.S new file +12 -0
+1:
+	msr	ICH_LR15_EL2, x20
+	msr	ICH_LR14_EL2, x19
+	msr	ICH_LR13_EL2, x18
+	msr	ICH_LR12_EL2, x17
+	msr	ICH_LR11_EL2, x16
+	msr	ICH_LR10_EL2, x15
+	msr	ICH_LR9_EL2,  x14
+	msr	ICH_LR8_EL2,  x13
+	msr	ICH_LR7_EL2,  x12
+	msr	ICH_LR6_EL2,  x11
+	msr	ICH_LR5_EL2,  x10

arch/arm64/kvm/vgic-v3-switch.S line 248

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+	msr	ICH_LR4_EL2,   x9
+	msr	ICH_LR3_EL2,   x8
+	msr	ICH_LR2_EL2,   x7
+	msr	ICH_LR1_EL2,   x6
+	msr	ICH_LR0_EL2,   x5
+
+	// Ensure that the above will be visible via the memory-mapped
+	// view of the CPU interface (GICV).
+	isb
+	dsb	sy

Bah, I'm sure I asked this before, but what is that dsb doing? I can't see any memory accesses or cache maintenance that need to be completed.

Will

#42 lore raw

PATCH v4 20/20 arm64: KVM: vgic: add GICv3 world switch

Quoted 75 lines · Will Deacon
Quoted 6 lines · Marc Zyngier

Introduce the GICv3 world switch code and helper functions, enabling GICv2 emulation on GICv3 hardware.

[...]

Quoted 38 lines
arch/arm64/kvm/vgic-v3-switch.S new file +32 -0
new file mode 100644
index 0000000..791a9ab
@@ -0,0 +1,271 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+#include <linux/irqchip/arm-gic-v3.h>
+
+#include <asm/assembler.h>
+#include <asm/memory.h>
+#include <asm/asm-offsets.h>
+#include <asm/kvm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_arm.h>
+
+	.text
+	.pushsection	.hyp.text, "ax"
+
+/*
+ * Save the VGIC CPU state into memory

arch/arm64/kvm/vgic-v3-switch.S line 42

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+ * x0: Register pointing to VCPU struct
+ * Do not corrupt x1!!!
+ */
+.macro	save_vgic_v3_state
+	// Compute the address of struct vgic_cpu
+	add	x3, x0, #VCPU_VGIC_CPU
+
+	// Make sure stores to the GIC via the memory mapped interface
+	// are now visible to the system register interface
+	dsb	sy

Stores you say? There's an option for that (-st).

Quoted 14 lines
arch/arm64/kvm/vgic-v3-switch.S new file +14 -0
+	// Save all interesting registers
+	mrs	x4, ICH_HCR_EL2
+	mrs	x5, ICH_VMCR_EL2
+	mrs	x6, ICH_MISR_EL2
+	mrs	x7, ICH_EISR_EL2
+	mrs	x8, ICH_ELSR_EL2
+
+	str	w4, [x3, #VGIC_V3_CPU_HCR]
+	str	w5, [x3, #VGIC_V3_CPU_VMCR]
+	str	w6, [x3, #VGIC_V3_CPU_MISR]
+	str	w7, [x3, #VGIC_V3_CPU_EISR]
+	str	w8, [x3, #VGIC_V3_CPU_ELRSR]
+
+	msr	ICH_HCR_EL2, xzr
Quoted 8 lines

arch/arm64/kvm/vgic-v3-switch.S line 62

Quoted 5 lines
arch/arm64/kvm/vgic-v3-switch.S new file +5 -0
+
+	mrs	x21, ICH_VTR_EL2
+	and	w22, w21, #0xf
+	mov	w23, #0xf
+	sub	w23, w23, w22	// How many regs we have to skip
	mvn	w22, w21
	ubfiz	w23, w22, 2, 4

Substract, extract and multiply in 2 instructions. Slick. Sick, even. ;-)

Quoted 4 lines

arch/arm64/kvm/vgic-v3-switch.S line 63

Quoted 2 lines
arch/arm64/kvm/vgic-v3-switch.S new file +2 -0
+	adr	x24, 1f
+	add	x24, x24, x23, lsl #2

... then you don't need this lsl.

Indeed.

Quoted 39 lines
Quoted 12 lines
arch/arm64/kvm/vgic-v3-switch.S new file +12 -0
+	br	x24
+
+1:
+	mrs	x20, ICH_LR15_EL2
+	mrs	x19, ICH_LR14_EL2
+	mrs	x18, ICH_LR13_EL2
+	mrs	x17, ICH_LR12_EL2
+	mrs	x16, ICH_LR11_EL2
+	mrs	x15, ICH_LR10_EL2
+	mrs	x14, ICH_LR9_EL2
+	mrs	x13, ICH_LR8_EL2
+	mrs	x12, ICH_LR7_EL2

arch/arm64/kvm/vgic-v3-switch.S line 87

Quoted 10 lines
arch/arm64/kvm/vgic-v3-switch.S new file +10 -0
+	mrs	x11, ICH_LR6_EL2
+	mrs	x10, ICH_LR5_EL2
+	mrs	x9, ICH_LR4_EL2
+	mrs	x8, ICH_LR3_EL2
+	mrs	x7, ICH_LR2_EL2
+	mrs	x6, ICH_LR1_EL2
+	mrs	x5, ICH_LR0_EL2
+
+	adr	x24, 1f
+	add	x24, x24, x23, lsl #2	// adr(1f) + unimp_nr*4

Same here (you can drop the shift with the above)

Quoted 14 lines
arch/arm64/kvm/vgic-v3-switch.S new file +14 -0
+	br	x24
+
+1:
+	str	x20, [x3, #(VGIC_V3_CPU_LR + 15*8)]
+	str	x19, [x3, #(VGIC_V3_CPU_LR + 14*8)]
+	str	x18, [x3, #(VGIC_V3_CPU_LR + 13*8)]
+	str	x17, [x3, #(VGIC_V3_CPU_LR + 12*8)]
+	str	x16, [x3, #(VGIC_V3_CPU_LR + 11*8)]
+	str	x15, [x3, #(VGIC_V3_CPU_LR + 10*8)]
+	str	x14, [x3, #(VGIC_V3_CPU_LR + 9*8)]
+	str	x13, [x3, #(VGIC_V3_CPU_LR + 8*8)]
+	str	x12, [x3, #(VGIC_V3_CPU_LR + 7*8)]
+	str	x11, [x3, #(VGIC_V3_CPU_LR + 6*8)]
+	str	x10, [x3, #(VGIC_V3_CPU_LR + 5*8)]
Quoted 8 lines

arch/arm64/kvm/vgic-v3-switch.S line 106

Quoted 5 lines
arch/arm64/kvm/vgic-v3-switch.S new file +5 -0
+	str	x9, [x3, #(VGIC_V3_CPU_LR + 4*8)]
+	str	x8, [x3, #(VGIC_V3_CPU_LR + 3*8)]
+	str	x7, [x3, #(VGIC_V3_CPU_LR + 2*8)]
+	str	x6, [x3, #(VGIC_V3_CPU_LR + 1*8)]
+	str	x5, [x3, #VGIC_V3_CPU_LR]

Do you have to store these backwards? I worry that it could defect some CPU optimisations detecting streaming stores.

The alternative is to organize the array back to front (element 0 would store LR15). Certainly doable with a bit of hacking in the backend functions that deal with an LR number.

Quoted 6 lines

arch/arm64/kvm/vgic-v3-switch.S line 110

Quoted 4 lines
arch/arm64/kvm/vgic-v3-switch.S new file +4 -0
+
+	lsr	w22, w21, #29	// Get PRIbits
+	cmp	w22, #4		// 5 bits
+	b.eq	5f

Can you lsr by 33 and use cbz for the 5 bits case?

One thing I could do use ICH_VTR_EL2[30:29], and just test one bit at a time:
- bit 1 set, 7 bits
- bit 0 set, 6 bits
- otherwise, 4 bits

This could entierly be implemented with a pair of tbz instructions, loosing all the cmps.

Quoted 10 lines

arch/arm64/kvm/vgic-v3-switch.S line 117

Quoted 7 lines
arch/arm64/kvm/vgic-v3-switch.S new file +7 -0
+	cmp	w22, #5		// 6 bits
+	b.eq	6f
+				// 7 bits
+	mrs	x20, ICH_AP0R3_EL2
+	str	w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
+	mrs	x19, ICH_AP0R2_EL2
+	str	w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]

I'm slightly confused here... Why do we access ICH_AP0R3_EL2 when we have 7 bits of priority? Shouldn't we have a check for 8 bits?

For n bits of priority, you need 2^n bits to describe the active priorities:

- 5 bits of priority: 32 levels -> 1 register
- 6 bits of priority: 64 levels -> 2 registers
- 7 bits of priority: 128 levels -> 4 registers

Quoted 17 lines
Quoted 17 lines
arch/arm64/kvm/vgic-v3-switch.S new file +17 -0
+1:
+	msr	ICH_LR15_EL2, x20
+	msr	ICH_LR14_EL2, x19
+	msr	ICH_LR13_EL2, x18
+	msr	ICH_LR12_EL2, x17
+	msr	ICH_LR11_EL2, x16
+	msr	ICH_LR10_EL2, x15
+	msr	ICH_LR9_EL2,  x14
+	msr	ICH_LR8_EL2,  x13
+	msr	ICH_LR7_EL2,  x12
+	msr	ICH_LR6_EL2,  x11
+	msr	ICH_LR5_EL2,  x10
+	msr	ICH_LR4_EL2,   x9
+	msr	ICH_LR3_EL2,   x8
+	msr	ICH_LR2_EL2,   x7
+	msr	ICH_LR1_EL2,   x6
+	msr	ICH_LR0_EL2,   x5
Quoted 8 lines

arch/arm64/kvm/vgic-v3-switch.S line 248

Quoted 5 lines
arch/arm64/kvm/vgic-v3-switch.S new file +5 -0
+
+	// Ensure that the above will be visible via the memory-mapped
+	// view of the CPU interface (GICV).
+	isb
+	dsb	sy

Bah, I'm sure I asked this before, but what is that dsb doing? I can't see any memory accesses or cache maintenance that need to be completed.

The GICv3 architecture uses dsb to synchronize between sysreg ang memory-mapped accesses. Otherwise, there is no guarantee that a memory-mapped guest will be able to observe the freshly populated list registers.

Thanks for the review!

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#43 lore raw

v4 cover arm64: GICv3 support

In reply to Marc Zyngier

Hi Marc,
The patch set is working for us on our platform. Below are some of the things we tested with the GICv3 driver.

System: Cavium's proprietary simulator
Cores: 16
GIC version: GICv3

1) SGI, PPI and SPI
2) MSI and MSI-x with SPI and also LPI (took previous version of an unposted LPI/ITS driver which now is missing from Marc's git tree)

The kind of devices that were tested are UARTs, AHCI controller, SR-IOV capable devices.

So,

regards,
Radha Mohan
Cavium Inc.

Quoted 144 lines · Marc Zyngier

GICv3 is the base for a new generation of interrupt controllers designed to overcome some of the most glaring limitations of GICv2.

Some of the features are:
- Support for more than 8 CPUs (a lot more...)
- System registers for CPU interface access (instead of the memory mapped GICC, GICV, GICH)
- Message based interrupts

This patch series currently support:
- Affinity Routing
- System Registers
- Non-Secure Group-1 interrupts only
- KVM support (GICv3 host, GICv2 guest)

What is *not yet* supported in this series (WIP):
- LPI/ITS/MSI
- KVM GICv3 guest support
- Any form of power management
- 32bit systems

To be built, this code requires a fairly recent compiler/binutils combo. Linaro 13.06 seems to do the trick. This has been tested on the ARM FVP and Foundation models, with non-regressions run on a VExpress TC-2 and another Cortex-A57 based platform.

So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for being the only ones to review it). While the documentation is unfortunately not public yet, it is available to those actively implementing GICv3 in their hardware, and I'm really eager to see reviews and test reports.

Without that kind of engagement, it is unlikely that this code will get merged any time soon.

Individuals without access to documentation and/or hardware can still review the code (it shares a lot of concepts with GICv2) and test in on the freely available Foundation model (see
http://releases.linaro.org/latest/openembedded/aarch64/ for details on how to use the Foundation model).

The code is also available at the following location (warning, unstable branch!):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv3

* From v3 [3]
- Fixed a lot of issues found by Christoffer (too many to report here, see the email thread)
- New .sync_lr_elrsr backend
- New probing method
- New irqchip_in_kernel implementation
- Checked full bisectability of the series (hopefully got it right

    this time...)

- rebased on top of 3.15-rc5

* From v2 [2]
- removed sharing of the xlate method with GICv2 (TI crossbar is now getting in the way...)
- Switched to a tree domain to accomodate for the LPI space
- Fixed more bisectability

* From the initial revision [1]
- Some code sharing with GICv2
- Barrier cleanup/clarification
- Revised boot protocol update
- Consistent use of the MPIDR access macros
- Fixed a number of embarassing bugs
- Fixed DT examples
- Fixed bisectability of the series

[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229959.html
[2]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241972.html
[3]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/248008.html

Marc Zyngier (20):
ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3
KVM: arm/arm64: vgic: move GICv2 registers to their own structure
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
KVM: ARM: vgic: abstract access to the ELRSR bitmap
KVM: ARM: vgic: abstract EISR bitmap access
KVM: ARM: vgic: abstract MISR decoding
KVM: ARM: vgic: move underflow handling to vgic_ops
KVM: ARM: vgic: abstract VMCR access
KVM: ARM: vgic: introduce vgic_enable
KVM: ARM: introduce vgic_params structure
KVM: ARM: vgic: split GICv2 backend from the main vgic code
KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S
arm64: KVM: split GICv2 world switch from hyp code
arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch
code
KVM: ARM: vgic: add the GICv3 backend
arm64: KVM: vgic: add GICv3 world switch

 Documentation/arm64/booting.txt                  |   6 +
 Documentation/devicetree/bindings/arm/gic-v3.txt |  79 +++
 arch/arm/include/asm/kvm_host.h                  |   5 +
 arch/arm/kernel/asm-offsets.c                    |  14 +-
 arch/arm/kvm/Makefile                            |   1 +
 arch/arm/kvm/interrupts_head.S                   |  26 +-
 arch/arm64/Kconfig                               |   1 +
 arch/arm64/include/asm/kvm_arm.h                 |   5 +-
 arch/arm64/include/asm/kvm_asm.h                 |  14 +-
 arch/arm64/include/asm/kvm_host.h                |  28 +
 arch/arm64/include/asm/virt.h                    |   4 +
 arch/arm64/kernel/asm-offsets.c                  |  25 +-
 arch/arm64/kernel/head.S                         |  18 +
 arch/arm64/kernel/hyp-stub.S                     |   1 +
 arch/arm64/kvm/Makefile                          |   4 +
 arch/arm64/kvm/hyp.S                             | 127 +----
 arch/arm64/kvm/vgic-v2-switch.S                  | 133 +++++
 arch/arm64/kvm/vgic-v3-switch.S                  | 271 +++++++++
 drivers/irqchip/Kconfig                          |   5 +
 drivers/irqchip/Makefile                         |   3 +-
 drivers/irqchip/irq-gic-common.c                 | 115 ++++
 drivers/irqchip/irq-gic-common.h                 |  29 +
 drivers/irqchip/irq-gic-v3.c                     | 684 +++++++++++++++++++++++
 drivers/irqchip/irq-gic.c                        |  59 +-
 include/kvm/arm_vgic.h                           | 115 +++-
 include/linux/irqchip/arm-gic-v3.h               | 190 +++++++
 virt/kvm/arm/vgic-v2.c                           | 236 ++++++++
 virt/kvm/arm/vgic-v3.c                           | 225 ++++++++
 virt/kvm/arm/vgic.c                              | 345 ++++++------
 29 files changed, 2415 insertions(+), 353 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
 create mode 100644 arch/arm64/kvm/vgic-v2-switch.S
 create mode 100644 arch/arm64/kvm/vgic-v3-switch.S
 create mode 100644 drivers/irqchip/irq-gic-common.c
 create mode 100644 drivers/irqchip/irq-gic-common.h
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h
 create mode 100644 virt/kvm/arm/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic-v3.c

--
1.8.3.4

_______________________________________________
kvmarm mailing list
kvmarm at lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

#44 lore raw

v4 cover arm64: GICv3 support

It still has lot of GICv2 specific code in vgic.c, i think it will change with the KVM GICv3 guest support.

Quoted 168 lines · Radha Mohan

Hi Marc,
The patch set is working for us on our platform. Below are some of the things we tested with the GICv3 driver.

System: Cavium's proprietary simulator
Cores: 16
GIC version: GICv3

1) SGI, PPI and SPI
2) MSI and MSI-x with SPI and also LPI (took previous version of an unposted LPI/ITS driver which now is missing from Marc's git tree)

The kind of devices that were tested are UARTs, AHCI controller, SR-IOV capable devices.

So,

regards,
Radha Mohan
Cavium Inc.

Quoted 144 lines · Marc Zyngier

GICv3 is the base for a new generation of interrupt controllers designed to overcome some of the most glaring limitations of GICv2.

Some of the features are:
- Support for more than 8 CPUs (a lot more...)
- System registers for CPU interface access (instead of the memory mapped GICC, GICV, GICH)
- Message based interrupts

This patch series currently support:
- Affinity Routing
- System Registers
- Non-Secure Group-1 interrupts only
- KVM support (GICv3 host, GICv2 guest)

What is *not yet* supported in this series (WIP):
- LPI/ITS/MSI
- KVM GICv3 guest support
- Any form of power management
- 32bit systems

To be built, this code requires a fairly recent compiler/binutils combo. Linaro 13.06 seems to do the trick. This has been tested on the ARM FVP and Foundation models, with non-regressions run on a VExpress TC-2 and another Cortex-A57 based platform.

So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for being the only ones to review it). While the documentation is unfortunately not public yet, it is available to those actively implementing GICv3 in their hardware, and I'm really eager to see reviews and test reports.

Without that kind of engagement, it is unlikely that this code will get merged any time soon.

Individuals without access to documentation and/or hardware can still review the code (it shares a lot of concepts with GICv2) and test in on the freely available Foundation model (see
http://releases.linaro.org/latest/openembedded/aarch64/ for details on how to use the Foundation model).

The code is also available at the following location (warning, unstable branch!):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv3

* From v3 [3]
- Fixed a lot of issues found by Christoffer (too many to report here, see the email thread)
- New .sync_lr_elrsr backend
- New probing method
- New irqchip_in_kernel implementation
- Checked full bisectability of the series (hopefully got it right this time...)
- rebased on top of 3.15-rc5

* From v2 [2]
- removed sharing of the xlate method with GICv2 (TI crossbar is now getting in the way...)
- Switched to a tree domain to accomodate for the LPI space
- Fixed more bisectability

* From the initial revision [1]
- Some code sharing with GICv2
- Barrier cleanup/clarification
- Revised boot protocol update
- Consistent use of the MPIDR access macros
- Fixed a number of embarassing bugs
- Fixed DT examples
- Fixed bisectability of the series

[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229959.html
[2]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241972.html
[3]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/248008.html

Marc Zyngier (20):
ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3
KVM: arm/arm64: vgic: move GICv2 registers to their own structure
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
KVM: ARM: vgic: abstract access to the ELRSR bitmap
KVM: ARM: vgic: abstract EISR bitmap access
KVM: ARM: vgic: abstract MISR decoding
KVM: ARM: vgic: move underflow handling to vgic_ops
KVM: ARM: vgic: abstract VMCR access
KVM: ARM: vgic: introduce vgic_enable
KVM: ARM: introduce vgic_params structure
KVM: ARM: vgic: split GICv2 backend from the main vgic code
KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S
arm64: KVM: split GICv2 world switch from hyp code
arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch
code
KVM: ARM: vgic: add the GICv3 backend
arm64: KVM: vgic: add GICv3 world switch

Documentation/arm64/booting.txt                  |   6 +
Documentation/devicetree/bindings/arm/gic-v3.txt |  79 +++
arch/arm/include/asm/kvm_host.h                  |   5 +
arch/arm/kernel/asm-offsets.c                    |  14 +-
arch/arm/kvm/Makefile                            |   1 +
arch/arm/kvm/interrupts_head.S                   |  26 +-
arch/arm64/Kconfig                               |   1 +
arch/arm64/include/asm/kvm_arm.h                 |   5 +-
arch/arm64/include/asm/kvm_asm.h                 |  14 +-
arch/arm64/include/asm/kvm_host.h                |  28 +
arch/arm64/include/asm/virt.h                    |   4 +
arch/arm64/kernel/asm-offsets.c                  |  25 +-
arch/arm64/kernel/head.S                         |  18 +
arch/arm64/kernel/hyp-stub.S                     |   1 +
arch/arm64/kvm/Makefile                          |   4 +
arch/arm64/kvm/hyp.S                             | 127 +----
arch/arm64/kvm/vgic-v2-switch.S                  | 133 +++++
arch/arm64/kvm/vgic-v3-switch.S                  | 271 +++++++++
drivers/irqchip/Kconfig                          |   5 +
drivers/irqchip/Makefile                         |   3 +-
drivers/irqchip/irq-gic-common.c                 | 115 ++++
drivers/irqchip/irq-gic-common.h                 |  29 +
drivers/irqchip/irq-gic-v3.c                     | 684 +++++++++++++++++++++++
drivers/irqchip/irq-gic.c                        |  59 +-
include/kvm/arm_vgic.h                           | 115 +++-
include/linux/irqchip/arm-gic-v3.h               | 190 +++++++
virt/kvm/arm/vgic-v2.c                           | 236 ++++++++
virt/kvm/arm/vgic-v3.c                           | 225 ++++++++
virt/kvm/arm/vgic.c                              | 345 ++++++------
29 files changed, 2415 insertions(+), 353 deletions(-)

create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt create mode 100644 arch/arm64/kvm/vgic-v2-switch.S create mode 100644 arch/arm64/kvm/vgic-v3-switch.S create mode 100644 drivers/irqchip/irq-gic-common.c create mode 100644 drivers/irqchip/irq-gic-common.h create mode 100644 drivers/irqchip/irq-gic-v3.c
create mode 100644 include/linux/irqchip/arm-gic-v3.h create mode 100644 virt/kvm/arm/vgic-v2.c
create mode 100644 virt/kvm/arm/vgic-v3.c

--
1.8.3.4

_______________________________________________
kvmarm mailing list
kvmarm at lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

#45 lore raw

v4 cover arm64: GICv3 support

Quoted 2 lines · Tirumalesh

It still has lot of GICv2 specific code in vgic.c, i think it will change with the KVM GICv3 guest support.

Which is exactly what is expected, as we don't support anything else so far.

Quoted 2 lines

Thanks for that. Can you specify the patches to which this applies?

Cheers,

	M.
Quoted 172 lines · Radha Mohan
Quoted 169 lines

Hi Marc,
The patch set is working for us on our platform. Below are some of the things we tested with the GICv3 driver.

System: Cavium's proprietary simulator
Cores: 16
GIC version: GICv3

1) SGI, PPI and SPI
2) MSI and MSI-x with SPI and also LPI (took previous version of an unposted LPI/ITS driver which now is missing from Marc's git tree)

The kind of devices that were tested are UARTs, AHCI controller, SR-IOV capable devices.

So,

regards,
Radha Mohan
Cavium Inc.

Quoted 144 lines · Marc Zyngier

GICv3 is the base for a new generation of interrupt controllers designed to overcome some of the most glaring limitations of GICv2.

Some of the features are:
- Support for more than 8 CPUs (a lot more...)
- System registers for CPU interface access (instead of the memory mapped GICC, GICV, GICH)
- Message based interrupts

This patch series currently support:
- Affinity Routing
- System Registers
- Non-Secure Group-1 interrupts only
- KVM support (GICv3 host, GICv2 guest)

What is *not yet* supported in this series (WIP):
- LPI/ITS/MSI
- KVM GICv3 guest support
- Any form of power management
- 32bit systems

To be built, this code requires a fairly recent compiler/binutils combo. Linaro 13.06 seems to do the trick. This has been tested on the ARM FVP and Foundation models, with non-regressions run on a VExpress TC-2 and another Cortex-A57 based platform.

So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for being the only ones to review it). While the documentation is unfortunately not public yet, it is available to those actively implementing GICv3 in their hardware, and I'm really eager to see reviews and test reports.

Without that kind of engagement, it is unlikely that this code will get merged any time soon.

Individuals without access to documentation and/or hardware can still review the code (it shares a lot of concepts with GICv2) and test in on the freely available Foundation model (see
http://releases.linaro.org/latest/openembedded/aarch64/ for details on how to use the Foundation model).

The code is also available at the following location (warning, unstable branch!):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv3

* From v3 [3]
- Fixed a lot of issues found by Christoffer (too many to report here, see the email thread)
- New .sync_lr_elrsr backend
- New probing method
- New irqchip_in_kernel implementation
- Checked full bisectability of the series (hopefully got it right this time...)
- rebased on top of 3.15-rc5

* From v2 [2]
- removed sharing of the xlate method with GICv2 (TI crossbar is now getting in the way...)
- Switched to a tree domain to accomodate for the LPI space
- Fixed more bisectability

* From the initial revision [1]
- Some code sharing with GICv2
- Barrier cleanup/clarification
- Revised boot protocol update
- Consistent use of the MPIDR access macros
- Fixed a number of embarassing bugs
- Fixed DT examples
- Fixed bisectability of the series

[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229959.html
[2]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241972.html
[3]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/248008.html

Marc Zyngier (20):
ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3
KVM: arm/arm64: vgic: move GICv2 registers to their own structure
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
KVM: ARM: vgic: abstract access to the ELRSR bitmap
KVM: ARM: vgic: abstract EISR bitmap access
KVM: ARM: vgic: abstract MISR decoding
KVM: ARM: vgic: move underflow handling to vgic_ops
KVM: ARM: vgic: abstract VMCR access
KVM: ARM: vgic: introduce vgic_enable
KVM: ARM: introduce vgic_params structure
KVM: ARM: vgic: split GICv2 backend from the main vgic code
KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S
arm64: KVM: split GICv2 world switch from hyp code
arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch
code
KVM: ARM: vgic: add the GICv3 backend
arm64: KVM: vgic: add GICv3 world switch

Documentation/arm64/booting.txt                  |   6 +
Documentation/devicetree/bindings/arm/gic-v3.txt |  79 +++
arch/arm/include/asm/kvm_host.h                  |   5 +
arch/arm/kernel/asm-offsets.c                    |  14 +-
arch/arm/kvm/Makefile                            |   1 +
arch/arm/kvm/interrupts_head.S                   |  26 +-
arch/arm64/Kconfig                               |   1 +
arch/arm64/include/asm/kvm_arm.h                 |   5 +-
arch/arm64/include/asm/kvm_asm.h                 |  14 +-
arch/arm64/include/asm/kvm_host.h                |  28 +
arch/arm64/include/asm/virt.h                    |   4 +
arch/arm64/kernel/asm-offsets.c                  |  25 +-
arch/arm64/kernel/head.S                         |  18 +
arch/arm64/kernel/hyp-stub.S                     |   1 +
arch/arm64/kvm/Makefile                          |   4 +
arch/arm64/kvm/hyp.S                             | 127 +----
arch/arm64/kvm/vgic-v2-switch.S                  | 133 +++++
arch/arm64/kvm/vgic-v3-switch.S                  | 271 +++++++++
drivers/irqchip/Kconfig                          |   5 +
drivers/irqchip/Makefile                         |   3 +-
drivers/irqchip/irq-gic-common.c                 | 115 ++++
drivers/irqchip/irq-gic-common.h                 |  29 +
drivers/irqchip/irq-gic-v3.c                     | 684 +++++++++++++++++++++++
drivers/irqchip/irq-gic.c                        |  59 +-
include/kvm/arm_vgic.h                           | 115 +++-
include/linux/irqchip/arm-gic-v3.h               | 190 +++++++
virt/kvm/arm/vgic-v2.c                           | 236 ++++++++
virt/kvm/arm/vgic-v3.c                           | 225 ++++++++
virt/kvm/arm/vgic.c                              | 345 ++++++------
29 files changed, 2415 insertions(+), 353 deletions(-)

create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt create mode 100644 arch/arm64/kvm/vgic-v2-switch.S create mode 100644 arch/arm64/kvm/vgic-v3-switch.S create mode 100644 drivers/irqchip/irq-gic-common.c create mode 100644 drivers/irqchip/irq-gic-common.h create mode 100644 drivers/irqchip/irq-gic-v3.c
create mode 100644 include/linux/irqchip/arm-gic-v3.h create mode 100644 virt/kvm/arm/vgic-v2.c
create mode 100644 virt/kvm/arm/vgic-v3.c

--
1.8.3.4

_______________________________________________
kvmarm mailing list
kvmarm at lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm

Signature · 1 line
Jazz is not dead. It just smells funny.
#46 lore raw

v4 cover arm64: GICv3 support

In reply to Radha Mohan
Quoted 12 lines · Radha Mohan

Hi Marc,
The patch set is working for us on our platform. Below are some of the things we tested with the GICv3 driver.

System: Cavium's proprietary simulator
Cores: 16
GIC version: GICv3

1) SGI, PPI and SPI
2) MSI and MSI-x with SPI and also LPI (took previous version of an unposted LPI/ITS driver which now is missing from Marc's git tree)

Quoted 6 lines

The kind of devices that were tested are UARTs, AHCI controller, SR-IOV capable devices.

So,

Thanks. I suppose this only applies to the first few patches, as you don't mention KVM here?

Cheers,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny.
#47 lore raw

v4 cover arm64: GICv3 support

In reply to Marc Zyngier

Hi Marc,

Add:

for the first 4 patches, that is:

Quoted 4 lines

ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3

Cheers,
Abel.

Quoted 137 lines · Marc Zyngier

GICv3 is the base for a new generation of interrupt controllers designed to overcome some of the most glaring limitations of GICv2.

Some of the features are:
- Support for more than 8 CPUs (a lot more...)
- System registers for CPU interface access (instead of the memory mapped GICC, GICV, GICH)
- Message based interrupts

This patch series currently support:
- Affinity Routing
- System Registers
- Non-Secure Group-1 interrupts only
- KVM support (GICv3 host, GICv2 guest)

What is *not yet* supported in this series (WIP):
- LPI/ITS/MSI
- KVM GICv3 guest support
- Any form of power management
- 32bit systems

To be built, this code requires a fairly recent compiler/binutils combo. Linaro 13.06 seems to do the trick. This has been tested on the ARM FVP and Foundation models, with non-regressions run on a VExpress TC-2 and another Cortex-A57 based platform.

So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for being the only ones to review it). While the documentation is unfortunately not public yet, it is available to those actively implementing GICv3 in their hardware, and I'm really eager to see reviews and test reports.

Without that kind of engagement, it is unlikely that this code will get merged any time soon.

Individuals without access to documentation and/or hardware can still review the code (it shares a lot of concepts with GICv2) and test in on the freely available Foundation model (see
http://releases.linaro.org/latest/openembedded/aarch64/ for details on how to use the Foundation model).

The code is also available at the following location (warning, unstable branch!):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv3

* From v3 [3]
- Fixed a lot of issues found by Christoffer (too many to report here, see the email thread)
- New .sync_lr_elrsr backend
- New probing method
- New irqchip_in_kernel implementation
- Checked full bisectability of the series (hopefully got it right

    this time...)

- rebased on top of 3.15-rc5

* From v2 [2]
- removed sharing of the xlate method with GICv2 (TI crossbar is now getting in the way...)
- Switched to a tree domain to accomodate for the LPI space
- Fixed more bisectability

* From the initial revision [1]
- Some code sharing with GICv2
- Barrier cleanup/clarification
- Revised boot protocol update
- Consistent use of the MPIDR access macros
- Fixed a number of embarassing bugs
- Fixed DT examples
- Fixed bisectability of the series

[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229959.html
[2]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241972.html
[3]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/248008.html

Marc Zyngier (20):
ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3
KVM: arm/arm64: vgic: move GICv2 registers to their own structure
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
KVM: ARM: vgic: abstract access to the ELRSR bitmap
KVM: ARM: vgic: abstract EISR bitmap access
KVM: ARM: vgic: abstract MISR decoding
KVM: ARM: vgic: move underflow handling to vgic_ops
KVM: ARM: vgic: abstract VMCR access
KVM: ARM: vgic: introduce vgic_enable
KVM: ARM: introduce vgic_params structure
KVM: ARM: vgic: split GICv2 backend from the main vgic code
KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S
arm64: KVM: split GICv2 world switch from hyp code
arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch
code
KVM: ARM: vgic: add the GICv3 backend
arm64: KVM: vgic: add GICv3 world switch

 Documentation/arm64/booting.txt                  |   6 +
 Documentation/devicetree/bindings/arm/gic-v3.txt |  79 +++
 arch/arm/include/asm/kvm_host.h                  |   5 +
 arch/arm/kernel/asm-offsets.c                    |  14 +-
 arch/arm/kvm/Makefile                            |   1 +
 arch/arm/kvm/interrupts_head.S                   |  26 +-
 arch/arm64/Kconfig                               |   1 +
 arch/arm64/include/asm/kvm_arm.h                 |   5 +-
 arch/arm64/include/asm/kvm_asm.h                 |  14 +-
 arch/arm64/include/asm/kvm_host.h                |  28 +
 arch/arm64/include/asm/virt.h                    |   4 +
 arch/arm64/kernel/asm-offsets.c                  |  25 +-
 arch/arm64/kernel/head.S                         |  18 +
 arch/arm64/kernel/hyp-stub.S                     |   1 +
 arch/arm64/kvm/Makefile                          |   4 +
 arch/arm64/kvm/hyp.S                             | 127 +----
 arch/arm64/kvm/vgic-v2-switch.S                  | 133 +++++
 arch/arm64/kvm/vgic-v3-switch.S                  | 271 +++++++++
 drivers/irqchip/Kconfig                          |   5 +
 drivers/irqchip/Makefile                         |   3 +-
 drivers/irqchip/irq-gic-common.c                 | 115 ++++
 drivers/irqchip/irq-gic-common.h                 |  29 +
 drivers/irqchip/irq-gic-v3.c                     | 684 +++++++++++++++++++++++
 drivers/irqchip/irq-gic.c                        |  59 +-
 include/kvm/arm_vgic.h                           | 115 +++-
 include/linux/irqchip/arm-gic-v3.h               | 190 +++++++
 virt/kvm/arm/vgic-v2.c                           | 236 ++++++++
 virt/kvm/arm/vgic-v3.c                           | 225 ++++++++
 virt/kvm/arm/vgic.c                              | 345 ++++++------
 29 files changed, 2415 insertions(+), 353 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
 create mode 100644 arch/arm64/kvm/vgic-v2-switch.S
 create mode 100644 arch/arm64/kvm/vgic-v3-switch.S
 create mode 100644 drivers/irqchip/irq-gic-common.c
 create mode 100644 drivers/irqchip/irq-gic-common.h
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h
 create mode 100644 virt/kvm/arm/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic-v3.c
#48 lore raw

v4 cover arm64: GICv3 support

Quoted 5 lines · Abel

Hi Marc,

Add:

s/Acked/Reviewed/ :)

Quoted 151 lines

for the first 4 patches, that is:

Quoted 4 lines

ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3

Cheers,
Abel.

Quoted 137 lines · Marc Zyngier

GICv3 is the base for a new generation of interrupt controllers designed to overcome some of the most glaring limitations of GICv2.

Some of the features are:
- Support for more than 8 CPUs (a lot more...)
- System registers for CPU interface access (instead of the memory mapped GICC, GICV, GICH)
- Message based interrupts

This patch series currently support:
- Affinity Routing
- System Registers
- Non-Secure Group-1 interrupts only
- KVM support (GICv3 host, GICv2 guest)

What is *not yet* supported in this series (WIP):
- LPI/ITS/MSI
- KVM GICv3 guest support
- Any form of power management
- 32bit systems

To be built, this code requires a fairly recent compiler/binutils combo. Linaro 13.06 seems to do the trick. This has been tested on the ARM FVP and Foundation models, with non-regressions run on a VExpress TC-2 and another Cortex-A57 based platform.

So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for being the only ones to review it). While the documentation is unfortunately not public yet, it is available to those actively implementing GICv3 in their hardware, and I'm really eager to see reviews and test reports.

Without that kind of engagement, it is unlikely that this code will get merged any time soon.

Individuals without access to documentation and/or hardware can still review the code (it shares a lot of concepts with GICv2) and test in on the freely available Foundation model (see
http://releases.linaro.org/latest/openembedded/aarch64/ for details on how to use the Foundation model).

The code is also available at the following location (warning, unstable branch!):
git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git kvm-arm64/gicv3

* From v3 [3]
- Fixed a lot of issues found by Christoffer (too many to report here, see the email thread)
- New .sync_lr_elrsr backend
- New probing method
- New irqchip_in_kernel implementation
- Checked full bisectability of the series (hopefully got it right

    this time...)

- rebased on top of 3.15-rc5

* From v2 [2]
- removed sharing of the xlate method with GICv2 (TI crossbar is now getting in the way...)
- Switched to a tree domain to accomodate for the LPI space
- Fixed more bisectability

* From the initial revision [1]
- Some code sharing with GICv2
- Barrier cleanup/clarification
- Revised boot protocol update
- Consistent use of the MPIDR access macros
- Fixed a number of embarassing bugs
- Fixed DT examples
- Fixed bisectability of the series

[1]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-February/229959.html
[2]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-March/241972.html
[3]: http://lists.infradead.org/pipermail/linux-arm-kernel/2014-April/248008.html

Marc Zyngier (20):
ARM: GIC: move some bits of GICv2 to a library-type file
arm64: initial support for GICv3
arm64: GICv3 device tree binding documentation
arm64: boot protocol documentation update for GICv3
KVM: arm/arm64: vgic: move GICv2 registers to their own structure
KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
KVM: ARM: vgic: abstract access to the ELRSR bitmap
KVM: ARM: vgic: abstract EISR bitmap access
KVM: ARM: vgic: abstract MISR decoding
KVM: ARM: vgic: move underflow handling to vgic_ops
KVM: ARM: vgic: abstract VMCR access
KVM: ARM: vgic: introduce vgic_enable
KVM: ARM: introduce vgic_params structure
KVM: ARM: vgic: split GICv2 backend from the main vgic code
KVM: ARM: vgic: revisit implementation of irqchip_in_kernel
arm64: KVM: remove __kvm_hyp_code_{start,end} from hyp.S
arm64: KVM: split GICv2 world switch from hyp code
arm64: KVM: move HCR_EL2.{IMO,FMO} manipulation into the vgic switch
code
KVM: ARM: vgic: add the GICv3 backend
arm64: KVM: vgic: add GICv3 world switch

 Documentation/arm64/booting.txt                  |   6 +
 Documentation/devicetree/bindings/arm/gic-v3.txt |  79 +++
 arch/arm/include/asm/kvm_host.h                  |   5 +
 arch/arm/kernel/asm-offsets.c                    |  14 +-
 arch/arm/kvm/Makefile                            |   1 +
 arch/arm/kvm/interrupts_head.S                   |  26 +-
 arch/arm64/Kconfig                               |   1 +
 arch/arm64/include/asm/kvm_arm.h                 |   5 +-
 arch/arm64/include/asm/kvm_asm.h                 |  14 +-
 arch/arm64/include/asm/kvm_host.h                |  28 +
 arch/arm64/include/asm/virt.h                    |   4 +
 arch/arm64/kernel/asm-offsets.c                  |  25 +-
 arch/arm64/kernel/head.S                         |  18 +
 arch/arm64/kernel/hyp-stub.S                     |   1 +
 arch/arm64/kvm/Makefile                          |   4 +
 arch/arm64/kvm/hyp.S                             | 127 +----
 arch/arm64/kvm/vgic-v2-switch.S                  | 133 +++++
 arch/arm64/kvm/vgic-v3-switch.S                  | 271 +++++++++
 drivers/irqchip/Kconfig                          |   5 +
 drivers/irqchip/Makefile                         |   3 +-
 drivers/irqchip/irq-gic-common.c                 | 115 ++++
 drivers/irqchip/irq-gic-common.h                 |  29 +
 drivers/irqchip/irq-gic-v3.c                     | 684 +++++++++++++++++++++++
 drivers/irqchip/irq-gic.c                        |  59 +-
 include/kvm/arm_vgic.h                           | 115 +++-
 include/linux/irqchip/arm-gic-v3.h               | 190 +++++++
 virt/kvm/arm/vgic-v2.c                           | 236 ++++++++
 virt/kvm/arm/vgic-v3.c                           | 225 ++++++++
 virt/kvm/arm/vgic.c                              | 345 ++++++------
 29 files changed, 2415 insertions(+), 353 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/gic-v3.txt
 create mode 100644 arch/arm64/kvm/vgic-v2-switch.S
 create mode 100644 arch/arm64/kvm/vgic-v3-switch.S
 create mode 100644 drivers/irqchip/irq-gic-common.c
 create mode 100644 drivers/irqchip/irq-gic-common.h
 create mode 100644 drivers/irqchip/irq-gic-v3.c
 create mode 100644 include/linux/irqchip/arm-gic-v3.h
 create mode 100644 virt/kvm/arm/vgic-v2.c
 create mode 100644 virt/kvm/arm/vgic-v3.c