From e2333269aeb627c7b1ef203812d6869e7bf77c28 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Wed, 28 Apr 2021 10:38:27 +0200 Subject: [PATCH] cache: Introduce external cache controller system support The cache API currently shipped in Zephyr is assuming that the cache controller is always on-core thus managed at the arch level. This is not always the case because many SoCs rely on external cache controllers as a peripheral external to the core (for example PL310 cache controller and the L2Cxxx family). In some cases you also want a single driver to control a whole set of cache controllers. Rework the cache code introducing support for external cache controllers. Signed-off-by: Carlo Caione --- CODEOWNERS | 1 + arch/Kconfig | 17 ++++ drivers/CMakeLists.txt | 1 + drivers/Kconfig | 2 + drivers/cache/CMakeLists.txt | 1 + drivers/cache/Kconfig | 18 ++++ include/cache.h | 165 +++++++++++------------------------ include/drivers/cache.h | 144 ++++++++++++++++++++++++++++++ include/sys/arch_interface.h | 4 +- kernel/CMakeLists.txt | 5 +- 10 files changed, 243 insertions(+), 115 deletions(-) create mode 100644 drivers/cache/CMakeLists.txt create mode 100644 drivers/cache/Kconfig create mode 100644 include/drivers/cache.h diff --git a/CODEOWNERS b/CODEOWNERS index a73b7a3d212..59655cdc967 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -184,6 +184,7 @@ /drivers/adc/ @anangl /drivers/adc/adc_stm32.c @cybertale /drivers/bluetooth/ @joerchan @jhedberg @Vudentz +/drivers/cache/ @carlocaione /drivers/can/ @alexanderwachter /drivers/can/*mcp2515* @karstenkoenig /drivers/clock_control/*nrf* @nordic-krch diff --git a/arch/Kconfig b/arch/Kconfig index 21d8b0c85ad..f5a69bbcbce 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -919,6 +919,23 @@ config ICACHE_LINE_SIZE Detect automatically at runtime by selecting ICACHE_LINE_SIZE_DETECT. +choice + prompt "Cache type" + depends on CACHE_MANAGEMENT + default HAS_ARCH_CACHE + +config HAS_ARCH_CACHE + bool "Integrated cache controller" + help + "Integrade on-core cache controller" + +config HAS_EXTERNAL_CACHE + bool "External cache controller" + help + "External cache controller or cache management system" + +endchoice + endmenu config ARCH diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index b974cfef230..483895f2266 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -56,3 +56,4 @@ add_subdirectory_ifdef(CONFIG_SYS_CLOCK_EXISTS timer) add_subdirectory_ifdef(CONFIG_NEURAL_NET_ACCEL neural_net) add_subdirectory_ifdef(CONFIG_PTP_CLOCK ptp_clock) add_subdirectory_ifdef(CONFIG_EDAC edac) +add_subdirectory_ifdef(CONFIG_CACHE_MANAGEMENT cache) diff --git a/drivers/Kconfig b/drivers/Kconfig index a762c13c1f6..546a3aaaa44 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -113,4 +113,6 @@ source "drivers/misc/Kconfig" source "drivers/disk/Kconfig" +source "drivers/cache/Kconfig" + endmenu diff --git a/drivers/cache/CMakeLists.txt b/drivers/cache/CMakeLists.txt new file mode 100644 index 00000000000..9881313609a --- /dev/null +++ b/drivers/cache/CMakeLists.txt @@ -0,0 +1 @@ +# SPDX-License-Identifier: Apache-2.0 diff --git a/drivers/cache/Kconfig b/drivers/cache/Kconfig new file mode 100644 index 00000000000..52cbc049dfd --- /dev/null +++ b/drivers/cache/Kconfig @@ -0,0 +1,18 @@ +# Copyright (c) 2021 Carlo Caione +# SPDX-License-Identifier: Apache-2.0 + +menuconfig CACHE + bool "External cache controllers drivers" + help + Enable support for external cache controllers drivers + +if CACHE + +module = CACHE +module-str = cache +source "subsys/logging/Kconfig.template.log_config" + +config CACHE_HAS_DRIVER + bool + +endif # CACHE diff --git a/include/cache.h b/include/cache.h index 4478c81a440..87a6402a7fa 100644 --- a/include/cache.h +++ b/include/cache.h @@ -8,6 +8,7 @@ #define ZEPHYR_INCLUDE_CACHE_H_ #include +#include #ifdef __cplusplus extern "C" { @@ -22,149 +23,89 @@ extern "C" { * INVD means invalidate and will mark cache lines as not valid. A future * access to the associated address is guaranteed to generate a memory fetch. */ + #define K_CACHE_WB BIT(0) #define K_CACHE_INVD BIT(1) #define K_CACHE_WB_INVD (K_CACHE_WB | K_CACHE_INVD) -/** - * - * @brief Enable d-cache - * - * Enable the d-cache. - * - * @return N/A - */ -void arch_dcache_enable(void); +#if defined(CONFIG_HAS_EXTERNAL_CACHE) -/** - * - * @brief Disable d-cache - * - * Disable the d-cache. - * - * @return N/A - */ -void arch_dcache_disable(void); +/* Driver interface mirrored in include/drivers/cache.h */ -/** - * - * @brief Enable i-cache - * - * Enable the i-cache. - * - * @return N/A - */ -void arch_icache_enable(void); +/* Enable d-cache */ +extern void dcache_enable(void); -/** - * - * @brief Disable i-cache - * - * Disable the i-cache. - * - * @return N/A - */ -void arch_icache_disable(void); +/* Disable d-cache */ +extern void dcache_disable(void); -/** - * - * @brief Write-back / Invalidate / Write-back + Invalidate all d-cache - * - * Write-back, Invalidate or Write-back + Invalidate the whole d-cache. - * - * @param op Operation to perform (one of the K_CACHE_* operations) - * - * @retval 0 On success - * @retval -ENOTSUP If the operation is not supported - */ -int arch_dcache_all(int op); +/* Enable i-cache */ +extern void icache_enable(void); -/** - * - * @brief Write-back / Invalidate / Write-back + Invalidate d-cache lines - * - * No alignment is required for either addr or size, but since - * arch_dcache_range() iterates on the d-cache lines, a d-cache line alignment - * for both is optimal. - * - * The d-cache line size is specified either via the CONFIG_DCACHE_LINE_SIZE - * kconfig option or it is detected at runtime. - * - * @param addr The pointer to start the multi-line operation - * @param size The number of bytes that are to be acted on - * @param op Operation to perform (one of the K_CACHE_* operations) - * - * @retval 0 On success - * @retval -ENOTSUP If the operation is not supported - */ -int arch_dcache_range(void *addr, size_t size, int op); +/* Disable i-cache */ +extern void icache_disable(void); -/** - * - * @brief Write-back / Invalidate / Write-back + Invalidate all i-cache - * - * Write-back, Invalidate or Write-back + Invalidate the whole i-cache. - * - * @param op Operation to perform (one of the K_CACHE_* operations) - * - * @retval 0 On success - * @retval -ENOTSUP If the operation is not supported - */ -int arch_icache_all(int op); +/* Write-back / Invalidate / Write-back + Invalidate all d-cache */ +extern int dcache_all(int op); -/** - * - * @brief Write-back / Invalidate / Write-back + Invalidate i-cache lines - * - * No alignment is required for either addr or size, but since - * arch_icache_range() iterates on the i-cache lines, an i-cache line alignment - * for both is optimal. - * - * The i-cache line size is specified either via the CONFIG_ICACHE_LINE_SIZE - * kconfig option or it is detected at runtime. - * - * @param addr The pointer to start the multi-line operation - * @param size The number of bytes that are to be acted on - * @param op Operation to perform (one of the K_CACHE_* operations) - * - * @retval 0 On success - * @retval -ENOTSUP If the operation is not supported - */ -int arch_icache_range(void *addr, size_t size, int op); +/* Write-back / Invalidate / Write-back + Invalidate d-cache lines */ +extern int dcache_range(void *addr, size_t size, int op); + +/* Write-back / Invalidate / Write-back + Invalidate all i-cache */ +extern int icache_all(int op); + +/* Write-back / Invalidate / Write-back + Invalidate i-cache lines */ +extern int icache_range(void *addr, size_t size, int op); + +#else + +/* Hooks into arch code */ + +#define dcache_enable arch_dcache_enable +#define dcache_disable arch_dcache_disable +#define icache_enable arch_icache_enable +#define icache_disable arch_icache_disable +#define dcache_all(op) arch_dcache_all(op) +#define dcache_range(addr, size, op) arch_dcache_range(addr, size, op) +#define icache_all(op) arch_icache_all(op) +#define icache_range(addr, size, op) arch_icache_range(addr, size, op) +#define dcache_line_size_get arch_dcache_line_size_get +#define icache_line_size_get arch_icache_line_size_get + +#endif __syscall int sys_dcache_all(int op); static inline int z_impl_sys_dcache_all(int op) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT)) { - return arch_dcache_all(op); - } +#if defined(CONFIG_CACHE_MANAGEMENT) + return dcache_all(op); +#endif return -ENOTSUP; } __syscall int sys_dcache_range(void *addr, size_t size, int op); static inline int z_impl_sys_dcache_range(void *addr, size_t size, int op) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT)) { - return arch_dcache_range(addr, size, op); - } +#if defined(CONFIG_CACHE_MANAGEMENT) + return dcache_range(addr, size, op); +#endif return -ENOTSUP; } __syscall int sys_icache_all(int op); static inline int z_impl_sys_icache_all(int op) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT)) { - return arch_icache_all(op); - } +#if defined(CONFIG_CACHE_MANAGEMENT) + return icache_all(op); +#endif return -ENOTSUP; } __syscall int sys_icache_range(void *addr, size_t size, int op); static inline int z_impl_sys_icache_range(void *addr, size_t size, int op) { - if (IS_ENABLED(CONFIG_CACHE_MANAGEMENT)) { - return arch_icache_range(addr, size, op); - } +#if defined(CONFIG_CACHE_MANAGEMENT) + return icache_range(addr, size, op); +#endif return -ENOTSUP; } @@ -188,7 +129,7 @@ static inline void sys_cache_flush(void *addr, size_t size) static inline size_t sys_dcache_line_size_get(void) { #ifdef CONFIG_DCACHE_LINE_SIZE_DETECT - return arch_dcache_line_size_get(); + return dcache_line_size_get(); #elif (CONFIG_DCACHE_LINE_SIZE != 0) return CONFIG_DCACHE_LINE_SIZE; #else @@ -207,7 +148,7 @@ static inline size_t sys_dcache_line_size_get(void) static inline size_t sys_icache_line_size_get(void) { #ifdef CONFIG_ICACHE_LINE_SIZE_DETECT - return arch_icache_line_size_get(); + return icache_line_size_get(); #elif (CONFIG_ICACHE_LINE_SIZE != 0) return CONFIG_ICACHE_LINE_SIZE; #else diff --git a/include/drivers/cache.h b/include/drivers/cache.h new file mode 100644 index 00000000000..5dcfa9a0d39 --- /dev/null +++ b/include/drivers/cache.h @@ -0,0 +1,144 @@ +/* + * Copyright 2021 Carlo Caione + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CACHE_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CACHE_H_ + +#include + +/** + * + * @brief Enable d-cache + * + * Enable the d-cache. + * + * @return N/A + */ +void dcache_enable(void); + +/** + * + * @brief Disable d-cache + * + * Disable the d-cache. + * + * @return N/A + */ +void dcache_disable(void); + +/** + * + * @brief Enable i-cache + * + * Enable the i-cache. + * + * @return N/A + */ +void icache_enable(void); + +/** + * + * @brief Disable i-cache + * + * Disable the i-cache. + * + * @return N/A + */ +void icache_disable(void); + +/** + * + * @brief Write-back / Invalidate / Write-back + Invalidate all d-cache + * + * Write-back, Invalidate or Write-back + Invalidate the whole d-cache. + * + * @param op Operation to perform (one of the K_CACHE_* operations) + * + * @retval 0 On success + * @retval -ENOTSUP If the operation is not supported + */ +int dcache_all(int op); + +/** + * + * @brief Write-back / Invalidate / Write-back + Invalidate d-cache lines + * + * No alignment is required for either addr or size, but since + * arch_dcache_range() iterates on the d-cache lines, a d-cache line alignment + * for both is optimal. + * + * The d-cache line size is specified either via the CONFIG_DCACHE_LINE_SIZE + * kconfig option or it is detected at runtime. + * + * @param addr The pointer to start the multi-line operation + * @param size The number of bytes that are to be acted on + * @param op Operation to perform (one of the K_CACHE_* operations) + * + * @retval 0 On success + * @retval -ENOTSUP If the operation is not supported + */ +int dcache_range(void *addr, size_t size, int op); + +/** + * + * @brief Write-back / Invalidate / Write-back + Invalidate all i-cache + * + * Write-back, Invalidate or Write-back + Invalidate the whole i-cache. + * + * @param op Operation to perform (one of the K_CACHE_* operations) + * + * @retval 0 On success + * @retval -ENOTSUP If the operation is not supported + */ +int icache_all(int op); + +/** + * + * @brief Write-back / Invalidate / Write-back + Invalidate i-cache lines + * + * No alignment is required for either addr or size, but since + * arch_icache_range() iterates on the i-cache lines, an i-cache line alignment + * for both is optimal. + * + * The i-cache line size is specified either via the CONFIG_ICACHE_LINE_SIZE + * kconfig option or it is detected at runtime. + * + * @param addr The pointer to start the multi-line operation + * @param size The number of bytes that are to be acted on + * @param op Operation to perform (one of the K_CACHE_* operations) + * + * @retval 0 On success + * @retval -ENOTSUP If the operation is not supported + */ +int icache_range(void *addr, size_t size, int op); + +#ifdef CONFIG_DCACHE_LINE_SIZE_DETECT +/** + * + * @brief Get the i-cache line size. + * + * The API is provided to get the i-cache line size. + * + * @return size of the i-cache line or 0 if the i-cache is not enabled. + */ +size_t dcache_line_size_get(void); + +#endif /* CONFIG_DCACHE_LINE_SIZE_DETECT */ + +#ifdef CONFIG_ICACHE_LINE_SIZE_DETECT +/** + * + * @brief Get the i-cache line size. + * + * The API is provided to get the i-cache line size. + * + * @return size of the i-cache line or 0 if the i-cache is not enabled. + */ +size_t icache_line_size_get(void); + +#endif /* CONFIG_ICACHE_LINE_SIZE_DETECT */ + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CACHE_H_ */ diff --git a/include/sys/arch_interface.h b/include/sys/arch_interface.h index 4db51dca09f..0597c460cea 100644 --- a/include/sys/arch_interface.h +++ b/include/sys/arch_interface.h @@ -820,7 +820,7 @@ void arch_gdb_step(void); * @{ */ -#ifdef CONFIG_CACHE_MANAGEMENT +#if defined(CONFIG_CACHE_MANAGEMENT) && defined(CONFIG_HAS_ARCH_CACHE) /** * * @brief Enable d-cache @@ -905,7 +905,7 @@ size_t arch_dcache_line_size_get(void); size_t arch_icache_line_size_get(void); #endif /* CONFIG_ICACHE_LINE_SIZE_DETECT */ -#endif /* CONFIG_CACHE_MANAGEMENT */ +#endif /* CONFIG_CACHE_MANAGEMENT && CONFIG_HAS_ARCH_CACHE */ /** @} */ diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index 3ecb87f6d36..496cc57472c 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -79,11 +79,14 @@ target_sources_ifdef( kernel PRIVATE futex.c mem_domain.c - cache_handlers.c userspace_handler.c userspace.c ) +if(CONFIG_CACHE_MANAGEMENT AND CONFIG_USERSPACE) + target_sources(kernel PRIVATE cache_handlers.c) +endif() + target_include_directories(kernel PRIVATE ${ZEPHYR_BASE}/kernel/include ${ARCH_DIR}/${ARCH}/include