diff mbox

[v2,3/6] KVM: arm/arm64: vgic: Support level-triggered mapped interrupts

Message ID 20170904102456.9025-4-cdall@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Christoffer Dall Sept. 4, 2017, 10:24 a.m. UTC
Level-triggered mapped IRQs are special because we only observe rising
edges as input to the VGIC, and we don't set the EOI flag and therefore
are not told when the level goes down, so that we can re-queue a new
interrupt when the level goes up.

One way to solve this problem is to side-step the logic of the VGIC and
special case the validation in the injection path, but it has the
unfortunate drawback of having to peak into the physical GIC state
whenever we want to know if the interrupt is pending on the virtual
distributor.

Instead, we can maintain the current semantics of a level triggered
interrupt by sort of treating it as an edge-triggered interrupt,
following from the fact that we only observe an asserting edge.  This
requires us to be a bit careful when populating the LRs and when folding
the state back in though:

 * We lower the line level when populating the LR, so that when
   subsequently observing an asserting edge, the VGIC will do the right
   thing.

 * If the guest never acked the interrupt while running (for example if
   it had masked interrupts at the CPU level while running), we have
   to preserve the pending state of the LR and move it back to the
   line_level field of the struct irq when folding LR state.

   If the guest never acked the interrupt while running, but changed the
   device state and lowered the line (again with interrupts masked) then
   we need to observe this change in the line_level.

   Both of the above situations are solved by sampling the physical line
   and set the line level when folding the LR back.

 * Finally, if the guest never acked the interrupt while running and
   sampling the line reveals that the device state has changed and the
   line has been lowered, we must clear the physical active state, since
   we will otherwise never be told when the interrupt becomes asserted
   again.

This has the added benefit of making the timer optimization patches
(https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026343.html) a
bit simpler, because the timer code doesn't have to clear the active
state on the sync anymore.  It also potentially improves the performance
of the timer implementation because the GIC knows the state or the LR
and only needs to clear the
active state when the pending bit in the LR is still set, where the
timer has to always clear it when returning from running the guest with
an injected timer interrupt.

Signed-off-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
---
 virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.c    | 23 +++++++++++++++++++++++
 virt/kvm/arm/vgic/vgic.h    |  7 +++++++
 4 files changed, 88 insertions(+)

Comments

Eric Auger Sept. 5, 2017, 9:38 a.m. UTC | #1
Hi Christoffer,

