Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andre Przywara and committed by
Marc Zyngier
0e4e82f1 2891a7df

+44 -5
+1 -1
Documentation/virtual/kvm/api.txt
··· 2162 2162 4.71 KVM_SIGNAL_MSI 2163 2163 2164 2164 Capability: KVM_CAP_SIGNAL_MSI 2165 - Architectures: x86 2165 + Architectures: x86 arm64 2166 2166 Type: vm ioctl 2167 2167 Parameters: struct kvm_msi (in) 2168 2168 Returns: >0 on delivery, 0 if guest blocked the MSI, and -1 on error
+1
arch/arm64/kvm/Kconfig
··· 36 36 select HAVE_KVM_IRQFD 37 37 select KVM_ARM_VGIC_V3 38 38 select KVM_ARM_PMU if HW_PERF_EVENTS 39 + select HAVE_KVM_MSI 39 40 ---help--- 40 41 Support hosting virtualized guest machines. 41 42 We don't support KVM with 16K page tables yet, due to the multiple
+1
arch/arm64/kvm/Makefile
··· 29 29 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v2.o 30 30 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic/vgic-mmio-v3.o 31 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 33 kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o 33 34 kvm-$(CONFIG_KVM_ARM_PMU) += $(KVM)/arm/pmu.o
+6
arch/arm64/kvm/reset.c
··· 86 86 case KVM_CAP_VCPU_ATTRIBUTES: 87 87 r = 1; 88 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 95 default: 90 96 r = 0; 91 97 }
+5
include/kvm/arm_vgic.h
··· 163 163 /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */ 164 164 u32 vgic_model; 165 165 166 + /* Do injected MSIs require an additional device ID? */ 167 + bool msis_require_devid; 168 + 166 169 int nr_spis; 167 170 168 171 /* TODO: Consider moving to global state */ ··· 310 307 { 311 308 return kvm_vgic_global_state.max_gic_vcpus; 312 309 } 310 + 311 + int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi); 313 312 314 313 #endif /* __KVM_ARM_VGIC_H */
+3
virt/kvm/arm/vgic/vgic-init.c
··· 258 258 if (ret) 259 259 goto out; 260 260 261 + if (vgic_has_its(kvm)) 262 + dist->msis_require_devid = true; 263 + 261 264 kvm_for_each_vcpu(i, vcpu, kvm) 262 265 kvm_vgic_vcpu_init(vcpu); 263 266
+3
virt/kvm/arm/vgic/vgic-kvm-device.c
··· 223 223 case KVM_DEV_TYPE_ARM_VGIC_V3: 224 224 ret = kvm_register_device_ops(&kvm_arm_vgic_v3_ops, 225 225 KVM_DEV_TYPE_ARM_VGIC_V3); 226 + if (ret) 227 + break; 228 + ret = kvm_vgic_register_its_device(); 226 229 break; 227 230 #endif 228 231 }
+10 -4
virt/kvm/arm/vgic/vgic-mmio-v3.c
··· 66 66 case GICD_TYPER: 67 67 value = vcpu->kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS; 68 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 75 break; 71 76 case GICD_IIDR: 72 77 value = (PRODUCT_ID_KVM << 24) | (IMPLEMENTER_ARM << 0); ··· 168 163 169 164 vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS; 170 165 171 - if (!was_enabled && vgic_cpu->lpis_enabled) { 172 - /* Eventually do something */ 173 - } 166 + if (!was_enabled && vgic_cpu->lpis_enabled) 167 + vgic_enable_lpis(vcpu); 174 168 } 175 169 176 170 static unsigned long vgic_mmio_read_v3r_typer(struct kvm_vcpu *vcpu, ··· 183 179 value |= ((target_vcpu_id & 0xffff) << 8); 184 180 if (target_vcpu_id == atomic_read(&vcpu->kvm->online_vcpus) - 1) 185 181 value |= GICR_TYPER_LAST; 182 + if (vgic_has_its(vcpu->kvm)) 183 + value |= GICR_TYPER_PLPIS; 186 184 187 185 return extract_bytes(value, addr & 7, len); 188 186 }
+8
virt/kvm/arm/vgic/vgic.c
··· 718 718 719 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 + }
+6
virt/kvm/arm/vgic/vgic.h
··· 77 77 int vgic_v3_map_resources(struct kvm *kvm); 78 78 int vgic_register_redist_iodevs(struct kvm *kvm, gpa_t dist_base_address); 79 79 bool vgic_has_its(struct kvm *kvm); 80 + int kvm_vgic_register_its_device(void); 80 81 void vgic_enable_lpis(struct kvm_vcpu *vcpu); 81 82 int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi); 82 83 #else ··· 135 134 static inline bool vgic_has_its(struct kvm *kvm) 136 135 { 137 136 return false; 137 + } 138 + 139 + static inline int kvm_vgic_register_its_device(void) 140 + { 141 + return -ENODEV; 138 142 } 139 143 140 144 static inline void vgic_enable_lpis(struct kvm_vcpu *vcpu)