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

KVM: arm64: gic: Introduce interrupt type helpers



GICv5 has moved from using interrupt ranges for different interrupt
types to using some of the upper bits of the interrupt ID to denote
the interrupt type. This is not compatible with older GICs (which rely
on ranges of interrupts to determine the type), and hence a set of
helpers is introduced. These helpers take a struct kvm*, and use the
vgic model to determine how to interpret the interrupt ID.

Helpers are introduced for PPIs, SPIs, and LPIs. Additionally, a
helper is introduced to determine if an interrupt is private - SGIs
and PPIs for older GICs, and PPIs only for GICv5.

Additionally, vgic_is_v5() is introduced (which unsurpisingly returns
true when running a GICv5 guest), and the existing vgic_is_v3() check
is moved from vgic.h to arm_vgic.h (to live alongside the vgic_is_v5()
one), and has been converted into a macro.

The helpers are plumbed into the core vgic code, as well as the Arch
Timer and PMU code.

There should be no functional changes as part of this change.

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


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent c547c51f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1603,7 +1603,7 @@ int kvm_arm_timer_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
	if (get_user(irq, uaddr))
		return -EFAULT;

	if (!(irq_is_ppi(irq)))
	if (!(irq_is_ppi(vcpu->kvm, irq)))
		return -EINVAL;

	mutex_lock(&vcpu->kvm->arch.config_lock);
+4 −3
Original line number Diff line number Diff line
@@ -939,7 +939,8 @@ int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
		 * number against the dimensions of the vgic and make sure
		 * it's valid.
		 */
		if (!irq_is_ppi(irq) && !vgic_valid_spi(vcpu->kvm, irq))
		if (!irq_is_ppi(vcpu->kvm, irq) &&
		    !vgic_valid_spi(vcpu->kvm, irq))
			return -EINVAL;
	} else if (kvm_arm_pmu_irq_initialized(vcpu)) {
		   return -EINVAL;
@@ -991,7 +992,7 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
		if (!kvm_arm_pmu_irq_initialized(vcpu))
			continue;

		if (irq_is_ppi(irq)) {
		if (irq_is_ppi(vcpu->kvm, irq)) {
			if (vcpu->arch.pmu.irq_num != irq)
				return false;
		} else {
@@ -1142,7 +1143,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
			return -EFAULT;

		/* The PMU overflow interrupt can be a PPI or a valid SPI. */
		if (!(irq_is_ppi(irq) || irq_is_spi(irq)))
		if (!(irq_is_ppi(vcpu->kvm, irq) || irq_is_spi(vcpu->kvm, irq)))
			return -EINVAL;

		if (!pmu_irq_is_valid(kvm, irq))
+1 −1
Original line number Diff line number Diff line
@@ -639,7 +639,7 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
		if (vgic_initialized(dev->kvm))
			return -EBUSY;

		if (!irq_is_ppi(val))
		if (!irq_is_ppi(dev->kvm, val))
			return -EINVAL;

		dev->kvm->arch.vgic.mi_intid = val;
+7 −7
Original line number Diff line number Diff line
@@ -94,7 +94,7 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
	}

	/* LPIs */
	if (intid >= VGIC_MIN_LPI)
	if (irq_is_lpi(kvm, intid))
		return vgic_get_lpi(kvm, intid);

	return NULL;
@@ -123,7 +123,7 @@ static void vgic_release_lpi_locked(struct vgic_dist *dist, struct vgic_irq *irq

static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
{
	if (irq->intid < VGIC_MIN_LPI)
	if (!irq_is_lpi(kvm, irq->intid))
		return false;

	return refcount_dec_and_test(&irq->refcount);
@@ -148,7 +148,7 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
	 * Acquire/release it early on lockdep kernels to make locking issues
	 * in rare release paths a bit more obvious.
	 */
	if (IS_ENABLED(CONFIG_LOCKDEP) && irq->intid >= VGIC_MIN_LPI) {
	if (IS_ENABLED(CONFIG_LOCKDEP) && irq_is_lpi(kvm, irq->intid)) {
		guard(spinlock_irqsave)(&dist->lpi_xa.xa_lock);
	}

@@ -186,7 +186,7 @@ void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
	raw_spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);

	list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
		if (irq->intid >= VGIC_MIN_LPI) {
		if (irq_is_lpi(vcpu->kvm, irq->intid)) {
			raw_spin_lock(&irq->irq_lock);
			list_del(&irq->ap_list);
			irq->vcpu = NULL;
@@ -521,12 +521,12 @@ int kvm_vgic_inject_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
	if (ret)
		return ret;

	if (!vcpu && intid < VGIC_NR_PRIVATE_IRQS)
	if (!vcpu && irq_is_private(kvm, intid))
		return -EINVAL;

	trace_vgic_update_irq_pending(vcpu ? vcpu->vcpu_idx : 0, intid, level);

	if (intid < VGIC_NR_PRIVATE_IRQS)
	if (irq_is_private(kvm, intid))
		irq = vgic_get_vcpu_irq(vcpu, intid);
	else
		irq = vgic_get_irq(kvm, intid);
@@ -700,7 +700,7 @@ int kvm_vgic_set_owner(struct kvm_vcpu *vcpu, unsigned int intid, void *owner)
		return -EAGAIN;

	/* SGIs and LPIs cannot be wired up to any device */
	if (!irq_is_ppi(intid) && !vgic_valid_spi(vcpu->kvm, intid))
	if (!irq_is_ppi(vcpu->kvm, intid) && !vgic_valid_spi(vcpu->kvm, intid))
		return -EINVAL;

	irq = vgic_get_vcpu_irq(vcpu, intid);
+0 −5
Original line number Diff line number Diff line
@@ -454,11 +454,6 @@ void vgic_v3_put_nested(struct kvm_vcpu *vcpu);
void vgic_v3_handle_nested_maint_irq(struct kvm_vcpu *vcpu);
void vgic_v3_nested_update_mi(struct kvm_vcpu *vcpu);

static inline bool vgic_is_v3(struct kvm *kvm)
{
	return kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3;
}

static inline bool vgic_host_has_gicv3(void)
{
	/*
Loading