On 04/09/2017 12:24, Christoffer Dall wrote:
> Level-triggered mapped IRQs are special because we only observe rising
> edges as input to the VGIC, and we don't set the EOI flag and therefore
> are not told when the level goes down, so that we can re-queue a new
> interrupt when the level goes up.
> 
> One way to solve this problem is to side-step the logic of the VGIC and
> special case the validation in the injection path, but it has the
> unfortunate drawback of having to peak into the physical GIC state
> whenever we want to know if the interrupt is pending on the virtual
> distributor.
> 
> Instead, we can maintain the current semantics of a level triggered
> interrupt by sort of treating it as an edge-triggered interrupt,
> following from the fact that we only observe an asserting edge.  This
> requires us to be a bit careful when populating the LRs and when folding
> the state back in though:
> 
>  * We lower the line level when populating the LR, so that when
>    subsequently observing an asserting edge, the VGIC will do the right
>    thing.
> 
>  * If the guest never acked the interrupt while running (for example if
>    it had masked interrupts at the CPU level while running), we have
>    to preserve the pending state of the LR and move it back to the
>    line_level field of the struct irq when folding LR state.
> 
>    If the guest never acked the interrupt while running, but changed the
>    device state and lowered the line (again with interrupts masked) then
>    we need to observe this change in the line_level.
> 
>    Both of the above situations are solved by sampling the physical line
>    and set the line level when folding the LR back.
> 
>  * Finally, if the guest never acked the interrupt while running and
>    sampling the line reveals that the device state has changed and the
>    line has been lowered, we must clear the physical active state, since
>    we will otherwise never be told when the interrupt becomes asserted
>    again.
> 
> This has the added benefit of making the timer optimization patches
> (https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026343.html) a
> bit simpler, because the timer code doesn't have to clear the active
> state on the sync anymore.  It also potentially improves the performance
> of the timer implementation because the GIC knows the state or the LR
> and only needs to clear the
> active state when the pending bit in the LR is still set, where the
> timer has to always clear it when returning from running the guest with
> an injected timer interrupt.
> 
> Signed-off-by: Christoffer Dall <cdall@linaro.org>
> Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> ---
>  virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.c    | 23 +++++++++++++++++++++++
>  virt/kvm/arm/vgic/vgic.h    |  7 +++++++
>  4 files changed, 88 insertions(+)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> index e4187e5..618ed3f 100644
> --- a/virt/kvm/arm/vgic/vgic-v2.c
> +++ b/virt/kvm/arm/vgic/vgic-v2.c
> @@ -104,6 +104,26 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
>  				irq->pending_latch = false;
>  		}
>  
> +		/*
> +		 * Level-triggered mapped IRQs are special because we only
> +		 * observe rising edges as input to the VGIC.
> +		 *
> +		 * If the guest never acked the interrupt we have to sample
> +		 * the physical line and set the line level, because the
> +		 * device state could have changed or we simply need to
> +		 * process the still pending interrupt later.
> +		 *
> +		 * 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.
> +		 */
> +		if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
> +			irq->line_level = vgic_get_phys_line_level(irq);
> +
> +			if (!irq->line_level)
> +				vgic_irq_set_phys_active(irq, false);
I am still unclear wrt ISPENDR case. Assume the guest writes into the
ISPENDR. So now we set the pending state on the phys distributor. The
SPI is acked by the host. I understand it becomes active (ie. not
pending and active). Then it gets injected into the guest and in the
above fold code the LR state is observed GICH_LR_PENDING_BIT. We are
going to read the physical pending state which is: not pending. So the
line level is low, the latch_pending is not used in mapped case and is
low. So to me the vIRQ is missed.

What do I miss?

Thanks

