linux/arch/mn10300/include/asm/atomic.h
<<
>>
Prefs
   1/* MN10300 Atomic counter operations
   2 *
   3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11#ifndef _ASM_ATOMIC_H
  12#define _ASM_ATOMIC_H
  13
  14#include <asm/irqflags.h>
  15
  16#ifndef __ASSEMBLY__
  17
  18#ifdef CONFIG_SMP
  19#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
  20static inline
  21unsigned long __xchg(volatile unsigned long *m, unsigned long val)
  22{
  23        unsigned long status;
  24        unsigned long oldval;
  25
  26        asm volatile(
  27                "1:     mov     %4,(_AAR,%3)    \n"
  28                "       mov     (_ADR,%3),%1    \n"
  29                "       mov     %5,(_ADR,%3)    \n"
  30                "       mov     (_ADR,%3),%0    \n"     /* flush */
  31                "       mov     (_ASR,%3),%0    \n"
  32                "       or      %0,%0           \n"
  33                "       bne     1b              \n"
  34                : "=&r"(status), "=&r"(oldval), "=m"(*m)
  35                : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m), "r"(val)
  36                : "memory", "cc");
  37
  38        return oldval;
  39}
  40
  41static inline unsigned long __cmpxchg(volatile unsigned long *m,
  42                                      unsigned long old, unsigned long new)
  43{
  44        unsigned long status;
  45        unsigned long oldval;
  46
  47        asm volatile(
  48                "1:     mov     %4,(_AAR,%3)    \n"
  49                "       mov     (_ADR,%3),%1    \n"
  50                "       cmp     %5,%1           \n"
  51                "       bne     2f              \n"
  52                "       mov     %6,(_ADR,%3)    \n"
  53                "2:     mov     (_ADR,%3),%0    \n"     /* flush */
  54                "       mov     (_ASR,%3),%0    \n"
  55                "       or      %0,%0           \n"
  56                "       bne     1b              \n"
  57                : "=&r"(status), "=&r"(oldval), "=m"(*m)
  58                : "a"(ATOMIC_OPS_BASE_ADDR), "r"(m),
  59                  "r"(old), "r"(new)
  60                : "memory", "cc");
  61
  62        return oldval;
  63}
  64#else  /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
  65#error "No SMP atomic operation support!"
  66#endif /* CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT */
  67
  68#else  /* CONFIG_SMP */
  69
  70/*
  71 * Emulate xchg for non-SMP MN10300
  72 */
  73struct __xchg_dummy { unsigned long a[100]; };
  74#define __xg(x) ((struct __xchg_dummy *)(x))
  75
  76static inline
  77unsigned long __xchg(volatile unsigned long *m, unsigned long val)
  78{
  79        unsigned long oldval;
  80        unsigned long flags;
  81
  82        flags = arch_local_cli_save();
  83        oldval = *m;
  84        *m = val;
  85        arch_local_irq_restore(flags);
  86        return oldval;
  87}
  88
  89/*
  90 * Emulate cmpxchg for non-SMP MN10300
  91 */
  92static inline unsigned long __cmpxchg(volatile unsigned long *m,
  93                                      unsigned long old, unsigned long new)
  94{
  95        unsigned long oldval;
  96        unsigned long flags;
  97
  98        flags = arch_local_cli_save();
  99        oldval = *m;
 100        if (oldval == old)
 101                *m = new;
 102        arch_local_irq_restore(flags);
 103        return oldval;
 104}
 105
 106#endif /* CONFIG_SMP */
 107
 108#define xchg(ptr, v)                                            \
 109        ((__typeof__(*(ptr))) __xchg((unsigned long *)(ptr),    \
 110                                     (unsigned long)(v)))
 111
 112#define cmpxchg(ptr, o, n)                                      \
 113        ((__typeof__(*(ptr))) __cmpxchg((unsigned long *)(ptr), \
 114                                        (unsigned long)(o),     \
 115                                        (unsigned long)(n)))
 116
 117#define atomic_xchg(ptr, v)             (xchg(&(ptr)->counter, (v)))
 118#define atomic_cmpxchg(v, old, new)     (cmpxchg(&((v)->counter), (old), (new)))
 119
 120#endif /* !__ASSEMBLY__ */
 121
 122#ifndef CONFIG_SMP
 123#include <asm-generic/atomic.h>
 124#else
 125
 126/*
 127 * Atomic operations that C can't guarantee us.  Useful for
 128 * resource counting etc..
 129 */
 130
 131#define ATOMIC_INIT(i)  { (i) }
 132
 133#ifdef __KERNEL__
 134
 135/**
 136 * atomic_read - read atomic variable
 137 * @v: pointer of type atomic_t
 138 *
 139 * Atomically reads the value of @v.  Note that the guaranteed
 140 * useful range of an atomic_t is only 24 bits.
 141 */
 142#define atomic_read(v)  (ACCESS_ONCE((v)->counter))
 143
 144/**
 145 * atomic_set - set atomic variable
 146 * @v: pointer of type atomic_t
 147 * @i: required value
 148 *
 149 * Atomically sets the value of @v to @i.  Note that the guaranteed
 150 * useful range of an atomic_t is only 24 bits.
 151 */
 152#define atomic_set(v, i) (((v)->counter) = (i))
 153
 154/**
 155 * atomic_add_return - add integer to atomic variable
 156 * @i: integer value to add
 157 * @v: pointer of type atomic_t
 158 *
 159 * Atomically adds @i to @v and returns the result
 160 * Note that the guaranteed useful range of an atomic_t is only 24 bits.
 161 */
 162static inline int atomic_add_return(int i, atomic_t *v)
 163{
 164        int retval;
 165#ifdef CONFIG_SMP
 166        int status;
 167
 168        asm volatile(
 169                "1:     mov     %4,(_AAR,%3)    \n"
 170                "       mov     (_ADR,%3),%1    \n"
 171                "       add     %5,%1           \n"
 172                "       mov     %1,(_ADR,%3)    \n"
 173                "       mov     (_ADR,%3),%0    \n"     /* flush */
 174                "       mov     (_ASR,%3),%0    \n"
 175                "       or      %0,%0           \n"
 176                "       bne     1b              \n"
 177                : "=&r"(status), "=&r"(retval), "=m"(v->counter)
 178                : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
 179                : "memory", "cc");
 180
 181#else
 182        unsigned long flags;
 183
 184        flags = arch_local_cli_save();
 185        retval = v->counter;
 186        retval += i;
 187        v->counter = retval;
 188        arch_local_irq_restore(flags);
 189#endif
 190        return retval;
 191}
 192
 193/**
 194 * atomic_sub_return - subtract integer from atomic variable
 195 * @i: integer value to subtract
 196 * @v: pointer of type atomic_t
 197 *
 198 * Atomically subtracts @i from @v and returns the result
 199 * Note that the guaranteed useful range of an atomic_t is only 24 bits.
 200 */
 201static inline int atomic_sub_return(int i, atomic_t *v)
 202{
 203        int retval;
 204#ifdef CONFIG_SMP
 205        int status;
 206
 207        asm volatile(
 208                "1:     mov     %4,(_AAR,%3)    \n"
 209                "       mov     (_ADR,%3),%1    \n"
 210                "       sub     %5,%1           \n"
 211                "       mov     %1,(_ADR,%3)    \n"
 212                "       mov     (_ADR,%3),%0    \n"     /* flush */
 213                "       mov     (_ASR,%3),%0    \n"
 214                "       or      %0,%0           \n"
 215                "       bne     1b              \n"
 216                : "=&r"(status), "=&r"(retval), "=m"(v->counter)
 217                : "a"(ATOMIC_OPS_BASE_ADDR), "r"(&v->counter), "r"(i)
 218                : "memory", "cc");
 219
 220#else
 221        unsigned long flags;
 222        flags = arch_local_cli_save();
 223        retval = v->counter;
 224        retval -= i;
 225        v->counter = retval;
 226        arch_local_irq_restore(flags);
 227#endif
 228        return retval;
 229}
 230
 231static inline int atomic_add_negative(int i, atomic_t *v)
 232{
 233        return atomic_add_return(i, v) < 0;
 234}
 235
 236static inline void atomic_add(int i, atomic_t *v)
 237{
 238        atomic_add_return(i, v);
 239}
 240
 241static inline void atomic_sub(int i, atomic_t *v)
 242{
 243        atomic_sub_return(i, v);
 244}
 245
 246static inline void atomic_inc(atomic_t *v)
 247{
 248        atomic_add_return(1, v);
 249}
 250
 251static inline void atomic_dec(atomic_t *v)
 252{
 253        atomic_sub_return(1, v);
 254}
 255
 256#define atomic_dec_return(v)            atomic_sub_return(1, (v))
 257#define atomic_inc_return(v)            atomic_add_return(1, (v))
 258
 259#define atomic_sub_and_test(i, v)       (atomic_sub_return((i), (v)) == 0)
 260#define atomic_dec_and_test(v)          (atomic_sub_return(1, (v)) == 0)
 261#define atomic_inc_and_test(v)          (atomic_add_return(1, (v)) == 0)
 262
 263#define __atomic_add_unless(v, a, u)                            \
 264({                                                              \
 265        int c, old;                                             \
 266        c = atomic_read(v);                                     \
 267        while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \
 268                c = old;                                        \
 269        c;                                                      \
 270})
 271
 272
 273/**
 274 * atomic_clear_mask - Atomically clear bits in memory
 275 * @mask: Mask of the bits to be cleared
 276 * @v: pointer to word in memory
 277 *
 278 * Atomically clears the bits set in mask from the memory word specified.
 279 */
 280static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
 281{
 282#ifdef CONFIG_SMP
 283        int status;
 284
 285        asm volatile(
 286                "1:     mov     %3,(_AAR,%2)    \n"
 287                "       mov     (_ADR,%2),%0    \n"
 288                "       and     %4,%0           \n"
 289                "       mov     %0,(_ADR,%2)    \n"
 290                "       mov     (_ADR,%2),%0    \n"     /* flush */
 291                "       mov     (_ASR,%2),%0    \n"
 292                "       or      %0,%0           \n"
 293                "       bne     1b              \n"
 294                : "=&r"(status), "=m"(*addr)
 295                : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask)
 296                : "memory", "cc");
 297#else
 298        unsigned long flags;
 299
 300        mask = ~mask;
 301        flags = arch_local_cli_save();
 302        *addr &= mask;
 303        arch_local_irq_restore(flags);
 304#endif
 305}
 306
 307/**
 308 * atomic_set_mask - Atomically set bits in memory
 309 * @mask: Mask of the bits to be set
 310 * @v: pointer to word in memory
 311 *
 312 * Atomically sets the bits set in mask from the memory word specified.
 313 */
 314static inline void atomic_set_mask(unsigned long mask, unsigned long *addr)
 315{
 316#ifdef CONFIG_SMP
 317        int status;
 318
 319        asm volatile(
 320                "1:     mov     %3,(_AAR,%2)    \n"
 321                "       mov     (_ADR,%2),%0    \n"
 322                "       or      %4,%0           \n"
 323                "       mov     %0,(_ADR,%2)    \n"
 324                "       mov     (_ADR,%2),%0    \n"     /* flush */
 325                "       mov     (_ASR,%2),%0    \n"
 326                "       or      %0,%0           \n"
 327                "       bne     1b              \n"
 328                : "=&r"(status), "=m"(*addr)
 329                : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask)
 330                : "memory", "cc");
 331#else
 332        unsigned long flags;
 333
 334        flags = arch_local_cli_save();
 335        *addr |= mask;
 336        arch_local_irq_restore(flags);
 337#endif
 338}
 339
 340/* Atomic operations are already serializing on MN10300??? */
 341#define smp_mb__before_atomic_dec()     barrier()
 342#define smp_mb__after_atomic_dec()      barrier()
 343#define smp_mb__before_atomic_inc()     barrier()
 344#define smp_mb__after_atomic_inc()      barrier()
 345
 346#endif /* __KERNEL__ */
 347#endif /* CONFIG_SMP */
 348#endif /* _ASM_ATOMIC_H */
 349