arm64: GICv3 support
Subsystems (7)
v2 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:
- LPI/ITS/MSI (patches are available in the below branch, though still in development)
- KVM GICv3 guest support (requires GICv3 distributor emulation, WIP)
- 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.
So far, the level of reviewing has been embarassingly low (my sincere thanks to Christoffer and Will for undertaking 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 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
Marc Zyngier (19):
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
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 setting into vgic-v2-switch.S
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_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 | 133 +---- arch/arm64/kvm/vgic-v2-switch.S | 149 ++++++ arch/arm64/kvm/vgic-v3-switch.S | 279 ++++++++++ drivers/irqchip/Kconfig | 5 + drivers/irqchip/Makefile | 3 +- drivers/irqchip/irq-gic-common.c | 132 +++++ drivers/irqchip/irq-gic-common.h | 33 ++ drivers/irqchip/irq-gic-v3.c | 650 +++++++++++++++++++++++ drivers/irqchip/irq-gic.c | 80 +-- include/kvm/arm_vgic.h | 103 +++- include/linux/irqchip/arm-gic-v3.h | 188 +++++++ virt/kvm/arm/vgic-v2.c | 228 ++++++++ virt/kvm/arm/vgic-v3.c | 220 ++++++++ virt/kvm/arm/vgic.c | 330 ++++++------ 28 files changed, 2365 insertions(+), 394 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
PATCH v2 1/19 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 | 132 +++++++++++++++++++++++++++++++++++++++ drivers/irqchip/irq-gic-common.h | 33 ++++++++++ drivers/irqchip/irq-gic.c | 80 ++---------------------- 4 files changed, 170 insertions(+), 77 deletions(-) create mode 100644 drivers/irqchip/irq-gic-common.c create mode 100644 drivers/irqchip/irq-gic-common.h
drivers/irqchip/Makefile +1 -1
@@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.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 +132 -0
132 lines not on this page · raw message
drivers/irqchip/irq-gic-common.h new file +33 -0
@@ -0,0 +1,33 @@ +/* +* 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 )); +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); + +#endif /* _IRQ_GIC_COMMON_H */
drivers/irqchip/irq-gic.c +4 -76
122 lines not on this page · raw message
Signature · 1 line
1.8.3.4
PATCH v2 2/19 arm64: initial support for GICv3
In reply to Marc ZyngierThe 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 | 650 +++++++++++++++++++++++++++++++++++++ include/linux/irqchip/arm-gic-v3.h | 188 +++++++++++ 7 files changed, 864 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
@@ -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
@@ -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>
@@ -183,6 +184,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
@@ -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
@@ -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
@@ -14,6 +14,7 @@ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.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 +650 -0
650 lines not on this page · raw message
include/linux/irqchip/arm-gic-v3.h new file +188 -0
188 lines not on this page · raw message
Signature · 1 line
1.8.3.4
A message that is not in the archive (sent off-list or not yet received): CAMDttNew0S7xVVKge7AAR3W6bdQzKdvN9Z7cHPDUCq=jZ98q1A@mail.gmail.com
PATCH v2 2/19 arm64: initial support for GICv3
Hi Zi,
Quoted 24 lines · Zi Shen Lim
Hi Marc,
On Thu, Mar 20, 2014 at 4:52 AM, Marc Zyngier <[email protected] <mailto:[email protected]>> wrote:
<snip>+ /*
+ * 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_linear(node,gic_irqs- 16,
+&gic_irq_domain_ops,
&gic_data);
Quoted 1 line
Why
gic_irqs- 16?
Because we keep the SGIs (all 16 of them) for the core kernel (drivers are not allowed to request them).
Quoted 10 lines
__irq_domain_add(of_node, size, size, 0, ops, host_data); domain->hwirq_max = hwirq_max;So
hwirq_maxis effectively set to actual_hwirq_max-16.Later, the following warning can be triggered:
Quoted 10 lines
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
{
struct irq_data *irq_data = irq_get_irq_data(virq);
int ret;
if (WARN(hwirq >= domain->hwirq_max,
"error: hwirq 0x%x is too large for %s\n",
(int)hwirq, domain->name))
return -EINVAL;Do you actually see this warning being triggered? I don't. We're using a linear domain that doesn't call into this function.
What am I missing?
Cheers,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
A message that is not in the archive (sent off-list or not yet received): CABg9mcucJ_UouRbJ_Urirz6ita5uUvYuQkmeA1-Df00KSjFcnA@mail.gmail.com
PATCH v2 2/19 arm64: initial support for GICv3
Quoted 60 lines · Z Lim
Hi Marc,
Quoted 7 lines · On Mon, Mar 24, 2014 at 4:10 AM, Marc Zyngier <[email protected]…
Hi Zi,
Quoted 3 lines · Zi Shen Lim
Hi Marc,
On Thu, Mar 20, 2014 at 4:52 AM, Marc Zyngier <[email protected]
<mailto:[email protected]>
Quoted 21 lines
Quoted 21 lines
<mailto:marc.zyngier at arm.com <mailto:[email protected]>>> wrote:
<snip>+ /*
+ * 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_linear(node,gic_irqs- 16,
+&gic_irq_domain_ops,
&gic_data);Quoted 16 lines
Quoted 1 line
Why
gic_irqs- 16?Because we keep the SGIs (all 16 of them) for the core kernel (drivers are not allowed to request them).
Quoted 11 lines
__irq_domain_add(of_node, size, size, 0, ops, host_data); domain->hwirq_max = hwirq_max;So
hwirq_maxis effectively set to actual_hwirq_max-16.Later, the following warning can be triggered:
int irq_domain_associate(struct
irq_domain*domain, unsigned intvirq,
Quoted 10 lines
Quoted 9 lines
irq_hw_number_t hwirq) { struct irq_data *irq_data = irq_get_irq_data(virq); int ret; if (WARN(hwirq >= domain->hwirq_max, "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name)) return -EINVAL;
Quoted 6 lines
Quoted 2 lines
Do you actually see this warning being triggered? I don't. We're using a linear domain that doesn't call into this function.
I see this warning :(
You can trigger it when a device's INT# falls within [gic_irqs-16,gic_irqs), which lines up with the -16 above.
Ah, got you. Hmmm. I may have to be slightly more creative then.
Thanks a lot for the report, I'll fix that as quickly as possible.
Cheers,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v2 2/19 arm64: initial support for GICv3
In reply to a message not in the archiveOn Tue, Mar 25 2014 at 6:35:18 am GMT, Z Lim <[email protected]> wrote:
Hi Zi,
Quoted 4 lines
I see this warning :(
You can trigger it when a device's INT# falls within [gic_irqs-16,gic_irqs), which lines up with the -16 above.
Quoted 11 lines
irq_create_of_mapping ?// SPI# from DT
domain->ops->xlate (gic_irq_domain_xlate) ?// SPI# + 32 = INT# = hwirq
irq_create_mapping ?// uses hwirq = INT#
irq_domain_associate ?// uses hwirq = INT#
if (WARN(hwirq >= domain->hwirq_max, "error: hwirq 0x%x is too
large for %s\n", (int)hwirq, domain->name)) ?// hwirq_max was
set to (MAX_INT# - 16) above, uh oh...I'm about to push out the following fix. Can you give it a go and let me know if that works for you?
Thanks,
M.
drivers/irqchip/irq-gic-v3.c +3 -1
@@ -552,6 +552,8 @@ static struct irq_chip gic_chip = {static int gic_irq_domain_map (struct irq_domain *d,unsigned int irq,irq_hw_number_t hw) { +if (hw <16 )/* SGIs are private to the core kernel */ +return -EPERM ;if (hw <32 ) {irq_set_percpu_devid (irq); irq_set_chip_and_handler(irq, &gic_chip,
@@ -642,7 +644,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare gic_irqs =1020 ; gic_data.irq_nr = gic_irqs; - gic_data.domain =irq_domain_add_linear (node, gic_irqs -16 , + gic_data.domain =irq_domain_add_linear (node, gic_irqs, &gic_irq_domain_ops, &gic_data); gic_data.rdist.rdist =alloc_percpu (typeof (*gic_data.rdist.rdist));
Signature · 1 line
Jazz is not dead. It just smells funny.
A message that is not in the archive (sent off-list or not yet received): CABg9mcsWrjsBaDbk0fdJPJdzhQ6jmgZOkDNG0_r7ZbWzcCdb0A@mail.gmail.com
PATCH v2 2/19 arm64: initial support for GICv3
Quoted 66 lines · Z Lim
On Tue, Mar 25, 2014 at 3:13 AM, Marc Zyngier <[email protected] <mailto:[email protected]>> wrote:
On Tue, Mar 25 2014 at 6:35:18 am GMT, Z Lim <[email protected] <mailto:[email protected]>> wrote: Hi Zi, > I see this warning :( > You can trigger it when a device's INT# falls within [gic_irqs-16, gic_irqs), > which lines up with the -16 above. > > irq_create_of_mapping // SPI# from DT > > domain->ops->xlate (gic_irq_domain_xlate) // SPI# + 32 = INT# = hwirq > > irq_create_mapping // uses hwirq = INT# > > irq_domain_associate // uses hwirq = INT# > > if (WARN(hwirq >= domain->hwirq_max, "error: hwirq 0x%x is too > large for %s\n", (int)hwirq, domain->name)) // hwirq_max was > set to (MAX_INT# - 16) above, uh oh... I'm about to push out the following fix. Can you give it a go and let me know if that works for you? Thanks, M. diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 60ef92d..b90ea2c 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -552,6 +552,8 @@ static struct irq_chip gic_chip = { static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { + if (hw < 16) /* SGIs are private to the core kernel */ + return -EPERM; if (hw < 32) { irq_set_percpu_devid(irq); irq_set_chip_and_handler(irq, &gic_chip, @@ -642,7 +644,7 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare gic_irqs = 1020; gic_data.irq_nr = gic_irqs; - gic_data.domain = irq_domain_add_linear(node, gic_irqs - 16, + gic_data.domain = irq_domain_add_linear(node, gic_irqs, &gic_irq_domain_ops, &gic_data); gic_data.rdist.rdist = alloc_percpu(typeof(*gic_data.rdist.rdist));
Quoted 3 lines
LGTM. Also tested on model.
Reviewed-by Zi Shen Lim <zlim at broadcom.com <mailto:[email protected]>>
Excellent. Thanks for testing!
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v2 2/19 arm64: initial support for GICv3
In reply to Marc ZyngierHi Marc,
Quoted 16 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.
Acked-by Catalin Marinas <[email protected]>Signed-off-by Marc Zyngier <[email protected]>
[...]
Quoted 8 lines
drivers/irqchip/irq-gic-v3.c new file +8
-0+#ifdef CONFIG_SMP +static int __init 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 ; +}
drivers/irqchip/irq-gic-v3.c line 409
Quoted 10 lines
drivers/irqchip/irq-gic-v3.c new file +10
-0+ +/* +* 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 __initdata gic_cpu_notifier = { + .notifier_call = gic_secondary_init, + .priority =100 , +}; +
You need to remove __init annotations in gic_populate_rdist, gic_cpu_init, and gic_secondary_init for CPU hotplug to work.
Regards,
Sudeep
PATCH v2 2/19 arm64: initial support for GICv3
Hi Sudeep,
Quoted 35 lines · Sudeep Holla
Hi Marc,
Quoted 16 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.
Acked-by Catalin Marinas <[email protected]>Signed-off-by Marc Zyngier <[email protected]>[...]
Quoted 13 lines
drivers/irqchip/irq-gic-v3.c new file +13
-0+#ifdef CONFIG_SMP +static int __init 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. +*/
Quoted 8 lines
drivers/irqchip/irq-gic-v3.c line 409
Quoted 5 lines
drivers/irqchip/irq-gic-v3.c new file +5
-0+static struct notifier_block __initdata gic_cpu_notifier = { + .notifier_call = gic_secondary_init, + .priority =100 , +}; +You need to remove
__initannotations ingic_populate_rdist,gic_cpu_init, andgic_secondary_initfor CPU hotplug to work.
Ah, who needs hotplug? ;-)
Very good point, thanks for noticing that. I'll fix it in the next revision!
Cheers,
M.
Signature · 1 line
Jazz is not dead. It just smells funny...
PATCH v2 3/19 arm64: GICv3 device tree binding documentation
In reply to Marc ZyngierAdd 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
@@ -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
PATCH v2 4/19 arm64: boot protocol documentation update for GICv3
In reply to Marc ZyngierLinux 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
@@ -131,6 +131,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
PATCH v2 5/19 KVM: arm/arm64: vgic: move GICv2 registers to their own structure
In reply to Marc ZyngierIn 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 +++++++++---------- drivers/irqchip/irq-gic-v3.c | 4 +-- include/kvm/arm_vgic.h | 20 +++++++++------ virt/kvm/arm/vgic.c | 56 ++++++++++++++++++++--------------------- 7 files changed, 83 insertions(+), 77 deletions(-)
arch/arm/kernel/asm-offsets.c +7 -7
@@ -181,13 +181,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
@@ -413,14 +413,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
@@ -428,7 +428,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
@@ -455,9 +455,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]
@@ -465,7 +465,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
@@ -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
@@ -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
drivers/irqchip/irq-gic-v3.c +2 -2
@@ -45,8 +45,8 @@ struct gic_chip_data {static struct gic_chip_data gic_data__read_mostly ; -#define gic_data_rdist () (this_cpu_ptr(gic_data.rdist.rdist)) -#define gic_data_rdist_rd_base () (gic_data_rdist()->rd_base) +#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
include/kvm/arm_vgic.h +13 -7
@@ -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
PATCH v2 6/19 KVM: ARM: vgic: introduce vgic_ops and LR manipulation primitives
In reply to Marc ZyngierIn 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 | 170 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 132 insertions(+), 56 deletions(-)
include/kvm/arm_vgic.h +18 -0
@@ -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 +114 -56
275 lines not on this page · raw message
Signature · 1 line
1.8.3.4
PATCH v2 7/19 KVM: ARM: vgic: abstract access to the ELRSR bitmap
In reply to Marc ZyngierMove the GICH_ELRSR access to its own function, and add it to the vgic_ops structure.
--- include/kvm/arm_vgic.h | 1 + virt/kvm/arm/vgic.c | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-)
include/kvm/arm_vgic.h +1 -0
@@ -84,6 +84,7 @@ 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 ); +u64 (*get_elrsr)(const struct kvm_vcpu *vcpu); };struct vgic_dist {
virt/kvm/arm/vgic.c +16 -4
@@ -1022,9 +1022,16 @@ static void vgic_v2_set_lr(struct kvm_vcpu *vcpu, int lr,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, + .get_elrsr = vgic_v2_get_elrsr, };static inline struct vgic_lr vgic_get_lr (const struct kvm_vcpu *vcpu,int lr)
@@ -1038,6 +1045,11 @@ static inline void vgic_set_lr(struct kvm_vcpu *vcpu, int lr, vgic_ops.set_lr (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;
@@ -1278,14 +1290,15 @@ 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 =vgic_get_elrsr (vcpu); +unsigned long *elrsr_ptr = (unsigned long *)&elrsr;int lr, pending;bool level_pending; level_pending =vgic_process_maintenance (vcpu);/* 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 +1311,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
PATCH v2 8/19 KVM: ARM: vgic: abstract EISR bitmap access
In reply to Marc ZyngierMove the GICH_EISR access to its own function.
--- include/kvm/arm_vgic.h | 1 + virt/kvm/arm/vgic.c | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-)
include/kvm/arm_vgic.h +1 -0
@@ -85,6 +85,7 @@ struct vgic_ops {struct vgic_lr (*get_lr)(const struct kvm_vcpu *,int );void (*set_lr)(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 -1
@@ -1028,10 +1028,17 @@ 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, .get_elrsr = vgic_v2_get_elrsr, + .get_eisr = vgic_v2_get_eisr, };static inline struct vgic_lr vgic_get_lr (const struct kvm_vcpu *vcpu,int lr)
@@ -1050,6 +1057,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;
@@ -1256,9 +1268,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, +for_each_set_bit (lr, eisr_ptr, vgic_cpu->nr_lr) { vgic_cpu->nr_lr) {struct vgic_lr vlr =vgic_get_lr (vcpu, lr);
Signature · 1 line
1.8.3.4
PATCH v2 9/19 KVM: ARM: vgic: abstract MISR decoding
In reply to Marc ZyngierInstead 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
@@ -86,6 +86,7 @@ struct vgic_ops {void (*set_lr)(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 {
@@ -164,6 +165,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
@@ -1034,11 +1034,25 @@ 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, .get_elrsr = vgic_v2_get_elrsr, .get_eisr = vgic_v2_get_eisr, + .get_interrupt_status = vgic_v2_get_interrupt_status, };static inline struct vgic_lr vgic_get_lr (const struct kvm_vcpu *vcpu,int lr)
@@ -1062,6 +1076,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;
@@ -1259,11 +1278,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.
@@ -1290,7 +1310,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
PATCH v2 10/19 KVM: ARM: vgic: move underflow handling to vgic_ops
In reply to Marc ZyngierMove 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
@@ -87,6 +87,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 (*set_underflow)(struct kvm_vcpu *vcpu); +void (*clear_underflow)(struct kvm_vcpu *vcpu); };struct vgic_dist {
virt/kvm/arm/vgic.c +25 -3
@@ -1047,12 +1047,24 @@ static u32 vgic_v2_get_interrupt_status(const struct kvm_vcpu *vcpu)return ret; } +static void vgic_v2_set_underflow (struct kvm_vcpu *vcpu) +{ + vcpu->arch.vgic_cpu.vgic_v2.vgic_hcr |=GICH_HCR_UIE ; +} + +static void vgic_v2_clear_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, .get_elrsr = vgic_v2_get_elrsr, .get_eisr = vgic_v2_get_eisr, .get_interrupt_status = vgic_v2_get_interrupt_status, + .set_underflow = vgic_v2_set_underflow, + .clear_underflow = vgic_v2_clear_underflow, };static inline struct vgic_lr vgic_get_lr (const struct kvm_vcpu *vcpu,int lr)
@@ -1081,6 +1093,16 @@ static inline u32 vgic_get_interrupt_status(struct kvm_vcpu *vcpu)return vgic_ops.get_interrupt_status (vcpu); } +static inline void vgic_set_underflow (struct kvm_vcpu *vcpu) +{ + vgic_ops.set_underflow (vcpu); +} + +static inline void vgic_clear_underflow (struct kvm_vcpu *vcpu) +{ + vgic_ops.clear_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;
@@ -1262,9 +1284,9 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu) epilog:if (overflow) { - vgic_cpu->vgic_v2.vgic_hcr |=GICH_HCR_UIE ; +vgic_set_underflow (vcpu); }else { - vgic_cpu->vgic_v2.vgic_hcr &= ~GICH_HCR_UIE ; +vgic_clear_underflow (vcpu);/* * We're about to run this VCPU, and we've consumed * everything the distributor had in store for
@@ -1311,7 +1333,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_clear_underflow (vcpu);return level_pending; }
Signature · 1 line
1.8.3.4
PATCH v2 11/19 KVM: ARM: vgic: abstract VMCR access
In reply to Marc ZyngierInstead 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
@@ -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 );
@@ -89,6 +96,8 @@ struct vgic_ops {u32 (*get_interrupt_status)(const struct kvm_vcpu *vcpu);void (*set_underflow)(struct kvm_vcpu *vcpu);void (*clear_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
PATCH v2 12/19 KVM: ARM: vgic: introduce vgic_enable
In reply to Marc ZyngierMove the code dealing with kicking 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
@@ -98,6 +98,7 @@ struct vgic_ops {void (*clear_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
@@ -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,
@@ -1091,6 +1104,7 @@ static const struct vgic_ops vgic_ops = { .clear_underflow = vgic_v2_clear_underflow, .get_vmcr = vgic_v2_get_vmcr, .set_vmcr = vgic_v2_set_vmcr, + .enable = vgic_v2_enable, };static inline struct vgic_lr vgic_get_lr (const struct kvm_vcpu *vcpu,int lr)
@@ -1139,6 +1153,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;
@@ -1593,15 +1612,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
PATCH v2 13/19 KVM: ARM: introduce vgic_params structure
In reply to Marc ZyngierMove 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 | 66 +++++++++++++++++++++----------------------------- 2 files changed, 39 insertions(+), 38 deletions(-)
include/kvm/arm_vgic.h +11 -0
@@ -101,6 +101,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 +28 -38
192 lines not on this page · raw message
Signature · 1 line
1.8.3.4
PATCH v2 14/19 KVM: ARM: vgic: split GICv2 backend from the main vgic code
In reply to Marc ZyngierBrutally 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 | 3 + virt/kvm/arm/vgic-v2.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++ virt/kvm/arm/vgic.c | 239 +++++++----------------------------------------- 5 files changed, 266 insertions(+), 208 deletions(-) create mode 100644 virt/kvm/arm/vgic-v2.c
arch/arm/kvm/Makefile +1 -0
@@ -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
@@ -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 +3 -0
@@ -213,6 +213,9 @@ 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 (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 +229 -0
229 lines not on this page · raw message
virt/kvm/arm/vgic.c +32 -207
370 lines not on this page · raw message
Signature · 1 line
1.8.3.4
PATCH v2 15/19 arm64: KVM: remove __kvm_hyp_code_{start, end} from hyp.S
In reply to Marc ZyngierWe 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
@@ -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.
@@ -95,8 +97,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_endextern 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
@@ -63,6 +63,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
@@ -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
PATCH v2 16/19 arm64: KVM: split GICv2 world switch from hyp code
In reply to Marc ZyngierMove 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 | 120 ++++++-------------------------- arch/arm64/kvm/vgic-v2-switch.S | 141 ++++++++++++++++++++++++++++++++++++++ include/kvm/arm_vgic.h | 7 +- virt/kvm/arm/vgic-v2.c | 15 ++-- virt/kvm/arm/vgic.c | 3 + 10 files changed, 213 insertions(+), 110 deletions(-) create mode 100644 arch/arm64/kvm/vgic-v2-switch.S
arch/arm/include/asm/kvm_host.h +5 -0
@@ -222,6 +222,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
@@ -104,6 +104,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
@@ -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
@@ -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
@@ -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 +20 -100
156 lines not on this page · raw message
arch/arm64/kvm/vgic-v2-switch.S new file +141 -0
141 lines not on this page · raw message
include/kvm/arm_vgic.h +6 -1
@@ -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
@@ -70,6 +69,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)
@@ -102,6 +105,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 +7 -8
@@ -170,7 +170,7 @@ int vgic_v2_probe(const struct vgic_ops **ops, vgic_node =of_find_compatible_node (NULL ,NULL ,"arm,cortex-a15-gic" );if (!vgic_node) { -kvm_err ("error: no compatible vgic node in DT\n" ); +kvm_err ("error: no compatible GICv2 node in DT\n" );return -ENODEV ; }
@@ -183,15 +183,15 @@ int vgic_v2_probe(const struct vgic_ops **ops, ret =of_address_to_resource (vgic_node,2 , &vctrl_res);if (ret) { -kvm_err ("Cannot obtain VCTRL resource\n" ); - goto out_free_irq; +kvm_err ("Cannot obtain GICH resource\n" ); + goto out; } vgic->vctrl_base =of_iomap (vgic_node,2 );if (!vgic->vctrl_base) { -kvm_err ("Cannot ioremap VCTRL\n" ); +kvm_err ("Cannot ioremap GICH\n" ); ret = -ENOMEM ; - goto out_free_irq; + goto out; } vgic->nr_lr =readl_relaxed (vgic->vctrl_base +GICH_VTR );
@@ -206,7 +206,7 @@ int vgic_v2_probe(const struct vgic_ops **ops, }if (of_address_to_resource (vgic_node,3 , &vcpu_res)) { -kvm_err ("Cannot obtain VCPU resource\n" ); +kvm_err ("Cannot obtain GICV resource\n" ); ret = -ENXIO ; goto out_unmap; }
@@ -215,14 +215,13 @@ int vgic_v2_probe(const struct vgic_ops **ops,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; out_unmap:iounmap (vgic->vctrl_base); -out_free_irq: -free_percpu_irq (vgic->maint_irq,kvm_get_running_vcpus ()); out:of_node_put (vgic_node);return ret;
virt/kvm/arm/vgic.c +3 -0
@@ -1531,6 +1531,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
PATCH v2 17/19 arm64: KVM: move hcr_el2 setting into vgic-v2-switch.S
In reply to Marc ZyngierGICv3 requires the hcr_el2 switch to be tightly coupled with some of the interrupt controller's register switch.
In order to have similar code paths, start moving the hcr_el2 manipulation code to the GICv2 switch code.
--- arch/arm64/kvm/hyp.S | 7 ------- arch/arm64/kvm/vgic-v2-switch.S | 8 ++++++++ 2 files changed, 8 insertions(+), 7 deletions(-)
arch/arm64/kvm/hyp.S +0 -7
@@ -335,11 +335,6 @@ .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, =(CPTR_EL2_TTA) msr cptr_el2, x2
@@ -353,8 +348,6 @@ .endm .macro deactivate_traps - mov x2, #HCR_RW - msr hcr_el2, x2 msr cptr_el2, xzr msr hstr_el2, xzr
arch/arm64/kvm/vgic-v2-switch.S +8 -0
@@ -85,6 +85,9 @@ CPU_BE( rev w5, w5 ) sub w4, w4, #1 cbnz w4, 1b 2: + mov x2, #HCR_RW + msr hcr_el2, x2 + isb .endm /*
@@ -92,6 +95,11 @@ CPU_BE( rev w5, w5 ) * x0: Register pointing to VCPU struct */ .macro restore_vgic_v2_state + ldr x2, [x0, #VCPU_IRQ_LINES] + ldr x1, [x0, #VCPU_HCR_EL2] + orr x2, x2, x1 + msr hcr_el2, x2 + /* Get VGIC VCTRL base into x2 */ ldr x2, [x0, #VCPU_KVM] kern_hyp_va x2
Signature · 1 line
1.8.3.4
PATCH v2 18/19 KVM: ARM: vgic: add the GICv3 backend
In reply to Marc ZyngierIntroduce the support code for emulating a GICv2 on top of GICv3 hardware.
--- include/kvm/arm_vgic.h | 26 ++++++ virt/kvm/arm/vgic-v3.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++ virt/kvm/arm/vgic.c | 2 + 3 files changed, 248 insertions(+) create mode 100644 virt/kvm/arm/vgic-v3.c
include/kvm/arm_vgic.h +26 -0
@@ -32,6 +32,7 @@#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_V3_MAX_LRS 16/* Sanity checks... */ #if (VGIC_MAX_CPUS >8 )
@@ -71,6 +72,7 @@ struct kvm_vcpu;enum vgic_type {VGIC_V2 ,/* Good ol' GICv2 */ +VGIC_V3 ,/* v2 on v3, really */ };#define LR_STATE_PENDING (1 << 0)
@@ -169,6 +171,19 @@ struct vgic_v2_cpu_if {u32 vgic_lr[VGIC_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 */
@@ -187,6 +202,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 };
@@ -220,6 +236,16 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,int vgic_v2_probe (const struct vgic_ops **ops,const struct vgic_params **params); +#ifdef CONFIG_ARM_GIC_V3 +int vgic_v3_probe (const struct vgic_ops **ops, +const struct vgic_params **params); +#else +static inline int vgic_v3_probe (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 +220 -0
220 lines not on this page · raw message
virt/kvm/arm/vgic.c +2 -0
@@ -1514,6 +1514,8 @@ int kvm_vgic_hyp_init(void) ret =vgic_v2_probe (&vgic_ops, &vgic);if (ret) + ret =vgic_v3_probe (&vgic_ops, &vgic); +if (ret)return ret; ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler,
Signature · 1 line
1.8.3.4
PATCH v2 19/19 arm64: KVM: vgic: add GICv3 world switch
In reply to Marc ZyngierIntroduce 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 | 279 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 300 insertions(+) create mode 100644 arch/arm64/kvm/vgic-v3-switch.S
arch/arm64/include/asm/kvm_asm.h +4 -0
@@ -105,8 +105,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
@@ -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
@@ -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
@@ -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 +279 -0
279 lines not on this page · raw message
Signature · 1 line
1.8.3.4