Eric
> +		}
> +
>  		spin_unlock(&irq->irq_lock);
>  		vgic_put_irq(vcpu->kvm, irq);
>  	}
> @@ -161,6 +181,15 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>  			val |= GICH_LR_EOI;
>  	}
>  
> +	/*
> +	 * Level-triggered mapped IRQs are special because we only observe
> +	 * rising edges as input to the VGIC.  We therefore lower the line
> +	 * level here, so that we can take new virtual IRQs.  See
> +	 * vgic_v2_fold_lr_state for more info.
> +	 */
> +	if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT))
> +		irq->line_level = false;
> +
>  	/* The GICv2 LR only holds five bits of priority. */
>  	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
>  
> diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> index 96ea597..0f72bcb 100644
> --- a/virt/kvm/arm/vgic/vgic-v3.c
> +++ b/virt/kvm/arm/vgic/vgic-v3.c
> @@ -94,6 +94,26 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
>  				irq->pending_latch = false;
>  		}
>  
> +		/*
> +		 * Level-triggered mapped IRQs are special because we only
> +		 * observe rising edges as input to the VGIC.
> +		 *
> +		 * If the guest never acked the interrupt we have to sample
> +		 * the physical line and set the line level, because the
> +		 * device state could have changed or we simply need to
> +		 * process the still pending interrupt later.
> +		 *
> +		 * 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.
> +		 */
> +		if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
> +			irq->line_level = vgic_get_phys_line_level(irq);
> +
> +			if (!irq->line_level)
> +				vgic_irq_set_phys_active(irq, false);
> +		}
> +
>  		spin_unlock(&irq->irq_lock);
>  		vgic_put_irq(vcpu->kvm, irq);
>  	}
> @@ -144,6 +164,15 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
>  	}
>  
>  	/*
> +	 * Level-triggered mapped IRQs are special because we only observe
> +	 * rising edges as input to the VGIC.  We therefore lower the line
> +	 * level here, so that we can take new virtual IRQs.  See
> +	 * vgic_v3_fold_lr_state for more info.
> +	 */
> +	if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT))
> +		irq->line_level = false;
> +
> +	/*
>  	 * We currently only support Group1 interrupts, which is a
>  	 * known defect. This needs to be addressed at some point.
>  	 */
> diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> index 9d557efd..8072969 100644
> --- a/virt/kvm/arm/vgic/vgic.c
> +++ b/virt/kvm/arm/vgic/vgic.c
> @@ -140,6 +140,29 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
>  	kfree(irq);
>  }
>  
> +/* Get the input level of a mapped IRQ directly from the physical GIC */
> +bool vgic_get_phys_line_level(struct vgic_irq *irq)
> +{
> +	bool line_level;
> +
> +	BUG_ON(!irq->hw);
> +
> +	WARN_ON(irq_get_irqchip_state(irq->host_irq,
> +				      IRQCHIP_STATE_PENDING,
> +				      &line_level));
> +	return line_level;
> +}
> +
> +/* Set/Clear the physical active state */
> +void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active)
> +{
> +
> +	BUG_ON(!irq->hw);
> +	WARN_ON(irq_set_irqchip_state(irq->host_irq,
> +				      IRQCHIP_STATE_ACTIVE,
> +				      active));
> +}
> +
>  /**
>   * kvm_vgic_target_oracle - compute the target vcpu for an irq
>   *
> diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> index bba7fa2..7bdcda2 100644
> --- a/virt/kvm/arm/vgic/vgic.h
> +++ b/virt/kvm/arm/vgic/vgic.h
> @@ -104,6 +104,11 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
>  		return irq->pending_latch || irq->line_level;
>  }
>  
> +static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
> +{
> +	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
> +}
> +
>  /*
>   * This struct provides an intermediate representation of the fields contained
>   * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
> @@ -140,6 +145,8 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
>  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
>  			      u32 intid);
>  void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
> +bool vgic_get_phys_line_level(struct vgic_irq *irq);
> +void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
>  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
>  void vgic_kick_vcpus(struct kvm *kvm);
>  
>
Christoffer Dall Sept. 5, 2017, 1:57 p.m. UTC | #2
On Tue, Sep 05, 2017 at 11:38:48AM +0200, Auger Eric wrote:
> Hi Christoffer,
> 
> On 04/09/2017 12:24, Christoffer Dall wrote:
> > Level-triggered mapped IRQs are special because we only observe rising
> > edges as input to the VGIC, and we don't set the EOI flag and therefore
> > are not told when the level goes down, so that we can re-queue a new
> > interrupt when the level goes up.
> > 
> > One way to solve this problem is to side-step the logic of the VGIC and
> > special case the validation in the injection path, but it has the
> > unfortunate drawback of having to peak into the physical GIC state
> > whenever we want to know if the interrupt is pending on the virtual
> > distributor.
> > 
> > Instead, we can maintain the current semantics of a level triggered
> > interrupt by sort of treating it as an edge-triggered interrupt,
> > following from the fact that we only observe an asserting edge.  This
> > requires us to be a bit careful when populating the LRs and when folding
> > the state back in though:
> > 
> >  * We lower the line level when populating the LR, so that when
> >    subsequently observing an asserting edge, the VGIC will do the right
> >    thing.
> > 
> >  * If the guest never acked the interrupt while running (for example if
> >    it had masked interrupts at the CPU level while running), we have
> >    to preserve the pending state of the LR and move it back to the
> >    line_level field of the struct irq when folding LR state.
> > 
> >    If the guest never acked the interrupt while running, but changed the
> >    device state and lowered the line (again with interrupts masked) then
> >    we need to observe this change in the line_level.
> > 
> >    Both of the above situations are solved by sampling the physical line
> >    and set the line level when folding the LR back.
> > 
> >  * Finally, if the guest never acked the interrupt while running and
> >    sampling the line reveals that the device state has changed and the
> >    line has been lowered, we must clear the physical active state, since
> >    we will otherwise never be told when the interrupt becomes asserted
> >    again.
> > 
> > This has the added benefit of making the timer optimization patches
> > (https://lists.cs.columbia.edu/pipermail/kvmarm/2017-July/026343.html) a
> > bit simpler, because the timer code doesn't have to clear the active
> > state on the sync anymore.  It also potentially improves the performance
> > of the timer implementation because the GIC knows the state or the LR
> > and only needs to clear the
> > active state when the pending bit in the LR is still set, where the
> > timer has to always clear it when returning from running the guest with
> > an injected timer interrupt.
> > 
> > Signed-off-by: Christoffer Dall <cdall@linaro.org>
> > Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
> > ---
> >  virt/kvm/arm/vgic/vgic-v2.c | 29 +++++++++++++++++++++++++++++
> >  virt/kvm/arm/vgic/vgic-v3.c | 29 +++++++++++++++++++++++++++++
> >  virt/kvm/arm/vgic/vgic.c    | 23 +++++++++++++++++++++++
> >  virt/kvm/arm/vgic/vgic.h    |  7 +++++++
> >  4 files changed, 88 insertions(+)
> > 
> > diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
> > index e4187e5..618ed3f 100644
> > --- a/virt/kvm/arm/vgic/vgic-v2.c
> > +++ b/virt/kvm/arm/vgic/vgic-v2.c
> > @@ -104,6 +104,26 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
> >  				irq->pending_latch = false;
> >  		}
> >  
> > +		/*
> > +		 * Level-triggered mapped IRQs are special because we only
> > +		 * observe rising edges as input to the VGIC.
> > +		 *
> > +		 * If the guest never acked the interrupt we have to sample
> > +		 * the physical line and set the line level, because the
> > +		 * device state could have changed or we simply need to
> > +		 * process the still pending interrupt later.
> > +		 *
> > +		 * 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.
> > +		 */
> > +		if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
> > +			irq->line_level = vgic_get_phys_line_level(irq);
> > +
> > +			if (!irq->line_level)
> > +				vgic_irq_set_phys_active(irq, false);
> I am still unclear wrt ISPENDR case. Assume the guest writes into the
> ISPENDR. So now we set the pending state on the phys distributor. The
> SPI is acked by the host. I understand it becomes active (ie. not
> pending and active). Then it gets injected into the guest and in the
> above fold code the LR state is observed GICH_LR_PENDING_BIT. We are
> going to read the physical pending state which is: not pending. So the
> line level is low, the latch_pending is not used in mapped case and is
> low. So to me the vIRQ is missed.
> 
> What do I miss?

