Commit f4d37c7c authored by Sascha Bischoff's avatar Sascha Bischoff Committed by Marc Zyngier
Browse files

KVM: arm64: gic-v5: Create and initialise vgic_v5



Update kvm_vgic_create to create a vgic_v5 device. When creating a
vgic, FEAT_GCIE in the ID_AA64PFR2 is only exposed to vgic_v5-based
guests, and is hidden otherwise. GIC in ~ID_AA64PFR0_EL1 is never
exposed for a vgic_v5 guest.

When initialising a vgic_v5, skip kvm_vgic_dist_init as GICv5 doesn't
support one. The current vgic_v5 implementation only supports PPIs, so
no SPIs are initialised either.

The current vgic_v5 support doesn't extend to nested guests. Therefore,
the init of vgic_v5 for a nested guest is failed in vgic_v5_init.

As the current vgic_v5 doesn't require any resources to be mapped,
vgic_v5_map_resources is simply used to check that the vgic has indeed
been initialised. Again, this will change as more GICv5 support is
merged in.

Signed-off-by: default avatarSascha Bischoff <sascha.bischoff@arm.com>
Reviewed-by: default avatarJonathan Cameron <jonathan.cameron@huawei.com>
Link: https://patch.msgid.link/20260319154937.3619520-29-sascha.bischoff@arm.com


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent b88d05a8
Loading
Loading
Loading
Loading
+34 −20
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type);
 * or through the generic KVM_CREATE_DEVICE API ioctl.
 * irqchip_in_kernel() tells you if this function succeeded or not.
 * @kvm: kvm struct pointer
 * @type: KVM_DEV_TYPE_ARM_VGIC_V[23]
 * @type: KVM_DEV_TYPE_ARM_VGIC_V[235]
 */
int kvm_vgic_create(struct kvm *kvm, u32 type)
{
@@ -131,8 +131,11 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)

	if (type == KVM_DEV_TYPE_ARM_VGIC_V2)
		kvm->max_vcpus = VGIC_V2_MAX_CPUS;
	else
	else if (type == KVM_DEV_TYPE_ARM_VGIC_V3)
		kvm->max_vcpus = VGIC_V3_MAX_CPUS;
	else if (type == KVM_DEV_TYPE_ARM_VGIC_V5)
		kvm->max_vcpus = min(VGIC_V5_MAX_CPUS,
				     kvm_vgic_global_state.max_gic_vcpus);

	if (atomic_read(&kvm->online_vcpus) > kvm->max_vcpus) {
		ret = -E2BIG;
@@ -426,13 +429,14 @@ int vgic_init(struct kvm *kvm)
	if (kvm->created_vcpus != atomic_read(&kvm->online_vcpus))
		return -EBUSY;

	if (!vgic_is_v5(kvm)) {
		/* freeze the number of spis */
		if (!dist->nr_spis)
			dist->nr_spis = VGIC_NR_IRQS_LEGACY - VGIC_NR_PRIVATE_IRQS;

		ret = kvm_vgic_dist_init(kvm, dist->nr_spis);
		if (ret)
		goto out;
			return ret;

		/*
		 * Ensure vPEs are allocated if direct IRQ injection (e.g. vSGIs,
@@ -441,7 +445,12 @@ int vgic_init(struct kvm *kvm)
		if (vgic_supports_direct_irqs(kvm)) {
			ret = vgic_v4_init(kvm);
			if (ret)
			goto out;
				return ret;
		}
	} else {
		ret = vgic_v5_init(kvm);
		if (ret)
			return ret;
	}

	kvm_for_each_vcpu(idx, vcpu, kvm)
@@ -449,12 +458,12 @@ int vgic_init(struct kvm *kvm)

	ret = kvm_vgic_setup_default_irq_routing(kvm);
	if (ret)
		goto out;
		return ret;

	vgic_debug_init(kvm);
	dist->initialized = true;
out:
	return ret;

	return 0;
}

static void kvm_vgic_dist_destroy(struct kvm *kvm)
@@ -598,6 +607,7 @@ int vgic_lazy_init(struct kvm *kvm)
int kvm_vgic_map_resources(struct kvm *kvm)
{
	struct vgic_dist *dist = &kvm->arch.vgic;
	bool needs_dist = true;
	enum vgic_type type;
	gpa_t dist_base;
	int ret = 0;
@@ -616,12 +626,16 @@ int kvm_vgic_map_resources(struct kvm *kvm)
	if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V2) {
		ret = vgic_v2_map_resources(kvm);
		type = VGIC_V2;
	} else {
	} else if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
		ret = vgic_v3_map_resources(kvm);
		type = VGIC_V3;
	} else {
		ret = vgic_v5_map_resources(kvm);
		type = VGIC_V5;
		needs_dist = false;
	}

	if (ret)
	if (ret || !needs_dist)
		goto out;

	dist_base = dist->vgic_dist_base;
+26 −0
Original line number Diff line number Diff line
@@ -87,6 +87,32 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
	return 0;
}

int vgic_v5_init(struct kvm *kvm)
{
	struct kvm_vcpu *vcpu;
	unsigned long idx;

	if (vgic_initialized(kvm))
		return 0;

	kvm_for_each_vcpu(idx, vcpu, kvm) {
		if (vcpu_has_nv(vcpu)) {
			kvm_err("Nested GICv5 VMs are currently unsupported\n");
			return -EINVAL;
		}
	}

	return 0;
}

int vgic_v5_map_resources(struct kvm *kvm)
{
	if (!vgic_initialized(kvm))
		return -EBUSY;

	return 0;
}

int vgic_v5_finalize_ppi_state(struct kvm *kvm)
{
	struct kvm_vcpu *vcpu0;
+2 −0
Original line number Diff line number Diff line
@@ -364,6 +364,8 @@ void vgic_debug_init(struct kvm *kvm);
void vgic_debug_destroy(struct kvm *kvm);

int vgic_v5_probe(const struct gic_kvm_info *info);
int vgic_v5_init(struct kvm *kvm);
int vgic_v5_map_resources(struct kvm *kvm);
void vgic_v5_set_ppi_ops(struct kvm_vcpu *vcpu, u32 vintid);
bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/irqchip/arm-gic-v4.h>
#include <linux/irqchip/arm-gic-v5.h>

#define VGIC_V5_MAX_CPUS	512
#define VGIC_V3_MAX_CPUS	512
#define VGIC_V2_MAX_CPUS	8
#define VGIC_NR_IRQS_LEGACY     256