linux/arch/xtensa/include/asm/atomic.h
<<
>>
Prefs
   1/*
   2 * include/asm-xtensa/atomic.h
   3 *
   4 * Atomic operations that C can't guarantee us.  Useful for resource counting..
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License.  See the file "COPYING" in the main directory of this archive
   8 * for more details.
   9 *
  10 * Copyright (C) 2001 - 2008 Tensilica Inc.
  11 */
  12
  13#ifndef _XTENSA_ATOMIC_H
  14#define _XTENSA_ATOMIC_H
  15
  16#include <linux/stringify.h>
  17#include <linux/types.h>
  18#include <asm/processor.h>
  19#include <asm/cmpxchg.h>
  20#include <asm/barrier.h>
  21
  22/*
  23 * This Xtensa implementation assumes that the right mechanism
  24 * for exclusion is for locking interrupts to level EXCM_LEVEL.
  25 *
  26 * Locking interrupts looks like this:
  27 *
  28 *    rsil a15, TOPLEVEL
  29 *    <code>
  30 *    wsr  a15, PS
  31 *    rsync
  32 *
  33 * Note that a15 is used here because the register allocation
  34 * done by the compiler is not guaranteed and a window overflow
  35 * may not occur between the rsil and wsr instructions. By using
  36 * a15 in the rsil, the machine is guaranteed to be in a state
  37 * where no register reference will cause an overflow.
  38 */
  39
  40/**
  41 * atomic_read - read atomic variable
  42 * @v: pointer of type atomic_t
  43 *
  44 * Atomically reads the value of @v.
  45 */
  46#define arch_atomic_read(v)             READ_ONCE((v)->counter)
  47
  48/**
  49 * atomic_set - set atomic variable
  50 * @v: pointer of type atomic_t
  51 * @i: required value
  52 *
  53 * Atomically sets the value of @v to @i.
  54 */
  55#define arch_atomic_set(v,i)            WRITE_ONCE((v)->counter, (i))
  56
  57#if XCHAL_HAVE_EXCLUSIVE
  58#define ATOMIC_OP(op)                                                   \
  59static inline void arch_atomic_##op(int i, atomic_t *v)                 \
  60{                                                                       \
  61        unsigned long tmp;                                              \
  62        int result;                                                     \
  63                                                                        \
  64        __asm__ __volatile__(                                           \
  65                        "1:     l32ex   %[tmp], %[addr]\n"              \
  66                        "       " #op " %[result], %[tmp], %[i]\n"      \
  67                        "       s32ex   %[result], %[addr]\n"           \
  68                        "       getex   %[result]\n"                    \
  69                        "       beqz    %[result], 1b\n"                \
  70                        : [result] "=&a" (result), [tmp] "=&a" (tmp)    \
  71                        : [i] "a" (i), [addr] "a" (v)                   \
  72                        : "memory"                                      \
  73                        );                                              \
  74}                                                                       \
  75
  76#define ATOMIC_OP_RETURN(op)                                            \
  77static inline int arch_atomic_##op##_return(int i, atomic_t *v)         \
  78{                                                                       \
  79        unsigned long tmp;                                              \
  80        int result;                                                     \
  81                                                                        \
  82        __asm__ __volatile__(                                           \
  83                        "1:     l32ex   %[tmp], %[addr]\n"              \
  84                        "       " #op " %[result], %[tmp], %[i]\n"      \
  85                        "       s32ex   %[result], %[addr]\n"           \
  86                        "       getex   %[result]\n"                    \
  87                        "       beqz    %[result], 1b\n"                \
  88                        "       " #op " %[result], %[tmp], %[i]\n"      \
  89                        : [result] "=&a" (result), [tmp] "=&a" (tmp)    \
  90                        : [i] "a" (i), [addr] "a" (v)                   \
  91                        : "memory"                                      \
  92                        );                                              \
  93                                                                        \
  94        return result;                                                  \
  95}
  96
  97#define ATOMIC_FETCH_OP(op)                                             \
  98static inline int arch_atomic_fetch_##op(int i, atomic_t *v)            \
  99{                                                                       \
 100        unsigned long tmp;                                              \
 101        int result;                                                     \
 102                                                                        \
 103        __asm__ __volatile__(                                           \
 104                        "1:     l32ex   %[tmp], %[addr]\n"              \
 105                        "       " #op " %[result], %[tmp], %[i]\n"      \
 106                        "       s32ex   %[result], %[addr]\n"           \
 107                        "       getex   %[result]\n"                    \
 108                        "       beqz    %[result], 1b\n"                \
 109                        : [result] "=&a" (result), [tmp] "=&a" (tmp)    \
 110                        : [i] "a" (i), [addr] "a" (v)                   \
 111                        : "memory"                                      \
 112                        );                                              \
 113                                                                        \
 114        return tmp;                                                     \
 115}
 116
 117#elif XCHAL_HAVE_S32C1I
 118#define ATOMIC_OP(op)                                                   \
 119static inline void arch_atomic_##op(int i, atomic_t * v)                \
 120{                                                                       \
 121        unsigned long tmp;                                              \
 122        int result;                                                     \
 123                                                                        \
 124        __asm__ __volatile__(                                           \
 125                        "1:     l32i    %[tmp], %[mem]\n"               \
 126                        "       wsr     %[tmp], scompare1\n"            \
 127                        "       " #op " %[result], %[tmp], %[i]\n"      \
 128                        "       s32c1i  %[result], %[mem]\n"            \
 129                        "       bne     %[result], %[tmp], 1b\n"        \
 130                        : [result] "=&a" (result), [tmp] "=&a" (tmp),   \
 131                          [mem] "+m" (*v)                               \
 132                        : [i] "a" (i)                                   \
 133                        : "memory"                                      \
 134                        );                                              \
 135}                                                                       \
 136
 137#define ATOMIC_OP_RETURN(op)                                            \
 138static inline int arch_atomic_##op##_return(int i, atomic_t * v)        \
 139{                                                                       \
 140        unsigned long tmp;                                              \
 141        int result;                                                     \
 142                                                                        \
 143        __asm__ __volatile__(                                           \
 144                        "1:     l32i    %[tmp], %[mem]\n"               \
 145                        "       wsr     %[tmp], scompare1\n"            \
 146                        "       " #op " %[result], %[tmp], %[i]\n"      \
 147                        "       s32c1i  %[result], %[mem]\n"            \
 148                        "       bne     %[result], %[tmp], 1b\n"        \
 149                        "       " #op " %[result], %[result], %[i]\n"   \
 150                        : [result] "=&a" (result), [tmp] "=&a" (tmp),   \
 151                          [mem] "+m" (*v)                               \
 152                        : [i] "a" (i)                                   \
 153                        : "memory"                                      \
 154                        );                                              \
 155                                                                        \
 156        return result;                                                  \
 157}
 158
 159#define ATOMIC_FETCH_OP(op)                                             \
 160static inline int arch_atomic_fetch_##op(int i, atomic_t * v)           \
 161{                                                                       \
 162        unsigned long tmp;                                              \
 163        int result;                                                     \
 164                                                                        \
 165        __asm__ __volatile__(                                           \
 166                        "1:     l32i    %[tmp], %[mem]\n"               \
 167                        "       wsr     %[tmp], scompare1\n"            \
 168                        "       " #op " %[result], %[tmp], %[i]\n"      \
 169                        "       s32c1i  %[result], %[mem]\n"            \
 170                        "       bne     %[result], %[tmp], 1b\n"        \
 171                        : [result] "=&a" (result), [tmp] "=&a" (tmp),   \
 172                          [mem] "+m" (*v)                               \
 173                        : [i] "a" (i)                                   \
 174                        : "memory"                                      \
 175                        );                                              \
 176                                                                        \
 177        return result;                                                  \
 178}
 179
 180#else /* XCHAL_HAVE_S32C1I */
 181
 182#define ATOMIC_OP(op)                                                   \
 183static inline void arch_atomic_##op(int i, atomic_t * v)                \
 184{                                                                       \
 185        unsigned int vval;                                              \
 186                                                                        \
 187        __asm__ __volatile__(                                           \
 188                        "       rsil    a15, "__stringify(TOPLEVEL)"\n" \
 189                        "       l32i    %[result], %[mem]\n"            \
 190                        "       " #op " %[result], %[result], %[i]\n"   \
 191                        "       s32i    %[result], %[mem]\n"            \
 192                        "       wsr     a15, ps\n"                      \
 193                        "       rsync\n"                                \
 194                        : [result] "=&a" (vval), [mem] "+m" (*v)        \
 195                        : [i] "a" (i)                                   \
 196                        : "a15", "memory"                               \
 197                        );                                              \
 198}                                                                       \
 199
 200#define ATOMIC_OP_RETURN(op)                                            \
 201static inline int arch_atomic_##op##_return(int i, atomic_t * v)        \
 202{                                                                       \
 203        unsigned int vval;                                              \
 204                                                                        \
 205        __asm__ __volatile__(                                           \
 206                        "       rsil    a15,"__stringify(TOPLEVEL)"\n"  \
 207                        "       l32i    %[result], %[mem]\n"            \
 208                        "       " #op " %[result], %[result], %[i]\n"   \
 209                        "       s32i    %[result], %[mem]\n"            \
 210                        "       wsr     a15, ps\n"                      \
 211                        "       rsync\n"                                \
 212                        : [result] "=&a" (vval), [mem] "+m" (*v)        \
 213                        : [i] "a" (i)                                   \
 214                        : "a15", "memory"                               \
 215                        );                                              \
 216                                                                        \
 217        return vval;                                                    \
 218}
 219
 220#define ATOMIC_FETCH_OP(op)                                             \
 221static inline int arch_atomic_fetch_##op(int i, atomic_t * v)           \
 222{                                                                       \
 223        unsigned int tmp, vval;                                         \
 224                                                                        \
 225        __asm__ __volatile__(                                           \
 226                        "       rsil    a15,"__stringify(TOPLEVEL)"\n"  \
 227                        "       l32i    %[result], %[mem]\n"            \
 228                        "       " #op " %[tmp], %[result], %[i]\n"      \
 229                        "       s32i    %[tmp], %[mem]\n"               \
 230                        "       wsr     a15, ps\n"                      \
 231                        "       rsync\n"                                \
 232                        : [result] "=&a" (vval), [tmp] "=&a" (tmp),     \
 233                          [mem] "+m" (*v)                               \
 234                        : [i] "a" (i)                                   \
 235                        : "a15", "memory"                               \
 236                        );                                              \
 237                                                                        \
 238        return vval;                                                    \
 239}
 240
 241#endif /* XCHAL_HAVE_S32C1I */
 242
 243#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op) ATOMIC_OP_RETURN(op)
 244
 245ATOMIC_OPS(add)
 246ATOMIC_OPS(sub)
 247
 248#undef ATOMIC_OPS
 249#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
 250
 251ATOMIC_OPS(and)
 252ATOMIC_OPS(or)
 253ATOMIC_OPS(xor)
 254
 255#undef ATOMIC_OPS
 256#undef ATOMIC_FETCH_OP
 257#undef ATOMIC_OP_RETURN
 258#undef ATOMIC_OP
 259
 260#define arch_atomic_cmpxchg(v, o, n) ((int)arch_cmpxchg(&((v)->counter), (o), (n)))
 261#define arch_atomic_xchg(v, new) (arch_xchg(&((v)->counter), new))
 262
 263#endif /* _XTENSA_ATOMIC_H */
 264