LCOV - code coverage report
Current view: top level - zephyr/arch/xtensa - atomic_xtensa.h Hit Total Coverage
Test: new.info Lines: 17 18 94.4 %
Date: 2024-12-22 00:14:23

          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 1.14