From b4004e899218b3269341b1916970ba5c7b06b7ae Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Fri, 6 Jul 2018 13:41:44 +0200 Subject: [PATCH] cpu: enabling and disabling slave cores Implements full flow for enabling and disabling slave cores. Core power operations availability based on architecture. Signed-off-by: Tomasz Lauda --- src/arch/xtensa/Makefile.am | 2 + src/arch/xtensa/include/arch/cpu.h | 6 +- src/arch/xtensa/smp/cpu.c | 103 ++++++++++++++++++ src/arch/xtensa/smp/include/arch/Makefile.am | 1 + src/arch/xtensa/smp/include/arch/alloc.h | 88 +++++++++++++++ src/arch/xtensa/smp/include/arch/idc.h | 45 ++++++-- src/arch/xtensa/smp/init.c | 2 +- src/arch/xtensa/smp/xtos/int-sethandler.c | 2 +- src/arch/xtensa/up/cpu.c | 42 +++++++ src/include/sof/Makefile.am | 1 + src/include/sof/cpu.h | 57 ++++++++++ src/init/init.c | 2 +- .../apollolake/include/platform/memory.h | 2 +- src/platform/apollolake/interrupt.c | 2 +- .../cannonlake/include/platform/memory.h | 2 +- src/platform/cannonlake/interrupt.c | 2 +- 16 files changed, 342 insertions(+), 17 deletions(-) create mode 100644 src/arch/xtensa/smp/cpu.c create mode 100644 src/arch/xtensa/smp/include/arch/alloc.h create mode 100644 src/arch/xtensa/up/cpu.c create mode 100644 src/include/sof/cpu.h diff --git a/src/arch/xtensa/Makefile.am b/src/arch/xtensa/Makefile.am index 1128297aa192..c37182b97918 100644 --- a/src/arch/xtensa/Makefile.am +++ b/src/arch/xtensa/Makefile.am @@ -52,6 +52,7 @@ if BUILD_XTENSA_SMP sof_SOURCES += \ smp/xtos/crt1-boards.S \ smp/xtos/_vectors.S \ + smp/cpu.c \ smp/init.c \ smp/schedule.c \ smp/task.c @@ -59,6 +60,7 @@ else sof_SOURCES += \ up/xtos/crt1-boards.S \ up/xtos/_vectors.S \ + up/cpu.c \ up/init.c \ up/schedule.c \ up/task.c diff --git a/src/arch/xtensa/include/arch/cpu.h b/src/arch/xtensa/include/arch/cpu.h index 6b1d3d6fec6e..54970a4cd08d 100644 --- a/src/arch/xtensa/include/arch/cpu.h +++ b/src/arch/xtensa/include/arch/cpu.h @@ -35,7 +35,11 @@ #include #include -static inline int cpu_get_id(void) +void arch_cpu_enable_core(int id); + +void arch_cpu_disable_core(int id); + +static inline int arch_cpu_get_id(void) { int prid; #if XCHAL_HAVE_PRID diff --git a/src/arch/xtensa/smp/cpu.c b/src/arch/xtensa/smp/cpu.c new file mode 100644 index 000000000000..2aa36def4d40 --- /dev/null +++ b/src/arch/xtensa/smp/cpu.c @@ -0,0 +1,103 @@ +/* + * 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: Tomasz Lauda + * + */ + +/** + * \file arch/xtensa/smp/cpu.c + * \brief Xtensa SMP CPU implementation file + * \authors Tomasz Lauda + */ + +#include +#include +#include +#include +#include +#include +#include + +static uint32_t active_cores_mask = 0x1; +static spinlock_t lock = { 0 }; + +void arch_cpu_enable_core(int id) +{ + struct idc_msg power_up = { + IDC_POWER_UP_MESSAGE, IDC_POWER_UP_EXTENSION, id }; + uint32_t flags; + + spin_lock_irq(&lock, flags); + + if (!(active_cores_mask & (1 << id))) { + /* allocate resources for core */ + alloc_core_context(id); + + /* enable IDC interrupt for the the slave core */ + idc_enable_interrupts(id, arch_cpu_get_id()); + + /* send IDC power up message */ + arch_idc_send_msg(&power_up); + + active_cores_mask |= (1 << id); + } + + spin_unlock_irq(&lock, flags); +} + +void arch_cpu_disable_core(int id) +{ + struct idc_msg power_down = { IDC_POWER_DOWN_MESSAGE, 0, id }; + uint32_t flags; + + spin_lock_irq(&lock, flags); + + if (active_cores_mask & (1 << id)) { + arch_idc_send_msg(&power_down); + + active_cores_mask ^= (1 << id); + } + + spin_unlock_irq(&lock, flags); +} + +void cpu_power_down_core(void) +{ + arch_interrupt_global_disable(); + + idc_free(); + + scheduler_free(); + + free_core_context(arch_cpu_get_id()); + + dcache_writeback_invalidate_all(); + + while (1) + arch_wait_for_interrupt(0); +} diff --git a/src/arch/xtensa/smp/include/arch/Makefile.am b/src/arch/xtensa/smp/include/arch/Makefile.am index eaf72bb55064..7a4a5e16ec92 100644 --- a/src/arch/xtensa/smp/include/arch/Makefile.am +++ b/src/arch/xtensa/smp/include/arch/Makefile.am @@ -1,2 +1,3 @@ noinst_HEADERS = \ + alloc.h \ idc.h diff --git a/src/arch/xtensa/smp/include/arch/alloc.h b/src/arch/xtensa/smp/include/arch/alloc.h new file mode 100644 index 000000000000..65cb9b0c8e20 --- /dev/null +++ b/src/arch/xtensa/smp/include/arch/alloc.h @@ -0,0 +1,88 @@ +/* + * 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: Tomasz Lauda + */ + +/** + * \file arch/xtensa/smp/include/arch/alloc.h + * \brief Xtensa SMP memory allocation header file + * \authors Tomasz Lauda + */ + +#ifndef __ARCH_ALLOC_H__ +#define __ARCH_ALLOC_H__ + +#include +#include + +extern struct core_context *core_ctx_ptr[PLATFORM_CORE_COUNT]; +extern struct xtos_core_data *core_data_ptr[PLATFORM_CORE_COUNT]; + +/** + * \brief Allocates memory for core specific data. + * \param[in] core Slave core for which data needs to be allocated. + */ +static inline void alloc_core_context(int core) +{ + struct core_context *core_ctx; + + core_ctx = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*core_ctx)); + dcache_writeback_invalidate_region(core_ctx, sizeof(*core_ctx)); + + /* xtos_core_data is a big struct, so allocate it from system heap + * and never free again. Allocating from runtime heap would be + * a waste of a very big memory block. + */ + if (!core_data_ptr[core]) + core_data_ptr[core] = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, + sizeof(*core_data_ptr[core])); + + core_data_ptr[core]->thread_data_ptr = &core_ctx->td; + dcache_writeback_invalidate_region(core_data_ptr[core], + sizeof(*core_data_ptr[core])); + + dcache_writeback_invalidate_region(core_data_ptr, + sizeof(core_data_ptr)); + + core_ctx_ptr[core] = core_ctx; + dcache_writeback_invalidate_region(core_ctx_ptr, + sizeof(core_ctx_ptr)); +} + +/** + * \brief Frees memory allocated for core specific data. + * \param[in] core Slave core for which data needs to be freed. + */ +static inline void free_core_context(int core) +{ + rfree(core_ctx_ptr[core]); + dcache_writeback_invalidate_region(core_ctx_ptr[core], + sizeof(*core_ctx_ptr[core])); +} + +#endif diff --git a/src/arch/xtensa/smp/include/arch/idc.h b/src/arch/xtensa/smp/include/arch/idc.h index df5bc7cc166b..67c53d1ea3b3 100644 --- a/src/arch/xtensa/smp/include/arch/idc.h +++ b/src/arch/xtensa/smp/include/arch/idc.h @@ -54,11 +54,25 @@ /** \brief IDC trace error function. */ #define trace_idc_error(__e) trace_error(TRACE_CLASS_IDC, __e) -/** \brief IDC header mask. */ -#define IDC_HEADER(x) ((x) & 0x7fffffff) -/** \brief IDC extension mask. */ -#define IDC_EXTENSION(x) ((x) & 0x0fffffff) +/** \brief ROM wake version parsed by ROM during core wake up. */ +#define IDC_ROM_WAKE_VERSION 0x2 + +/** \brief ROM control version parsed by ROM during core wake up. */ +#define IDC_ROM_CONTROL_VERSION 0x1 + +// TODO: refactor below defines after universal IDC message template +// will be defined and ready + +/** \brief Power up message header. */ +#define IDC_POWER_UP_MESSAGE \ + (IDC_ROM_WAKE_VERSION | (IDC_ROM_CONTROL_VERSION << 24)) + +/** \brief Power up message extension. */ +#define IDC_POWER_UP_EXTENSION (SOF_TEXT_START >> 2) + +/** \brief Power down message header. */ +#define IDC_POWER_DOWN_MESSAGE 0x7FFFFFFF /** \brief IDC message. */ struct idc_msg { @@ -76,6 +90,8 @@ struct idc { struct idc_msg received_msg; /**< received message */ }; +extern void cpu_power_down_core(void); + /** * \brief Returns IDC data. * \return Pointer to pointer of IDC data. @@ -87,6 +103,13 @@ static inline struct idc **idc_get(void) return &ctx->idc; } +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. @@ -94,7 +117,7 @@ static inline struct idc **idc_get(void) static void idc_irq_handler(void *arg) { struct idc *idc = arg; - int core = cpu_get_id(); + int core = arch_cpu_get_id(); uint32_t idctfc; uint32_t idctefc; uint32_t idcietc; @@ -146,7 +169,7 @@ static void idc_irq_handler(void *arg) static inline void arch_idc_send_msg(struct idc_msg *msg) { struct idc *idc = *idc_get(); - int core = cpu_get_id(); + int core = arch_cpu_get_id(); uint32_t flags; tracev_idc("Msg"); @@ -166,7 +189,11 @@ static inline void arch_idc_send_msg(struct idc_msg *msg) */ static inline int32_t idc_cmd(struct idc_msg *msg) { - /* execute message based on type */ + /* right now we only handle power down */ + /* TODO: universal implementation */ + if (msg->header == IDC_POWER_DOWN_MESSAGE) + cpu_power_down_core(); + return 0; } @@ -176,7 +203,7 @@ static inline int32_t idc_cmd(struct idc_msg *msg) */ static inline void idc_do_cmd(struct idc *idc) { - int core = cpu_get_id(); + int core = arch_cpu_get_id(); int initiator = idc->received_msg.core; trace_idc("Cmd"); @@ -253,7 +280,7 @@ static inline uint32_t idc_get_done_bit_mask(int core) */ static inline void arch_idc_init(void) { - int core = cpu_get_id(); + int core = arch_cpu_get_id(); trace_idc("IDI"); diff --git a/src/arch/xtensa/smp/init.c b/src/arch/xtensa/smp/init.c index 57618968eef4..16389c1ebcd7 100644 --- a/src/arch/xtensa/smp/init.c +++ b/src/arch/xtensa/smp/init.c @@ -71,7 +71,7 @@ struct xtos_core_data *core_data_ptr[PLATFORM_CORE_COUNT]; */ static void initialize_pointers_per_core(void) { - int core = cpu_get_id(); + int core = arch_cpu_get_id(); struct xtos_core_data *core_data = core_data_ptr[core]; if (core == PLATFORM_MASTER_CORE_ID) { diff --git a/src/arch/xtensa/smp/xtos/int-sethandler.c b/src/arch/xtensa/smp/xtos/int-sethandler.c index 59eec07fde27..ecb7b78e7eb3 100644 --- a/src/arch/xtensa/smp/xtos/int-sethandler.c +++ b/src/arch/xtensa/smp/xtos/int-sethandler.c @@ -42,7 +42,7 @@ _xtos_handler _xtos_set_interrupt_handler_arg( int n, _xtos_handler f, void *arg ret = 0; /* priority level too high to safely handle in C */ } else { - entry = &(core_data_ptr[cpu_get_id()]->xtos_int_data.xtos_interrupt_table.array[MAPINT(n)]); + entry = &(core_data_ptr[arch_cpu_get_id()]->xtos_int_data.xtos_interrupt_table.array[MAPINT(n)]); old = entry->handler; if (f) { entry->handler = f; diff --git a/src/arch/xtensa/up/cpu.c b/src/arch/xtensa/up/cpu.c new file mode 100644 index 000000000000..e5e7c70a6cee --- /dev/null +++ b/src/arch/xtensa/up/cpu.c @@ -0,0 +1,42 @@ +/* + * 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: Tomasz Lauda + * + */ + +/** + * \file arch/xtensa/up/cpu.c + * \brief Xtensa UP CPU implementation file + * \authors Tomasz Lauda + */ + +#include + +void arch_cpu_enable_core(int id) { } + +void arch_cpu_disable_core(int id) { } diff --git a/src/include/sof/Makefile.am b/src/include/sof/Makefile.am index 7eaba9a590b6..a69cffc96edb 100644 --- a/src/include/sof/Makefile.am +++ b/src/include/sof/Makefile.am @@ -9,6 +9,7 @@ include_HEADERS = \ alloc.h \ atomic.h \ clock.h \ + cpu.h \ dai.h \ debug.h \ dma.h \ diff --git a/src/include/sof/cpu.h b/src/include/sof/cpu.h new file mode 100644 index 000000000000..f5debaa9d7d2 --- /dev/null +++ b/src/include/sof/cpu.h @@ -0,0 +1,57 @@ +/* + * 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: Tomasz Lauda + */ + +/** + * \file include/sof/cpu.h + * \brief CPU header file + * \authors Tomasz Lauda + */ + +#ifndef __SOF_CPU_H__ +#define __SOF_CPU_H__ + +#include + +static inline int cpu_get_id(void) +{ + return arch_cpu_get_id(); +} + +static inline void cpu_enable_core(int id) +{ + arch_cpu_enable_core(id); +} + +static inline void cpu_disable_core(int id) +{ + arch_cpu_disable_core(id); +} + +#endif diff --git a/src/init/init.c b/src/init/init.c index 2bd86d8efaeb..03683dfac0c2 100644 --- a/src/init/init.c +++ b/src/init/init.c @@ -43,9 +43,9 @@ #include #include #include +#include #include #include -#include /* main firmware context */ static struct sof sof; diff --git a/src/platform/apollolake/include/platform/memory.h b/src/platform/apollolake/include/platform/memory.h index a7e6532f29cd..dbd712a11399 100644 --- a/src/platform/apollolake/include/platform/memory.h +++ b/src/platform/apollolake/include/platform/memory.h @@ -147,7 +147,7 @@ #define HEAP_SYSTEM_BASE \ (SOF_TEXT_BASE + SOF_TEXT_SIZE +\ SOF_DATA_SIZE + SOF_BSS_DATA_SIZE) -#define HEAP_SYSTEM_SIZE 0x5000 +#define HEAP_SYSTEM_SIZE 0x8000 #define HEAP_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) #define HEAP_RUNTIME_SIZE \ diff --git a/src/platform/apollolake/interrupt.c b/src/platform/apollolake/interrupt.c index 7d515d87f1ff..f06d868bb376 100644 --- a/src/platform/apollolake/interrupt.c +++ b/src/platform/apollolake/interrupt.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/platform/cannonlake/include/platform/memory.h b/src/platform/cannonlake/include/platform/memory.h index 7743fd5134a4..1c0396eab5d0 100644 --- a/src/platform/cannonlake/include/platform/memory.h +++ b/src/platform/cannonlake/include/platform/memory.h @@ -247,7 +247,7 @@ #define HEAP_SYSTEM_BASE (SOF_TEXT_BASE + SOF_TEXT_SIZE + \ SOF_DATA_SIZE + SOF_BSS_DATA_SIZE) -#define HEAP_SYSTEM_SIZE 0x8000 +#define HEAP_SYSTEM_SIZE 0x11000 #define HEAP_RUNTIME_BASE (HEAP_SYSTEM_BASE + HEAP_SYSTEM_SIZE) #define HEAP_RUNTIME_SIZE \ diff --git a/src/platform/cannonlake/interrupt.c b/src/platform/cannonlake/interrupt.c index f281e86a00bf..c2d7b1a71741 100644 --- a/src/platform/cannonlake/interrupt.c +++ b/src/platform/cannonlake/interrupt.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include