Commit 354920e7 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: vgic: Implement SW-driven deactivation



In order to deal with these systems that do not offer HW-based
deactivation of interrupts, let implement a SW-based approach:

- When the irq is queued into a LR, treat it as a pure virtual
  interrupt and set the EOI flag in the LR.

- When the interrupt state is read back from the LR, force a
  deactivation when the state is invalid (neither active nor
  pending)

Interrupts requiring such treatment get the VGIC_SW_RESAMPLE flag.

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent db75f1a3
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -108,11 +108,22 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
		 * If this causes us to lower the level, we have to also clear
		 * the physical active state, since we will otherwise never be
		 * told when the interrupt becomes asserted again.
		 *
		 * Another case is when the interrupt requires a helping hand
		 * on deactivation (no HW deactivation, for example).
		 */
		if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
		if (vgic_irq_is_mapped_level(irq)) {
			bool resample = false;

			if (val & GICH_LR_PENDING_BIT) {
				irq->line_level = vgic_get_phys_line_level(irq);
				resample = !irq->line_level;
			} else if (vgic_irq_needs_resampling(irq) &&
				   !(irq->active || irq->pending_latch)) {
				resample = true;
			}

			if (!irq->line_level)
			if (resample)
				vgic_irq_set_phys_active(irq, false);
		}

@@ -152,7 +163,7 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
	if (irq->group)
		val |= GICH_LR_GROUP1;

	if (irq->hw) {
	if (irq->hw && !vgic_irq_needs_resampling(irq)) {
		val |= GICH_LR_HW;
		val |= irq->hwintid << GICH_LR_PHYSID_CPUID_SHIFT;
		/*
+15 −4
Original line number Diff line number Diff line
@@ -101,11 +101,22 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
		 * If this causes us to lower the level, we have to also clear
		 * the physical active state, since we will otherwise never be
		 * told when the interrupt becomes asserted again.
		 *
		 * Another case is when the interrupt requires a helping hand
		 * on deactivation (no HW deactivation, for example).
		 */
		if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
		if (vgic_irq_is_mapped_level(irq)) {
			bool resample = false;

			if (val & ICH_LR_PENDING_BIT) {
				irq->line_level = vgic_get_phys_line_level(irq);
				resample = !irq->line_level;
			} else if (vgic_irq_needs_resampling(irq) &&
				   !(irq->active || irq->pending_latch)) {
				resample = true;
			}

			if (!irq->line_level)
			if (resample)
				vgic_irq_set_phys_active(irq, false);
		}

@@ -136,7 +147,7 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
		}
	}

	if (irq->hw) {
	if (irq->hw && !vgic_irq_needs_resampling(irq)) {
		val |= ICH_LR_HW;
		val |= ((u64)irq->hwintid) << ICH_LR_PHYS_ID_SHIFT;
		/*
+10 −0
Original line number Diff line number Diff line
@@ -99,6 +99,11 @@ enum vgic_irq_config {
 * kvm_arm_get_running_vcpu() to get the vcpu pointer for private IRQs.
 */
struct irq_ops {
	/* Per interrupt flags for special-cased interrupts */
	unsigned long flags;

#define VGIC_IRQ_SW_RESAMPLE	BIT(0)	/* Clear the active state for resampling */

	/*
	 * Callback function pointer to in-kernel devices that can tell us the
	 * state of the input level of mapped level-triggered IRQ faster than
@@ -150,6 +155,11 @@ struct vgic_irq {
					   for in-kernel devices. */
};

static inline bool vgic_irq_needs_resampling(struct vgic_irq *irq)
{
	return irq->ops && (irq->ops->flags & VGIC_IRQ_SW_RESAMPLE);
}

struct vgic_register_region;
struct vgic_its;