Add CONFIG_ARM_GIC_V3_PER_VCPU_VLPI to control whether vLPI direct injection is to be enabled on a system-wide or a per-vCPU basis.
When enabled, vPEs can be allocated/deallocated to vCPUs on an ad-hoc, per-vCPU basis in runtime. When disabled, keep current vgic_v4_init behavior of automatic vCPU vPE allocation upon VM initialization.
We declare three ioctls numbers to manage per-vCPU vLPI enablement: - KVM_ENABLE_VCPU_VLPI, which given a vCPU ID, allocates a vPE and initializes the vCPU for receiving direct vLPI interrupts. - KVM_DISABLE_VCPU_VLPI, which given a vCPU ID, disables the vCPU’s ability to receive direct vLPI interrupts and frees its underlying vPE structure. - KVM_QUERY_VCPU_VLPI, which given a vCPU ID, returns a boolean describing whether the vCPU is configured to receive direct vLPI interrupts.
This commit declares the kconfig, ioctl numbers, and documentation. Implementation will come throughout this patch set.
Signed-off-by: Maximilian Dittgen mdittgen@amazon.de --- Documentation/virt/kvm/api.rst | 56 ++++++++++++++++++++++++++++++++++ arch/arm64/kvm/arm.c | 15 +++++++++ arch/arm64/kvm/vgic/vgic-v4.c | 9 ++++++ arch/arm64/kvm/vgic/vgic.h | 2 ++ drivers/irqchip/Kconfig | 13 ++++++++ include/uapi/linux/kvm.h | 6 ++++ 6 files changed, 101 insertions(+)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 27f726ff8fe0..dcfb326dff10 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6517,6 +6517,62 @@ the capability to be present.
`flags` must currently be zero.
+4.XXX KVM_ENABLE_VCPU_VLPI +-------------------------- + +:Capability: KVM_CAP_ARM_PER_VCPU_VLPI +:Architectures: arm64 +:Type: vm ioctl +:Parameters: int vcpu_id (in) +:Returns: 0 on success, negative value on error + +This ioctl enables GICv4 direct vLPI injection for the specified vCPU. +Allocates vPE structures (doorbell IRQ, vPE table entry, virtual pending +table, vPEID) and upgrades existing software-forwarded LPIs targeting +this vCPU to hardware-forwarded vLPIs. + +If GICv4.1 is supported and vSGIs are disabled on the specified vCPU, +this ioctl enables vCPU vSGI support. + +Requires CONFIG_ARM_GIC_V3_PER_VCPU_VLPI and GICv4 hardware support. + +Returns -EINVAL if vGICv4 is not initialized or if the passed vcpu_id +does not map to a vCPU. + +4.XXX KVM_DISABLE_VCPU_VLPI +--------------------------- + +:Capability: KVM_CAP_ARM_PER_VCPU_VLPI +:Architectures: arm64 +:Type: vm ioctl +:Parameters: int vcpu_id (in) +:Returns: 0 on success, negative value on error + +This ioctl disables GICv4 direct vLPI injection for the specified vCPU. +Downgrades hardware-forwarded vLPIs to software-forwarded LPIs and frees +vPE structures. Pending interrupts in the virtual pending table may be +lost. + +If vSGIs are enabled on the specified vCPU, this ioctl disables them. + +Returns -EINVAL if vGICv4 is not initialized or if the passed vcpu_id +does not map to a vCPU. + +4.XXX KVM_QUERY_VCPU_VLPI +------------------------- + +:Capability: KVM_CAP_ARM_PER_VCPU_VLPI +:Architectures: arm64 +:Type: vm ioctl +:Parameters: int vcpu_id (in) +:Returns: 1 if enabled, 0 if disabled, negative value on error + +This ioctl queries whether GICv4 direct vLPI injection is enabled for +the specified vCPU. + +Returns -EINVAL if vGICv4 is not initialized or if the passed vcpu_id +does not map to a vCPU. +
.. _kvm_run:
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 452d0c85281e..2839e11ba2c1 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -424,6 +424,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) else r = kvm_supports_cacheable_pfnmap(); break; + case KVM_CAP_ARM_PER_VCPU_VLPI: + r = kvm_per_vcpu_vlpi_supported(); + break;
default: r = 0; @@ -1947,6 +1950,18 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) return -EFAULT; return kvm_vm_ioctl_get_reg_writable_masks(kvm, &range); } + case KVM_ENABLE_VCPU_VLPI: { + /* TODO: create ioctl handler function */ + return -ENOSYS; + } + case KVM_DISABLE_VCPU_VLPI: { + /* TODO: create ioctl handler function */ + return -ENOSYS; + } + case KVM_QUERY_VCPU_VLPI: { + /* TODO: create ioctl handler function */ + return -ENOSYS; + } default: return -EINVAL; } diff --git a/arch/arm64/kvm/vgic/vgic-v4.c b/arch/arm64/kvm/vgic/vgic-v4.c index 09c3e9eb23f8..9ef12c33b3f7 100644 --- a/arch/arm64/kvm/vgic/vgic-v4.c +++ b/arch/arm64/kvm/vgic/vgic-v4.c @@ -226,6 +226,15 @@ void vgic_v4_get_vlpi_state(struct vgic_irq *irq, bool *val) *val = !!(*ptr & mask); }
+bool kvm_per_vcpu_vlpi_supported(void) +{ +#ifdef CONFIG_ARM_GIC_V3_PER_VCPU_VLPI + return kvm_vgic_global_state.has_gicv4; +#else + return false; +#endif +} + int vgic_v4_request_vpe_irq(struct kvm_vcpu *vcpu, int irq) { return request_irq(irq, vgic_v4_doorbell_handler, 0, "vcpu", vcpu); diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h index 5f0fc96b4dc2..99894806a4e9 100644 --- a/arch/arm64/kvm/vgic/vgic.h +++ b/arch/arm64/kvm/vgic/vgic.h @@ -467,4 +467,6 @@ static inline bool vgic_is_v3(struct kvm *kvm) int vgic_its_debug_init(struct kvm_device *dev); void vgic_its_debug_destroy(struct kvm_device *dev);
+bool kvm_per_vcpu_vlpi_supported(void); + #endif diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index a61c6dc63c29..1c3e0c6d3177 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -52,6 +52,19 @@ config ARM_GIC_V3_ITS default ARM_GIC_V3 select IRQ_MSI_IOMMU
+config ARM_GIC_V3_PER_VCPU_VLPI + bool "ARM GICv4 per-vCPU vLPI direct injection support" + depends on ARM_GIC_V3_ITS + default n + help + Enable GICv4 direct injection of MSIs as vLPIs on a per vCPU + basis. Enables partial vLPI enablement on systems with more + vCPU capacity than vPE capacity. When enabled, all vCPUs + will boot without GICv4 vPE structures and handle interrupts + as software LPIs. KVM_ENABLE_VCPU_VLPI ioctl must then be called on + individual vCPUs to initialize their GICv4 structs and upgrade + targeting LPIs to vLPIs. + config ARM_GIC_V3_ITS_FSL_MC bool depends on ARM_GIC_V3_ITS diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 1e541193e98d..002fe0f4841d 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -973,6 +973,7 @@ struct kvm_enable_cap { #define KVM_CAP_ARM_CACHEABLE_PFNMAP_SUPPORTED 243 #define KVM_CAP_GUEST_MEMFD_FLAGS 244 #define KVM_CAP_ARM_SEA_TO_USER 245 +#define KVM_CAP_ARM_PER_VCPU_VLPI 246
struct kvm_irq_routing_irqchip { __u32 irqchip; @@ -1451,6 +1452,11 @@ struct kvm_enc_region { #define KVM_GET_SREGS2 _IOR(KVMIO, 0xcc, struct kvm_sregs2) #define KVM_SET_SREGS2 _IOW(KVMIO, 0xcd, struct kvm_sregs2)
+/* Per-vCPU vLPI enablement/disablement */ +#define KVM_ENABLE_VCPU_VLPI _IOW(KVMIO, 0xf0, int) +#define KVM_DISABLE_VCPU_VLPI _IOW(KVMIO, 0xf1, int) +#define KVM_QUERY_VCPU_VLPI _IOR(KVMIO, 0xf2, int) + #define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0) #define KVM_DIRTY_LOG_INITIALLY_SET (1 << 1)