firmware: arm_ffa: Fix FFA notifications cleanup path

We allow the FF-A to be initialised successfully even when notification
fails. When the notification fails, ffa_notifications_cleanup() gets
called on the failure path.

However, the driver information about the notifications like the irq,
workqueues and cpu hotplug state for enabling and disabling percpu IRQ
are not cleared. This may result in unexpected behaviour during CPU
hotplug because of percpu IRQ being enabled and disabled or during the
driver removal when ffa_notifications_cleanup() gets executed again.

Fix the FFA notifications cleanup path by clearing all the notification
related driver information.

Link: https://lore.kernel.org/r/20231024-ffa-notification-fixes-v1-4-d552c0ec260d@arm.com
Tested-by: Jens Wiklander <jens.wiklander@linaro.org>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
This commit is contained in:
Sudeep Holla 2023-10-24 11:56:20 +01:00
parent f4bfcaee34
commit 6d67cbe67a

View File

@ -1326,8 +1326,10 @@ static int ffa_sched_recv_irq_map(void)
static void ffa_sched_recv_irq_unmap(void) static void ffa_sched_recv_irq_unmap(void)
{ {
if (drv_info->sched_recv_irq) if (drv_info->sched_recv_irq) {
irq_dispose_mapping(drv_info->sched_recv_irq); irq_dispose_mapping(drv_info->sched_recv_irq);
drv_info->sched_recv_irq = 0;
}
} }
static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu) static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu)
@ -1344,17 +1346,23 @@ static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu)
static void ffa_uninit_pcpu_irq(void) static void ffa_uninit_pcpu_irq(void)
{ {
if (drv_info->cpuhp_state) if (drv_info->cpuhp_state) {
cpuhp_remove_state(drv_info->cpuhp_state); cpuhp_remove_state(drv_info->cpuhp_state);
drv_info->cpuhp_state = 0;
}
if (drv_info->notif_pcpu_wq) if (drv_info->notif_pcpu_wq) {
destroy_workqueue(drv_info->notif_pcpu_wq); destroy_workqueue(drv_info->notif_pcpu_wq);
drv_info->notif_pcpu_wq = NULL;
}
if (drv_info->sched_recv_irq) if (drv_info->sched_recv_irq)
free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu); free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu);
if (drv_info->irq_pcpu) if (drv_info->irq_pcpu) {
free_percpu(drv_info->irq_pcpu); free_percpu(drv_info->irq_pcpu);
drv_info->irq_pcpu = NULL;
}
} }
static int ffa_init_pcpu_irq(unsigned int irq) static int ffa_init_pcpu_irq(unsigned int irq)