arm64: KVM: Use static keys for selecting the GIC backend
authorVladimir Murzin <vladimir.murzin@arm.com>
Mon, 12 Sep 2016 14:49:15 +0000 (15:49 +0100)
committerChristoffer Dall <christoffer.dall@linaro.org>
Thu, 22 Sep 2016 11:21:35 +0000 (13:21 +0200)
Currently GIC backend is selected via alternative framework and this
is fine. We are going to introduce vgic-v3 to 32-bit world and there
we don't have patching framework in hand, so we can either check
support for GICv3 every time we need to choose which backend to use or
try to optimise it by using static keys. The later looks quite
promising because we can share logic involved in selecting GIC backend
between architectures if both uses static keys.

This patch moves arm64 from alternative to static keys framework for
selecting GIC backend. For that we embed static key into vgic_global
and enable the key during vgic initialisation based on what has
already been exposed by the host GIC driver.

Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
arch/arm64/kvm/hyp/switch.c
include/kvm/arm_vgic.h
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic.c

index 731519cfee8e840dc3bbb16234655907b58c2573..83037cd62d013afa36b85788bccb757508ffcb00 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 #include <linux/types.h>
+#include <linux/jump_label.h>
+
 #include <asm/kvm_asm.h>
 #include <asm/kvm_emulate.h>
 #include <asm/kvm_hyp.h>
@@ -136,17 +138,13 @@ static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
        write_sysreg(0, vttbr_el2);
 }
 
-static hyp_alternate_select(__vgic_call_save_state,
-                           __vgic_v2_save_state, __vgic_v3_save_state,
-                           ARM64_HAS_SYSREG_GIC_CPUIF);
-
-static hyp_alternate_select(__vgic_call_restore_state,
-                           __vgic_v2_restore_state, __vgic_v3_restore_state,
-                           ARM64_HAS_SYSREG_GIC_CPUIF);
-
 static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
 {
-       __vgic_call_save_state()(vcpu);
+       if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+               __vgic_v3_save_state(vcpu);
+       else
+               __vgic_v2_save_state(vcpu);
+
        write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
 }
 
@@ -159,7 +157,10 @@ static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
        val |= vcpu->arch.irq_lines;
        write_sysreg(val, hcr_el2);
 
-       __vgic_call_restore_state()(vcpu);
+       if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif))
+               __vgic_v3_restore_state(vcpu);
+       else
+               __vgic_v2_restore_state(vcpu);
 }
 
 static bool __hyp_text __true_value(void)
index bb46c03eb3c730e7ece3ab447ad6e44dbf756478..8d22adcfe522cf061d26291386752442afb2d5a2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/types.h>
 #include <kvm/iodev.h>
 #include <linux/list.h>
+#include <linux/jump_label.h>
 
 #define VGIC_V3_MAX_CPUS       255
 #define VGIC_V2_MAX_CPUS       8
@@ -67,6 +68,9 @@ struct vgic_global {
 
        /* Only needed for the legacy KVM_CREATE_IRQCHIP */
        bool                    can_emulate_gicv2;
+
+       /* GIC system register CPU interface */
+       struct static_key_false gicv3_cpuif;
 };
 
 extern struct vgic_global kvm_vgic_global_state;
index 83777c1cbae0693c14e1d3f23df927c5cae25fef..8cebfbc19e90ef053ec325f7d7d75ab7e626a049 100644 (file)
@@ -405,6 +405,10 @@ int kvm_vgic_hyp_init(void)
                break;
        case GIC_V3:
                ret = vgic_v3_probe(gic_kvm_info);
+               if (!ret) {
+                       static_branch_enable(&kvm_vgic_global_state.gicv3_cpuif);
+                       kvm_info("GIC system register CPU interface enabled\n");
+               }
                break;
        default:
                ret = -ENODEV;
index e83b7fe4baaed1e1c5bc5f7fd520995002186b61..8a529a732941633189c7d3662f9227727ea9dcfc 100644 (file)
@@ -29,7 +29,7 @@
 #define DEBUG_SPINLOCK_BUG_ON(p)
 #endif
 
-struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
+struct vgic_global __section(.hyp.text) kvm_vgic_global_state = {.gicv3_cpuif = STATIC_KEY_FALSE_INIT,};
 
 /*
  * Locking order is always: