LCOV - code coverage report
Current view: top level - zephyr/arch/xtensa - cache.h Coverage Total Hit
Test: new.info Lines: 73.9 % 23 17
Test Date: 2025-09-05 20:47:19

            Line data    Source code
       1            0 : /*
       2              :  * Copyright 2021 Intel Corporation
       3              :  * SPDX-License-Identifier: Apache-2.0
       4              :  */
       5              : #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_CACHE_H_
       6              : #define ZEPHYR_INCLUDE_ARCH_XTENSA_CACHE_H_
       7              : 
       8              : #include <xtensa/config/core-isa.h>
       9              : #include <zephyr/toolchain.h>
      10              : #include <zephyr/sys/util.h>
      11              : #include <zephyr/debug/sparse.h>
      12              : #include <xtensa/hal.h>
      13              : 
      14              : #ifdef __cplusplus
      15              : extern "C" {
      16              : #endif
      17              : 
      18              : #define Z_DCACHE_MAX (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
      19              : 
      20              : #if XCHAL_DCACHE_SIZE
      21              : BUILD_ASSERT(Z_IS_POW2(XCHAL_DCACHE_LINESIZE));
      22              : BUILD_ASSERT(Z_IS_POW2(Z_DCACHE_MAX));
      23              : #endif
      24              : 
      25              : #if defined(CONFIG_DCACHE) || defined(__DOXYGEN__)
      26              : 
      27              : /** Implementation of @ref arch_dcache_flush_range. */
      28            1 : static ALWAYS_INLINE int arch_dcache_flush_range(void *addr, size_t bytes)
      29              : {
      30              : #if XCHAL_DCACHE_SIZE
      31              :         size_t step = XCHAL_DCACHE_LINESIZE;
      32              :         size_t first = ROUND_DOWN(addr, step);
      33              :         size_t last = ROUND_UP(((long)addr) + bytes, step);
      34              :         size_t line;
      35              : 
      36              :         for (line = first; bytes && line < last; line += step) {
      37              :                 __asm__ volatile("dhwb %0, 0" :: "r"(line));
      38              :         }
      39              : #endif
      40              :         return 0;
      41              : }
      42              : 
      43              : /** Implementation of @ref arch_dcache_flush_and_invd_range. */
      44            1 : static ALWAYS_INLINE int arch_dcache_flush_and_invd_range(void *addr, size_t bytes)
      45              : {
      46              : #if XCHAL_DCACHE_SIZE
      47              :         size_t step = XCHAL_DCACHE_LINESIZE;
      48              :         size_t first = ROUND_DOWN(addr, step);
      49              :         size_t last = ROUND_UP(((long)addr) + bytes, step);
      50              :         size_t line;
      51              : 
      52              :         for (line = first; bytes && line < last; line += step) {
      53              :                 __asm__ volatile("dhwbi %0, 0" :: "r"(line));
      54              :         }
      55              : #endif
      56              :         return 0;
      57              : }
      58              : 
      59              : /** Implementation of @ref arch_dcache_invd_range. */
      60            1 : static ALWAYS_INLINE int arch_dcache_invd_range(void *addr, size_t bytes)
      61              : {
      62              : #if XCHAL_DCACHE_SIZE
      63              :         size_t step = XCHAL_DCACHE_LINESIZE;
      64              :         size_t first = ROUND_DOWN(addr, step);
      65              :         size_t last = ROUND_UP(((long)addr) + bytes, step);
      66              :         size_t line;
      67              : 
      68              :         for (line = first; bytes && line < last; line += step) {
      69              :                 __asm__ volatile("dhi %0, 0" :: "r"(line));
      70              :         }
      71              : #endif
      72              :         return 0;
      73              : }
      74              : 
      75              : /** Implementation of @ref arch_dcache_invd_all. */
      76            1 : static ALWAYS_INLINE int arch_dcache_invd_all(void)
      77              : {
      78              : #if XCHAL_DCACHE_SIZE
      79              :         size_t step = XCHAL_DCACHE_LINESIZE;
      80              :         size_t line;
      81              : 
      82              :         for (line = 0; line < XCHAL_DCACHE_SIZE; line += step) {
      83              :                 __asm__ volatile("dii %0, 0" :: "r"(line));
      84              :         }
      85              : #endif
      86              :         return 0;
      87              : }
      88              : 
      89              : /** Implementation of @ref arch_dcache_flush_all. */
      90            1 : static ALWAYS_INLINE int arch_dcache_flush_all(void)
      91              : {
      92              : #if XCHAL_DCACHE_SIZE
      93              :         size_t step = XCHAL_DCACHE_LINESIZE;
      94              :         size_t line;
      95              : 
      96              :         for (line = 0; line < XCHAL_DCACHE_SIZE; line += step) {
      97              :                 __asm__ volatile("diwb %0, 0" :: "r"(line));
      98              :         }
      99              : #endif
     100              :         return 0;
     101              : }
     102              : 
     103              : /** Implementation of @ref arch_dcache_flush_and_invd_all. */
     104            1 : static ALWAYS_INLINE int arch_dcache_flush_and_invd_all(void)
     105              : {
     106              : #if XCHAL_DCACHE_SIZE
     107              :         size_t step = XCHAL_DCACHE_LINESIZE;
     108              :         size_t line;
     109              : 
     110              :         for (line = 0; line < XCHAL_DCACHE_SIZE; line += step) {
     111              :                 __asm__ volatile("diwbi %0, 0" :: "r"(line));
     112              :         }
     113              : #endif
     114              :         return 0;
     115              : }
     116              : 
     117              : /** Implementation of @ref arch_dcache_enable. */
     118            1 : static ALWAYS_INLINE void arch_dcache_enable(void)
     119              : {
     120              :         /* nothing */
     121              : }
     122              : 
     123              : /** Implementation of @ref arch_dcache_disable. */
     124            1 : static ALWAYS_INLINE void arch_dcache_disable(void)
     125              : {
     126              :         /* nothing */
     127              : }
     128              : 
     129              : #endif /* CONFIG_DCACHE */
     130              : 
     131              : #if defined(CONFIG_ICACHE) || defined(__DOXYGEN__)
     132              : 
     133              : /** Implementation of @ref arch_icache_line_size_get. */
     134            1 : static ALWAYS_INLINE size_t arch_icache_line_size_get(void)
     135              : {
     136              :         return -ENOTSUP;
     137              : }
     138              : 
     139              : /** Implementation of @ref arch_icache_flush_all. */
     140            1 : static ALWAYS_INLINE int arch_icache_flush_all(void)
     141              : {
     142              :         return -ENOTSUP;
     143              : }
     144              : 
     145              : /** Implementation of @ref arch_icache_invd_all. */
     146            1 : static ALWAYS_INLINE int arch_icache_invd_all(void)
     147              : {
     148              : #if XCHAL_ICACHE_SIZE
     149              :         xthal_icache_all_invalidate();
     150              : #endif
     151              :         return 0;
     152              : }
     153              : 
     154              : /** Implementation of @ref arch_icache_flush_and_invd_all. */
     155            1 : static ALWAYS_INLINE int arch_icache_flush_and_invd_all(void)
     156              : {
     157              :         return -ENOTSUP;
     158              : }
     159              : 
     160              : /** Implementation of @ref arch_icache_flush_range. */
     161            1 : static ALWAYS_INLINE int arch_icache_flush_range(void *addr, size_t size)
     162              : {
     163              :         return -ENOTSUP;
     164              : }
     165              : 
     166              : /** Implementation of @ref arch_icache_invd_range. */
     167            1 : static ALWAYS_INLINE int arch_icache_invd_range(void *addr, size_t size)
     168              : {
     169              : #if XCHAL_ICACHE_SIZE
     170              :         xthal_icache_region_invalidate(addr, size);
     171              : #endif
     172              :         return 0;
     173              : }
     174              : 
     175              : /** Implementation of @ref arch_icache_flush_and_invd_range. */
     176            1 : static ALWAYS_INLINE int arch_icache_flush_and_invd_range(void *addr, size_t size)
     177              : {
     178              :         return -ENOTSUP;
     179              : }
     180              : 
     181              : /** Implementation of @ref arch_icache_enable. */
     182            1 : static ALWAYS_INLINE void arch_icache_enable(void)
     183              : {
     184              :         /* nothing */
     185              : }
     186              : 
     187              : /** Implementation of @ref arch_icache_disable. */
     188            1 : static ALWAYS_INLINE void arch_icache_disable(void)
     189              : {
     190              :         /* nothing */
     191              : }
     192              : 
     193              : #endif /* CONFIG_ICACHE */
     194              : 
     195              : #if defined(CONFIG_CACHE_DOUBLEMAP)
     196              : /**
     197              :  * @brief Test if a pointer is in cached region.
     198              :  *
     199              :  * Some hardware may map the same physical memory twice
     200              :  * so that it can be seen in both (incoherent) cached mappings
     201              :  * and a coherent "shared" area. This tests if a particular
     202              :  * pointer is within the cached, coherent area.
     203              :  *
     204              :  * @param ptr Pointer
     205              :  *
     206              :  * @retval True if pointer is in cached region.
     207              :  * @retval False if pointer is not in cached region.
     208              :  */
     209              : static inline bool arch_cache_is_ptr_cached(void *ptr)
     210              : {
     211              :         size_t addr = (size_t) ptr;
     212              : 
     213              :         return (addr >> 29) == CONFIG_XTENSA_CACHED_REGION;
     214              : }
     215              : 
     216              : /**
     217              :  * @brief Test if a pointer is in un-cached region.
     218              :  *
     219              :  * Some hardware may map the same physical memory twice
     220              :  * so that it can be seen in both (incoherent) cached mappings
     221              :  * and a coherent "shared" area. This tests if a particular
     222              :  * pointer is within the un-cached, incoherent area.
     223              :  *
     224              :  * @param ptr Pointer
     225              :  *
     226              :  * @retval True if pointer is not in cached region.
     227              :  * @retval False if pointer is in cached region.
     228              :  */
     229              : static inline bool arch_cache_is_ptr_uncached(void *ptr)
     230              : {
     231              :         size_t addr = (size_t) ptr;
     232              : 
     233              :         return (addr >> 29) == CONFIG_XTENSA_UNCACHED_REGION;
     234              : }
     235              : 
     236              : static ALWAYS_INLINE uint32_t z_xtrpoflip(uint32_t addr, uint32_t rto, uint32_t rfrom)
     237              : {
     238              :         /* The math here is all compile-time: when the two regions
     239              :          * differ by a power of two, we can convert between them by
     240              :          * setting or clearing just one bit.  Otherwise it needs two
     241              :          * operations.
     242              :          */
     243              :         uint32_t rxor = (rto ^ rfrom) << 29;
     244              : 
     245              :         rto <<= 29;
     246              :         if (Z_IS_POW2(rxor)) {
     247              :                 if ((rxor & rto) == 0) {
     248              :                         return addr & ~rxor;
     249              :                 } else {
     250              :                         return addr | rxor;
     251              :                 }
     252              :         } else {
     253              :                 return (addr & ~(7U << 29)) | rto;
     254              :         }
     255              : }
     256              : 
     257              : /**
     258              :  * @brief Return cached pointer to a RAM address
     259              :  *
     260              :  * The Xtensa coherence architecture maps addressable RAM twice, in
     261              :  * two different 512MB regions whose L1 cache settings can be
     262              :  * controlled independently.  So for any given pointer, it is possible
     263              :  * to convert it to and from a cached version.
     264              :  *
     265              :  * This function takes a pointer to any addressable object (either in
     266              :  * cacheable memory or not) and returns a pointer that can be used to
     267              :  * refer to the same memory through the L1 data cache.  Data read
     268              :  * through the resulting pointer will reflect locally cached values on
     269              :  * the current CPU if they exist, and writes will go first into the
     270              :  * cache and be written back later.
     271              :  *
     272              :  * @see arch_uncached_ptr()
     273              :  *
     274              :  * @param ptr A pointer to a valid C object
     275              :  * @return A pointer to the same object via the L1 dcache
     276              :  */
     277              : static inline void __sparse_cache *arch_cache_cached_ptr_get(void *ptr)
     278              : {
     279              :         return (__sparse_force void __sparse_cache *)z_xtrpoflip((uint32_t) ptr,
     280              :                                                 CONFIG_XTENSA_CACHED_REGION,
     281              :                                                 CONFIG_XTENSA_UNCACHED_REGION);
     282              : }
     283              : 
     284              : /**
     285              :  * @brief Return uncached pointer to a RAM address
     286              :  *
     287              :  * The Xtensa coherence architecture maps addressable RAM twice, in
     288              :  * two different 512MB regions whose L1 cache settings can be
     289              :  * controlled independently.  So for any given pointer, it is possible
     290              :  * to convert it to and from a cached version.
     291              :  *
     292              :  * This function takes a pointer to any addressable object (either in
     293              :  * cacheable memory or not) and returns a pointer that can be used to
     294              :  * refer to the same memory while bypassing the L1 data cache.  Data
     295              :  * in the L1 cache will not be inspected nor modified by the access.
     296              :  *
     297              :  * @see arch_cached_ptr()
     298              :  *
     299              :  * @param ptr A pointer to a valid C object
     300              :  * @return A pointer to the same object bypassing the L1 dcache
     301              :  */
     302              : static inline void *arch_cache_uncached_ptr_get(void __sparse_cache *ptr)
     303              : {
     304              :         return (void *)z_xtrpoflip((__sparse_force uint32_t)ptr,
     305              :                                    CONFIG_XTENSA_UNCACHED_REGION,
     306              :                                    CONFIG_XTENSA_CACHED_REGION);
     307              : }
     308              : #else
     309            0 : static inline bool arch_cache_is_ptr_cached(void *ptr)
     310              : {
     311              :         ARG_UNUSED(ptr);
     312              : 
     313              :         return false;
     314              : }
     315              : 
     316            0 : static inline bool arch_cache_is_ptr_uncached(void *ptr)
     317              : {
     318              :         ARG_UNUSED(ptr);
     319              : 
     320              :         return false;
     321              : }
     322              : 
     323            0 : static inline void *arch_cache_cached_ptr_get(void *ptr)
     324              : {
     325              :         return ptr;
     326              : }
     327              : 
     328            0 : static inline void *arch_cache_uncached_ptr_get(void *ptr)
     329              : {
     330              :         return ptr;
     331              : }
     332              : #endif
     333              : 
     334            0 : static ALWAYS_INLINE void arch_cache_init(void)
     335              : {
     336              : }
     337              : 
     338              : 
     339              : #ifdef __cplusplus
     340              : } /* extern "C" */
     341              : #endif
     342              : 
     343              : #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_CACHE_H_ */
        

Generated by: LCOV version 2.0-1