diff --git a/src/arch/xtensa/CMakeLists.txt b/src/arch/xtensa/CMakeLists.txt index 7704d3fdd10f..d398a6ac2c54 100644 --- a/src/arch/xtensa/CMakeLists.txt +++ b/src/arch/xtensa/CMakeLists.txt @@ -139,7 +139,7 @@ else() ) endif() -add_local_sources(sof timer.c) +add_local_sources(sof task.c timer.c) if(CONFIG_GDB_DEBUG) add_subdirectory(gdb) diff --git a/src/arch/xtensa/include/arch/task.h b/src/arch/xtensa/include/arch/task.h index de8ded4f91fb..5193fd2e5e3c 100644 --- a/src/arch/xtensa/include/arch/task.h +++ b/src/arch/xtensa/include/arch/task.h @@ -38,11 +38,9 @@ #ifndef __ARCH_TASK_H_ #define __ARCH_TASK_H_ -#include -#include -#include -#include -#include +#include + +#include /** \brief IRQ task data. */ struct irq_task { @@ -51,6 +49,8 @@ struct irq_task { uint32_t irq; /**< IRQ level */ }; +struct task; + /** * \brief Returns IRQ low task data. * \return Pointer to pointer of IRQ low task data. @@ -69,231 +69,26 @@ struct irq_task **task_irq_med_get(void); */ struct irq_task **task_irq_high_get(void); -/** - * \brief Retrieves task IRQ level. - * \param[in,out] task Task data. - * \return IRQ level. - */ -static inline uint32_t task_get_irq(struct task *task) -{ - uint32_t irq; - - switch (task->priority) { - case TASK_PRI_MED + 1 ... TASK_PRI_LOW: - irq = PLATFORM_IRQ_TASK_LOW; - break; - case TASK_PRI_HIGH ... TASK_PRI_MED - 1: - irq = PLATFORM_IRQ_TASK_HIGH; - break; - case TASK_PRI_MED: - default: - irq = PLATFORM_IRQ_TASK_MED; - break; - } - - return irq; -} - -/** - * \brief Adds task to the list per IRQ level. - * \param[in,out] task Task data. - */ -static inline int task_set_data(struct task *task) -{ - struct list_item *dst = NULL; - struct irq_task *irq_task; - uint32_t flags; - - switch (task->priority) { -#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM - case TASK_PRI_MED + 1 ... TASK_PRI_LOW: - irq_task = *task_irq_low_get(); - break; - case TASK_PRI_HIGH ... TASK_PRI_MED - 1: - irq_task = *task_irq_high_get(); - break; - case TASK_PRI_MED: - irq_task = *task_irq_med_get(); - break; -#else - case TASK_PRI_MED ... TASK_PRI_LOW: - irq_task = *task_irq_low_get(); - break; - case TASK_PRI_HIGH ... TASK_PRI_MED - 1: - irq_task = *task_irq_high_get(); - break; -#endif - default: - trace_error(TRACE_CLASS_IRQ, - "task_set_data() error: task priority %d", - task->priority); - return -EINVAL; - } - - dst = &irq_task->list; - spin_lock_irq(&irq_task->lock, flags); - list_item_append(&task->irq_list, dst); - spin_unlock_irq(&irq_task->lock, flags); - - return 0; -} - -/** - * \brief Interrupt handler for the IRQ task. - * \param[in,out] arg IRQ task data. - */ -static void _irq_task(void *arg) -{ - struct irq_task *irq_task = *(struct irq_task **)arg; - struct list_item *tlist; - struct list_item *clist; - struct task *task; - uint32_t flags; - int run_task = 0; - - 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); - list_item_del(clist); - - if (task->func && task->state == TASK_STATE_PENDING) { - schedule_task_running(task); - run_task = 1; - } else { - run_task = 0; - } - - /* run task without holding task lock */ - spin_unlock_irq(&irq_task->lock, flags); - - if (run_task) - task->func(task->data); - - spin_lock_irq(&irq_task->lock, flags); - schedule_task_complete(task); - } - - spin_unlock_irq(&irq_task->lock, flags); -} - /** * \brief Runs task. * \param[in,out] task Task data. */ -static inline int arch_run_task(struct task *task) -{ - uint32_t irq; - int ret; - - ret = task_set_data(task); - - if (ret < 0) - return ret; - - irq = task_get_irq(task); - interrupt_set(irq); - - return 0; -} +int arch_run_task(struct task *task); /** * \brief Allocates IRQ tasks. */ -static inline int arch_allocate_tasks(void) -{ - /* irq low */ - struct irq_task **low = task_irq_low_get(); - *low = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**low)); - - list_init(&((*low)->list)); - spinlock_init(&((*low)->lock)); - (*low)->irq = PLATFORM_IRQ_TASK_LOW; - -#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM - /* irq medium */ - struct irq_task **med = task_irq_med_get(); - *med = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**med)); - - list_init(&((*med)->list)); - spinlock_init(&((*med)->lock)); - (*med)->irq = PLATFORM_IRQ_TASK_MED; -#endif - - /* irq high */ - struct irq_task **high = task_irq_high_get(); - *high = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**high)); - - list_init(&((*high)->list)); - spinlock_init(&((*high)->lock)); - (*high)->irq = PLATFORM_IRQ_TASK_HIGH; - - return 0; -} +int arch_allocate_tasks(void); /** * \brief Frees IRQ tasks. */ -static inline void arch_free_tasks(void) -{ - uint32_t flags; -/* TODO: do not want to free the tasks, just the entire heap */ - /* free IRQ low task */ - struct irq_task **low = task_irq_low_get(); - - spin_lock_irq(&(*low)->lock, flags); - interrupt_disable(PLATFORM_IRQ_TASK_LOW); - interrupt_unregister(PLATFORM_IRQ_TASK_LOW); - list_item_del(&(*low)->list); - spin_unlock_irq(&(*low)->lock, flags); - -#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM - /* free IRQ medium task */ - struct irq_task **med = task_irq_med_get(); - - spin_lock_irq(&(*med)->lock, flags); - interrupt_disable(PLATFORM_IRQ_TASK_MED); - interrupt_unregister(PLATFORM_IRQ_TASK_MED); - list_item_del(&(*med)->list); - spin_unlock_irq(&(*med)->lock, flags); -#endif - - /* free IRQ high task */ - struct irq_task **high = task_irq_high_get(); - - spin_lock_irq(&(*high)->lock, flags); - interrupt_disable(PLATFORM_IRQ_TASK_HIGH); - interrupt_unregister(PLATFORM_IRQ_TASK_HIGH); - list_item_del(&(*high)->list); - spin_unlock_irq(&(*high)->lock, flags); -} +void arch_free_tasks(void); /** * \brief Assigns IRQ tasks to interrupts. */ -static inline int arch_assign_tasks(void) -{ - /* irq low */ - interrupt_register(PLATFORM_IRQ_TASK_LOW, IRQ_AUTO_UNMASK, _irq_task, - task_irq_low_get()); - interrupt_enable(PLATFORM_IRQ_TASK_LOW); - -#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM - /* irq medium */ - interrupt_register(PLATFORM_IRQ_TASK_MED, IRQ_AUTO_UNMASK, _irq_task, - task_irq_med_get()); - interrupt_enable(PLATFORM_IRQ_TASK_MED); -#endif - - /* irq high */ - interrupt_register(PLATFORM_IRQ_TASK_HIGH, IRQ_AUTO_UNMASK, _irq_task, - task_irq_high_get()); - interrupt_enable(PLATFORM_IRQ_TASK_HIGH); +int arch_assign_tasks(void); - return 0; -} #endif diff --git a/src/arch/xtensa/include/arch/wait.h b/src/arch/xtensa/include/arch/wait.h index 857b50e09560..8c80949f3dc7 100644 --- a/src/arch/xtensa/include/arch/wait.h +++ b/src/arch/xtensa/include/arch/wait.h @@ -28,10 +28,14 @@ * Author: Liam Girdwood */ +#ifndef __ARCH_WAIT_H_ +#define __ARCH_WAIT_H_ + #include #include #include +#include #if defined(PLATFORM_WAITI_DELAY) @@ -78,3 +82,4 @@ static inline void idelay(int n) } } +#endif diff --git a/src/arch/xtensa/smp/init.c b/src/arch/xtensa/smp/init.c index f8342a360941..d91132c14fa4 100644 --- a/src/arch/xtensa/smp/init.c +++ b/src/arch/xtensa/smp/init.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include diff --git a/src/arch/xtensa/task.c b/src/arch/xtensa/task.c new file mode 100644 index 000000000000..b0a630b1d047 --- /dev/null +++ b/src/arch/xtensa/task.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +/** + * \file arch/xtensa/task.c + * \brief Arch task implementation file + * \authors Liam Girdwood + */ + +#include +#include +#include +#include + +#include + +#include + +/** + * \brief Retrieves task IRQ level. + * \param[in,out] task Task data. + * \return IRQ level. + */ +static uint32_t task_get_irq(struct task *task) +{ + uint32_t irq; + + switch (task->priority) { + case TASK_PRI_MED + 1 ... TASK_PRI_LOW: + irq = PLATFORM_IRQ_TASK_LOW; + break; + case TASK_PRI_HIGH ... TASK_PRI_MED - 1: + irq = PLATFORM_IRQ_TASK_HIGH; + break; + case TASK_PRI_MED: + default: + irq = PLATFORM_IRQ_TASK_MED; + break; + } + + return irq; +} + +/** + * \brief Adds task to the list per IRQ level. + * \param[in,out] task Task data. + */ +static int task_set_data(struct task *task) +{ + struct list_item *dst = NULL; + struct irq_task *irq_task; + uint32_t flags; + + switch (task->priority) { +#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM + case TASK_PRI_MED + 1 ... TASK_PRI_LOW: + irq_task = *task_irq_low_get(); + break; + case TASK_PRI_HIGH ... TASK_PRI_MED - 1: + irq_task = *task_irq_high_get(); + break; + case TASK_PRI_MED: + irq_task = *task_irq_med_get(); + break; +#else + case TASK_PRI_MED ... TASK_PRI_LOW: + irq_task = *task_irq_low_get(); + break; + case TASK_PRI_HIGH ... TASK_PRI_MED - 1: + irq_task = *task_irq_high_get(); + break; +#endif + default: + trace_error(TRACE_CLASS_IRQ, + "task_set_data() error: task priority %d", + task->priority); + return -EINVAL; + } + + dst = &irq_task->list; + spin_lock_irq(&irq_task->lock, flags); + list_item_append(&task->irq_list, dst); + spin_unlock_irq(&irq_task->lock, flags); + + return 0; +} + +/** + * \brief Interrupt handler for the IRQ task. + * \param[in,out] arg IRQ task data. + */ +static void _irq_task(void *arg) +{ + struct irq_task *irq_task = *(struct irq_task **)arg; + struct list_item *tlist; + struct list_item *clist; + struct task *task; + uint32_t flags; + int run_task = 0; + + 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); + list_item_del(clist); + + if (task->func && task->state == TASK_STATE_PENDING) { + schedule_task_running(task); + run_task = 1; + } else { + run_task = 0; + } + + /* run task without holding task lock */ + spin_unlock_irq(&irq_task->lock, flags); + + if (run_task) + task->func(task->data); + + spin_lock_irq(&irq_task->lock, flags); + schedule_task_complete(task); + } + + spin_unlock_irq(&irq_task->lock, flags); +} + +int arch_run_task(struct task *task) +{ + uint32_t irq; + int ret; + + ret = task_set_data(task); + + if (ret < 0) + return ret; + + irq = task_get_irq(task); + interrupt_set(irq); + + return 0; +} + +int arch_allocate_tasks(void) +{ + /* irq low */ + struct irq_task **low = task_irq_low_get(); + *low = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**low)); + + list_init(&((*low)->list)); + spinlock_init(&((*low)->lock)); + (*low)->irq = PLATFORM_IRQ_TASK_LOW; + +#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM + /* irq medium */ + struct irq_task **med = task_irq_med_get(); + *med = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**med)); + + list_init(&((*med)->list)); + spinlock_init(&((*med)->lock)); + (*med)->irq = PLATFORM_IRQ_TASK_MED; +#endif + + /* irq high */ + struct irq_task **high = task_irq_high_get(); + *high = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**high)); + + list_init(&((*high)->list)); + spinlock_init(&((*high)->lock)); + (*high)->irq = PLATFORM_IRQ_TASK_HIGH; + + return 0; +} + +void arch_free_tasks(void) +{ + uint32_t flags; +/* TODO: do not want to free the tasks, just the entire heap */ + /* free IRQ low task */ + struct irq_task **low = task_irq_low_get(); + + spin_lock_irq(&(*low)->lock, flags); + interrupt_disable(PLATFORM_IRQ_TASK_LOW); + interrupt_unregister(PLATFORM_IRQ_TASK_LOW); + list_item_del(&(*low)->list); + spin_unlock_irq(&(*low)->lock, flags); + +#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM + /* free IRQ medium task */ + struct irq_task **med = task_irq_med_get(); + + spin_lock_irq(&(*med)->lock, flags); + interrupt_disable(PLATFORM_IRQ_TASK_MED); + interrupt_unregister(PLATFORM_IRQ_TASK_MED); + list_item_del(&(*med)->list); + spin_unlock_irq(&(*med)->lock, flags); +#endif + + /* free IRQ high task */ + struct irq_task **high = task_irq_high_get(); + + spin_lock_irq(&(*high)->lock, flags); + interrupt_disable(PLATFORM_IRQ_TASK_HIGH); + interrupt_unregister(PLATFORM_IRQ_TASK_HIGH); + list_item_del(&(*high)->list); + spin_unlock_irq(&(*high)->lock, flags); +} + +int arch_assign_tasks(void) +{ + /* irq low */ + interrupt_register(PLATFORM_IRQ_TASK_LOW, IRQ_AUTO_UNMASK, _irq_task, + task_irq_low_get()); + interrupt_enable(PLATFORM_IRQ_TASK_LOW); + +#ifdef CONFIG_TASK_HAVE_PRIORITY_MEDIUM + /* irq medium */ + interrupt_register(PLATFORM_IRQ_TASK_MED, IRQ_AUTO_UNMASK, _irq_task, + task_irq_med_get()); + interrupt_enable(PLATFORM_IRQ_TASK_MED); +#endif + + /* irq high */ + interrupt_register(PLATFORM_IRQ_TASK_HIGH, IRQ_AUTO_UNMASK, _irq_task, + task_irq_high_get()); + interrupt_enable(PLATFORM_IRQ_TASK_HIGH); + + return 0; +} diff --git a/src/arch/xtensa/up/init.c b/src/arch/xtensa/up/init.c index 1a013eaad07e..1aeac1c9b0a5 100644 --- a/src/arch/xtensa/up/init.c +++ b/src/arch/xtensa/up/init.c @@ -36,6 +36,7 @@ #include #include #include +#include #include /** diff --git a/src/audio/dai.c b/src/audio/dai.c index b88fddada7e3..0fa7ce6a3b6a 100644 --- a/src/audio/dai.c +++ b/src/audio/dai.c @@ -46,6 +46,8 @@ #include #include +#include + #define DAI_PTR_INIT_DAI 1 /* buffer ptr initialized by dai */ #define DAI_PTR_INIT_HOST 2 /* buffer ptr initialized by host */ diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index 35b5856250af..8d65b2e3a7c6 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include diff --git a/src/drivers/intel/cavs/hda-dma.c b/src/drivers/intel/cavs/hda-dma.c index b7c6a45e233f..2136d3a9fbff 100644 --- a/src/drivers/intel/cavs/hda-dma.c +++ b/src/drivers/intel/cavs/hda-dma.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -45,10 +46,12 @@ #include #include #include +#include #include #include #include #include +#include #include #define trace_hddma(__e, ...) \ diff --git a/src/include/sof/panic.h b/src/include/sof/panic.h index 00d9ec66779f..e56738e9d14e 100644 --- a/src/include/sof/panic.h +++ b/src/include/sof/panic.h @@ -31,71 +31,16 @@ #ifndef __INCLUDE_SOF_IPC_PANIC__ #define __INCLUDE_SOF_IPC_PANIC__ -#include -#include -#include -#include -#include -#include -#include #include -#include -static inline void dump_panicinfo(void *addr, - struct sof_ipc_panic_info *panic_info) -{ - if (!panic_info) - return; - rmemcpy(addr, panic_info, sizeof(struct sof_ipc_panic_info)); - dcache_writeback_region(addr, sizeof(struct sof_ipc_panic_info)); -} +struct sof_ipc_panic_info; -/* panic and rewind stack */ -static inline void panic_rewind(uint32_t p, uint32_t stack_rewind_frames, - struct sof_ipc_panic_info *panic_info) -{ - void *ext_offset; - size_t count; - uint32_t oldps; - - /* disable all IRQs */ - oldps = interrupt_global_disable(); - - /* dump DSP core registers */ - ext_offset = arch_dump_regs(oldps); - - /* dump panic info, filename ane linenum */ - dump_panicinfo(ext_offset, panic_info); - ext_offset += sizeof(struct sof_ipc_panic_info); - - count = MAILBOX_EXCEPTION_SIZE - - (size_t)(ext_offset - mailbox_get_exception_base()); - /* dump stack frames */ - p = dump_stack(p, ext_offset, stack_rewind_frames, count); - - /* panic - send IPC oops message to host */ - platform_panic(p); - - /* flush last trace messages */ - trace_flush(); - - /* and loop forever */ - while (1) {}; -} +void dump_panicinfo(void *addr, struct sof_ipc_panic_info *panic_info); +void panic_rewind(uint32_t p, uint32_t stack_rewind_frames, + struct sof_ipc_panic_info *panic_info); +void __panic(uint32_t p, char *filename, uint32_t linenum); /* panic dump filename and linenumber of the call */ #define panic(x) __panic((x), (__FILE__), (__LINE__)) -static void __panic(uint32_t p, char *filename, uint32_t linenum) -{ - struct sof_ipc_panic_info panicinfo; - int strlen; - - strlen = rstrlen(filename); - panicinfo.linenum = linenum; - rmemcpy(panicinfo.filename, filename, strlen + 1); - - panic_rewind(p, 0, &panicinfo); -} - #endif diff --git a/src/include/sof/wait.h b/src/include/sof/wait.h index 8a1d7eafe454..82e923356299 100644 --- a/src/include/sof/wait.h +++ b/src/include/sof/wait.h @@ -34,31 +34,10 @@ #define __INCLUDE_WAIT__ #include -#include + #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if DEBUG_LOCKS -#define wait_atomic_check \ - if (lock_dbg_atomic) { \ - trace_error_atomic(TRACE_CLASS_WAIT, "atm"); \ - } -#else -#define wait_atomic_check -#endif -#define DEFAULT_TRY_TIMES 8 +#include typedef struct { uint32_t complete; @@ -66,16 +45,6 @@ typedef struct { uint64_t timeout; } completion_t; -void arch_wait_for_interrupt(int level); - -static inline void wait_for_interrupt(int level) -{ - tracev_event(TRACE_CLASS_WAIT, "WFE"); - wait_atomic_check; - arch_wait_for_interrupt(level); - tracev_event(TRACE_CLASS_WAIT, "WFX"); -} - static uint64_t _wait_cb(void *data, uint64_t delay) { volatile completion_t *wc = (volatile completion_t*)data; @@ -113,6 +82,13 @@ static inline void wait_clear(completion_t *comp) c->complete = 0; } +void wait_for_interrupt(int level); +int wait_for_completion_timeout(completion_t *comp); +void wait_delay(uint64_t number_of_clks); +int poll_for_completion_delay(completion_t *comp, uint64_t us); +int poll_for_register_delay(uint32_t reg, uint32_t mask, + uint32_t val, uint64_t us); + /* simple interrupt based wait for completion */ static inline void wait_for_completion(completion_t *comp) { @@ -121,95 +97,4 @@ static inline void wait_for_completion(completion_t *comp) wait_for_interrupt(0); } - -/* simple interrupt based wait for completion with timeout */ -static inline int wait_for_completion_timeout(completion_t *comp) -{ - volatile completion_t *c = (volatile completion_t *)comp; - - work_schedule_default(&comp->work, comp->timeout); - comp->timeout = 0; - - /* check for completion after every wake from IRQ */ - while (1) { - - if (c->complete || c->timeout) - break; - - wait_for_interrupt(0); - } - - /* did we complete */ - if (c->complete) { - /* no timeout so cancel work and return 0 */ - work_cancel_default(&comp->work); - return 0; - } else { - /* timeout */ - trace_error_value(c->timeout); - trace_error_value(c->complete); - return -ETIME; - } -} - -/** - * \brief Waits at least passed number of clocks. - * \param[in] number_of_clks Minimum number of clocks to wait. - */ -static inline void wait_delay(uint64_t number_of_clks) -{ - uint64_t current = platform_timer_get(platform_timer); - - while ((platform_timer_get(platform_timer) - current) < number_of_clks) - idelay(PLATFORM_DEFAULT_DELAY); -} - -static inline int poll_for_completion_delay(completion_t *comp, uint64_t us) -{ - uint64_t tick = clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1) * - us / 1000; - 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_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1) * - us / 1000; - 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 diff --git a/src/ipc/handler.c b/src/ipc/handler.c index c5893ca828ae..d1a188e5f3d8 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 74d36c3424e7..14090a630c1f 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -12,4 +12,6 @@ add_local_sources(sof clk.c dma.c dai.c + panic.c + wait.c ) diff --git a/src/lib/panic.c b/src/lib/panic.c new file mode 100644 index 000000000000..52cd8c223264 --- /dev/null +++ b/src/lib/panic.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +void dump_panicinfo(void *addr, struct sof_ipc_panic_info *panic_info) +{ + if (!panic_info) + return; + rmemcpy(addr, panic_info, sizeof(struct sof_ipc_panic_info)); + dcache_writeback_region(addr, sizeof(struct sof_ipc_panic_info)); +} + +/* panic and rewind stack */ +void panic_rewind(uint32_t p, uint32_t stack_rewind_frames, + struct sof_ipc_panic_info *panic_info) +{ + void *ext_offset; + size_t count; + uint32_t oldps; + + /* disable all IRQs */ + oldps = interrupt_global_disable(); + + /* dump DSP core registers */ + ext_offset = arch_dump_regs(oldps); + + /* dump panic info, filename ane linenum */ + dump_panicinfo(ext_offset, panic_info); + ext_offset += sizeof(struct sof_ipc_panic_info); + + count = MAILBOX_EXCEPTION_SIZE - + (size_t)(ext_offset - mailbox_get_exception_base()); + /* dump stack frames */ + p = dump_stack(p, ext_offset, stack_rewind_frames, count); + + /* panic - send IPC oops message to host */ + platform_panic(p); + + /* flush last trace messages */ + trace_flush(); + + /* and loop forever */ + while (1) + ; +} + +void __panic(uint32_t p, char *filename, uint32_t linenum) +{ + struct sof_ipc_panic_info panicinfo; + int strlen; + + strlen = rstrlen(filename); + panicinfo.linenum = linenum; + rmemcpy(panicinfo.filename, filename, strlen + 1); + + panic_rewind(p, 0, &panicinfo); +} diff --git a/src/lib/schedule.c b/src/lib/schedule.c index b3f612b8d453..58ebaad3e59c 100644 --- a/src/lib/schedule.c +++ b/src/lib/schedule.c @@ -43,6 +43,7 @@ #include #include #include +#include #include struct schedule_data { diff --git a/src/lib/trace.c b/src/lib/trace.c index 6eca956700e6..c49cddb5e655 100644 --- a/src/lib/trace.c +++ b/src/lib/trace.c @@ -38,6 +38,7 @@ #include #include #include +#include #include struct trace { diff --git a/src/lib/wait.c b/src/lib/wait.c new file mode 100644 index 000000000000..37dd2a031330 --- /dev/null +++ b/src/lib/wait.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + * + * Simple wait for event completion and signaling with timeouts. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_TRY_TIMES 8 + +void wait_for_interrupt(int level) +{ + tracev_event(TRACE_CLASS_WAIT, "WFE"); +#if DEBUG_LOCKS + if (lock_dbg_atomic) + trace_error_atomic(TRACE_CLASS_WAIT, "atm"); +#endif + arch_wait_for_interrupt(level); + tracev_event(TRACE_CLASS_WAIT, "WFX"); +} + +/* simple interrupt based wait for completion with timeout */ +int wait_for_completion_timeout(completion_t *comp) +{ + volatile completion_t *c = (volatile completion_t *)comp; + + work_schedule_default(&comp->work, comp->timeout); + comp->timeout = 0; + + /* check for completion after every wake from IRQ */ + while (1) { + + if (c->complete || c->timeout) + break; + + wait_for_interrupt(0); + } + + /* did we complete */ + if (c->complete) { + /* no timeout so cancel work and return 0 */ + work_cancel_default(&comp->work); + return 0; + } else { + /* timeout */ + trace_error_value(c->timeout); + trace_error_value(c->complete); + return -ETIME; + } +} + +/** + * \brief Waits at least passed number of clocks. + * \param[in] number_of_clks Minimum number of clocks to wait. + */ +void wait_delay(uint64_t number_of_clks) +{ + uint64_t current = platform_timer_get(platform_timer); + + while ((platform_timer_get(platform_timer) - current) < number_of_clks) + idelay(PLATFORM_DEFAULT_DELAY); +} + +int poll_for_completion_delay(completion_t *comp, uint64_t us) +{ + uint64_t tick = clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1) * + us / 1000; + 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; +} + +int poll_for_register_delay(uint32_t reg, uint32_t mask, + uint32_t val, uint64_t us) +{ + uint64_t tick = clock_ms_to_ticks(PLATFORM_DEFAULT_CLOCK, 1) * + us / 1000; + 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; +} diff --git a/src/platform/apollolake/include/platform/clk.h b/src/platform/apollolake/include/platform/clk.h index 6c5dd831f27e..3ee8b791a9c4 100644 --- a/src/platform/apollolake/include/platform/clk.h +++ b/src/platform/apollolake/include/platform/clk.h @@ -34,6 +34,7 @@ #include #include +#include #define CLK_CPU(x) (x) #define CLK_SSP 2 diff --git a/src/platform/apollolake/include/platform/platform.h b/src/platform/apollolake/include/platform/platform.h index 85433f380721..51d69a9f8bc6 100644 --- a/src/platform/apollolake/include/platform/platform.h +++ b/src/platform/apollolake/include/platform/platform.h @@ -34,6 +34,7 @@ #define __PLATFORM_PLATFORM_H__ #include +#include #include #include #include diff --git a/src/platform/baytrail/include/platform/clk.h b/src/platform/baytrail/include/platform/clk.h index 1fe895e56b91..5288f17ab2b2 100644 --- a/src/platform/baytrail/include/platform/clk.h +++ b/src/platform/baytrail/include/platform/clk.h @@ -33,6 +33,7 @@ #include #include +#include #define CLK_CPU(x) (x) #define CLK_SSP 1 diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 5a836aeb4945..aa373bc0b4b7 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -34,6 +34,7 @@ #define __PLATFORM_PLATFORM_H__ #include +#include #include #include diff --git a/src/platform/cannonlake/include/platform/clk.h b/src/platform/cannonlake/include/platform/clk.h index c074652b19f8..5a66e288a4d2 100644 --- a/src/platform/cannonlake/include/platform/clk.h +++ b/src/platform/cannonlake/include/platform/clk.h @@ -35,6 +35,7 @@ #include #include +#include #define CLK_CPU(x) (x) #define CLK_SSP 4 diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index fd209d7a2c6a..56864d61c8b0 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -35,6 +35,7 @@ #define __PLATFORM_PLATFORM_H__ #include +#include #include #include #include diff --git a/src/platform/haswell/include/platform/clk.h b/src/platform/haswell/include/platform/clk.h index db0a6ac2d62e..36ff9e457f69 100644 --- a/src/platform/haswell/include/platform/clk.h +++ b/src/platform/haswell/include/platform/clk.h @@ -32,6 +32,7 @@ #define __PLATFORM_CLOCK__ #include +#include #define CLK_CPU(x) (x) #define CLK_SSP 1 diff --git a/src/platform/haswell/include/platform/platform.h b/src/platform/haswell/include/platform/platform.h index 8f61e3e9ea99..b2048b6a1d09 100644 --- a/src/platform/haswell/include/platform/platform.h +++ b/src/platform/haswell/include/platform/platform.h @@ -33,6 +33,7 @@ #define __PLATFORM_PLATFORM_H__ #include +#include #include #include diff --git a/src/platform/icelake/include/platform/clk.h b/src/platform/icelake/include/platform/clk.h index c074652b19f8..5a66e288a4d2 100644 --- a/src/platform/icelake/include/platform/clk.h +++ b/src/platform/icelake/include/platform/clk.h @@ -35,6 +35,7 @@ #include #include +#include #define CLK_CPU(x) (x) #define CLK_SSP 4 diff --git a/src/platform/icelake/include/platform/platform.h b/src/platform/icelake/include/platform/platform.h index 9bc6dab5db21..6c6277db1cc0 100644 --- a/src/platform/icelake/include/platform/platform.h +++ b/src/platform/icelake/include/platform/platform.h @@ -35,6 +35,7 @@ #define __PLATFORM_PLATFORM_H__ #include +#include #include #include #include diff --git a/src/platform/intel/cavs/platform.c b/src/platform/intel/cavs/platform.c index 5621594e6b28..6e8345e15ea0 100644 --- a/src/platform/intel/cavs/platform.c +++ b/src/platform/intel/cavs/platform.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include diff --git a/src/platform/suecreek/include/platform/clk.h b/src/platform/suecreek/include/platform/clk.h index c074652b19f8..5a66e288a4d2 100644 --- a/src/platform/suecreek/include/platform/clk.h +++ b/src/platform/suecreek/include/platform/clk.h @@ -35,6 +35,7 @@ #include #include +#include #define CLK_CPU(x) (x) #define CLK_SSP 4