From e338a57a64314b5fea99c1fbc9a55c673cc0fe02 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 13 Feb 2019 15:10:51 +0100 Subject: [PATCH 1/6] idc: move code from a header to a .c file src/arch/xtensa/smp/include/arch/idc.h has way too much code for a header, it is included by platform/idc.h on various platforms, and that header in turn is included by bultiple .c files, which builds the code multiple times into the firmware. Move it to a C file. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/CMakeLists.txt | 1 + src/arch/xtensa/smp/cpu.c | 1 + src/arch/xtensa/smp/idc.c | 353 ++++++++++++++++++++++++ src/arch/xtensa/smp/include/arch/idc.h | 355 +------------------------ 4 files changed, 361 insertions(+), 349 deletions(-) create mode 100644 src/arch/xtensa/smp/idc.c diff --git a/src/arch/xtensa/CMakeLists.txt b/src/arch/xtensa/CMakeLists.txt index 7704d3fdd10f..75ca9f2998ce 100644 --- a/src/arch/xtensa/CMakeLists.txt +++ b/src/arch/xtensa/CMakeLists.txt @@ -152,6 +152,7 @@ if(CONFIG_SMP) smp/xtos/crt1-boards.S smp/xtos/_vectors.S smp/cpu.c + smp/idc.c smp/init.c smp/notifier.c smp/schedule.c diff --git a/src/arch/xtensa/smp/cpu.c b/src/arch/xtensa/smp/cpu.c index bf525c6de536..c5890b75c607 100644 --- a/src/arch/xtensa/smp/cpu.c +++ b/src/arch/xtensa/smp/cpu.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/src/arch/xtensa/smp/idc.c b/src/arch/xtensa/smp/idc.c new file mode 100644 index 000000000000..18815367fcfa --- /dev/null +++ b/src/arch/xtensa/smp/idc.c @@ -0,0 +1,353 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern struct ipc *_ipc; + +/** + * \brief Returns IDC data. + * \return Pointer to pointer of IDC data. + */ +static struct idc **idc_get(void) +{ + struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); + + return &ctx->idc; +} + +/** + * \brief Enables IDC interrupts. + * \param[in] target_core Target core id. + * \param[in] source_core Source core id. + */ +void idc_enable_interrupts(int target_core, int source_core) +{ + idc_write(IPC_IDCCTL, target_core, + IPC_IDCCTL_IDCTBIE(source_core)); + platform_interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core), 0); +} + +/** + * \brief IDC interrupt handler. + * \param[in,out] arg Pointer to IDC data. + */ +static void idc_irq_handler(void *arg) +{ + struct idc *idc = arg; + int core = arch_cpu_get_id(); + uint32_t idctfc; + uint32_t idctefc; + uint32_t idcietc; + uint32_t i; + + tracev_idc("idc_irq_handler()"); + + for (i = 0; i < PLATFORM_CORE_COUNT; i++) { + idctfc = idc_read(IPC_IDCTFC(i), core); + + if (idctfc & IPC_IDCTFC_BUSY) { + trace_idc("idc_irq_handler(), IPC_IDCTFC_BUSY"); + + /* disable BUSY interrupt */ + idc_write(IPC_IDCCTL, core, idc->done_bit_mask); + + idc->received_msg.core = i; + idc->received_msg.header = + idctfc & IPC_IDCTFC_MSG_MASK; + + idctefc = idc_read(IPC_IDCTEFC(i), core); + idc->received_msg.extension = + idctefc & IPC_IDCTEFC_MSG_MASK; + + schedule_task(&idc->idc_task, 0, IDC_DEADLINE); + + break; + } + } + + for (i = 0; i < PLATFORM_CORE_COUNT; i++) { + idcietc = idc_read(IPC_IDCIETC(i), core); + + if (idcietc & IPC_IDCIETC_DONE) { + tracev_idc("idc_irq_handler(), IPC_IDCIETC_DONE"); + + idc_write(IPC_IDCIETC(i), core, + idcietc | IPC_IDCIETC_DONE); + + break; + } + } +} + +/** + * \brief Sends IDC message. + * \param[in,out] msg Pointer to IDC message. + * \param[in] mode Is message blocking or not. + * \return Error code. + */ +int arch_idc_send_msg(struct idc_msg *msg, uint32_t mode) +{ + struct idc *idc = *idc_get(); + int core = arch_cpu_get_id(); + int ret = 0; + uint32_t timeout = 0; + uint32_t idcietc; + uint32_t flags; + + tracev_idc("arch_idc_send_msg()"); + + spin_lock_irq(&idc->lock, flags); + + idc_write(IPC_IDCIETC(msg->core), core, msg->extension); + idc_write(IPC_IDCITC(msg->core), core, msg->header | IPC_IDCITC_BUSY); + + if (mode == IDC_BLOCKING) { + do { + idelay(PLATFORM_DEFAULT_DELAY); + timeout += PLATFORM_DEFAULT_DELAY; + idcietc = idc_read(IPC_IDCIETC(msg->core), core); + } while (!(idcietc & IPC_IDCIETC_DONE) && + timeout < IDC_TIMEOUT); + + if (timeout >= IDC_TIMEOUT) { + trace_idc_error("arch_idc_send_msg() error: timeout"); + ret = -ETIME; + } + } + + spin_unlock_irq(&idc->lock, flags); + + return ret; +} + +/** + * \brief Executes IDC pipeline trigger message. + * \param[in] cmd Trigger command. + * \return Error code. + */ +static int idc_pipeline_trigger(uint32_t cmd) +{ + struct sof_ipc_stream *data = _ipc->comp_data; + struct ipc_comp_dev *pcm_dev; + int ret; + + /* invalidate stream data */ + dcache_invalidate_region(data, sizeof(*data)); + + /* check whether component exists */ + pcm_dev = ipc_get_comp(_ipc, data->comp_id); + if (!pcm_dev) + return -ENODEV; + + /* check whether we are executing from the right core */ + if (arch_cpu_get_id() != pcm_dev->cd->pipeline->ipc_pipe.core) + return -EINVAL; + + /* invalidate pipeline on start */ + if (cmd == COMP_TRIGGER_START) + pipeline_cache(pcm_dev->cd->pipeline, + pcm_dev->cd, CACHE_INVALIDATE); + + /* trigger pipeline */ + ret = pipeline_trigger(pcm_dev->cd->pipeline, pcm_dev->cd, cmd); + + /* writeback pipeline on stop */ + if (cmd == COMP_TRIGGER_STOP) + pipeline_cache(pcm_dev->cd->pipeline, + pcm_dev->cd, CACHE_WRITEBACK_INV); + + return ret; +} + +/** + * \brief Executes IDC component command message. + * \param[in] cmd Component command. + * \return Error code. + */ +static int idc_component_command(uint32_t cmd) +{ + struct sof_ipc_ctrl_data *data = _ipc->comp_data; + struct ipc_comp_dev *comp_dev; + int ret; + + /* invalidate control data */ + dcache_invalidate_region(data, sizeof(*data)); + dcache_invalidate_region(data + 1, + data->rhdr.hdr.size - sizeof(*data)); + + /* check whether component exists */ + comp_dev = ipc_get_comp(_ipc, data->comp_id); + if (!comp_dev) + return -ENODEV; + + /* check whether we are executing from the right core */ + if (arch_cpu_get_id() != comp_dev->cd->pipeline->ipc_pipe.core) + return -EINVAL; + + /* execute component command */ + ret = comp_cmd(comp_dev->cd, cmd, data, data->rhdr.hdr.size); + + /* writeback control data */ + dcache_writeback_region(data, data->rhdr.hdr.size); + + return ret; +} + +/** + * \brief Executes IDC message based on type. + * \param[in,out] msg Pointer to IDC message. + */ +static void idc_cmd(struct idc_msg *msg) +{ + uint32_t type = iTS(msg->header); + + switch (type) { + case iTS(IDC_MSG_POWER_DOWN): + cpu_power_down_core(); + break; + case iTS(IDC_MSG_PPL_TRIGGER): + idc_pipeline_trigger(msg->extension); + break; + case iTS(IDC_MSG_COMP_CMD): + idc_component_command(msg->extension); + break; + case iTS(IDC_MSG_NOTIFY): + notifier_notify(); + break; + default: + trace_idc_error("idc_cmd() error: invalid msg->header = %u", + msg->header); + } +} + +/** + * \brief Handles received IDC message. + * \param[in,out] data Pointer to IDC data. + */ +static void idc_do_cmd(void *data) +{ + struct idc *idc = data; + int core = arch_cpu_get_id(); + int initiator = idc->received_msg.core; + + trace_idc("idc_do_cmd()"); + + idc_cmd(&idc->received_msg); + + /* clear BUSY bit */ + idc_write(IPC_IDCTFC(initiator), core, + idc_read(IPC_IDCTFC(initiator), core) | IPC_IDCTFC_BUSY); + + /* enable BUSY interrupt */ + idc_write(IPC_IDCCTL, core, idc->busy_bit_mask | idc->done_bit_mask); +} + +/** + * \brief Returns BUSY interrupt mask based on core id. + * \param[in] core Core id. + * \return BUSY interrupt mask. + */ +static uint32_t idc_get_busy_bit_mask(int core) +{ + uint32_t busy_mask = 0; + int i; + + if (core == PLATFORM_MASTER_CORE_ID) { + for (i = 0; i < PLATFORM_CORE_COUNT; i++) { + if (i != PLATFORM_MASTER_CORE_ID) + busy_mask |= IPC_IDCCTL_IDCTBIE(i); + } + } else { + busy_mask = IPC_IDCCTL_IDCTBIE(PLATFORM_MASTER_CORE_ID); + } + + return busy_mask; +} + +/** + * \brief Returns DONE interrupt mask based on core id. + * \param[in] core Core id. + * \return DONE interrupt mask. + */ +static uint32_t idc_get_done_bit_mask(int core) +{ + uint32_t done_mask = 0; + int i; + + if (core == PLATFORM_MASTER_CORE_ID) { + for (i = 0; i < PLATFORM_CORE_COUNT; i++) { + if (i != PLATFORM_MASTER_CORE_ID) + done_mask |= IPC_IDCCTL_IDCIDIE(i); + } + } else { + done_mask = 0; + } + + return done_mask; +} + +/** + * \brief Initializes IDC data and registers for interrupt. + */ +void arch_idc_init(void) +{ + int core = arch_cpu_get_id(); + + trace_idc("arch_idc_init()"); + + /* initialize idc data */ + struct idc **idc = idc_get(); + *idc = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**idc)); + spinlock_init(&((*idc)->lock)); + (*idc)->busy_bit_mask = idc_get_busy_bit_mask(core); + (*idc)->done_bit_mask = idc_get_done_bit_mask(core); + + /* process task */ + schedule_task_init(&(*idc)->idc_task, idc_do_cmd, *idc); + schedule_task_config(&(*idc)->idc_task, TASK_PRI_IDC, core); + + /* configure interrupt */ + interrupt_register(PLATFORM_IDC_INTERRUPT(core), IRQ_AUTO_UNMASK, + idc_irq_handler, *idc); + interrupt_enable(PLATFORM_IDC_INTERRUPT(core)); + + /* enable BUSY and DONE (only for master core) interrupts */ + idc_write(IPC_IDCCTL, core, + (*idc)->busy_bit_mask | (*idc)->done_bit_mask); +} + +/** + * \brief Frees IDC data and unregisters interrupt. + */ +void idc_free(void) +{ + struct idc *idc = *idc_get(); + int core = arch_cpu_get_id(); + int i = 0; + uint32_t idctfc; + + trace_idc("idc_free()"); + + /* disable and unregister interrupt */ + interrupt_disable(PLATFORM_IDC_INTERRUPT(core)); + interrupt_unregister(PLATFORM_IDC_INTERRUPT(core)); + + /* clear BUSY bits */ + for (i = 0; i < PLATFORM_CORE_COUNT; i++) { + idctfc = idc_read(IPC_IDCTFC(i), core); + if (idctfc & IPC_IDCTFC_BUSY) + idc_write(IPC_IDCTFC(i), core, idctfc); + } + + schedule_task_free(&idc->idc_task); +} diff --git a/src/arch/xtensa/smp/include/arch/idc.h b/src/arch/xtensa/smp/include/arch/idc.h index c8c4265793bb..5b7c07ad4feb 100644 --- a/src/arch/xtensa/smp/include/arch/idc.h +++ b/src/arch/xtensa/smp/include/arch/idc.h @@ -37,356 +37,13 @@ #ifndef __ARCH_IDC_H__ #define __ARCH_IDC_H__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +struct idc_msg; -extern struct ipc *_ipc; -extern void cpu_power_down_core(void); +void cpu_power_down_core(void); -/** - * \brief Returns IDC data. - * \return Pointer to pointer of IDC data. - */ -static inline struct idc **idc_get(void) -{ - struct core_context *ctx = (struct core_context *)cpu_read_threadptr(); - - return &ctx->idc; -} - -/** - * \brief Enables IDC interrupts. - * \param[in] target_core Target core id. - * \param[in] source_core Source core id. - */ -static inline void idc_enable_interrupts(int target_core, int source_core) -{ - idc_write(IPC_IDCCTL, target_core, - IPC_IDCCTL_IDCTBIE(source_core)); - platform_interrupt_unmask(PLATFORM_IDC_INTERRUPT(target_core), 0); -} - -/** - * \brief IDC interrupt handler. - * \param[in,out] arg Pointer to IDC data. - */ -static void idc_irq_handler(void *arg) -{ - struct idc *idc = arg; - int core = arch_cpu_get_id(); - uint32_t idctfc; - uint32_t idctefc; - uint32_t idcietc; - uint32_t i; - - tracev_idc("idc_irq_handler()"); - - for (i = 0; i < PLATFORM_CORE_COUNT; i++) { - idctfc = idc_read(IPC_IDCTFC(i), core); - - if (idctfc & IPC_IDCTFC_BUSY) { - trace_idc("idc_irq_handler(), IPC_IDCTFC_BUSY"); - - /* disable BUSY interrupt */ - idc_write(IPC_IDCCTL, core, idc->done_bit_mask); - - idc->received_msg.core = i; - idc->received_msg.header = - idctfc & IPC_IDCTFC_MSG_MASK; - - idctefc = idc_read(IPC_IDCTEFC(i), core); - idc->received_msg.extension = - idctefc & IPC_IDCTEFC_MSG_MASK; - - schedule_task(&idc->idc_task, 0, IDC_DEADLINE); - - break; - } - } - - for (i = 0; i < PLATFORM_CORE_COUNT; i++) { - idcietc = idc_read(IPC_IDCIETC(i), core); - - if (idcietc & IPC_IDCIETC_DONE) { - tracev_idc("idc_irq_handler(), IPC_IDCIETC_DONE"); - - idc_write(IPC_IDCIETC(i), core, - idcietc | IPC_IDCIETC_DONE); - - break; - } - } -} - -/** - * \brief Sends IDC message. - * \param[in,out] msg Pointer to IDC message. - * \param[in] mode Is message blocking or not. - * \return Error code. - */ -static inline int arch_idc_send_msg(struct idc_msg *msg, uint32_t mode) -{ - struct idc *idc = *idc_get(); - int core = arch_cpu_get_id(); - int ret = 0; - uint32_t timeout = 0; - uint32_t idcietc; - uint32_t flags; - - tracev_idc("arch_idc_send_msg()"); - - spin_lock_irq(&idc->lock, flags); - - idc_write(IPC_IDCIETC(msg->core), core, msg->extension); - idc_write(IPC_IDCITC(msg->core), core, msg->header | IPC_IDCITC_BUSY); - - if (mode == IDC_BLOCKING) { - do { - idelay(PLATFORM_DEFAULT_DELAY); - timeout += PLATFORM_DEFAULT_DELAY; - idcietc = idc_read(IPC_IDCIETC(msg->core), core); - } while (!(idcietc & IPC_IDCIETC_DONE) && - timeout < IDC_TIMEOUT); - - if (timeout >= IDC_TIMEOUT) { - trace_idc_error("arch_idc_send_msg() error: timeout"); - ret = -ETIME; - } - } - - spin_unlock_irq(&idc->lock, flags); - - return ret; -} - -/** - * \brief Executes IDC pipeline trigger message. - * \param[in] cmd Trigger command. - * \return Error code. - */ -static inline int idc_pipeline_trigger(uint32_t cmd) -{ - struct sof_ipc_stream *data = _ipc->comp_data; - struct ipc_comp_dev *pcm_dev; - int ret; - - /* invalidate stream data */ - dcache_invalidate_region(data, sizeof(*data)); - - /* check whether component exists */ - pcm_dev = ipc_get_comp(_ipc, data->comp_id); - if (!pcm_dev) - return -ENODEV; - - /* check whether we are executing from the right core */ - if (arch_cpu_get_id() != pcm_dev->cd->pipeline->ipc_pipe.core) - return -EINVAL; - - /* invalidate pipeline on start */ - if (cmd == COMP_TRIGGER_START) - pipeline_cache(pcm_dev->cd->pipeline, - pcm_dev->cd, CACHE_INVALIDATE); - - /* trigger pipeline */ - ret = pipeline_trigger(pcm_dev->cd->pipeline, pcm_dev->cd, cmd); - - /* writeback pipeline on stop */ - if (cmd == COMP_TRIGGER_STOP) - pipeline_cache(pcm_dev->cd->pipeline, - pcm_dev->cd, CACHE_WRITEBACK_INV); - - return ret; -} - -/** - * \brief Executes IDC component command message. - * \param[in] cmd Component command. - * \return Error code. - */ -static inline int idc_component_command(uint32_t cmd) -{ - struct sof_ipc_ctrl_data *data = _ipc->comp_data; - struct ipc_comp_dev *comp_dev; - int ret; - - /* invalidate control data */ - dcache_invalidate_region(data, sizeof(*data)); - dcache_invalidate_region(data + 1, - data->rhdr.hdr.size - sizeof(*data)); - - /* check whether component exists */ - comp_dev = ipc_get_comp(_ipc, data->comp_id); - if (!comp_dev) - return -ENODEV; - - /* check whether we are executing from the right core */ - if (arch_cpu_get_id() != comp_dev->cd->pipeline->ipc_pipe.core) - return -EINVAL; - - /* execute component command */ - ret = comp_cmd(comp_dev->cd, cmd, data, data->rhdr.hdr.size); - - /* writeback control data */ - dcache_writeback_region(data, data->rhdr.hdr.size); - - return ret; -} - -/** - * \brief Executes IDC message based on type. - * \param[in,out] msg Pointer to IDC message. - */ -static inline void idc_cmd(struct idc_msg *msg) -{ - uint32_t type = iTS(msg->header); - - switch (type) { - case iTS(IDC_MSG_POWER_DOWN): - cpu_power_down_core(); - break; - case iTS(IDC_MSG_PPL_TRIGGER): - idc_pipeline_trigger(msg->extension); - break; - case iTS(IDC_MSG_COMP_CMD): - idc_component_command(msg->extension); - break; - case iTS(IDC_MSG_NOTIFY): - notifier_notify(); - break; - default: - trace_idc_error("idc_cmd() error: invalid msg->header = %u", - msg->header); - } -} - -/** - * \brief Handles received IDC message. - * \param[in,out] data Pointer to IDC data. - */ -static inline void idc_do_cmd(void *data) -{ - struct idc *idc = data; - int core = arch_cpu_get_id(); - int initiator = idc->received_msg.core; - - trace_idc("idc_do_cmd()"); - - idc_cmd(&idc->received_msg); - - /* clear BUSY bit */ - idc_write(IPC_IDCTFC(initiator), core, - idc_read(IPC_IDCTFC(initiator), core) | IPC_IDCTFC_BUSY); - - /* enable BUSY interrupt */ - idc_write(IPC_IDCCTL, core, idc->busy_bit_mask | idc->done_bit_mask); -} - -/** - * \brief Returns BUSY interrupt mask based on core id. - * \param[in] core Core id. - * \return BUSY interrupt mask. - */ -static inline uint32_t idc_get_busy_bit_mask(int core) -{ - uint32_t busy_mask = 0; - int i; - - if (core == PLATFORM_MASTER_CORE_ID) { - for (i = 0; i < PLATFORM_CORE_COUNT; i++) { - if (i != PLATFORM_MASTER_CORE_ID) - busy_mask |= IPC_IDCCTL_IDCTBIE(i); - } - } else { - busy_mask = IPC_IDCCTL_IDCTBIE(PLATFORM_MASTER_CORE_ID); - } - - return busy_mask; -} - -/** - * \brief Returns DONE interrupt mask based on core id. - * \param[in] core Core id. - * \return DONE interrupt mask. - */ -static inline uint32_t idc_get_done_bit_mask(int core) -{ - uint32_t done_mask = 0; - int i; - - if (core == PLATFORM_MASTER_CORE_ID) { - for (i = 0; i < PLATFORM_CORE_COUNT; i++) { - if (i != PLATFORM_MASTER_CORE_ID) - done_mask |= IPC_IDCCTL_IDCIDIE(i); - } - } else { - done_mask = 0; - } - - return done_mask; -} - -/** - * \brief Initializes IDC data and registers for interrupt. - */ -static inline void arch_idc_init(void) -{ - int core = arch_cpu_get_id(); - - trace_idc("arch_idc_init()"); - - /* initialize idc data */ - struct idc **idc = idc_get(); - *idc = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(**idc)); - spinlock_init(&((*idc)->lock)); - (*idc)->busy_bit_mask = idc_get_busy_bit_mask(core); - (*idc)->done_bit_mask = idc_get_done_bit_mask(core); - - /* process task */ - schedule_task_init(&(*idc)->idc_task, idc_do_cmd, *idc); - schedule_task_config(&(*idc)->idc_task, TASK_PRI_IDC, core); - - /* configure interrupt */ - interrupt_register(PLATFORM_IDC_INTERRUPT(core), IRQ_AUTO_UNMASK, - idc_irq_handler, *idc); - interrupt_enable(PLATFORM_IDC_INTERRUPT(core)); - - /* enable BUSY and DONE (only for master core) interrupts */ - idc_write(IPC_IDCCTL, core, - (*idc)->busy_bit_mask | (*idc)->done_bit_mask); -} - -/** - * \brief Frees IDC data and unregisters interrupt. - */ -static inline void idc_free(void) -{ - struct idc *idc = *idc_get(); - int core = arch_cpu_get_id(); - int i = 0; - uint32_t idctfc; - - trace_idc("idc_free()"); - - /* disable and unregister interrupt */ - interrupt_disable(PLATFORM_IDC_INTERRUPT(core)); - interrupt_unregister(PLATFORM_IDC_INTERRUPT(core)); - - /* clear BUSY bits */ - for (i = 0; i < PLATFORM_CORE_COUNT; i++) { - idctfc = idc_read(IPC_IDCTFC(i), core); - if (idctfc & IPC_IDCTFC_BUSY) - idc_write(IPC_IDCTFC(i), core, idctfc); - } - - schedule_task_free(&idc->idc_task); -} +void idc_enable_interrupts(int target_core, int source_core); +int arch_idc_send_msg(struct idc_msg *msg, uint32_t mode); +void arch_idc_init(void); +void idc_free(void); #endif From 3e06542693e3c6d3cc3d03bb44f549ce88b319b4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 14 Feb 2019 13:08:29 +0100 Subject: [PATCH 2/6] panic: move most functions from the header to a .c file Many functions in src/include/sof/panic.h are too large to be inlined and repeated every time the header is included. Move them out to src/lib/panic.c Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/include/arch/wait.h | 5 ++ src/include/sof/panic.h | 65 ++----------------- src/lib/CMakeLists.txt | 1 + src/lib/panic.c | 97 +++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 60 deletions(-) create mode 100644 src/lib/panic.c 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/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/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 74d36c3424e7..bc458c735b4d 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -12,4 +12,5 @@ add_local_sources(sof clk.c dma.c dai.c + panic.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); +} From d235631c3fcc2e2b20cde558459ff2501c1a7435 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 14 Feb 2019 14:07:54 +0100 Subject: [PATCH 3/6] task: move most functions from a header to a new .c file Move large functions from src/arch/xtensa/include/arch/task.h to src/arch/xtensa/smp/init.c to avoid building them multiple times. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/CMakeLists.txt | 2 +- src/arch/xtensa/include/arch/task.h | 235 +----------------------- src/arch/xtensa/smp/init.c | 1 + src/arch/xtensa/task.c | 269 ++++++++++++++++++++++++++++ 4 files changed, 280 insertions(+), 227 deletions(-) create mode 100644 src/arch/xtensa/task.c diff --git a/src/arch/xtensa/CMakeLists.txt b/src/arch/xtensa/CMakeLists.txt index 75ca9f2998ce..3965259ba55c 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 1bd042472dbf..d663de3ea147 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,242 +69,25 @@ 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; -#elif CONFIG_TASK_HAVE_PRIORITY_LOW - 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; -#else - case TASK_PRI_HIGH ... TASK_PRI_LOW: - 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) -{ -#ifdef CONFIG_TASK_HAVE_PRIORITY_LOW - /* 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; -#endif - -#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 */ - -#ifdef CONFIG_TASK_HAVE_PRIORITY_LOW - /* 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); -#endif - -#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) -{ -#ifdef CONFIG_TASK_HAVE_PRIORITY_LOW - /* irq low */ - interrupt_register(PLATFORM_IRQ_TASK_LOW, IRQ_AUTO_UNMASK, _irq_task, - task_irq_low_get()); - interrupt_enable(PLATFORM_IRQ_TASK_LOW); -#endif - -#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; -} +int arch_assign_tasks(void); #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..1aba6bed773f --- /dev/null +++ b/src/arch/xtensa/task.c @@ -0,0 +1,269 @@ +/* + * 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; +#elif CONFIG_TASK_HAVE_PRIORITY_LOW + 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; +#else + case TASK_PRI_HIGH ... TASK_PRI_LOW: + 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) +{ +#ifdef CONFIG_TASK_HAVE_PRIORITY_LOW + /* 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; +#endif + +#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 */ + +#ifdef CONFIG_TASK_HAVE_PRIORITY_LOW + /* 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); +#endif + +#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) +{ +#ifdef CONFIG_TASK_HAVE_PRIORITY_LOW + /* irq low */ + interrupt_register(PLATFORM_IRQ_TASK_LOW, IRQ_AUTO_UNMASK, _irq_task, + task_irq_low_get()); + interrupt_enable(PLATFORM_IRQ_TASK_LOW); +#endif + +#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; +} From 9c96785a85fbfd4fb5a4dc372c7285e6eded232c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 14 Feb 2019 14:34:26 +0100 Subject: [PATCH 4/6] wait: move most functions from the header to a new .c file Move large functions from src/include/sof/wait.h to src/lib/wait.c to avoid building them multiple times. Signed-off-by: Guennadi Liakhovetski --- src/arch/xtensa/up/init.c | 1 + src/audio/dai.c | 2 + src/audio/pipeline.c | 1 + src/drivers/intel/cavs/hda-dma.c | 3 + src/include/sof/wait.h | 115 ++-------------- src/ipc/handler.c | 1 + src/lib/CMakeLists.txt | 1 + src/lib/schedule.c | 1 + src/lib/trace.c | 1 + src/lib/wait.c | 124 ++++++++++++++++++ .../apollolake/include/platform/clk.h | 1 + .../apollolake/include/platform/platform.h | 1 + src/platform/baytrail/include/platform/clk.h | 1 + .../baytrail/include/platform/platform.h | 1 + src/platform/baytrail/platform.c | 1 + .../cannonlake/include/platform/clk.h | 1 + .../cannonlake/include/platform/platform.h | 1 + src/platform/haswell/include/platform/clk.h | 1 + .../haswell/include/platform/platform.h | 1 + src/platform/haswell/platform.c | 1 + src/platform/icelake/include/platform/clk.h | 1 + .../icelake/include/platform/platform.h | 1 + src/platform/intel/cavs/platform.c | 1 + src/platform/suecreek/include/platform/clk.h | 1 + .../suecreek/include/platform/platform.h | 1 + 25 files changed, 162 insertions(+), 103 deletions(-) create mode 100644 src/lib/wait.c 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/wait.h b/src/include/sof/wait.h index 8a1d7eafe454..7cfe746eeb7a 100644 --- a/src/include/sof/wait.h +++ b/src/include/sof/wait.h @@ -34,31 +34,13 @@ #define __INCLUDE_WAIT__ #include -#include + #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 typedef struct { uint32_t complete; @@ -66,12 +48,13 @@ 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; +#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"); } @@ -121,37 +104,6 @@ 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. @@ -164,52 +116,9 @@ 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_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; -} +int wait_for_completion_timeout(completion_t *comp); +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); #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 bc458c735b4d..14090a630c1f 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -13,4 +13,5 @@ add_local_sources(sof dma.c dai.c panic.c + wait.c ) 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..141bbcd49c67 --- /dev/null +++ b/src/lib/wait.c @@ -0,0 +1,124 @@ +/* + * 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 + +/* 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 (!c->complete && !c->timeout) + 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; + } + + /* timeout */ + trace_error_value(c->timeout); + trace_error_value(c->complete); + + return -ETIME; +} + +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/baytrail/platform.c b/src/platform/baytrail/platform.c index 9318e808f1d2..dc1a3b0a0b72 100644 --- a/src/platform/baytrail/platform.c +++ b/src/platform/baytrail/platform.c @@ -51,6 +51,7 @@ #include #include #include +#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/haswell/platform.c b/src/platform/haswell/platform.c index a28c4a77d7e7..6c9094e2f8c3 100644 --- a/src/platform/haswell/platform.c +++ b/src/platform/haswell/platform.c @@ -50,6 +50,7 @@ #include #include #include +#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 diff --git a/src/platform/suecreek/include/platform/platform.h b/src/platform/suecreek/include/platform/platform.h index 7e0c8f52ad7e..66bf72c6dfa6 100644 --- a/src/platform/suecreek/include/platform/platform.h +++ b/src/platform/suecreek/include/platform/platform.h @@ -35,6 +35,7 @@ #define __PLATFORM_PLATFORM_H__ #include +#include #include #include #include From 9e92719a47a1da44c643760099412379e1f8a68c Mon Sep 17 00:00:00 2001 From: Janusz Jankowski Date: Wed, 13 Feb 2019 21:16:22 +0100 Subject: [PATCH 5/6] tests: fix idc for smp Signed-off-by: Janusz Jankowski --- test/cmocka/src/audio/pipeline/CMakeLists.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/test/cmocka/src/audio/pipeline/CMakeLists.txt b/test/cmocka/src/audio/pipeline/CMakeLists.txt index f1c1fcd80089..443b84e8969b 100644 --- a/test/cmocka/src/audio/pipeline/CMakeLists.txt +++ b/test/cmocka/src/audio/pipeline/CMakeLists.txt @@ -1,3 +1,19 @@ +if(CONFIG_SMP) + SET(arch_src ${PROJECT_SOURCE_DIR}/src/arch/xtensa/smp/idc.c) + + # make small lib for stripping so we don't have to care + # about unused missing references + + add_compile_options(-fdata-sections -ffunction-sections) + link_libraries(-Wl,--gc-sections) + + add_library(pipeline_lib STATIC ${arch_src}) + + target_link_libraries(pipeline_lib PRIVATE sof_options) + + link_libraries(pipeline_lib) +endif() + cmocka_test(pipeline_new pipeline_new.c pipeline_mocks.c From 071dd5dbfb9bce0812f02dcc5b12fa06f010913f Mon Sep 17 00:00:00 2001 From: Janusz Jankowski Date: Sun, 17 Feb 2019 19:32:37 +0100 Subject: [PATCH 6/6] tests: add panic symbols for alloc Signed-off-by: Janusz Jankowski --- test/cmocka/src/lib/alloc/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/cmocka/src/lib/alloc/CMakeLists.txt b/test/cmocka/src/lib/alloc/CMakeLists.txt index 3a3099a7d1a7..c65960ba4db0 100644 --- a/test/cmocka/src/lib/alloc/CMakeLists.txt +++ b/test/cmocka/src/lib/alloc/CMakeLists.txt @@ -2,5 +2,6 @@ cmocka_test(alloc alloc.c mock.c ${PROJECT_SOURCE_DIR}/src/lib/alloc.c + ${PROJECT_SOURCE_DIR}/src/lib/panic.c ${PROJECT_SOURCE_DIR}/src/platform/intel/cavs/memory.c )