You're not missing anything.  It was supposed to set pending first then
followed by active.  I can fix that.

Thanks,
-Christoffer

> > +		}
> > +
> >  		spin_unlock(&irq->irq_lock);
> >  		vgic_put_irq(vcpu->kvm, irq);
> >  	}
> > @@ -161,6 +181,15 @@ void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >  			val |= GICH_LR_EOI;
> >  	}
> >  
> > +	/*
> > +	 * Level-triggered mapped IRQs are special because we only observe
> > +	 * rising edges as input to the VGIC.  We therefore lower the line
> > +	 * level here, so that we can take new virtual IRQs.  See
> > +	 * vgic_v2_fold_lr_state for more info.
> > +	 */
> > +	if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT))
> > +		irq->line_level = false;
> > +
> >  	/* The GICv2 LR only holds five bits of priority. */
> >  	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
> >  
> > diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
> > index 96ea597..0f72bcb 100644
> > --- a/virt/kvm/arm/vgic/vgic-v3.c
> > +++ b/virt/kvm/arm/vgic/vgic-v3.c
> > @@ -94,6 +94,26 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
> >  				irq->pending_latch = false;
> >  		}
> >  
> > +		/*
> > +		 * Level-triggered mapped IRQs are special because we only
> > +		 * observe rising edges as input to the VGIC.
> > +		 *
> > +		 * If the guest never acked the interrupt we have to sample
> > +		 * the physical line and set the line level, because the
> > +		 * device state could have changed or we simply need to
> > +		 * process the still pending interrupt later.
> > +		 *
> > +		 * 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.
> > +		 */
> > +		if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
> > +			irq->line_level = vgic_get_phys_line_level(irq);
> > +
> > +			if (!irq->line_level)
> > +				vgic_irq_set_phys_active(irq, false);
> > +		}
> > +
> >  		spin_unlock(&irq->irq_lock);
> >  		vgic_put_irq(vcpu->kvm, irq);
> >  	}
> > @@ -144,6 +164,15 @@ void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
> >  	}
> >  
> >  	/*
> > +	 * Level-triggered mapped IRQs are special because we only observe
> > +	 * rising edges as input to the VGIC.  We therefore lower the line
> > +	 * level here, so that we can take new virtual IRQs.  See
> > +	 * vgic_v3_fold_lr_state for more info.
> > +	 */
> > +	if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT))
> > +		irq->line_level = false;
> > +
> > +	/*
> >  	 * We currently only support Group1 interrupts, which is a
> >  	 * known defect. This needs to be addressed at some point.
> >  	 */
> > diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
> > index 9d557efd..8072969 100644
> > --- a/virt/kvm/arm/vgic/vgic.c
> > +++ b/virt/kvm/arm/vgic/vgic.c
> > @@ -140,6 +140,29 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
> >  	kfree(irq);
> >  }
> >  
> > +/* Get the input level of a mapped IRQ directly from the physical GIC */
> > +bool vgic_get_phys_line_level(struct vgic_irq *irq)
> > +{
> > +	bool line_level;
> > +
> > +	BUG_ON(!irq->hw);
> > +
> > +	WARN_ON(irq_get_irqchip_state(irq->host_irq,
> > +				      IRQCHIP_STATE_PENDING,
> > +				      &line_level));
> > +	return line_level;
> > +}
> > +
> > +/* Set/Clear the physical active state */
> > +void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active)
> > +{
> > +
> > +	BUG_ON(!irq->hw);
> > +	WARN_ON(irq_set_irqchip_state(irq->host_irq,
> > +				      IRQCHIP_STATE_ACTIVE,
> > +				      active));
> > +}
> > +
> >  /**
> >   * kvm_vgic_target_oracle - compute the target vcpu for an irq
> >   *
> > diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
> > index bba7fa2..7bdcda2 100644
> > --- a/virt/kvm/arm/vgic/vgic.h
> > +++ b/virt/kvm/arm/vgic/vgic.h
> > @@ -104,6 +104,11 @@ static inline bool irq_is_pending(struct vgic_irq *irq)
> >  		return irq->pending_latch || irq->line_level;
> >  }
> >  
> > +static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
> > +{
> > +	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
> > +}
> > +
> >  /*
> >   * This struct provides an intermediate representation of the fields contained
> >   * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
> > @@ -140,6 +145,8 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
> >  struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
> >  			      u32 intid);
> >  void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
> > +bool vgic_get_phys_line_level(struct vgic_irq *irq);
> > +void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
> >  bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
> >  void vgic_kick_vcpus(struct kvm *kvm);
> >  
> >
diff mbox

Patch

diff --git a/virt/kvm/arm/vgic/vgic-v2.c b/virt/kvm/arm/vgic/vgic-v2.c
index e4187e5..618ed3f 100644
--- a/virt/kvm/arm/vgic/vgic-v2.c
+++ b/virt/kvm/arm/vgic/vgic-v2.c
@@ -104,6 +104,26 @@  void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
 				irq->pending_latch = false;
 		}
 
+		/*
+		 * Level-triggered mapped IRQs are special because we only
+		 * observe rising edges as input to the VGIC.
+		 *
+		 * If the guest never acked the interrupt we have to sample
+		 * the physical line and set the line level, because the
+		 * device state could have changed or we simply need to
+		 * process the still pending interrupt later.
+		 *
+		 * 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.
+		 */
+		if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT)) {
+			irq->line_level = vgic_get_phys_line_level(irq);
+
+			if (!irq->line_level)
+				vgic_irq_set_phys_active(irq, false);
+		}
+
 		spin_unlock(&irq->irq_lock);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
