Linux KVM/arm64 development list
 help / color / mirror / Atom feed
From: Joey Gouly <joey.gouly@arm.com>
To: Sascha Bischoff <Sascha.Bischoff@arm.com>
Cc: "linux-arm-kernel@lists.infradead.org"
	<linux-arm-kernel@lists.infradead.org>,
	"kvmarm@lists.linux.dev" <kvmarm@lists.linux.dev>,
	"kvm@vger.kernel.org" <kvm@vger.kernel.org>, nd <nd@arm.com>,
	"maz@kernel.org" <maz@kernel.org>,
	"oliver.upton@linux.dev" <oliver.upton@linux.dev>,
	Suzuki Poulose <Suzuki.Poulose@arm.com>,
	"yuzenghui@huawei.com" <yuzenghui@huawei.com>,
	"peter.maydell@linaro.org" <peter.maydell@linaro.org>,
	"lpieralisi@kernel.org" <lpieralisi@kernel.org>,
	Timothy Hayes <Timothy.Hayes@arm.com>
Subject: Re: [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs
Date: Wed, 17 Dec 2025 12:00:35 +0000	[thread overview]
Message-ID: <20251217120035.GA1628893@e124191.cambridge.arm.com> (raw)
In-Reply-To: <20251217114932.GA1626516@e124191.cambridge.arm.com>

On Wed, Dec 17, 2025 at 11:49:32AM +0000, Joey Gouly wrote:
> Hi Sascha,
> 
> On Fri, Dec 12, 2025 at 03:22:41PM +0000, Sascha Bischoff wrote:
> > This change allows KVM to check for pending PPI interrupts. This has
> > two main components:
> > 
> > First of all, the effective priority mask is calculated.  This is a
> > combination of the priority mask in the VPEs ICC_PCR_EL1.PRIORITY and
> > the currently running priority as determined from the VPE's
> > ICH_APR_EL1. If an interrupt's prioirity is greater than or equal to
> > the effective priority mask, it can be signalled. Otherwise, it
> > cannot.
> > 
> > Secondly, any Enabled and Pending PPIs must be checked against this
> > compound priority mask. The reqires the PPI priorities to by synced
> > back to the KVM shadow state - this is skipped in general operation as
> > it isn't required and is rather expensive. If any Enabled and Pending
> > PPIs are of sufficient priority to be signalled, then there are
> > pending PPIs. Else, there are not.  This ensures that a VPE is not
> > woken when it cannot actually process the pending interrupts.
> > 
> > Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
> > ---
> >  arch/arm64/kvm/vgic/vgic-v5.c | 123 ++++++++++++++++++++++++++++++++++
> >  arch/arm64/kvm/vgic/vgic.c    |  10 ++-
> >  arch/arm64/kvm/vgic/vgic.h    |   1 +
> >  3 files changed, 131 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm64/kvm/vgic/vgic-v5.c b/arch/arm64/kvm/vgic/vgic-v5.c
> > index d54595fbf4586..35740e88b3591 100644
> > --- a/arch/arm64/kvm/vgic/vgic-v5.c
> > +++ b/arch/arm64/kvm/vgic/vgic-v5.c
> > @@ -54,6 +54,31 @@ int vgic_v5_probe(const struct gic_kvm_info *info)
> >  	return 0;
> >  }
> >  
> > +static u32 vgic_v5_get_effective_priority_mask(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +	unsigned highest_ap, priority_mask;
> > +
> > +	/*
> > +	 * Counting the number of trailing zeros gives the current
> > +	 * active priority. Explicitly use the 32-bit version here as
> > +	 * we have 32 priorities. 0x20 then means that there are no
> > +	 * active priorities.
> > +	 */
> > +	highest_ap = __builtin_ctz(cpu_if->vgic_apr);
> 
> __builtin_ctz(0) is undefined (https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html)
> 
> Looking at __vgic_v3_clear_highest_active_priority(), it handles that like this:
> 
> 	c0 = ap0 ? __ffs(ap0) : 32;

Sorry forgot ffs() was 1-based, so:

	highest_ap = cpu_if->vgic_apr ? __builtin_ctz(cpu_if->vgic_apr) : 32;

Thanks,
Joey

> 
> Thanks,
> Joey
> 
> > +
> > +	/*
> > +	 * An interrupt is of sufficient priority if it is equal to or
> > +	 * greater than the priority mask. Add 1 to the priority mask
> > +	 * (i.e., lower priority) to match the APR logic before taking
> > +	 * the min. This gives us the lowest priority that is masked.
> > +	 */
> > +	priority_mask = FIELD_GET(FEAT_GCIE_ICH_VMCR_EL2_VPMR, cpu_if->vgic_vmcr);
> > +	priority_mask = min(highest_ap, priority_mask + 1);
> > +
> > +	return priority_mask;
> > +}
> > +
> >  static bool vgic_v5_ppi_set_pending_state(struct kvm_vcpu *vcpu,
> >  					  struct vgic_irq *irq)
> >  {
> > @@ -121,6 +146,104 @@ void vgic_v5_set_ppi_ops(struct vgic_irq *irq)
> >  	irq->ops = &vgic_v5_ppi_irq_ops;
> >  }
> >  
> > +
> > +/*
> > + * Sync back the PPI priorities to the vgic_irq shadow state
> > + */
> > +static void vgic_v5_sync_ppi_priorities(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +	unsigned long flags;
> > +	int i, reg;
> > +
> > +	/* We have 16 PPI Priority regs */
> > +	for (reg = 0; reg < 16; reg++) {
> > +		const unsigned long priorityr = cpu_if->vgic_ppi_priorityr[reg];
> > +
> > +		for (i = 0; i < 8; ++i) {
> > +			struct vgic_irq *irq;
> > +			u32 intid;
> > +			u8 priority;
> > +
> > +			priority = (priorityr >> (i * 8)) & 0x1f;
> > +
> > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 8 + i);
> > +
> > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> > +
> > +			irq->priority = priority;
> > +
> > +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> > +			vgic_put_irq(vcpu->kvm, irq);
> > +		}
> > +	}
> > +}
> > +
> > +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu)
> > +{
> > +	struct vgic_v5_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v5;
> > +	unsigned long flags;
> > +	int i, reg;
> > +	unsigned int priority_mask;
> > +
> > +	/* If no pending bits are set, exit early */
> > +	if (likely(!cpu_if->vgic_ppi_pendr[0] && !cpu_if->vgic_ppi_pendr[1]))
> > +		return false;
> > +
> > +	priority_mask = vgic_v5_get_effective_priority_mask(vcpu);
> > +
> > +	/* If the combined priority mask is 0, nothing can be signalled! */
> > +	if (!priority_mask)
> > +		return false;
> > +
> > +	/* The shadow priority is only updated on demand, sync it across first */
> > +	vgic_v5_sync_ppi_priorities(vcpu);
> > +
> > +	for (reg = 0; reg < 2; reg++) {
> > +		unsigned long possible_bits;
> > +		const unsigned long enabler = cpu_if->vgic_ich_ppi_enabler_exit[reg];
> > +		const unsigned long pendr = cpu_if->vgic_ppi_pendr_exit[reg];
> > +		bool has_pending = false;
> > +
> > +		/* Check all interrupts that are enabled and pending */
> > +		possible_bits = enabler & pendr;
> > +
> > +		/*
> > +		 * Optimisation: pending and enabled with no active priorities
> > +		 */
> > +		if (possible_bits && priority_mask > 0x1f)
> > +			return true;
> > +
> > +		for_each_set_bit(i, &possible_bits, 64) {
> > +			struct vgic_irq *irq;
> > +			u32 intid;
> > +
> > +			intid = FIELD_PREP(GICV5_HWIRQ_TYPE, GICV5_HWIRQ_TYPE_PPI);
> > +			intid |= FIELD_PREP(GICV5_HWIRQ_ID, reg * 64 + i);
> > +
> > +			irq = vgic_get_vcpu_irq(vcpu, intid);
> > +			raw_spin_lock_irqsave(&irq->irq_lock, flags);
> > +
> > +			/*
> > +			 * We know that the interrupt is enabled and pending, so
> > +			 * only check the priority.
> > +			 */
> > +			if (irq->priority <= priority_mask)
> > +				has_pending = true;
> > +
> > +			raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
> > +			vgic_put_irq(vcpu->kvm, irq);
> > +
> > +			if (has_pending)
> > +				return true;
> > +		}
> > +	}
> > +
> > +	return false;
> > +}
> > +
> >  /*
> >   * Detect any PPIs state changes, and propagate the state with KVM's
> >   * shadow structures.
> > diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
> > index e534876656ca7..5d18a03cc11d5 100644
> > --- a/arch/arm64/kvm/vgic/vgic.c
> > +++ b/arch/arm64/kvm/vgic/vgic.c
> > @@ -1174,11 +1174,15 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
> >  	unsigned long flags;
> >  	struct vgic_vmcr vmcr;
> >  
> > -	if (!vcpu->kvm->arch.vgic.enabled)
> > +	if (!vcpu->kvm->arch.vgic.enabled && !vgic_is_v5(vcpu->kvm))
> >  		return false;
> >  
> > -	if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> > -		return true;
> > +	if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V5) {
> > +		return vgic_v5_has_pending_ppi(vcpu);
> > +	} else {
> > +		if (vcpu->arch.vgic_cpu.vgic_v3.its_vpe.pending_last)
> > +			return true;
> > +	}
> >  
> >  	vgic_get_vmcr(vcpu, &vmcr);
> >  
> > diff --git a/arch/arm64/kvm/vgic/vgic.h b/arch/arm64/kvm/vgic/vgic.h
> > index 5a77318ddb87a..4b3a1e7ca3fb4 100644
> > --- a/arch/arm64/kvm/vgic/vgic.h
> > +++ b/arch/arm64/kvm/vgic/vgic.h
> > @@ -387,6 +387,7 @@ void vgic_debug_destroy(struct kvm *kvm);
> >  int vgic_v5_probe(const struct gic_kvm_info *info);
> >  void vgic_v5_set_ppi_ops(struct vgic_irq *irq);
> >  int vgic_v5_set_ppi_dvi(struct kvm_vcpu *vcpu, u32 irq, bool dvi);
> > +bool vgic_v5_has_pending_ppi(struct kvm_vcpu *vcpu);
> >  void vgic_v5_flush_ppi_state(struct kvm_vcpu *vcpu);
> >  void vgic_v5_fold_irq_state(struct kvm_vcpu *vcpu);
> >  void vgic_v5_load(struct kvm_vcpu *vcpu);
> > -- 
> > 2.34.1

  reply	other threads:[~2025-12-17 12:00 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-12-12 15:22 [PATCH 00/32] KVM: arm64: Introduce vGIC-v5 with PPI support Sascha Bischoff
2025-12-12 15:22 ` [PATCH 02/32] KVM: arm64: gic-v3: Switch vGIC-v3 to use generated ICH_VMCR_EL2 Sascha Bischoff
2025-12-15 11:52   ` Marc Zyngier
2025-12-15 14:15     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 01/32] KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co Sascha Bischoff
2025-12-12 15:22 ` [PATCH 04/32] arm64/sysreg: Add remaining GICv5 ICC_ & ICH_ sysregs for KVM support Sascha Bischoff
2025-12-12 15:22 ` [PATCH 03/32] arm64/sysreg: Drop ICH_HFGRTR_EL2.ICC_HAPR_EL1 and make RES1 Sascha Bischoff
2025-12-12 15:22 ` [PATCH 05/32] arm64/sysreg: Add GICR CDNMIA encoding Sascha Bischoff
2025-12-12 15:22 ` [PATCH 06/32] KVM: arm64: gic-v5: Add ARM_VGIC_V5 device to KVM headers Sascha Bischoff
2025-12-12 15:22 ` [PATCH 07/32] KVM: arm64: gic: Introduce interrupt type helpers Sascha Bischoff
2025-12-15 13:32   ` Marc Zyngier
2025-12-15 16:01     ` Sascha Bischoff
2025-12-15 16:05     ` Marc Zyngier
2025-12-16  8:57       ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 08/32] KVM: arm64: gic-v5: Sanitize ID_AA64PFR2_EL1.GCIE Sascha Bischoff
2025-12-12 15:22 ` [PATCH 09/32] KVM: arm64: gic-v5: Compute GICv5 FGTs on vcpu load Sascha Bischoff
2025-12-12 16:24   ` Marc Zyngier
2025-12-15 17:37     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 10/32] KVM: arm64: gic-v5: Add emulation for ICC_IAFFID_EL1 accesses Sascha Bischoff
2025-12-15 17:31   ` Marc Zyngier
2025-12-16 10:57     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 13/32] KVM: arm64: gic-v5: Add vgic-v5 save/restore hyp interface Sascha Bischoff
2025-12-17 11:07   ` Marc Zyngier
2025-12-17 21:42     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 12/32] KVM: arm64: gic: Set vgic_model before initing private IRQs Sascha Bischoff
2025-12-12 15:22 ` [PATCH 11/32] KVM: arm64: gic-v5: Trap and emulate ICH_PPI_HMRx_EL1 accesses Sascha Bischoff
2025-12-16 10:41   ` Marc Zyngier
2025-12-16 11:54     ` Sascha Bischoff
2025-12-16 15:09       ` Marc Zyngier
2025-12-12 15:22 ` [PATCH 16/32] KVM: arm64: gic: Introduce irq_queue and set_pending_state to irq_ops Sascha Bischoff
2025-12-17  9:34   ` Marc Zyngier
2025-12-17 20:50     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 15/32] KVM: arm64: gic-v5: Implement direct injection of PPIs Sascha Bischoff
2025-12-17 11:40   ` Marc Zyngier
2026-01-07 14:50     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 14/32] KVM: arm64: gic-v5: Implement GICv5 load/put and save/restore Sascha Bischoff
2025-12-13  5:59   ` kernel test robot
2025-12-15 10:54     ` Sascha Bischoff
2025-12-13  8:05   ` kernel test robot
2025-12-22 16:52   ` kernel test robot
2025-12-12 15:22 ` [PATCH 17/32] KVM: arm64: gic-v5: Implement PPI interrupt injection Sascha Bischoff
2025-12-17 10:33   ` Marc Zyngier
2025-12-17 21:10     ` Sascha Bischoff
2025-12-17 15:54   ` Joey Gouly
2026-01-07 16:28     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 18/32] KVM: arm64: gic-v5: Check for pending PPIs Sascha Bischoff
2025-12-17 11:49   ` Joey Gouly
2025-12-17 12:00     ` Joey Gouly [this message]
2025-12-18  8:17       ` Sascha Bischoff
2025-12-17 14:29   ` Marc Zyngier
2026-01-07 15:59     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 19/32] KVM: arm64: gic-v5: Init Private IRQs (PPIs) for GICv5 Sascha Bischoff
2025-12-17 17:13   ` Marc Zyngier
2025-12-12 15:22 ` [PATCH 20/32] KVM: arm64: gic-v5: Support GICv5 interrupts with KVM_IRQ_LINE Sascha Bischoff
2025-12-12 15:22 ` [PATCH 21/32] KVM: arm64: gic-v5: Create, init vgic_v5 Sascha Bischoff
2025-12-12 15:22 ` [PATCH 22/32] KVM: arm64: gic-v5: Reset vcpu state Sascha Bischoff
2025-12-12 15:22 ` [PATCH 24/32] KVM: arm64: gic-v5: Mandate architected PPI for PMU emulation on GICv5 Sascha Bischoff
2025-12-12 15:22 ` [PATCH 23/32] KVM: arm64: gic-v5: Bump arch timer for GICv5 Sascha Bischoff
2025-12-15 15:50   ` Marc Zyngier
2025-12-16 10:55     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 27/32] KVM: arm64: gic-v5: Introduce kvm_arm_vgic_v5_ops and register them Sascha Bischoff
2025-12-12 15:22 ` [PATCH 26/32] KVM: arm64: gic-v5: Hide FEAT_GCIE from NV GICv5 guests Sascha Bischoff
2025-12-12 15:22 ` [PATCH 28/32] KVM: arm64: gic-v5: Set ICH_VCTLR_EL2.En on boot Sascha Bischoff
2025-12-12 15:22 ` [PATCH 25/32] KVM: arm64: gic: Hide GICv5 for protected guests Sascha Bischoff
2025-12-12 15:22 ` [PATCH 29/32] irqchip/gic-v5: Check if impl is virt capable Sascha Bischoff
2025-12-16 15:40   ` Lorenzo Pieralisi
2025-12-17 20:46     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 30/32] KVM: arm64: gic-v5: Probe for GICv5 device Sascha Bischoff
2025-12-12 15:22 ` [PATCH 31/32] Documentation: KVM: Introduce documentation for VGICv5 Sascha Bischoff
2025-12-15  0:15   ` kernel test robot
2025-12-15  9:56   ` Peter Maydell
2025-12-15 13:01     ` Sascha Bischoff
2025-12-12 15:22 ` [PATCH 32/32] KVM: arm64: selftests: Introduce a minimal GICv5 PPI selftest Sascha Bischoff

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20251217120035.GA1628893@e124191.cambridge.arm.com \
    --to=joey.gouly@arm.com \
    --cc=Sascha.Bischoff@arm.com \
    --cc=Suzuki.Poulose@arm.com \
    --cc=Timothy.Hayes@arm.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=lpieralisi@kernel.org \
    --cc=maz@kernel.org \
    --cc=nd@arm.com \
    --cc=oliver.upton@linux.dev \
    --cc=peter.maydell@linaro.org \
    --cc=yuzenghui@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox