KVM: arm64: vgic-its: Enable ITS emulation as a virtual MSI controller
authorAndre Przywara <andre.przywara@arm.com>
Fri, 15 Jul 2016 11:43:38 +0000 (12:43 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Mon, 18 Jul 2016 17:14:38 +0000 (18:14 +0100)
Now that all ITS emulation functionality is in place, we advertise
MSI functionality to userland and also the ITS device to the guest - if
userland has configured that.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Documentation/virtual/kvm/api.txt
arch/arm64/kvm/Kconfig
arch/arm64/kvm/Makefile
arch/arm64/kvm/reset.c
include/kvm/arm_vgic.h
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.c
virt/kvm/arm/vgic/vgic.h

index 65513119fee87d2a774df5758edfafea7e979425..07049eadb1243258f50fca9f924ccf17c1789066 100644 (file)
@@ -2162,7 +2162,7 @@ after pausing the vcpu, but before it is resumed.
 4.71 KVM_SIGNAL_MSI
 
 Capability: KVM_CAP_SIGNAL_MSI
-Architectures: x86
+Architectures: x86 arm64
 Type: vm ioctl
 Parameters: struct kvm_msi (in)
 Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
index aa2e34e99582dfd1bd308d0a39829f3ae33a99c5..9d2eff0b3ad347b95d9e8a5ddd0b3e24f9ae24e1 100644 (file)
@@ -36,6 +36,7 @@ config KVM
        select HAVE_KVM_IRQFD
        select KVM_ARM_VGIC_V3
        select KVM_ARM_PMU if HW_PERF_EVENTS
+       select HAVE_KVM_MSI
        ---help---
          Support hosting virtualized guest machines.
          We don't support KVM with 16K page tables yet, due to the multiple
index f00b2cdd0d337dc7a775deb829121aef37a85a14..a5b96642a9cb9cf97d842e785711a9c7f9125a4c 100644 (file)
@@ -29,5 +29,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o
+kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o
 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
index e95d4f68bf544f652ab9a24005ac57d76c6356ec..5bc460884639f1dcf3298393ed92bf75a612d5f2 100644 (file)
@@ -86,6 +86,12 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_VCPU_ATTRIBUTES:
                r = 1;
                break;
+       case KVM_CAP_MSI_DEVID:
+               if (!kvm)
+                       r = -EINVAL;
+               else
+                       r = kvm->arch.vgic.msis_require_devid;
+               break;
        default:
                r = 0;
        }
index a6ca326055cffdddda63152278e8e88df7f44402..4e63a07b9001f5fa248a9e611d87c9100676e0ed 100644 (file)
@@ -163,6 +163,9 @@ struct vgic_dist {
        /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */
        u32                     vgic_model;
 
+       /* Do injected MSIs require an additional device ID? */
+       bool                    msis_require_devid;
+
        int                     nr_spis;
 
        /* TODO: Consider moving to global state */
@@ -308,4 +311,6 @@ static inline int kvm_vgic_get_max_vcpus(void)
        return kvm_vgic_global_state.max_gic_vcpus;
 }
 
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi);
+
 #endif /* __KVM_ARM_VGIC_H */
index 535e713704f08f9955e0023923efc1562492918b..01a60dcd05d626f2d6a52b5e8bcefd1683184b5f 100644 (file)
@@ -258,6 +258,9 @@ int vgic_init(struct kvm *kvm)
        if (ret)
                goto out;
 
+       if (vgic_has_its(kvm))
+               dist->msis_require_devid = true;
+
        kvm_for_each_vcpu(i, vcpu, kvm)
                kvm_vgic_vcpu_init(vcpu);
 
index 561d2ba96a4f2ed3f6a2c83860d76c5732eb1045..1813f93b5cde0ac95edbe1719abc827cfc47cd4a 100644 (file)
@@ -223,6 +223,9 @@ int kvm_register_vgic_device(unsigned long type)
        case KVM_DEV_TYPE_ARM_VGIC_V3:
                ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops,
                                              KVM_DEV_TYPE_ARM_VGIC_V3);
+               if (ret)
+                       break;
+               ret = kvm_vgic_register_its_device();
                break;
 #endif
        }
index 84a301d789e0158d3e6c4ca9771879cee6e2df83..ff668e0dd586de477767b796e780597c6736eeca 100644 (file)
@@ -66,7 +66,12 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu,
        case GICD_TYPER:
                value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS;
                value = (value >> 5) - 1;
-               value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+               if (vgic_has_its(vcpu->kvm)) {
+                       value |= (INTERRUPT_ID_BITS_ITS - 1) << 19;
+                       value |= GICD_TYPER_LPIS;
+               } else {
+                       value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19;
+               }
                break;
        case GICD_IIDR:
                value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0);
@@ -163,9 +168,8 @@ static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
 
        vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS;
 
-       if (!was_enabled && vgic_cpu->lpis_enabled) {
-               /* Eventually do something */
-       }
+       if (!was_enabled && vgic_cpu->lpis_enabled)
+               vgic_enable_lpis(vcpu);
 }
 
 static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
@@ -179,6 +183,8 @@ static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu,
        value |= ((target_vcpu_id & 0xffff) << 8);
        if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1)
                value |= GICR_TYPER_LAST;
+       if (vgic_has_its(vcpu->kvm))
+               value |= GICR_TYPER_PLPIS;
 
        return extract_bytes(value, addr & 7, len);
 }
index 53299fc93c157c0c73f6c9b1ab8698a5a3f4340a..424cb9ceebd9785051a28869e057e63eb9e5c7b3 100644 (file)
@@ -718,3 +718,11 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq)
 
        return map_is_active;
 }
+
+int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi)
+{
+       if (vgic_has_its(kvm))
+               return vgic_its_inject_msi(kvm, msi);
+       else
+               return -ENODEV;
+}
index 9d557f25cbfc20abba356a0285b300b77b71a769..9d40d7bb89f7ee881742804e13affa2fee237fcd 100644 (file)
@@ -77,6 +77,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info);
 int vgic_v3_map_resources(struct kvm *kvm);
 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address);
 bool vgic_has_its(struct kvm *kvm);
+int kvm_vgic_register_its_device(void);
 void vgic_enable_lpis(struct kvm_vcpu *vcpu);
 int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
 #else
@@ -136,6 +137,11 @@ static inline bool vgic_has_its(struct kvm *kvm)
        return false;
 }
 
+static inline int kvm_vgic_register_its_device(void)
+{
+       return -ENODEV;
+}
+
 static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu)
 {
 }