From dc02b5924e5858b7c3174e451fc1bc6dce8757bf Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 23 Sep 2021 11:09:28 +0200 Subject: [PATCH 1/3] timer_domain: don't unregister interrupt handler from itself If the last task in the timer domain is completed, the ll_scheduler tries to unregister the task from the domain. The timer domain driver currently tries to unregister the interruptin its .domain_unregister handler, which then leads to a crash. Avoid unregistering the handler from itself. Signed-off-by: Guennadi Liakhovetski --- src/schedule/timer_domain.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/src/schedule/timer_domain.c b/src/schedule/timer_domain.c index 48c7862033b4..8d30dc26f321 100644 --- a/src/schedule/timer_domain.c +++ b/src/schedule/timer_domain.c @@ -49,42 +49,30 @@ static int timer_domain_register(struct ll_schedule_domain *domain, { struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); int core = cpu_get_id(); - int ret = 0; tr_dbg(&ll_tr, "timer_domain_register()"); /* tasks already registered on this core */ if (timer_domain->arg[core]) - goto out; + return 0; timer_domain->arg[core] = arg; - ret = timer_register(timer_domain->timer, handler, arg); tr_info(&ll_tr, "timer_domain_register domain->type %d domain->clk %d domain->ticks_per_ms %d", domain->type, domain->clk, domain->ticks_per_ms); -out: - return ret; + return timer_register(timer_domain->timer, handler, arg); } static int timer_domain_unregister(struct ll_schedule_domain *domain, struct task *task, uint32_t num_tasks) { - struct timer_domain *timer_domain = ll_sch_domain_get_pdata(domain); - int core = cpu_get_id(); - - tr_dbg(&ll_tr, "timer_domain_unregister()"); - - /* tasks still registered on this core */ - if (!timer_domain->arg[core] || num_tasks) - return 0; - - tr_info(&ll_tr, "timer_domain_unregister domain->type %d domain->clk %d", - domain->type, domain->clk); - - timer_unregister(timer_domain->timer, timer_domain->arg[core]); - - timer_domain->arg[core] = NULL; + /* + * domain_unregister() can be called from the domain handler itself, + * and we cannot unregister the timer interrupt handler from the handler + * itself. Keep the interrupt registered but disabled. This assumes that + * the handler is at least not unloaded. + */ return 0; } From 94f7b2098eba15539a1db9ec706ee0ca9a576891 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 23 Sep 2021 11:14:36 +0200 Subject: [PATCH 2/3] ll_schedule: don't re-enable the domain if no tasks are active If the last task completes in a domain, don't re-enable it. It will be re-enabled when a new task is submitted. Signed-off-by: Guennadi Liakhovetski --- src/schedule/ll_schedule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index 0a19d3d7e32b..d9cdff107798 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -238,7 +238,8 @@ static void schedule_ll_tasks_run(void *data) } /* tasks on current core finished, re-enable domain on it */ - domain_enable(domain, core); + if (atomic_read(&sch->num_tasks)) + domain_enable(domain, core); spin_unlock(&domain->lock); From 87d9c5e9f837fe89428a1a937254b40ffa51e270 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 24 Sep 2021 14:28:08 +0200 Subject: [PATCH 3/3] ll_schedule: (cosmetic) remove a redundant type-cast atomic_read() returns values of type uint32_t, no need to cast to it again. Signed-off-by: Guennadi Liakhovetski --- src/schedule/ll_schedule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/schedule/ll_schedule.c b/src/schedule/ll_schedule.c index d9cdff107798..a650cd065cea 100644 --- a/src/schedule/ll_schedule.c +++ b/src/schedule/ll_schedule.c @@ -330,7 +330,7 @@ static void schedule_ll_domain_clear(struct ll_schedule_data *sch, domain_disable(domain, cpu_get_id()); /* unregister the task */ - domain_unregister(domain, task, (uint32_t)atomic_read(&sch->num_tasks)); + domain_unregister(domain, task, atomic_read(&sch->num_tasks)); tr_info(&ll_tr, "num_tasks %d total_num_tasks %d", atomic_read(&sch->num_tasks),