ll_schedule_domain: use pipeline_task in DMA domains

Uses pipeline_task in DMA domains to check, if tasks should be even
registered on interrupts. Non registrable tasks are the one,
whose pipelines are not the owners of scheduling component e.g.
host pipelines connected to mixer pipeline. Such tasks are still
added to the scheduler's list and executed, but they are driven
by the pipelines with scheduling component.

Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
Tomasz Lauda 2019-10-10 11:55:06 +02:00 committed by Liam Girdwood
parent 5ead758e24
commit f42ddc06fd
2 changed files with 55 additions and 7 deletions

View File

@ -7,9 +7,11 @@
#include <sof/audio/component.h>
#include <sof/bit.h>
#include <sof/drivers/interrupt.h>
#include <sof/drivers/timer.h>
#include <sof/lib/alloc.h>
#include <sof/lib/cpu.h>
#include <sof/lib/dma.h>
#include <sof/platform.h>
#include <sof/schedule/ll_schedule.h>
#include <sof/schedule/ll_schedule_domain.h>
#include <sof/schedule/schedule.h>
@ -21,7 +23,7 @@
struct dma_domain_data {
int irq;
struct task *task;
struct pipeline_task *task;
void (*handler)(void *arg);
void *arg;
};
@ -96,6 +98,7 @@ static int dma_multi_chan_domain_register(struct ll_schedule_domain *domain,
void (*handler)(void *arg), void *arg)
{
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct pipeline_task *pipe_task = pipeline_task_get(task);
struct dma *dmas = dma_domain->dma_array;
int core = cpu_get_id();
int ret;
@ -104,6 +107,10 @@ static int dma_multi_chan_domain_register(struct ll_schedule_domain *domain,
trace_ll("dma_multi_chan_domain_register()");
/* check if task should be registered */
if (!pipe_task->registrable)
return 0;
for (i = 0; i < dma_domain->num_dma; ++i) {
for (j = 0; j < dmas[i].plat_data.channels; ++j) {
/* channel not set as scheduling source */
@ -146,7 +153,7 @@ static int dma_multi_chan_domain_register(struct ll_schedule_domain *domain,
dma_interrupt(&dmas[i].chan[j], DMA_IRQ_UNMASK);
dma_domain->data[i][j].task = task;
dma_domain->data[i][j].task = pipe_task;
dma_domain->channel_mask[i][core] |= BIT(j);
return 0;
@ -180,6 +187,7 @@ static void dma_multi_chan_domain_unregister(struct ll_schedule_domain *domain,
uint32_t num_tasks)
{
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct pipeline_task *pipe_task = pipeline_task_get(task);
struct dma *dmas = dma_domain->dma_array;
int core = cpu_get_id();
int i;
@ -187,6 +195,10 @@ static void dma_multi_chan_domain_unregister(struct ll_schedule_domain *domain,
trace_ll("dma_multi_chan_domain_unregister()");
/* check if task should be unregistered */
if (!pipe_task->registrable)
return;
for (i = 0; i < dma_domain->num_dma; ++i) {
for (j = 0; j < dmas[i].plat_data.channels; ++j) {
/* channel not set as scheduling source */
@ -236,6 +248,7 @@ static bool dma_multi_chan_domain_is_pending(struct ll_schedule_domain *domain,
struct task *task)
{
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct pipeline_task *pipe_task = pipeline_task_get(task);
struct dma *dmas = dma_domain->dma_array;
uint32_t status;
int i;
@ -248,8 +261,15 @@ static bool dma_multi_chan_domain_is_pending(struct ll_schedule_domain *domain,
if (!status)
continue;
/* not this task */
if (dma_domain->data[i][j].task != task)
/* not the same scheduling component */
if (dma_domain->data[i][j].task->sched_comp !=
pipe_task->sched_comp)
continue;
/* it's too soon for this task */
if (!pipe_task->registrable &&
pipe_task->task.start >
platform_timer_get(platform_timer))
continue;
/* execute callback if exists */
@ -257,9 +277,11 @@ static bool dma_multi_chan_domain_is_pending(struct ll_schedule_domain *domain,
dmas[i].chan[j].irq_callback(&dmas[i].chan[j]);
/* clear interrupt */
dma_interrupt(&dmas[i].chan[j], DMA_IRQ_CLEAR);
interrupt_clear_mask(dma_domain->data[i][j].irq,
BIT(j));
if (pipe_task->registrable) {
dma_interrupt(&dmas[i].chan[j], DMA_IRQ_CLEAR);
interrupt_clear_mask(dma_domain->data[i][j].irq,
BIT(j));
}
return true;
}

View File

@ -181,6 +181,7 @@ static int dma_single_chan_domain_register(struct ll_schedule_domain *domain,
void *arg)
{
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct pipeline_task *pipe_task = pipeline_task_get(task);
int core = cpu_get_id();
struct dma_domain_data *data = &dma_domain->data[core];
struct dma_chan_data *channel;
@ -189,6 +190,10 @@ static int dma_single_chan_domain_register(struct ll_schedule_domain *domain,
trace_ll("dma_single_chan_domain_register()");
/* check if task should be registered */
if (!pipe_task->registrable)
return 0;
/* get running channel with min period */
channel = dma_chan_min_period(dma_domain);
if (!channel)
@ -341,12 +346,17 @@ static void dma_single_chan_domain_unregister(struct ll_schedule_domain *domain,
uint32_t num_tasks)
{
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct pipeline_task *pipe_task = pipeline_task_get(task);
struct dma *dmas = dma_domain->dma_array;
int core = cpu_get_id();
struct dma_domain_data *data = &dma_domain->data[core];
trace_ll("dma_single_chan_domain_unregister()");
/* check if task should be unregistered */
if (!pipe_task->registrable)
return;
/* channel not registered */
if (!data->channel)
return;
@ -377,6 +387,10 @@ static void dma_single_chan_domain_enable(struct ll_schedule_domain *domain,
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct dma_domain_data *data = &dma_domain->data[core];
/* channel not registered */
if (!data->channel)
return;
dma_interrupt(data->channel, DMA_IRQ_UNMASK);
interrupt_unmask(data->irq, core);
@ -393,6 +407,10 @@ static void dma_single_chan_domain_disable(struct ll_schedule_domain *domain,
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct dma_domain_data *data = &dma_domain->data[core];
/* channel not registered */
if (!data->channel)
return;
interrupt_mask(data->irq, core);
}
@ -408,6 +426,10 @@ static void dma_single_chan_domain_set(struct ll_schedule_domain *domain,
struct dma_domain_data *data = &dma_domain->data[cpu_get_id()];
uint64_t ticks;
/* channel not registered */
if (!data->channel)
return;
if (dma_domain->channel_changed) {
domain->last_tick = platform_timer_get(platform_timer);
@ -429,6 +451,10 @@ static void dma_single_chan_domain_clear(struct ll_schedule_domain *domain)
struct dma_domain *dma_domain = ll_sch_domain_get_pdata(domain);
struct dma_domain_data *data = &dma_domain->data[cpu_get_id()];
/* channel not registered */
if (!data->channel)
return;
dma_interrupt(data->channel, DMA_IRQ_CLEAR);
}