]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
KVM: arm/arm64: Register iodevs when setting redist base and creating VCPUs
authorChristoffer Dall <cdall@linaro.org>
Mon, 8 May 2017 10:30:24 +0000 (12:30 +0200)
committerChristoffer Dall <cdall@linaro.org>
Tue, 9 May 2017 10:19:36 +0000 (12:19 +0200)
Instead of waiting with registering KVM iodevs until the first VCPU is
run, we can actually create the iodevs when the redist base address is
set.  The only downside is that we must now also check if we need to do
this for VCPUs which are created after creating the VGIC, because there
is no enforced ordering between creating the VGIC (and setting its base
addresses) and creating the VCPUs.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
include/kvm/arm_vgic.h
virt/kvm/arm/arm.c
virt/kvm/arm/vgic/vgic-init.c
virt/kvm/arm/vgic/vgic-kvm-device.c
virt/kvm/arm/vgic/vgic-mmio-v3.c
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic.h

index fabcc649e2ce5ad5ef6af042cd8e90e982273d54..4ff65efcfebd19227a587752da109a5718672ed5 100644 (file)
@@ -286,6 +286,7 @@ extern struct static_key_false vgic_v2_cpuif_trap;
 
 int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write);
 void kvm_vgic_early_init(struct kvm *kvm);
+int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu);
 int kvm_vgic_create(struct kvm *kvm, u32 type);
 void kvm_vgic_destroy(struct kvm *kvm);
 void kvm_vgic_vcpu_early_init(struct kvm_vcpu *vcpu);
index 7941699a766d43c4d3372839a7b360815f387511..9f6f522a4bfc411adf8025f99466e40afd685bcc 100644 (file)
@@ -335,7 +335,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 
        kvm_arm_reset_debug_ptr(vcpu);
 
-       return 0;
+       return kvm_vgic_vcpu_init(vcpu);
 }
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
index 0ea64a1beff9ac7e122c7c89ba09d31392a72722..962bb577a1a0556bce5103961a595415a4260e09 100644 (file)
@@ -226,6 +226,27 @@ static int kvm_vgic_dist_init(struct kvm *kvm, unsigned int nr_spis)
        return 0;
 }
 
+/**
+ * kvm_vgic_vcpu_init() - Register VCPU-specific KVM iodevs
+ * @vcpu: pointer to the VCPU being created and initialized
+ */
+int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
+{
+       int ret = 0;
+       struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+       if (!irqchip_in_kernel(vcpu->kvm))
+               return 0;
+
+       /*
+        * If we are creating a VCPU with a GICv3 we must also register the
+        * KVM io device for the redistributor that belongs to this VCPU.
+        */
+       if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
+               ret = vgic_register_redist_iodev(vcpu);
+       return ret;
+}
+
 static void kvm_vgic_vcpu_enable(struct kvm_vcpu *vcpu)
 {
        if (kvm_vgic_global_state.type == VGIC_V2)
index 69ccfd5b22713e57f77d61f5d3dcc82645bfc7f6..10ae6f394b718d8e49805d23481974b0526764d1 100644 (file)
@@ -86,8 +86,13 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
                break;
        case KVM_VGIC_V3_ADDR_TYPE_REDIST:
                r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V3);
+               if (r)
+                       break;
+               if (write) {
+                       r = vgic_v3_set_redist_base(kvm, *addr);
+                       goto out;
+               }
                addr_ptr = &vgic->vgic_redist_base;
-               alignment = SZ_64K;
                break;
        default:
                r = -ENODEV;
index 168269b4e28d4f5258a207a7bf9a7f39c2094516..99da1a207c19b0563030bf4ad842d8d805b1b153 100644 (file)
@@ -565,7 +565,7 @@ unsigned int vgic_v3_init_dist_iodev(struct vgic_io_device *dev)
  *
  * Return 0 on success, -ERRNO otherwise.
  */
-static int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
+int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
 {
        struct kvm *kvm = vcpu->kvm;
        struct vgic_dist *vgic = &kvm->arch.vgic;
@@ -574,6 +574,18 @@ static int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
        gpa_t rd_base, sgi_base;
        int ret;
 
+       /*
+        * We may be creating VCPUs before having set the base address for the
+        * redistributor region, in which case we will come back to this
+        * function for all VCPUs when the base address is set.  Just return
+        * without doing any work for now.
+        */
+       if (IS_VGIC_ADDR_UNDEF(vgic->vgic_redist_base))
+               return 0;
+
+       if (!vgic_v3_check_base(kvm))
+               return -EINVAL;
+
        rd_base = vgic->vgic_redist_base + kvm_vcpu_get_idx(vcpu) * SZ_64K * 2;
        sgi_base = rd_base + SZ_64K;
 
@@ -619,7 +631,7 @@ static void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu)
        kvm_io_bus_unregister_dev(vcpu->kvm, KVM_MMIO_BUS, &sgi_dev->dev);
 }
 
-int vgic_register_redist_iodevs(struct kvm *kvm)
+static int vgic_register_all_redist_iodevs(struct kvm *kvm)
 {
        struct kvm_vcpu *vcpu;
        int c, ret = 0;
@@ -641,6 +653,33 @@ int vgic_register_redist_iodevs(struct kvm *kvm)
        return ret;
 }
 
+int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr)
+{
+       struct vgic_dist *vgic = &kvm->arch.vgic;
+       int ret;
+
+       /* vgic_check_ioaddr makes sure we don't do this twice */
+       ret = vgic_check_ioaddr(kvm, &vgic->vgic_redist_base, addr, SZ_64K);
+       if (ret)
+               return ret;
+
+       vgic->vgic_redist_base = addr;
+       if (!vgic_v3_check_base(kvm)) {
+               vgic->vgic_redist_base = VGIC_ADDR_UNDEF;
+               return -EINVAL;
+       }
+
+       /*
+        * Register iodevs for each existing VCPU.  Adding more VCPUs
+        * afterwards will register the iodevs when needed.
+        */
+       ret = vgic_register_all_redist_iodevs(kvm);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)
 {
        const struct vgic_register_region *region;
index 2d53d7a24bda65e439f8b4138654ae1a24db46be..bb35078f4e408e0ff0fe5acf35a392ccc9f74116 100644 (file)
@@ -397,12 +397,6 @@ int vgic_v3_map_resources(struct kvm *kvm)
                goto out;
        }
 
-       ret = vgic_register_redist_iodevs(kvm);
-       if (ret) {
-               kvm_err("Unable to register VGICv3 redist MMIO regions\n");
-               goto out;
-       }
-
        if (vgic_has_its(kvm)) {
                ret = vgic_register_its_iodevs(kvm);
                if (ret) {
index 89eb935c05befb9c10f295dedeb0e54f5dee0701..5f17eace077c360aec9afde43b0200625d419e15 100644 (file)
@@ -174,7 +174,8 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_v3_lpi_sync_pending_status(struct kvm *kvm, struct vgic_irq *irq);
 int vgic_v3_save_pending_tables(struct kvm *kvm);
-int vgic_register_redist_iodevs(struct kvm *kvm);
+int vgic_v3_set_redist_base(struct kvm *kvm, u64 addr);
+int vgic_register_redist_iodev(struct kvm_vcpu *vcpu);
 bool vgic_v3_check_base(struct kvm *kvm);
 
 void vgic_v3_load(struct kvm_vcpu *vcpu);