LCOV - code coverage report
Current view: top level - zephyr/arch/xtensa - atomic_xtensa.h Coverage Total Hit
Test: new.info Lines: 94.4 % 18 17
Test Date: 2025-09-05 16:43:28

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (c) 2021 Intel Corporation
       3              :  * SPDX-License-Identifier: Apache-2.0
       4              :  */
       5              : 
       6              : #ifndef ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_
       7              : #define ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_
       8              : 
       9              : /* Included from <zephyr/sys/atomic.h> */
      10              : 
      11              : /* Recent GCC versions actually do have working atomics support on
      12              :  * Xtensa (and so should work with CONFIG_ATOMIC_OPERATIONS_BUILTIN),
      13              :  * but existing versions of Xtensa's XCC do not.  So we define an
      14              :  * inline implementation here that is more or less identical
      15              :  */
      16              : 
      17              : /** Implementation of @ref atomic_get. */
      18            1 : static ALWAYS_INLINE atomic_val_t atomic_get(const atomic_t *target)
      19              : {
      20              :         atomic_val_t ret;
      21              : 
      22              :         /* Actual Xtensa hardware seems to have only in-order
      23              :          * pipelines, but the architecture does define a barrier load,
      24              :          * so use it.  There is a matching s32ri instruction, but
      25              :          * nothing in the Zephyr API requires a barrier store (all the
      26              :          * atomic write ops have exchange semantics.
      27              :          */
      28              :         __asm__ volatile("l32ai %0, %1, 0"
      29              :                          : "=r"(ret) : "r"(target) : "memory");
      30              :         return ret;
      31              : }
      32              : 
      33              : /**
      34              :  * @brief Xtensa specific atomic compare-and-set (CAS).
      35              :  *
      36              :  * @param addr Address of atomic variable.
      37              :  * @param oldval Original value to compare against.
      38              :  * @param newval New value to store.
      39              :  *
      40              :  * This utilizes SCOMPARE1 register and s32c1i instruction to
      41              :  * perform compare-and-set atomic operation. This will
      42              :  * unconditionally read from the atomic variable at @p addr
      43              :  * before the comparison. This value is returned from
      44              :  * the function.
      45              :  *
      46              :  * @return The value at the memory location before CAS.
      47              :  *
      48              :  * @see atomic_cas.
      49              :  */
      50              : static ALWAYS_INLINE
      51            1 : atomic_val_t xtensa_cas(atomic_t *addr, atomic_val_t oldval,
      52              :                         atomic_val_t newval)
      53              : {
      54              :         __asm__ volatile("wsr %1, SCOMPARE1; s32c1i %0, %2, 0"
      55              :                          : "+r"(newval), "+r"(oldval) : "r"(addr) : "memory");
      56              : 
      57              :         return newval; /* got swapped with the old memory by s32c1i */
      58              : }
      59              : 
      60              : /** Implementation of @ref atomic_cas. */
      61              : static ALWAYS_INLINE
      62            1 : bool atomic_cas(atomic_t *target, atomic_val_t oldval, atomic_val_t newval)
      63              : {
      64              :         return oldval == xtensa_cas(target, oldval, newval);
      65              : }
      66              : 
      67              : /** Implementation of @ref atomic_ptr_cas. */
      68              : static ALWAYS_INLINE
      69            1 : bool atomic_ptr_cas(atomic_ptr_t *target, void *oldval, void *newval)
      70              : {
      71              :         return (atomic_val_t) oldval
      72              :                 == xtensa_cas((atomic_t *) target, (atomic_val_t) oldval,
      73              :                               (atomic_val_t) newval);
      74              : }
      75              : 
      76              : /* Generates an atomic exchange sequence that swaps the value at
      77              :  * address "target", whose old value is read to be "cur", with the
      78              :  * specified expression.  Evaluates to the old value which was
      79              :  * atomically replaced.
      80              :  */
      81              : #define Z__GEN_ATOMXCHG(expr) ({                                \
      82              :         atomic_val_t res, cur;                          \
      83              :         do {                                            \
      84              :                 cur = *target;                          \
      85              :                 res = xtensa_cas(target, cur, (expr));  \
      86              :         } while (res != cur);                           \
      87              :         res; })
      88              : 
      89              : /** Implementation of @ref atomic_set. */
      90              : static ALWAYS_INLINE
      91            1 : atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
      92              : {
      93              :         return Z__GEN_ATOMXCHG(value);
      94              : }
      95              : 
      96              : /** Implementation of @ref atomic_add. */
      97              : static ALWAYS_INLINE
      98            1 : atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
      99              : {
     100              :         return Z__GEN_ATOMXCHG(cur + value);
     101              : }
     102              : 
     103              : /** Implementation of @ref atomic_sub. */
     104              : static ALWAYS_INLINE
     105            1 : atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
     106              : {
     107              :         return Z__GEN_ATOMXCHG(cur - value);
     108              : }
     109              : 
     110              : /** Implementation of @ref atomic_inc. */
     111              : static ALWAYS_INLINE
     112            1 : atomic_val_t atomic_inc(atomic_t *target)
     113              : {
     114              :         return Z__GEN_ATOMXCHG(cur + 1);
     115              : }
     116              : 
     117              : /** Implementation of @ref atomic_dec. */
     118              : static ALWAYS_INLINE
     119            1 : atomic_val_t atomic_dec(atomic_t *target)
     120              : {
     121              :         return Z__GEN_ATOMXCHG(cur - 1);
     122              : }
     123              : 
     124              : /** Implementation of @ref atomic_or. */
     125            1 : static ALWAYS_INLINE atomic_val_t atomic_or(atomic_t *target,
     126              :                                             atomic_val_t value)
     127              : {
     128              :         return Z__GEN_ATOMXCHG(cur | value);
     129              : }
     130              : 
     131              : /** Implementation of @ref atomic_xor. */
     132            1 : static ALWAYS_INLINE atomic_val_t atomic_xor(atomic_t *target,
     133              :                                              atomic_val_t value)
     134              : {
     135              :         return Z__GEN_ATOMXCHG(cur ^ value);
     136              : }
     137              : 
     138              : /** Implementation of @ref atomic_and. */
     139            1 : static ALWAYS_INLINE atomic_val_t atomic_and(atomic_t *target,
     140              :                                              atomic_val_t value)
     141              : {
     142              :         return Z__GEN_ATOMXCHG(cur & value);
     143              : }
     144              : 
     145              : /** Implementation of @ref atomic_nand. */
     146            1 : static ALWAYS_INLINE atomic_val_t atomic_nand(atomic_t *target,
     147              :                                               atomic_val_t value)
     148              : {
     149              :         return Z__GEN_ATOMXCHG(~(cur & value));
     150              : }
     151              : 
     152              : /** Implementation of @ref atomic_ptr_get. */
     153            1 : static ALWAYS_INLINE void *atomic_ptr_get(const atomic_ptr_t *target)
     154              : {
     155              :         return (void *) atomic_get((atomic_t *)target);
     156              : }
     157              : 
     158              : /** Implementation of @ref atomic_ptr_set. */
     159            1 : static ALWAYS_INLINE void *atomic_ptr_set(atomic_ptr_t *target, void *value)
     160              : {
     161              :         return (void *) atomic_set((atomic_t *) target, (atomic_val_t) value);
     162              : }
     163              : 
     164              : /** Implementation of @ref atomic_clear. */
     165            1 : static ALWAYS_INLINE atomic_val_t atomic_clear(atomic_t *target)
     166              : {
     167              :         return atomic_set(target, 0);
     168              : }
     169              : 
     170              : /** Implementation of @ref atomic_ptr_clear. */
     171            1 : static ALWAYS_INLINE void *atomic_ptr_clear(atomic_ptr_t *target)
     172              : {
     173              :         return (void *) atomic_set((atomic_t *) target, 0);
     174              : }
     175              : 
     176              : #endif /* ZEPHYR_INCLUDE_ATOMIC_XTENSA_H_ */
        

Generated by: LCOV version 2.0-1