diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-01-27 14:37:51 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-01-31 12:49:09 +0100 |
commit | 4cf93658eff5cf6b0c02e98a0d1ec33dea5ed85c (patch) | |
tree | 8ce105a37991b79f38da9da31c1cb6ce13ef6beb /bsps/or1k | |
parent | bsps: Move network define to source files (diff) | |
download | rtems-4cf93658eff5cf6b0c02e98a0d1ec33dea5ed85c.tar.bz2 |
bsps: Rework cache manager implementation
The previous cache manager support used a single souce file
(cache_manager.c) which included an implementation header (cache_.h).
This required the use of specialized include paths to find the right
header file. Change this to include a generic implementation header
(cacheimpl.h) in specialized source files.
Use the following directories and files:
* bsps/shared/cache
* bsps/@RTEMS_CPU@/shared/cache
* bsps/@RTEMS_CPU@/@RTEMS_BSP_FAMILY/start/cache.c
Update #3285.
Diffstat (limited to 'bsps/or1k')
-rw-r--r-- | bsps/or1k/headers.am | 1 | ||||
-rw-r--r-- | bsps/or1k/include/bsp/cache_.h | 43 | ||||
-rw-r--r-- | bsps/or1k/shared/cache/cache.c | 388 |
3 files changed, 388 insertions, 44 deletions
diff --git a/bsps/or1k/headers.am b/bsps/or1k/headers.am index 7729a76231..670c0c40ab 100644 --- a/bsps/or1k/headers.am +++ b/bsps/or1k/headers.am @@ -2,5 +2,4 @@ include_bspdir = $(includedir)/bsp include_bsp_HEADERS = -include_bsp_HEADERS += ../../../../../bsps/or1k/include/bsp/cache_.h include_bsp_HEADERS += ../../../../../bsps/or1k/include/bsp/linker-symbols.h diff --git a/bsps/or1k/include/bsp/cache_.h b/bsps/or1k/include/bsp/cache_.h deleted file mode 100644 index ed2053858e..0000000000 --- a/bsps/or1k/include/bsp/cache_.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * COPYRIGHT (c) 2014 Hesham ALMatary <heshamelmatary@gmail.com> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#ifndef LIBBSP_OR1K_SHARED_CACHE_H -#define LIBBSP_OR1K_SHARED_CACHE_H - -#include <assert.h> -#include <bsp.h> -#include <rtems/rtems/intr.h> - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* These two defines also ensure that the rtems_cache_* functions have bodies */ -#define CPU_DATA_CACHE_ALIGNMENT 32 -#define CPU_INSTRUCTION_CACHE_ALIGNMENT 32 - -#define CPU_CACHE_SUPPORT_PROVIDES_CACHE_SIZE_FUNCTIONS 1 - -static inline size_t -_CPU_cache_get_data_cache_size( const uint32_t level ) -{ - return (level == 0 || level == 1)? 8192 : 0; -} - -static inline size_t -_CPU_cache_get_instruction_cache_size( const uint32_t level ) -{ - return (level == 0 || level == 1)? 8192 : 0; -} - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* LIBBSP_OR1K_SHARED_CACHE_H */ diff --git a/bsps/or1k/shared/cache/cache.c b/bsps/or1k/shared/cache/cache.c new file mode 100644 index 0000000000..55fa54e62f --- /dev/null +++ b/bsps/or1k/shared/cache/cache.c @@ -0,0 +1,388 @@ +/* + * COPYRIGHT (c) 2014, 2016 ÅAC Microtec AB <www.aacmicrotec.com> + * Contributor(s): + * Karol Gugala <kgugala@antmicro.com> + * Martin Werner <martin.werner@aacmicrotec.com> + * + * COPYRIGHT (c) 2014 Hesham ALMatary <heshamelmatary@gmail.com> + * + * COPYRIGHT (c) 1989-2006 + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <rtems/score/cpu.h> +#include <rtems/score/interr.h> +#include <rtems/score/or1k-utility.h> +#include <rtems/score/percpu.h> + +#define CPU_DATA_CACHE_ALIGNMENT 32 +#define CPU_INSTRUCTION_CACHE_ALIGNMENT 32 + +#define CPU_CACHE_SUPPORT_PROVIDES_RANGE_FUNCTIONS 1 +#define CPU_CACHE_SUPPORT_PROVIDES_CACHE_SIZE_FUNCTIONS 1 + +static inline size_t +_CPU_cache_get_data_cache_size( const uint32_t level ) +{ + return (level == 0 || level == 1)? 8192 : 0; +} + +static inline size_t +_CPU_cache_get_instruction_cache_size( const uint32_t level ) +{ + return (level == 0 || level == 1)? 8192 : 0; +} + +static inline void _CPU_OR1K_Cache_data_block_prefetch(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_DCBPR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +static inline void _CPU_OR1K_Cache_data_block_writeback(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_DCBWR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +static inline void _CPU_OR1K_Cache_data_block_lock(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_DCBLR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +static inline void _CPU_OR1K_Cache_instruction_block_prefetch +(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_ICBPR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +static inline void _CPU_OR1K_Cache_instruction_block_lock +(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_ICBLR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +/* Implement RTEMS cache manager functions */ + +static void _CPU_cache_flush_1_data_line(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_DCBFR, (uintptr_t) d_addr); + + //__asm__ volatile("l.csync"); + + _ISR_Local_enable(level); +} + +static void _CPU_cache_invalidate_1_data_line(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_DCBIR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +static void _CPU_cache_freeze_data(void) +{ + /* Do nothing */ +} + +static void _CPU_cache_unfreeze_data(void) +{ + /* Do nothing */ +} + +static void _CPU_cache_invalidate_1_instruction_line(const void *d_addr) +{ + ISR_Level level; + + _ISR_Local_disable (level); + + _OR1K_mtspr(CPU_OR1K_SPR_ICBIR, (uintptr_t) d_addr); + + _ISR_Local_enable(level); +} + +static void _CPU_cache_freeze_instruction(void) +{ + /* Do nothing */ +} + +static void _CPU_cache_unfreeze_instruction(void) +{ + /* Do nothing */ +} + +static void _CPU_cache_flush_entire_data(void) +{ + size_t addr; + ISR_Level level; + + _ISR_Local_disable (level); + + /* We have only 0 level cache so we do not need to invalidate others */ + for ( + addr = _CPU_cache_get_data_cache_size(0); + addr > 0; + addr -= CPU_DATA_CACHE_ALIGNMENT + ) { + _OR1K_mtspr(CPU_OR1K_SPR_DCBFR, (uintptr_t) addr); + } + + _ISR_Local_enable (level); +} + +static void _CPU_cache_invalidate_entire_data(void) +{ + size_t addr; + ISR_Level level; + + _ISR_Local_disable (level); + + /* We have only 0 level cache so we do not need to invalidate others */ + for ( + addr = _CPU_cache_get_data_cache_size(0); + addr > 0; + addr -= CPU_DATA_CACHE_ALIGNMENT + ) { + _OR1K_mtspr(CPU_OR1K_SPR_DCBIR, (uintptr_t) addr); + } + + _ISR_Local_enable (level); +} + +static void _CPU_cache_invalidate_entire_instruction(void) +{ + size_t addr; + ISR_Level level; + + _ISR_Local_disable (level); + + /* We have only 0 level cache so we do not need to invalidate others */ + for ( + addr = _CPU_cache_get_instruction_cache_size(0); + addr > 0; + addr -= CPU_INSTRUCTION_CACHE_ALIGNMENT + ) { + _OR1K_mtspr(CPU_OR1K_SPR_ICBIR, (uintptr_t) addr); + } + + /* Flush instructions out of instruction buffer */ + __asm__ volatile("l.nop"); + __asm__ volatile("l.nop"); + __asm__ volatile("l.nop"); + __asm__ volatile("l.nop"); + __asm__ volatile("l.nop"); + + _ISR_Local_enable (level); +} + +/* + * The range functions are copied almost verbatim from the generic + * implementations in c/src/lib/libcpu/shared/src/cache_manager.c. The main + * modification here is avoiding reapeated off/on toggling of the ISR for each + * cache line operation. + */ + +static void _CPU_cache_flush_data_range(const void *d_addr, size_t n_bytes) +{ + const void * final_address; + ISR_Level level; + + /* + * Set d_addr to the beginning of the cache line; final_address indicates + * the last address_t which needs to be pushed. Increment d_addr and push + * the resulting line until final_address is passed. + */ + + if( n_bytes == 0 ) + /* Do nothing if number of bytes to flush is zero */ + return; + + final_address = (void *)((size_t)d_addr + n_bytes - 1); + d_addr = (void *)((size_t)d_addr & ~(CPU_DATA_CACHE_ALIGNMENT - 1)); + + if( final_address - d_addr > _CPU_cache_get_data_cache_size(0) ) { + /* + * Avoid iterating over the whole cache multiple times if the range is + * larger than the cache size. + */ + _CPU_cache_flush_entire_data(); + return; + } + + _ISR_Local_disable (level); + + while( d_addr <= final_address ) { + _OR1K_mtspr(CPU_OR1K_SPR_DCBFR, (uintptr_t) d_addr); + d_addr = (void *)((size_t)d_addr + CPU_DATA_CACHE_ALIGNMENT); + } + + _ISR_Local_enable (level); +} + +static void _CPU_cache_invalidate_data_range(const void *d_addr, size_t n_bytes) +{ + const void * final_address; + ISR_Level level; + + /* + * Set d_addr to the beginning of the cache line; final_address indicates + * the last address_t which needs to be pushed. Increment d_addr and push + * the resulting line until final_address is passed. + */ + + if( n_bytes == 0 ) + /* Do nothing if number of bytes to flush is zero */ + return; + + final_address = (void *)((size_t)d_addr + n_bytes - 1); + d_addr = (void *)((size_t)d_addr & ~(CPU_DATA_CACHE_ALIGNMENT - 1)); + + if( final_address - d_addr > _CPU_cache_get_data_cache_size(0) ) { + /* + * Avoid iterating over the whole cache multiple times if the range is + * larger than the cache size. + */ + _CPU_cache_invalidate_entire_data(); + return; + } + + _ISR_Local_disable (level); + + while( d_addr <= final_address ) { + _OR1K_mtspr(CPU_OR1K_SPR_DCBIR, (uintptr_t) d_addr); + d_addr = (void *)((size_t)d_addr + CPU_DATA_CACHE_ALIGNMENT); + } + + _ISR_Local_enable (level); +} + +static void _CPU_cache_invalidate_instruction_range(const void *i_addr, size_t n_bytes) +{ + const void * final_address; + ISR_Level level; + + /* + * Set i_addr to the beginning of the cache line; final_address indicates + * the last address_t which needs to be pushed. Increment i_addr and push + * the resulting line until final_address is passed. + */ + + if( n_bytes == 0 ) + /* Do nothing if number of bytes to flush is zero */ + return; + + final_address = (void *)((size_t)i_addr + n_bytes - 1); + i_addr = (void *)((size_t)i_addr & ~(CPU_INSTRUCTION_CACHE_ALIGNMENT - 1)); + + if( final_address - i_addr > _CPU_cache_get_data_cache_size(0) ) { + /* + * Avoid iterating over the whole cache multiple times if the range is + * larger than the cache size. + */ + _CPU_cache_invalidate_entire_instruction(); + return; + } + + _ISR_Local_disable (level); + + while( i_addr <= final_address ) { + _OR1K_mtspr(CPU_OR1K_SPR_ICBIR, (uintptr_t) i_addr); + i_addr = (void *)((size_t)i_addr + CPU_DATA_CACHE_ALIGNMENT); + } + + _ISR_Local_enable (level); +} + +static void _CPU_cache_enable_data(void) +{ + uint32_t sr; + ISR_Level level; + + _ISR_Local_disable (level); + + sr = _OR1K_mfspr(CPU_OR1K_SPR_SR); + _OR1K_mtspr(CPU_OR1K_SPR_SR, sr | CPU_OR1K_SPR_SR_DCE); + + _ISR_Local_enable(level); +} + +static void _CPU_cache_disable_data(void) +{ + uint32_t sr; + ISR_Level level; + + _ISR_Local_disable (level); + + sr = _OR1K_mfspr(CPU_OR1K_SPR_SR); + _OR1K_mtspr(CPU_OR1K_SPR_SR, (sr & ~CPU_OR1K_SPR_SR_DCE)); + + _ISR_Local_enable(level); +} + +static void _CPU_cache_enable_instruction(void) +{ + uint32_t sr; + ISR_Level level; + + _ISR_Local_disable (level); + + sr = _OR1K_mfspr(CPU_OR1K_SPR_SR); + _OR1K_mtspr(CPU_OR1K_SPR_SR, sr | CPU_OR1K_SPR_SR_ICE); + + _ISR_Local_enable(level); +} + +static void _CPU_cache_disable_instruction(void) +{ + uint32_t sr; + ISR_Level level; + + _ISR_Local_disable (level); + + sr = _OR1K_mfspr(CPU_OR1K_SPR_SR); + _OR1K_mtspr(CPU_OR1K_SPR_SR, (sr & ~CPU_OR1K_SPR_SR_ICE)); + + _ISR_Local_enable(level); +} + +#include "../../../shared/cache/cacheimpl.h" |