@@ -161,6 +181,15 @@  void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 			val |= GICH_LR_EOI;
 	}
 
+	/*
+	 * Level-triggered mapped IRQs are special because we only observe
+	 * rising edges as input to the VGIC.  We therefore lower the line
+	 * level here, so that we can take new virtual IRQs.  See
+	 * vgic_v2_fold_lr_state for more info.
+	 */
+	if (vgic_irq_is_mapped_level(irq) && (val & GICH_LR_PENDING_BIT))
+		irq->line_level = false;
+
 	/* The GICv2 LR only holds five bits of priority. */
 	val |= (irq->priority >> 3) << GICH_LR_PRIORITY_SHIFT;
 
diff --git a/virt/kvm/arm/vgic/vgic-v3.c b/virt/kvm/arm/vgic/vgic-v3.c
index 96ea597..0f72bcb 100644
--- a/virt/kvm/arm/vgic/vgic-v3.c
+++ b/virt/kvm/arm/vgic/vgic-v3.c
@@ -94,6 +94,26 @@  void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
 				irq->pending_latch = false;
 		}
 
+		/*
+		 * Level-triggered mapped IRQs are special because we only
+		 * observe rising edges as input to the VGIC.
+		 *
+		 * If the guest never acked the interrupt we have to sample
+		 * the physical line and set the line level, because the
+		 * device state could have changed or we simply need to
+		 * process the still pending interrupt later.
+		 *
+		 * 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.
+		 */
+		if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT)) {
+			irq->line_level = vgic_get_phys_line_level(irq);
+
+			if (!irq->line_level)
+				vgic_irq_set_phys_active(irq, false);
+		}
+
 		spin_unlock(&irq->irq_lock);
 		vgic_put_irq(vcpu->kvm, irq);
 	}
