arch/xtensa: Add non-HAL caching primitives

The Xtensa L1 cache layer has straightforward semantics accessible via
single-instructions that operate on cache lines via physical
addresses.  These are very amenable to inlining.

Unfortunately the Xtensa HAL layer requires function calls to do this,
leading to significant code waste at the calling site, an extra frame
on the stack and needless runtime instructions for situations where
the call is over a constant region that could elide the loop.  This is
made even worse because the HAL library is not built with
-ffunction-sections, so pulling in even one of these tiny cache
functions has the effect of importing a 1500-byte object file into the
link!

Add our own tiny cache layer to include/arch/xtensa/cache.h and use
that instead.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
Andy Ross 2021-02-14 16:09:43 -08:00 committed by Anas Nashif
commit 64cf33952d
10 changed files with 105 additions and 19 deletions

View file

@ -0,0 +1,81 @@
/*
* Copyright 2021 Intel Corporation
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_CACHE_H_
#define ZEPHYR_INCLUDE_ARCH_XTENSA_CACHE_H_
#include <xtensa/config/core-isa.h>
#include <sys/util.h>
#ifdef __cplusplus
extern "C" {
#endif
#define Z_DCACHE_MAX (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
#if XCHAL_DCACHE_SIZE
#define Z_IS_POW2(x) (((x) != 0) && (((x) & ((x)-1)) == 0))
BUILD_ASSERT(Z_IS_POW2(XCHAL_DCACHE_LINESIZE));
BUILD_ASSERT(Z_IS_POW2(Z_DCACHE_MAX));
#endif
static inline void z_xtensa_cache_flush(void *addr, size_t bytes)
{
#if XCHAL_DCACHE_SIZE
size_t step = XCHAL_DCACHE_LINESIZE;
size_t first = ROUND_DOWN(addr, step);
size_t last = ROUND_UP(((long)addr) + bytes, step);
for (size_t line = first; bytes && line < last; line += step) {
__asm__ volatile("dhwb %0, 0" :: "r"(line));
}
#endif
}
static inline void z_xtensa_cache_flush_inv(void *addr, size_t bytes)
{
#if XCHAL_DCACHE_SIZE
size_t step = XCHAL_DCACHE_LINESIZE;
size_t first = ROUND_DOWN(addr, step);
size_t last = ROUND_UP(((long)addr) + bytes, step);
for (size_t line = first; bytes && line < last; line += step) {
__asm__ volatile("dhwbi %0, 0" :: "r"(line));
}
#endif
}
static inline void z_xtensa_cache_inv(void *addr, size_t bytes)
{
#if XCHAL_DCACHE_SIZE
size_t step = XCHAL_DCACHE_LINESIZE;
size_t first = ROUND_DOWN(addr, step);
size_t last = ROUND_UP(((long)addr) + bytes, step);
for (size_t line = first; bytes && line < last; line += step) {
__asm__ volatile("dhi %0, 0" :: "r"(line));
}
#endif
}
static inline void z_xtensa_cache_inv_all(void)
{
z_xtensa_cache_inv(NULL, Z_DCACHE_MAX);
}
static inline void z_xtensa_cache_flush_all(void)
{
z_xtensa_cache_flush(NULL, Z_DCACHE_MAX);
}
static inline void z_xtensa_cache_flush_inv_all(void)
{
z_xtensa_cache_flush_inv(NULL, Z_DCACHE_MAX);
}
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_CACHE_H_ */