RX-buffer-full notifications currently inject the notification pending
interrupt through vcpu0 only. Secure notification delivery already walks
the domain's online vCPUs, but the RX-buffer-full path does not. When
vcpu0 is offline, the notification remains pending and the guest never
receives it.
Extract the common notification injection path and reuse it from
ffa_raise_rx_buffer_full(). The shared helper delivers the global
notification to the first online vCPU and keeps the existing ratelimited
debug message when none are online.
Functional impact: RX-buffer-full notifications are delivered even when
vcpu0 is offline.
Fixes: 3935c705688e ("xen/arm: ffa: Add buffer full notification support")
Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com>
---
xen/arch/arm/tee/ffa_notif.c | 45 ++++++++++++++++++++----------------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c
index 186e72641237..07bc5cb3a430 100644
--- a/xen/arch/arm/tee/ffa_notif.c
+++ b/xen/arch/arm/tee/ffa_notif.c
@@ -19,6 +19,29 @@
static bool __ro_after_init fw_notif_enabled;
static unsigned int __ro_after_init notif_sri_irq;
+static void inject_notif_pending(struct domain *d)
+{
+ struct vcpu *v;
+
+ /*
+ * Since we're only delivering global notification, always
+ * deliver to the first online vCPU. It doesn't matter
+ * which we chose, as long as it's available.
+ */
+ for_each_vcpu(d, v)
+ {
+ if ( is_vcpu_online(v) )
+ {
+ vgic_inject_irq(d, v, GUEST_FFA_NOTIF_PEND_INTR_ID, true);
+ return;
+ }
+ }
+
+ if ( printk_ratelimit() )
+ printk(XENLOG_G_DEBUG "%pd: ffa: can't inject NPI, all vCPUs offline\n",
+ d);
+}
+
int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs)
{
struct domain *d = current->domain;
@@ -190,7 +213,7 @@ void ffa_raise_rx_buffer_full(struct domain *d)
ACCESS_ONCE(ctx->notif.buff_full_pending) = true;
if ( !test_and_set_bool(ctx->notif.vm_pending) )
- vgic_inject_irq(d, d->vcpu[0], GUEST_FFA_NOTIF_PEND_INTR_ID, true);
+ inject_notif_pending(d);
}
#endif
@@ -238,7 +261,6 @@ static void notif_vm_pend_intr(uint16_t vm_id)
{
struct ffa_ctx *ctx;
struct domain *d;
- struct vcpu *v;
/*
* vm_id == 0 means a notifications pending for Xen itself, but
@@ -277,24 +299,7 @@ static void notif_vm_pend_intr(uint16_t vm_id)
* it.
*/
ACCESS_ONCE(ctx->notif.secure_pending) = true;
-
- /*
- * Since we're only delivering global notification, always
- * deliver to the first online vCPU. It doesn't matter
- * which we chose, as long as it's available.
- */
- for_each_vcpu(d, v)
- {
- if ( is_vcpu_online(v) )
- {
- vgic_inject_irq(d, v, GUEST_FFA_NOTIF_PEND_INTR_ID,
- true);
- break;
- }
- }
- if ( !v && printk_ratelimit() )
- printk(XENLOG_G_DEBUG "%pd: ffa: can't inject NPI, all vCPUs offline\n",
- d);
+ inject_notif_pending(d);
out_unlock:
rcu_unlock_domain(d);
--
2.53.0
Hi Bertrand,
On Fri, Apr 17, 2026 at 3:41 PM Bertrand Marquis
<bertrand.marquis@arm.com> wrote:
>
> RX-buffer-full notifications currently inject the notification pending
> interrupt through vcpu0 only. Secure notification delivery already walks
> the domain's online vCPUs, but the RX-buffer-full path does not. When
> vcpu0 is offline, the notification remains pending and the guest never
> receives it.
>
> Extract the common notification injection path and reuse it from
> ffa_raise_rx_buffer_full(). The shared helper delivers the global
> notification to the first online vCPU and keeps the existing ratelimited
> debug message when none are online.
>
> Functional impact: RX-buffer-full notifications are delivered even when
> vcpu0 is offline.
>
> Fixes: 3935c705688e ("xen/arm: ffa: Add buffer full notification support")
>
> Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com>
> ---
> xen/arch/arm/tee/ffa_notif.c | 45 ++++++++++++++++++++----------------
> 1 file changed, 25 insertions(+), 20 deletions(-)
Looks good:
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
Cheers,
Jens
>
> diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c
> index 186e72641237..07bc5cb3a430 100644
> --- a/xen/arch/arm/tee/ffa_notif.c
> +++ b/xen/arch/arm/tee/ffa_notif.c
> @@ -19,6 +19,29 @@
> static bool __ro_after_init fw_notif_enabled;
> static unsigned int __ro_after_init notif_sri_irq;
>
> +static void inject_notif_pending(struct domain *d)
> +{
> + struct vcpu *v;
> +
> + /*
> + * Since we're only delivering global notification, always
> + * deliver to the first online vCPU. It doesn't matter
> + * which we chose, as long as it's available.
> + */
> + for_each_vcpu(d, v)
> + {
> + if ( is_vcpu_online(v) )
> + {
> + vgic_inject_irq(d, v, GUEST_FFA_NOTIF_PEND_INTR_ID, true);
> + return;
> + }
> + }
> +
> + if ( printk_ratelimit() )
> + printk(XENLOG_G_DEBUG "%pd: ffa: can't inject NPI, all vCPUs offline\n",
> + d);
> +}
> +
> int32_t ffa_handle_notification_bind(struct cpu_user_regs *regs)
> {
> struct domain *d = current->domain;
> @@ -190,7 +213,7 @@ void ffa_raise_rx_buffer_full(struct domain *d)
>
> ACCESS_ONCE(ctx->notif.buff_full_pending) = true;
> if ( !test_and_set_bool(ctx->notif.vm_pending) )
> - vgic_inject_irq(d, d->vcpu[0], GUEST_FFA_NOTIF_PEND_INTR_ID, true);
> + inject_notif_pending(d);
> }
> #endif
>
> @@ -238,7 +261,6 @@ static void notif_vm_pend_intr(uint16_t vm_id)
> {
> struct ffa_ctx *ctx;
> struct domain *d;
> - struct vcpu *v;
>
> /*
> * vm_id == 0 means a notifications pending for Xen itself, but
> @@ -277,24 +299,7 @@ static void notif_vm_pend_intr(uint16_t vm_id)
> * it.
> */
> ACCESS_ONCE(ctx->notif.secure_pending) = true;
> -
> - /*
> - * Since we're only delivering global notification, always
> - * deliver to the first online vCPU. It doesn't matter
> - * which we chose, as long as it's available.
> - */
> - for_each_vcpu(d, v)
> - {
> - if ( is_vcpu_online(v) )
> - {
> - vgic_inject_irq(d, v, GUEST_FFA_NOTIF_PEND_INTR_ID,
> - true);
> - break;
> - }
> - }
> - if ( !v && printk_ratelimit() )
> - printk(XENLOG_G_DEBUG "%pd: ffa: can't inject NPI, all vCPUs offline\n",
> - d);
> + inject_notif_pending(d);
>
> out_unlock:
> rcu_unlock_domain(d);
> --
> 2.53.0
>
© 2016 - 2026 Red Hat, Inc.