Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/arch/xtensa/include/arch/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ static void _irq_task(void *arg)
uint32_t flags;

spin_lock_irq(&irq_task->lock, flags);

interrupt_clear(irq_task->irq);

list_for_item_safe(clist, tlist, &irq_task->list) {

task = container_of(clist, struct task, irq_list);
Expand All @@ -152,8 +155,6 @@ static void _irq_task(void *arg)
spin_lock_irq(&irq_task->lock, flags);
}

interrupt_clear(irq_task->irq);

spin_unlock_irq(&irq_task->lock, flags);
}

Expand Down
27 changes: 27 additions & 0 deletions src/drivers/intel/dw-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@
#define INT_UNMASK_ALL 0xFFFF
#define CHAN_ENABLE(chan) (0x101 << chan)
#define CHAN_DISABLE(chan) (0x100 << chan)
#define CHAN_MASK(chan) (0x1 << chan)

#define DW_CFG_CH_SUSPEND 0x100
#define DW_CFG_CH_FIFO_EMPTY 0x200
Expand Down Expand Up @@ -491,6 +492,31 @@ static int dw_dma_pause(struct dma *dma, int channel)
return 0;
}

#if defined CONFIG_BAYTRAIL || defined CONFIG_CHERRYTRAIL
static int dw_dma_stop(struct dma *dma, int channel)
{
struct dma_pdata *p = dma_get_drvdata(dma);
int ret = 0;
uint32_t flags;
uint32_t val = 0;

spin_lock_irq(&dma->lock, flags);

trace_dma("DDi");

ret = poll_for_register_delay(dma_base(dma) + DW_DMA_CHAN_EN,
CHAN_MASK(channel), val,
PLATFORM_DMA_TIMEOUT);
if (ret < 0)
trace_dma_error("esp");

dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel);
p->chan[channel].status = COMP_STATE_PREPARE;

spin_unlock_irq(&dma->lock, flags);
return ret;
}
#else
static int dw_dma_stop(struct dma *dma, int channel)
{
struct dma_pdata *p = dma_get_drvdata(dma);
Expand Down Expand Up @@ -528,6 +554,7 @@ static int dw_dma_stop(struct dma *dma, int channel)
spin_unlock_irq(&dma->lock, flags);
return ret;
}
#endif

/* fill in "status" with current DMA channel state and position */
static int dw_dma_status(struct dma *dma, int channel,
Expand Down
52 changes: 52 additions & 0 deletions src/include/sof/wait.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,18 @@
#include <stdint.h>
#include <errno.h>
#include <arch/wait.h>
#include <sof/io.h>
#include <sof/debug.h>
#include <sof/work.h>
#include <sof/timer.h>
#include <sof/interrupt.h>
#include <sof/trace.h>
#include <sof/lock.h>
#include <sof/clock.h>
#include <platform/clk.h>
#include <platform/interrupt.h>
#include <sof/drivers/timer.h>
#include <platform/platform.h>

#if DEBUG_LOCKS
#define wait_atomic_check \
Expand All @@ -54,6 +58,8 @@
#define wait_atomic_check
#endif

#define DEFAULT_TRY_TIMES 8

typedef struct {
uint32_t complete;
struct work work;
Expand Down Expand Up @@ -158,4 +164,50 @@ static inline void wait_delay(uint64_t number_of_clks)
idelay(PLATFORM_DEFAULT_DELAY);
}

static inline int poll_for_completion_delay(completion_t *comp, uint64_t us)
{
uint64_t tick = clock_us_to_ticks(CLK_CPU, us);
uint32_t tries = DEFAULT_TRY_TIMES;
uint64_t delta = tick / tries;

if (!delta) {
delta = us;
tries = 1;
}

while (!wait_is_completed(comp)) {
if (!tries--) {
trace_error(TRACE_CLASS_WAIT, "ewt");
return -EIO;
}

wait_delay(delta);
}

return 0;
}

static inline int poll_for_register_delay(uint32_t reg,
uint32_t mask,
uint32_t val, uint64_t us)
{
uint64_t tick = clock_us_to_ticks(CLK_CPU, us);
uint32_t tries = DEFAULT_TRY_TIMES;
uint64_t delta = tick / tries;

if (!delta) {
delta = us;
tries = 1;
}

while ((io_reg_read(reg) & mask) != val) {
if (!tries--) {
trace_error(TRACE_CLASS_WAIT, "ewt");
return -EIO;
}
wait_delay(delta);
}
return 0;
}

#endif
5 changes: 3 additions & 2 deletions src/ipc/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,8 +501,9 @@ int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table,
}

/* wait for DMA to complete */
complete.timeout = PLATFORM_HOST_DMA_TIMEOUT;
ret = wait_for_completion_timeout(&complete);
ret = poll_for_completion_delay(&complete, PLATFORM_DMA_TIMEOUT);
if (ret < 0)
trace_ipc_error("eDt");

/* compressed page tables now in buffer at _ipc->page_table */
out:
Expand Down
56 changes: 28 additions & 28 deletions src/lib/schedule.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,9 @@ static inline struct task *edf_get_next(uint64_t current,
uint64_t delta;
uint64_t deadline;
int reschedule = 0;
uint32_t flags;

spin_lock_irq(&sch->lock, flags);

/* any tasks in the scheduler ? */
if (list_is_empty(&sch->list)) {
spin_unlock_irq(&sch->lock, flags);
return NULL;
}

Expand Down Expand Up @@ -159,7 +155,6 @@ static inline struct task *edf_get_next(uint64_t current,
}
}

spin_unlock_irq(&sch->lock, flags);
return next_task;
}

Expand Down Expand Up @@ -187,35 +182,40 @@ static struct task *schedule_edf(void)

tracev_pipe("edf");

/* get the current time */
current = platform_timer_get(platform_timer);

/* get next task to be scheduled */
task = edf_get_next(current, NULL);

interrupt_clear(PLATFORM_SCHEDULE_IRQ);

/* any tasks ? */
if (task == NULL)
return NULL;
while (!list_is_empty(&sch->list)) {
spin_lock_irq(&sch->lock, flags);

/* can task be started now ? */
if (task->start > current) {
/* no, then schedule wake up */
future_task = task;
} else {
/* yes, run current task */
task->start = current;
/* get the current time */
current = platform_timer_get(platform_timer);

/* init task for running */
wait_init(&task->complete);
spin_lock_irq(&sch->lock, flags);
task->state = TASK_STATE_RUNNING;
list_item_del(&task->list);
/* get next task to be scheduled */
task = edf_get_next(current, NULL);
spin_unlock_irq(&sch->lock, flags);

/* now run task at correct run level */
run_task(task);
/* any tasks ? */
if (!task)
return NULL;

/* can task be started now ? */
if (task->start <= current) {
/* yes, run current task */
task->start = current;

/* init task for running */
spin_lock_irq(&sch->lock, flags);
task->state = TASK_STATE_RUNNING;
list_item_del(&task->list);
spin_unlock_irq(&sch->lock, flags);

/* now run task at correct run level */
run_task(task);
} else {
/* no, then schedule wake up */
future_task = task;
break;
}
}

/* tell caller about future task */
Expand Down