From: Mykola Kvach <mykola_kvach@epam.com>
The FF-A notification SRI interrupt handler was not correctly tied to
CPU hotplug and suspend/resume. As a result, CPUs going offline and
back online could end up with stale or missing handlers, breaking
delivery of FF-A notifications.
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
---
xen/arch/arm/tee/ffa_notif.c | 63 ++++++++++++++++++++++++++++--------
1 file changed, 50 insertions(+), 13 deletions(-)
diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c
index 86bef6b3b2..84f5c6b43b 100644
--- a/xen/arch/arm/tee/ffa_notif.c
+++ b/xen/arch/arm/tee/ffa_notif.c
@@ -359,10 +359,28 @@ static int32_t ffa_notification_bitmap_destroy(uint16_t vm_id)
return ffa_simple_call(FFA_NOTIFICATION_BITMAP_DESTROY, vm_id, 0, 0, 0);
}
-void ffa_notif_init_interrupt(void)
+static DEFINE_PER_CPU_READ_MOSTLY(struct irqaction, sri_irq);
+
+static int request_sri_irq(void)
{
int ret;
+ struct irqaction *sri_action = &this_cpu(sri_irq);
+
+ sri_action->name = "FF-A notif";
+ sri_action->handler = notif_irq_handler;
+ sri_action->dev_id = NULL;
+ sri_action->free_on_release = 0;
+
+ ret = setup_irq(notif_sri_irq, 0, sri_action);
+ if ( ret )
+ printk(XENLOG_ERR "ffa: setup_irq irq %u failed: error %d\n",
+ notif_sri_irq, ret);
+ return ret;
+}
+
+void ffa_notif_init_interrupt(void)
+{
if ( fw_notif_enabled && notif_sri_irq < NR_GIC_SGI )
{
/*
@@ -375,14 +393,36 @@ void ffa_notif_init_interrupt(void)
* pending, while the SPMC in the secure world will not notice that
* the interrupt was lost.
*/
- ret = request_irq(notif_sri_irq, 0, notif_irq_handler, "FF-A notif",
- NULL);
- if ( ret )
- printk(XENLOG_ERR "ffa: request_irq irq %u failed: error %d\n",
- notif_sri_irq, ret);
+ request_sri_irq();
}
}
+static void deinit_ffa_notif_interrupt(void)
+{
+ if ( fw_notif_enabled && notif_sri_irq < NR_GIC_SGI )
+ release_irq(notif_sri_irq, NULL);
+}
+
+static int cpu_ffa_notif_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ switch ( action )
+ {
+ case CPU_DYING:
+ deinit_ffa_notif_interrupt();
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block cpu_ffa_notif_nfb = {
+ .notifier_call = cpu_ffa_notif_callback,
+};
+
void ffa_notif_init(void)
{
const struct arm_smccc_1_2_regs arg = {
@@ -391,7 +431,6 @@ void ffa_notif_init(void)
};
struct arm_smccc_1_2_regs resp;
unsigned int irq;
- int ret;
/* Only enable fw notification if all ABIs we need are supported */
if ( ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_CREATE) &&
@@ -407,13 +446,11 @@ void ffa_notif_init(void)
notif_sri_irq = irq;
if ( irq >= NR_GIC_SGI )
irq_set_type(irq, IRQ_TYPE_EDGE_RISING);
- ret = request_irq(irq, 0, notif_irq_handler, "FF-A notif", NULL);
- if ( ret )
- {
- printk(XENLOG_ERR "ffa: request_irq irq %u failed: error %d\n",
- irq, ret);
+
+ if ( request_sri_irq() )
return;
- }
+
+ register_cpu_notifier(&cpu_ffa_notif_nfb);
fw_notif_enabled = true;
}
}
--
2.43.0