@@ -144,6 +164,15 @@  void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr)
 	}
 
 	/*
+	 * Level-triggered mapped IRQs are special because we only observe
+	 * rising edges as input to the VGIC.  We therefore lower the line
+	 * level here, so that we can take new virtual IRQs.  See
+	 * vgic_v3_fold_lr_state for more info.
+	 */
+	if (vgic_irq_is_mapped_level(irq) && (val & ICH_LR_PENDING_BIT))
+		irq->line_level = false;
+
+	/*
 	 * We currently only support Group1 interrupts, which is a
 	 * known defect. This needs to be addressed at some point.
 	 */
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 9d557efd..8072969 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -140,6 +140,29 @@  void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
 	kfree(irq);
 }
 
+/* Get the input level of a mapped IRQ directly from the physical GIC */
+bool vgic_get_phys_line_level(struct vgic_irq *irq)
+{
+	bool line_level;
+
+	BUG_ON(!irq->hw);
+
+	WARN_ON(irq_get_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_PENDING,
+				      &line_level));
+	return line_level;
+}
+
+/* Set/Clear the physical active state */
+void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active)
+{
+
+	BUG_ON(!irq->hw);
+	WARN_ON(irq_set_irqchip_state(irq->host_irq,
+				      IRQCHIP_STATE_ACTIVE,
+				      active));
+}
+
 /**
  * kvm_vgic_target_oracle - compute the target vcpu for an irq
  *
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index bba7fa2..7bdcda2 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -104,6 +104,11 @@  static inline bool irq_is_pending(struct vgic_irq *irq)
 		return irq->pending_latch || irq->line_level;
 }
 
+static inline bool vgic_irq_is_mapped_level(struct vgic_irq *irq)
+{
+	return irq->config == VGIC_CONFIG_LEVEL && irq->hw;
+}
+
 /*
  * This struct provides an intermediate representation of the fields contained
  * in the GICH_VMCR and ICH_VMCR registers, such that code exporting the GIC
@@ -140,6 +145,8 @@  vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
 struct vgic_irq *vgic_get_irq(struct kvm *kvm, struct kvm_vcpu *vcpu,
 			      u32 intid);
 void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq);
+bool vgic_get_phys_line_level(struct vgic_irq *irq);
+void vgic_irq_set_phys_active(struct vgic_irq *irq, bool active);
 bool vgic_queue_irq_unlock(struct kvm *kvm, struct vgic_irq *irq);
 void vgic_kick_vcpus(struct kvm *kvm);