diff options
| author | Andre Przywara <andre.przywara@arm.com> | 2016-07-15 07:43:38 -0400 |
|---|---|---|
| committer | Marc Zyngier <marc.zyngier@arm.com> | 2016-07-18 13:14:38 -0400 |
| commit | 0e4e82f154e387969ea7ecd2c8876689fb68f710 (patch) | |
| tree | 684d959f3f33a71e91e5d53a868ba87d45d0e495 | |
| parent | 2891a7dfb6c4a273996f0047660a75e88e3b8690 (diff) | |
KVM: arm64: vgic-its: Enable ITS emulation as a virtual MSI controller
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>
| -rw-r--r-- | Documentation/virtual/kvm/api.txt | 2 | ||||
| -rw-r--r-- | arch/arm64/kvm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm64/kvm/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm64/kvm/reset.c | 6 | ||||
| -rw-r--r-- | include/kvm/arm_vgic.h | 5 | ||||
| -rw-r--r-- | virt/kvm/arm/vgic/vgic-init.c | 3 | ||||
| -rw-r--r-- | virt/kvm/arm/vgic/vgic-kvm-device.c | 3 | ||||
| -rw-r--r-- | virt/kvm/arm/vgic/vgic-mmio-v3.c | 14 | ||||
| -rw-r--r-- | virt/kvm/arm/vgic/vgic.c | 8 | ||||
| -rw-r--r-- | virt/kvm/arm/vgic/vgic.h | 6 |
10 files changed, 44 insertions, 5 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 65513119fee8..07049eadb124 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
| @@ -2162,7 +2162,7 @@ after pausing the vcpu, but before it is resumed. | |||
| 2162 | 4.71 KVM_SIGNAL_MSI | 2162 | 4.71 KVM_SIGNAL_MSI |
| 2163 | 2163 | ||
| 2164 | Capability: KVM_CAP_SIGNAL_MSI | 2164 | Capability: KVM_CAP_SIGNAL_MSI |
| 2165 | Architectures: x86 | 2165 | Architectures: x86 arm64 |
| 2166 | Type: vm ioctl | 2166 | Type: vm ioctl |
| 2167 | Parameters: struct kvm_msi (in) | 2167 | Parameters: struct kvm_msi (in) |
| 2168 | Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error | 2168 | Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error |
diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig index aa2e34e99582..9d2eff0b3ad3 100644 --- a/arch/arm64/kvm/Kconfig +++ b/arch/arm64/kvm/Kconfig | |||
| @@ -36,6 +36,7 @@ config KVM | |||
| 36 | select HAVE_KVM_IRQFD | 36 | select HAVE_KVM_IRQFD |
| 37 | select KVM_ARM_VGIC_V3 | 37 | select KVM_ARM_VGIC_V3 |
| 38 | select KVM_ARM_PMU if HW_PERF_EVENTS | 38 | select KVM_ARM_PMU if HW_PERF_EVENTS |
| 39 | select HAVE_KVM_MSI | ||
| 39 | ---help--- | 40 | ---help--- |
| 40 | Support hosting virtualized guest machines. | 41 | Support hosting virtualized guest machines. |
| 41 | We don't support KVM with 16K page tables yet, due to the multiple | 42 | We don't support KVM with 16K page tables yet, due to the multiple |
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index f00b2cdd0d33..a5b96642a9cb 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile | |||
| @@ -29,5 +29,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio.o | |||
| 29 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o | 29 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o |
| 30 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o | 30 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o |
| 31 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o | 31 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-kvm-device.o |
| 32 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-its.o | ||
| 32 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o | 33 | kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o |
| 33 | kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o | 34 | kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o |
diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index e95d4f68bf54..5bc460884639 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c | |||
| @@ -86,6 +86,12 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext) | |||
| 86 | case KVM_CAP_VCPU_ATTRIBUTES: | 86 | case KVM_CAP_VCPU_ATTRIBUTES: |
| 87 | r = 1; | 87 | r = 1; |
| 88 | break; | 88 | break; |
| 89 | case KVM_CAP_MSI_DEVID: | ||
| 90 | if (!kvm) | ||
| 91 | r = -EINVAL; | ||
| 92 | else | ||
| 93 | r = kvm->arch.vgic.msis_require_devid; | ||
| 94 | break; | ||
| 89 | default: | 95 | default: |
| 90 | r = 0; | 96 | r = 0; |
| 91 | } | 97 | } |
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index a6ca326055cf..4e63a07b9001 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h | |||
| @@ -163,6 +163,9 @@ struct vgic_dist { | |||
| 163 | /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */ | 163 | /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */ |
| 164 | u32 vgic_model; | 164 | u32 vgic_model; |
| 165 | 165 | ||
| 166 | /* Do injected MSIs require an additional device ID? */ | ||
| 167 | bool msis_require_devid; | ||
| 168 | |||
| 166 | int nr_spis; | 169 | int nr_spis; |
| 167 | 170 | ||
| 168 | /* TODO: Consider moving to global state */ | 171 | /* TODO: Consider moving to global state */ |
| @@ -308,4 +311,6 @@ static inline int kvm_vgic_get_max_vcpus(void) | |||
| 308 | return kvm_vgic_global_state.max_gic_vcpus; | 311 | return kvm_vgic_global_state.max_gic_vcpus; |
| 309 | } | 312 | } |
| 310 | 313 | ||
| 314 | int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); | ||
| 315 | |||
| 311 | #endif /* __KVM_ARM_VGIC_H */ | 316 | #endif /* __KVM_ARM_VGIC_H */ |
diff --git a/virt/kvm/arm/vgic/vgic-init.c b/virt/kvm/arm/vgic/vgic-init.c index 535e713704f0..01a60dcd05d6 100644 --- a/virt/kvm/arm/vgic/vgic-init.c +++ b/virt/kvm/arm/vgic/vgic-init.c | |||
| @@ -258,6 +258,9 @@ int vgic_init(struct kvm *kvm) | |||
| 258 | if (ret) | 258 | if (ret) |
| 259 | goto out; | 259 | goto out; |
| 260 | 260 | ||
| 261 | if (vgic_has_its(kvm)) | ||
| 262 | dist->msis_require_devid = true; | ||
| 263 | |||
| 261 | kvm_for_each_vcpu(i, vcpu, kvm) | 264 | kvm_for_each_vcpu(i, vcpu, kvm) |
| 262 | kvm_vgic_vcpu_init(vcpu); | 265 | kvm_vgic_vcpu_init(vcpu); |
| 263 | 266 | ||
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c index 561d2ba96a4f..1813f93b5cde 100644 --- a/virt/kvm/arm/vgic/vgic-kvm-device.c +++ b/virt/kvm/arm/vgic/vgic-kvm-device.c | |||
| @@ -223,6 +223,9 @@ int kvm_register_vgic_device(unsigned long type) | |||
| 223 | case KVM_DEV_TYPE_ARM_VGIC_V3: | 223 | case KVM_DEV_TYPE_ARM_VGIC_V3: |
| 224 | ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops, | 224 | ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops, |
| 225 | KVM_DEV_TYPE_ARM_VGIC_V3); | 225 | KVM_DEV_TYPE_ARM_VGIC_V3); |
| 226 | if (ret) | ||
| 227 | break; | ||
| 228 | ret = kvm_vgic_register_its_device(); | ||
| 226 | break; | 229 | break; |
| 227 | #endif | 230 | #endif |
| 228 | } | 231 | } |
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c index 84a301d789e0..ff668e0dd586 100644 --- a/virt/kvm/arm/vgic/vgic-mmio-v3.c +++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c | |||
| @@ -66,7 +66,12 @@ static unsigned long vgic_mmio_read_v3_misc(struct kvm_vcpu *vcpu, | |||
| 66 | case GICD_TYPER: | 66 | case GICD_TYPER: |
| 67 | value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS; | 67 | value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS; |
| 68 | value = (value >> 5) - 1; | 68 | value = (value >> 5) - 1; |
| 69 | value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19; | 69 | if (vgic_has_its(vcpu->kvm)) { |
| 70 | value |= (INTERRUPT_ID_BITS_ITS - 1) << 19; | ||
| 71 | value |= GICD_TYPER_LPIS; | ||
| 72 | } else { | ||
| 73 | value |= (INTERRUPT_ID_BITS_SPIS - 1) << 19; | ||
| 74 | } | ||
| 70 | break; | 75 | break; |
| 71 | case GICD_IIDR: | 76 | case GICD_IIDR: |
| 72 | value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0); | 77 | value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0); |
| @@ -163,9 +168,8 @@ static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu, | |||
| 163 | 168 | ||
| 164 | vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS; | 169 | vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS; |
| 165 | 170 | ||
| 166 | if (!was_enabled && vgic_cpu->lpis_enabled) { | 171 | if (!was_enabled && vgic_cpu->lpis_enabled) |
| 167 | /* Eventually do something */ | 172 | vgic_enable_lpis(vcpu); |
| 168 | } | ||
| 169 | } | 173 | } |
| 170 | 174 | ||
| 171 | static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu, | 175 | 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, | |||
| 179 | value |= ((target_vcpu_id & 0xffff) << 8); | 183 | value |= ((target_vcpu_id & 0xffff) << 8); |
| 180 | if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1) | 184 | if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1) |
| 181 | value |= GICR_TYPER_LAST; | 185 | value |= GICR_TYPER_LAST; |
| 186 | if (vgic_has_its(vcpu->kvm)) | ||
| 187 | value |= GICR_TYPER_PLPIS; | ||
| 182 | 188 | ||
| 183 | return extract_bytes(value, addr & 7, len); | 189 | return extract_bytes(value, addr & 7, len); |
| 184 | } | 190 | } |
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c index 53299fc93c15..424cb9ceebd9 100644 --- a/virt/kvm/arm/vgic/vgic.c +++ b/virt/kvm/arm/vgic/vgic.c | |||
| @@ -718,3 +718,11 @@ bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, unsigned int virt_irq) | |||
| 718 | 718 | ||
| 719 | return map_is_active; | 719 | return map_is_active; |
| 720 | } | 720 | } |
| 721 | |||
| 722 | int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) | ||
| 723 | { | ||
| 724 | if (vgic_has_its(kvm)) | ||
| 725 | return vgic_its_inject_msi(kvm, msi); | ||
| 726 | else | ||
| 727 | return -ENODEV; | ||
| 728 | } | ||
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h index 9d557f25cbfc..9d40d7bb89f7 100644 --- a/virt/kvm/arm/vgic/vgic.h +++ b/virt/kvm/arm/vgic/vgic.h | |||
| @@ -77,6 +77,7 @@ int vgic_v3_probe(const struct gic_kvm_info *info); | |||
| 77 | int vgic_v3_map_resources(struct kvm *kvm); | 77 | int vgic_v3_map_resources(struct kvm *kvm); |
| 78 | int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address); | 78 | int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address); |
| 79 | bool vgic_has_its(struct kvm *kvm); | 79 | bool vgic_has_its(struct kvm *kvm); |
| 80 | int kvm_vgic_register_its_device(void); | ||
| 80 | void vgic_enable_lpis(struct kvm_vcpu *vcpu); | 81 | void vgic_enable_lpis(struct kvm_vcpu *vcpu); |
| 81 | int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi); | 82 | int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi); |
| 82 | #else | 83 | #else |
| @@ -136,6 +137,11 @@ static inline bool vgic_has_its(struct kvm *kvm) | |||
| 136 | return false; | 137 | return false; |
| 137 | } | 138 | } |
| 138 | 139 | ||
| 140 | static inline int kvm_vgic_register_its_device(void) | ||
| 141 | { | ||
| 142 | return -ENODEV; | ||
| 143 | } | ||
| 144 | |||
| 139 | static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu) | 145 | static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu) |
| 140 | { | 146 | { |
