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 | { |
141 | } | 147 | } |