linux/arch/arm64/include/asm/atomic_lse.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * Based on arch/arm/include/asm/atomic.h
   4 *
   5 * Copyright (C) 1996 Russell King.
   6 * Copyright (C) 2002 Deep Blue Solutions Ltd.
   7 * Copyright (C) 2012 ARM Ltd.
   8 */
   9
  10#ifndef __ASM_ATOMIC_LSE_H
  11#define __ASM_ATOMIC_LSE_H
  12
  13#define ATOMIC_OP(op, asm_op)                                           \
  14static inline void __lse_atomic_##op(int i, atomic_t *v)                        \
  15{                                                                       \
  16        asm volatile(                                                   \
  17        __LSE_PREAMBLE                                                  \
  18"       " #asm_op "     %w[i], %[v]\n"                                  \
  19        : [i] "+r" (i), [v] "+Q" (v->counter)                           \
  20        : "r" (v));                                                     \
  21}
  22
  23ATOMIC_OP(andnot, stclr)
  24ATOMIC_OP(or, stset)
  25ATOMIC_OP(xor, steor)
  26ATOMIC_OP(add, stadd)
  27
  28#undef ATOMIC_OP
  29
  30#define ATOMIC_FETCH_OP(name, mb, op, asm_op, cl...)                    \
  31static inline int __lse_atomic_fetch_##op##name(int i, atomic_t *v)     \
  32{                                                                       \
  33        asm volatile(                                                   \
  34        __LSE_PREAMBLE                                                  \
  35"       " #asm_op #mb " %w[i], %w[i], %[v]"                             \
  36        : [i] "+r" (i), [v] "+Q" (v->counter)                           \
  37        : "r" (v)                                                       \
  38        : cl);                                                          \
  39                                                                        \
  40        return i;                                                       \
  41}
  42
  43#define ATOMIC_FETCH_OPS(op, asm_op)                                    \
  44        ATOMIC_FETCH_OP(_relaxed,   , op, asm_op)                       \
  45        ATOMIC_FETCH_OP(_acquire,  a, op, asm_op, "memory")             \
  46        ATOMIC_FETCH_OP(_release,  l, op, asm_op, "memory")             \
  47        ATOMIC_FETCH_OP(        , al, op, asm_op, "memory")
  48
  49ATOMIC_FETCH_OPS(andnot, ldclr)
  50ATOMIC_FETCH_OPS(or, ldset)
  51ATOMIC_FETCH_OPS(xor, ldeor)
  52ATOMIC_FETCH_OPS(add, ldadd)
  53
  54#undef ATOMIC_FETCH_OP
  55#undef ATOMIC_FETCH_OPS
  56
  57#define ATOMIC_OP_ADD_RETURN(name, mb, cl...)                           \
  58static inline int __lse_atomic_add_return##name(int i, atomic_t *v)     \
  59{                                                                       \
  60        u32 tmp;                                                        \
  61                                                                        \
  62        asm volatile(                                                   \
  63        __LSE_PREAMBLE                                                  \
  64        "       ldadd" #mb "    %w[i], %w[tmp], %[v]\n"                 \
  65        "       add     %w[i], %w[i], %w[tmp]"                          \
  66        : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)        \
  67        : "r" (v)                                                       \
  68        : cl);                                                          \
  69                                                                        \
  70        return i;                                                       \
  71}
  72
  73ATOMIC_OP_ADD_RETURN(_relaxed,   )
  74ATOMIC_OP_ADD_RETURN(_acquire,  a, "memory")
  75ATOMIC_OP_ADD_RETURN(_release,  l, "memory")
  76ATOMIC_OP_ADD_RETURN(        , al, "memory")
  77
  78#undef ATOMIC_OP_ADD_RETURN
  79
  80static inline void __lse_atomic_and(int i, atomic_t *v)
  81{
  82        asm volatile(
  83        __LSE_PREAMBLE
  84        "       mvn     %w[i], %w[i]\n"
  85        "       stclr   %w[i], %[v]"
  86        : [i] "+&r" (i), [v] "+Q" (v->counter)
  87        : "r" (v));
  88}
  89
  90#define ATOMIC_FETCH_OP_AND(name, mb, cl...)                            \
  91static inline int __lse_atomic_fetch_and##name(int i, atomic_t *v)      \
  92{                                                                       \
  93        asm volatile(                                                   \
  94        __LSE_PREAMBLE                                                  \
  95        "       mvn     %w[i], %w[i]\n"                                 \
  96        "       ldclr" #mb "    %w[i], %w[i], %[v]"                     \
  97        : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
  98        : "r" (v)                                                       \
  99        : cl);                                                          \
 100                                                                        \
 101        return i;                                                       \
 102}
 103
 104ATOMIC_FETCH_OP_AND(_relaxed,   )
 105ATOMIC_FETCH_OP_AND(_acquire,  a, "memory")
 106ATOMIC_FETCH_OP_AND(_release,  l, "memory")
 107ATOMIC_FETCH_OP_AND(        , al, "memory")
 108
 109#undef ATOMIC_FETCH_OP_AND
 110
 111static inline void __lse_atomic_sub(int i, atomic_t *v)
 112{
 113        asm volatile(
 114        __LSE_PREAMBLE
 115        "       neg     %w[i], %w[i]\n"
 116        "       stadd   %w[i], %[v]"
 117        : [i] "+&r" (i), [v] "+Q" (v->counter)
 118        : "r" (v));
 119}
 120
 121#define ATOMIC_OP_SUB_RETURN(name, mb, cl...)                           \
 122static inline int __lse_atomic_sub_return##name(int i, atomic_t *v)     \
 123{                                                                       \
 124        u32 tmp;                                                        \
 125                                                                        \
 126        asm volatile(                                                   \
 127        __LSE_PREAMBLE                                                  \
 128        "       neg     %w[i], %w[i]\n"                                 \
 129        "       ldadd" #mb "    %w[i], %w[tmp], %[v]\n"                 \
 130        "       add     %w[i], %w[i], %w[tmp]"                          \
 131        : [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)       \
 132        : "r" (v)                                                       \
 133        : cl);                                                  \
 134                                                                        \
 135        return i;                                                       \
 136}
 137
 138ATOMIC_OP_SUB_RETURN(_relaxed,   )
 139ATOMIC_OP_SUB_RETURN(_acquire,  a, "memory")
 140ATOMIC_OP_SUB_RETURN(_release,  l, "memory")
 141ATOMIC_OP_SUB_RETURN(        , al, "memory")
 142
 143#undef ATOMIC_OP_SUB_RETURN
 144
 145#define ATOMIC_FETCH_OP_SUB(name, mb, cl...)                            \
 146static inline int __lse_atomic_fetch_sub##name(int i, atomic_t *v)      \
 147{                                                                       \
 148        asm volatile(                                                   \
 149        __LSE_PREAMBLE                                                  \
 150        "       neg     %w[i], %w[i]\n"                                 \
 151        "       ldadd" #mb "    %w[i], %w[i], %[v]"                     \
 152        : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
 153        : "r" (v)                                                       \
 154        : cl);                                                          \
 155                                                                        \
 156        return i;                                                       \
 157}
 158
 159ATOMIC_FETCH_OP_SUB(_relaxed,   )
 160ATOMIC_FETCH_OP_SUB(_acquire,  a, "memory")
 161ATOMIC_FETCH_OP_SUB(_release,  l, "memory")
 162ATOMIC_FETCH_OP_SUB(        , al, "memory")
 163
 164#undef ATOMIC_FETCH_OP_SUB
 165
 166#define ATOMIC64_OP(op, asm_op)                                         \
 167static inline void __lse_atomic64_##op(s64 i, atomic64_t *v)            \
 168{                                                                       \
 169        asm volatile(                                                   \
 170        __LSE_PREAMBLE                                                  \
 171"       " #asm_op "     %[i], %[v]\n"                                   \
 172        : [i] "+r" (i), [v] "+Q" (v->counter)                           \
 173        : "r" (v));                                                     \
 174}
 175
 176ATOMIC64_OP(andnot, stclr)
 177ATOMIC64_OP(or, stset)
 178ATOMIC64_OP(xor, steor)
 179ATOMIC64_OP(add, stadd)
 180
 181#undef ATOMIC64_OP
 182
 183#define ATOMIC64_FETCH_OP(name, mb, op, asm_op, cl...)                  \
 184static inline long __lse_atomic64_fetch_##op##name(s64 i, atomic64_t *v)\
 185{                                                                       \
 186        asm volatile(                                                   \
 187        __LSE_PREAMBLE                                                  \
 188"       " #asm_op #mb " %[i], %[i], %[v]"                               \
 189        : [i] "+r" (i), [v] "+Q" (v->counter)                           \
 190        : "r" (v)                                                       \
 191        : cl);                                                          \
 192                                                                        \
 193        return i;                                                       \
 194}
 195
 196#define ATOMIC64_FETCH_OPS(op, asm_op)                                  \
 197        ATOMIC64_FETCH_OP(_relaxed,   , op, asm_op)                     \
 198        ATOMIC64_FETCH_OP(_acquire,  a, op, asm_op, "memory")           \
 199        ATOMIC64_FETCH_OP(_release,  l, op, asm_op, "memory")           \
 200        ATOMIC64_FETCH_OP(        , al, op, asm_op, "memory")
 201
 202ATOMIC64_FETCH_OPS(andnot, ldclr)
 203ATOMIC64_FETCH_OPS(or, ldset)
 204ATOMIC64_FETCH_OPS(xor, ldeor)
 205ATOMIC64_FETCH_OPS(add, ldadd)
 206
 207#undef ATOMIC64_FETCH_OP
 208#undef ATOMIC64_FETCH_OPS
 209
 210#define ATOMIC64_OP_ADD_RETURN(name, mb, cl...)                         \
 211static inline long __lse_atomic64_add_return##name(s64 i, atomic64_t *v)\
 212{                                                                       \
 213        unsigned long tmp;                                              \
 214                                                                        \
 215        asm volatile(                                                   \
 216        __LSE_PREAMBLE                                                  \
 217        "       ldadd" #mb "    %[i], %x[tmp], %[v]\n"                  \
 218        "       add     %[i], %[i], %x[tmp]"                            \
 219        : [i] "+r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)        \
 220        : "r" (v)                                                       \
 221        : cl);                                                          \
 222                                                                        \
 223        return i;                                                       \
 224}
 225
 226ATOMIC64_OP_ADD_RETURN(_relaxed,   )
 227ATOMIC64_OP_ADD_RETURN(_acquire,  a, "memory")
 228ATOMIC64_OP_ADD_RETURN(_release,  l, "memory")
 229ATOMIC64_OP_ADD_RETURN(        , al, "memory")
 230
 231#undef ATOMIC64_OP_ADD_RETURN
 232
 233static inline void __lse_atomic64_and(s64 i, atomic64_t *v)
 234{
 235        asm volatile(
 236        __LSE_PREAMBLE
 237        "       mvn     %[i], %[i]\n"
 238        "       stclr   %[i], %[v]"
 239        : [i] "+&r" (i), [v] "+Q" (v->counter)
 240        : "r" (v));
 241}
 242
 243#define ATOMIC64_FETCH_OP_AND(name, mb, cl...)                          \
 244static inline long __lse_atomic64_fetch_and##name(s64 i, atomic64_t *v) \
 245{                                                                       \
 246        asm volatile(                                                   \
 247        __LSE_PREAMBLE                                                  \
 248        "       mvn     %[i], %[i]\n"                                   \
 249        "       ldclr" #mb "    %[i], %[i], %[v]"                       \
 250        : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
 251        : "r" (v)                                                       \
 252        : cl);                                                          \
 253                                                                        \
 254        return i;                                                       \
 255}
 256
 257ATOMIC64_FETCH_OP_AND(_relaxed,   )
 258ATOMIC64_FETCH_OP_AND(_acquire,  a, "memory")
 259ATOMIC64_FETCH_OP_AND(_release,  l, "memory")
 260ATOMIC64_FETCH_OP_AND(        , al, "memory")
 261
 262#undef ATOMIC64_FETCH_OP_AND
 263
 264static inline void __lse_atomic64_sub(s64 i, atomic64_t *v)
 265{
 266        asm volatile(
 267        __LSE_PREAMBLE
 268        "       neg     %[i], %[i]\n"
 269        "       stadd   %[i], %[v]"
 270        : [i] "+&r" (i), [v] "+Q" (v->counter)
 271        : "r" (v));
 272}
 273
 274#define ATOMIC64_OP_SUB_RETURN(name, mb, cl...)                         \
 275static inline long __lse_atomic64_sub_return##name(s64 i, atomic64_t *v)        \
 276{                                                                       \
 277        unsigned long tmp;                                              \
 278                                                                        \
 279        asm volatile(                                                   \
 280        __LSE_PREAMBLE                                                  \
 281        "       neg     %[i], %[i]\n"                                   \
 282        "       ldadd" #mb "    %[i], %x[tmp], %[v]\n"                  \
 283        "       add     %[i], %[i], %x[tmp]"                            \
 284        : [i] "+&r" (i), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)       \
 285        : "r" (v)                                                       \
 286        : cl);                                                          \
 287                                                                        \
 288        return i;                                                       \
 289}
 290
 291ATOMIC64_OP_SUB_RETURN(_relaxed,   )
 292ATOMIC64_OP_SUB_RETURN(_acquire,  a, "memory")
 293ATOMIC64_OP_SUB_RETURN(_release,  l, "memory")
 294ATOMIC64_OP_SUB_RETURN(        , al, "memory")
 295
 296#undef ATOMIC64_OP_SUB_RETURN
 297
 298#define ATOMIC64_FETCH_OP_SUB(name, mb, cl...)                          \
 299static inline long __lse_atomic64_fetch_sub##name(s64 i, atomic64_t *v) \
 300{                                                                       \
 301        asm volatile(                                                   \
 302        __LSE_PREAMBLE                                                  \
 303        "       neg     %[i], %[i]\n"                                   \
 304        "       ldadd" #mb "    %[i], %[i], %[v]"                       \
 305        : [i] "+&r" (i), [v] "+Q" (v->counter)                          \
 306        : "r" (v)                                                       \
 307        : cl);                                                          \
 308                                                                        \
 309        return i;                                                       \
 310}
 311
 312ATOMIC64_FETCH_OP_SUB(_relaxed,   )
 313ATOMIC64_FETCH_OP_SUB(_acquire,  a, "memory")
 314ATOMIC64_FETCH_OP_SUB(_release,  l, "memory")
 315ATOMIC64_FETCH_OP_SUB(        , al, "memory")
 316
 317#undef ATOMIC64_FETCH_OP_SUB
 318
 319static inline s64 __lse_atomic64_dec_if_positive(atomic64_t *v)
 320{
 321        unsigned long tmp;
 322
 323        asm volatile(
 324        __LSE_PREAMBLE
 325        "1:     ldr     %x[tmp], %[v]\n"
 326        "       subs    %[ret], %x[tmp], #1\n"
 327        "       b.lt    2f\n"
 328        "       casal   %x[tmp], %[ret], %[v]\n"
 329        "       sub     %x[tmp], %x[tmp], #1\n"
 330        "       sub     %x[tmp], %x[tmp], %[ret]\n"
 331        "       cbnz    %x[tmp], 1b\n"
 332        "2:"
 333        : [ret] "+&r" (v), [v] "+Q" (v->counter), [tmp] "=&r" (tmp)
 334        :
 335        : "cc", "memory");
 336
 337        return (long)v;
 338}
 339
 340#define __CMPXCHG_CASE(w, sfx, name, sz, mb, cl...)                     \
 341static __always_inline u##sz                                            \
 342__lse__cmpxchg_case_##name##sz(volatile void *ptr,                      \
 343                                              u##sz old,                \
 344                                              u##sz new)                \
 345{                                                                       \
 346        register unsigned long x0 asm ("x0") = (unsigned long)ptr;      \
 347        register u##sz x1 asm ("x1") = old;                             \
 348        register u##sz x2 asm ("x2") = new;                             \
 349        unsigned long tmp;                                              \
 350                                                                        \
 351        asm volatile(                                                   \
 352        __LSE_PREAMBLE                                                  \
 353        "       mov     %" #w "[tmp], %" #w "[old]\n"                   \
 354        "       cas" #mb #sfx "\t%" #w "[tmp], %" #w "[new], %[v]\n"    \
 355        "       mov     %" #w "[ret], %" #w "[tmp]"                     \
 356        : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr),            \
 357          [tmp] "=&r" (tmp)                                             \
 358        : [old] "r" (x1), [new] "r" (x2)                                \
 359        : cl);                                                          \
 360                                                                        \
 361        return x0;                                                      \
 362}
 363
 364__CMPXCHG_CASE(w, b,     ,  8,   )
 365__CMPXCHG_CASE(w, h,     , 16,   )
 366__CMPXCHG_CASE(w,  ,     , 32,   )
 367__CMPXCHG_CASE(x,  ,     , 64,   )
 368__CMPXCHG_CASE(w, b, acq_,  8,  a, "memory")
 369__CMPXCHG_CASE(w, h, acq_, 16,  a, "memory")
 370__CMPXCHG_CASE(w,  , acq_, 32,  a, "memory")
 371__CMPXCHG_CASE(x,  , acq_, 64,  a, "memory")
 372__CMPXCHG_CASE(w, b, rel_,  8,  l, "memory")
 373__CMPXCHG_CASE(w, h, rel_, 16,  l, "memory")
 374__CMPXCHG_CASE(w,  , rel_, 32,  l, "memory")
 375__CMPXCHG_CASE(x,  , rel_, 64,  l, "memory")
 376__CMPXCHG_CASE(w, b,  mb_,  8, al, "memory")
 377__CMPXCHG_CASE(w, h,  mb_, 16, al, "memory")
 378__CMPXCHG_CASE(w,  ,  mb_, 32, al, "memory")
 379__CMPXCHG_CASE(x,  ,  mb_, 64, al, "memory")
 380
 381#undef __CMPXCHG_CASE
 382
 383#define __CMPXCHG_DBL(name, mb, cl...)                                  \
 384static __always_inline long                                             \
 385__lse__cmpxchg_double##name(unsigned long old1,                         \
 386                                         unsigned long old2,            \
 387                                         unsigned long new1,            \
 388                                         unsigned long new2,            \
 389                                         volatile void *ptr)            \
 390{                                                                       \
 391        unsigned long oldval1 = old1;                                   \
 392        unsigned long oldval2 = old2;                                   \
 393        register unsigned long x0 asm ("x0") = old1;                    \
 394        register unsigned long x1 asm ("x1") = old2;                    \
 395        register unsigned long x2 asm ("x2") = new1;                    \
 396        register unsigned long x3 asm ("x3") = new2;                    \
 397        register unsigned long x4 asm ("x4") = (unsigned long)ptr;      \
 398                                                                        \
 399        asm volatile(                                                   \
 400        __LSE_PREAMBLE                                                  \
 401        "       casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\
 402        "       eor     %[old1], %[old1], %[oldval1]\n"                 \
 403        "       eor     %[old2], %[old2], %[oldval2]\n"                 \
 404        "       orr     %[old1], %[old1], %[old2]"                      \
 405        : [old1] "+&r" (x0), [old2] "+&r" (x1),                         \
 406          [v] "+Q" (*(unsigned long *)ptr)                              \
 407        : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4),             \
 408          [oldval1] "r" (oldval1), [oldval2] "r" (oldval2)              \
 409        : cl);                                                          \
 410                                                                        \
 411        return x0;                                                      \
 412}
 413
 414__CMPXCHG_DBL(   ,   )
 415__CMPXCHG_DBL(_mb, al, "memory")
 416
 417#undef __CMPXCHG_DBL
 418
 419#endif  /* __ASM_ATOMIC_LSE_H */
 420