Commit ef364c5b authored by Oliver Upton's avatar Oliver Upton
Browse files

KVM: arm64: vgic-v3: Consolidate MAINT_IRQ handling



Consolidate the duplicated handling of the VGICv3 maintenance IRQ
attribute as a regular GICv3 attribute, as it is neither a register nor
a common attribute. As this is now handled separately from the VGIC
registers, the locking is relaxed to only acquire the intended
config_lock.

Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250724062805.2658919-3-oliver.upton@linux.dev


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 82221a4e
Loading
Loading
Loading
Loading
+25 −26
Original line number Diff line number Diff line
@@ -303,12 +303,6 @@ static int vgic_get_common_attr(struct kvm_device *dev,
			     VGIC_NR_PRIVATE_IRQS, uaddr);
		break;
	}
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: {
		u32 __user *uaddr = (u32 __user *)(long)attr->addr;

		r = put_user(dev->kvm->arch.vgic.mi_intid, uaddr);
		break;
	}
	}

	return r;
@@ -523,7 +517,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
	struct vgic_reg_attr reg_attr;
	gpa_t addr;
	struct kvm_vcpu *vcpu;
	bool uaccess, post_init = true;
	bool uaccess;
	u32 val;
	int ret;

@@ -539,9 +533,6 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
		/* Sysregs uaccess is performed by the sysreg handling code */
		uaccess = false;
		break;
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
		post_init = false;
		fallthrough;
	default:
		uaccess = true;
	}
@@ -561,7 +552,7 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,

	mutex_lock(&dev->kvm->arch.config_lock);

	if (post_init != vgic_initialized(dev->kvm)) {
	if (!vgic_initialized(dev->kvm)) {
		ret = -EBUSY;
		goto out;
	}
@@ -591,19 +582,6 @@ static int vgic_v3_attr_regs_access(struct kvm_device *dev,
		}
		break;
	}
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
		if (!is_write) {
			val = dev->kvm->arch.vgic.mi_intid;
			ret = 0;
			break;
		}

		ret = -EINVAL;
		if ((val < VGIC_NR_PRIVATE_IRQS) && (val >= VGIC_NR_SGIS)) {
			dev->kvm->arch.vgic.mi_intid = val;
			ret = 0;
		}
		break;
	default:
		ret = -EINVAL;
		break;
@@ -630,8 +608,24 @@ static int vgic_v3_set_attr(struct kvm_device *dev,
	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
		return vgic_v3_attr_regs_access(dev, attr, true);
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: {
		u32 __user *uaddr = (u32 __user *)attr->addr;
		u32 val;

		if (get_user(val, uaddr))
			return -EFAULT;

		guard(mutex)(&dev->kvm->arch.config_lock);
		if (vgic_initialized(dev->kvm))
			return -EBUSY;

		if (!irq_is_ppi(val))
			return -EINVAL;

		dev->kvm->arch.vgic.mi_intid = val;
		return 0;
	}
	default:
		return vgic_set_common_attr(dev, attr);
	}
@@ -645,8 +639,13 @@ static int vgic_v3_get_attr(struct kvm_device *dev,
	case KVM_DEV_ARM_VGIC_GRP_REDIST_REGS:
	case KVM_DEV_ARM_VGIC_GRP_CPU_SYSREGS:
	case KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO:
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ:
		return vgic_v3_attr_regs_access(dev, attr, false);
	case KVM_DEV_ARM_VGIC_GRP_MAINT_IRQ: {
		u32 __user *uaddr = (u32 __user *)(long)attr->addr;

		guard(mutex)(&dev->kvm->arch.config_lock);
		return put_user(dev->kvm->arch.vgic.mi_intid, uaddr);
	}
	default:
		return vgic_get_common_attr(dev, attr);
	}