Commit 7fa2ac3728ce828070fa3d5846c08157fe5ef431

Authored by Mathieu Desnoyers
Committed by Linus Torvalds
1 parent df0f65f02a

local_t m32r use architecture specific cmpxchg_local

On m32r, use the new cmpxchg_local as primitive for the local_cmpxchg
operation.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Acked-by: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 361 additions and 1 deletions Side-by-side Diff

include/asm-m32r/local.h
1 1 #ifndef __M32R_LOCAL_H
2 2 #define __M32R_LOCAL_H
3 3  
4   -#include <asm-generic/local.h>
  4 +/*
  5 + * linux/include/asm-m32r/local.h
  6 + *
  7 + * M32R version:
  8 + * Copyright (C) 2001, 2002 Hitoshi Yamamoto
  9 + * Copyright (C) 2004 Hirokazu Takata <takata at linux-m32r.org>
  10 + * Copyright (C) 2007 Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
  11 + */
  12 +
  13 +#include <linux/percpu.h>
  14 +#include <asm/assembler.h>
  15 +#include <asm/system.h>
  16 +#include <asm/local.h>
  17 +
  18 +/*
  19 + * Atomic operations that C can't guarantee us. Useful for
  20 + * resource counting etc..
  21 + */
  22 +
  23 +/*
  24 + * Make sure gcc doesn't try to be clever and move things around
  25 + * on us. We need to use _exactly_ the address the user gave us,
  26 + * not some alias that contains the same information.
  27 + */
  28 +typedef struct { volatile int counter; } local_t;
  29 +
  30 +#define LOCAL_INIT(i) { (i) }
  31 +
  32 +/**
  33 + * local_read - read local variable
  34 + * @l: pointer of type local_t
  35 + *
  36 + * Atomically reads the value of @l.
  37 + */
  38 +#define local_read(l) ((l)->counter)
  39 +
  40 +/**
  41 + * local_set - set local variable
  42 + * @l: pointer of type local_t
  43 + * @i: required value
  44 + *
  45 + * Atomically sets the value of @l to @i.
  46 + */
  47 +#define local_set(l, i) (((l)->counter) = (i))
  48 +
  49 +/**
  50 + * local_add_return - add long to local variable and return it
  51 + * @i: long value to add
  52 + * @l: pointer of type local_t
  53 + *
  54 + * Atomically adds @i to @l and return (@i + @l).
  55 + */
  56 +static inline long local_add_return(long i, local_t *l)
  57 +{
  58 + unsigned long flags;
  59 + long result;
  60 +
  61 + local_irq_save(flags);
  62 + __asm__ __volatile__ (
  63 + "# local_add_return \n\t"
  64 + DCACHE_CLEAR("%0", "r4", "%1")
  65 + "ld %0, @%1; \n\t"
  66 + "add %0, %2; \n\t"
  67 + "st %0, @%1; \n\t"
  68 + : "=&r" (result)
  69 + : "r" (&l->counter), "r" (i)
  70 + : "memory"
  71 +#ifdef CONFIG_CHIP_M32700_TS1
  72 + , "r4"
  73 +#endif /* CONFIG_CHIP_M32700_TS1 */
  74 + );
  75 + local_irq_restore(flags);
  76 +
  77 + return result;
  78 +}
  79 +
  80 +/**
  81 + * local_sub_return - subtract long from local variable and return it
  82 + * @i: long value to subtract
  83 + * @l: pointer of type local_t
  84 + *
  85 + * Atomically subtracts @i from @l and return (@l - @i).
  86 + */
  87 +static inline long local_sub_return(long i, local_t *l)
  88 +{
  89 + unsigned long flags;
  90 + long result;
  91 +
  92 + local_irq_save(flags);
  93 + __asm__ __volatile__ (
  94 + "# local_sub_return \n\t"
  95 + DCACHE_CLEAR("%0", "r4", "%1")
  96 + "ld %0, @%1; \n\t"
  97 + "sub %0, %2; \n\t"
  98 + "st %0, @%1; \n\t"
  99 + : "=&r" (result)
  100 + : "r" (&l->counter), "r" (i)
  101 + : "memory"
  102 +#ifdef CONFIG_CHIP_M32700_TS1
  103 + , "r4"
  104 +#endif /* CONFIG_CHIP_M32700_TS1 */
  105 + );
  106 + local_irq_restore(flags);
  107 +
  108 + return result;
  109 +}
  110 +
  111 +/**
  112 + * local_add - add long to local variable
  113 + * @i: long value to add
  114 + * @l: pointer of type local_t
  115 + *
  116 + * Atomically adds @i to @l.
  117 + */
  118 +#define local_add(i, l) ((void) local_add_return((i), (l)))
  119 +
  120 +/**
  121 + * local_sub - subtract the local variable
  122 + * @i: long value to subtract
  123 + * @l: pointer of type local_t
  124 + *
  125 + * Atomically subtracts @i from @l.
  126 + */
  127 +#define local_sub(i, l) ((void) local_sub_return((i), (l)))
  128 +
  129 +/**
  130 + * local_sub_and_test - subtract value from variable and test result
  131 + * @i: integer value to subtract
  132 + * @l: pointer of type local_t
  133 + *
  134 + * Atomically subtracts @i from @l and returns
  135 + * true if the result is zero, or false for all
  136 + * other cases.
  137 + */
  138 +#define local_sub_and_test(i, l) (local_sub_return((i), (l)) == 0)
  139 +
  140 +/**
  141 + * local_inc_return - increment local variable and return it
  142 + * @l: pointer of type local_t
  143 + *
  144 + * Atomically increments @l by 1 and returns the result.
  145 + */
  146 +static inline long local_inc_return(local_t *l)
  147 +{
  148 + unsigned long flags;
  149 + long result;
  150 +
  151 + local_irq_save(flags);
  152 + __asm__ __volatile__ (
  153 + "# local_inc_return \n\t"
  154 + DCACHE_CLEAR("%0", "r4", "%1")
  155 + "ld %0, @%1; \n\t"
  156 + "addi %0, #1; \n\t"
  157 + "st %0, @%1; \n\t"
  158 + : "=&r" (result)
  159 + : "r" (&l->counter)
  160 + : "memory"
  161 +#ifdef CONFIG_CHIP_M32700_TS1
  162 + , "r4"
  163 +#endif /* CONFIG_CHIP_M32700_TS1 */
  164 + );
  165 + local_irq_restore(flags);
  166 +
  167 + return result;
  168 +}
  169 +
  170 +/**
  171 + * local_dec_return - decrement local variable and return it
  172 + * @l: pointer of type local_t
  173 + *
  174 + * Atomically decrements @l by 1 and returns the result.
  175 + */
  176 +static inline long local_dec_return(local_t *l)
  177 +{
  178 + unsigned long flags;
  179 + long result;
  180 +
  181 + local_irq_save(flags);
  182 + __asm__ __volatile__ (
  183 + "# local_dec_return \n\t"
  184 + DCACHE_CLEAR("%0", "r4", "%1")
  185 + "ld %0, @%1; \n\t"
  186 + "addi %0, #-1; \n\t"
  187 + "st %0, @%1; \n\t"
  188 + : "=&r" (result)
  189 + : "r" (&l->counter)
  190 + : "memory"
  191 +#ifdef CONFIG_CHIP_M32700_TS1
  192 + , "r4"
  193 +#endif /* CONFIG_CHIP_M32700_TS1 */
  194 + );
  195 + local_irq_restore(flags);
  196 +
  197 + return result;
  198 +}
  199 +
  200 +/**
  201 + * local_inc - increment local variable
  202 + * @l: pointer of type local_t
  203 + *
  204 + * Atomically increments @l by 1.
  205 + */
  206 +#define local_inc(l) ((void)local_inc_return(l))
  207 +
  208 +/**
  209 + * local_dec - decrement local variable
  210 + * @l: pointer of type local_t
  211 + *
  212 + * Atomically decrements @l by 1.
  213 + */
  214 +#define local_dec(l) ((void)local_dec_return(l))
  215 +
  216 +/**
  217 + * local_inc_and_test - increment and test
  218 + * @l: pointer of type local_t
  219 + *
  220 + * Atomically increments @l by 1
  221 + * and returns true if the result is zero, or false for all
  222 + * other cases.
  223 + */
  224 +#define local_inc_and_test(l) (local_inc_return(l) == 0)
  225 +
  226 +/**
  227 + * local_dec_and_test - decrement and test
  228 + * @l: pointer of type local_t
  229 + *
  230 + * Atomically decrements @l by 1 and
  231 + * returns true if the result is 0, or false for all
  232 + * other cases.
  233 + */
  234 +#define local_dec_and_test(l) (local_dec_return(l) == 0)
  235 +
  236 +/**
  237 + * local_add_negative - add and test if negative
  238 + * @l: pointer of type local_t
  239 + * @i: integer value to add
  240 + *
  241 + * Atomically adds @i to @l and returns true
  242 + * if the result is negative, or false when
  243 + * result is greater than or equal to zero.
  244 + */
  245 +#define local_add_negative(i, l) (local_add_return((i), (l)) < 0)
  246 +
  247 +#define local_cmpxchg(l, o, n) (cmpxchg_local(&((l)->counter), (o), (n)))
  248 +#define local_xchg(v, new) (xchg_local(&((l)->counter), new))
  249 +
  250 +/**
  251 + * local_add_unless - add unless the number is a given value
  252 + * @l: pointer of type local_t
  253 + * @a: the amount to add to l...
  254 + * @u: ...unless l is equal to u.
  255 + *
  256 + * Atomically adds @a to @l, so long as it was not @u.
  257 + * Returns non-zero if @l was not @u, and zero otherwise.
  258 + */
  259 +static inline int local_add_unless(local_t *l, long a, long u)
  260 +{
  261 + long c, old;
  262 + c = local_read(l);
  263 + for (;;) {
  264 + if (unlikely(c == (u)))
  265 + break;
  266 + old = local_cmpxchg((l), c, c + (a));
  267 + if (likely(old == c))
  268 + break;
  269 + c = old;
  270 + }
  271 + return c != (u);
  272 +}
  273 +
  274 +#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
  275 +
  276 +static inline void local_clear_mask(unsigned long mask, local_t *addr)
  277 +{
  278 + unsigned long flags;
  279 + unsigned long tmp;
  280 +
  281 + local_irq_save(flags);
  282 + __asm__ __volatile__ (
  283 + "# local_clear_mask \n\t"
  284 + DCACHE_CLEAR("%0", "r5", "%1")
  285 + "ld %0, @%1; \n\t"
  286 + "and %0, %2; \n\t"
  287 + "st %0, @%1; \n\t"
  288 + : "=&r" (tmp)
  289 + : "r" (addr), "r" (~mask)
  290 + : "memory"
  291 +#ifdef CONFIG_CHIP_M32700_TS1
  292 + , "r5"
  293 +#endif /* CONFIG_CHIP_M32700_TS1 */
  294 + );
  295 + local_irq_restore(flags);
  296 +}
  297 +
  298 +static inline void local_set_mask(unsigned long mask, local_t *addr)
  299 +{
  300 + unsigned long flags;
  301 + unsigned long tmp;
  302 +
  303 + local_irq_save(flags);
  304 + __asm__ __volatile__ (
  305 + "# local_set_mask \n\t"
  306 + DCACHE_CLEAR("%0", "r5", "%1")
  307 + "ld %0, @%1; \n\t"
  308 + "or %0, %2; \n\t"
  309 + "st %0, @%1; \n\t"
  310 + : "=&r" (tmp)
  311 + : "r" (addr), "r" (mask)
  312 + : "memory"
  313 +#ifdef CONFIG_CHIP_M32700_TS1
  314 + , "r5"
  315 +#endif /* CONFIG_CHIP_M32700_TS1 */
  316 + );
  317 + local_irq_restore(flags);
  318 +}
  319 +
  320 +/* Atomic operations are already serializing on m32r */
  321 +#define smp_mb__before_local_dec() barrier()
  322 +#define smp_mb__after_local_dec() barrier()
  323 +#define smp_mb__before_local_inc() barrier()
  324 +#define smp_mb__after_local_inc() barrier()
  325 +
  326 +/* Use these for per-cpu local_t variables: on some archs they are
  327 + * much more efficient than these naive implementations. Note they take
  328 + * a variable, not an address.
  329 + */
  330 +
  331 +#define __local_inc(l) ((l)->a.counter++)
  332 +#define __local_dec(l) ((l)->a.counter++)
  333 +#define __local_add(i, l) ((l)->a.counter += (i))
  334 +#define __local_sub(i, l) ((l)->a.counter -= (i))
  335 +
  336 +/* Use these for per-cpu local_t variables: on some archs they are
  337 + * much more efficient than these naive implementations. Note they take
  338 + * a variable, not an address.
  339 + */
  340 +
  341 +/* Need to disable preemption for the cpu local counters otherwise we could
  342 + still access a variable of a previous CPU in a non local way. */
  343 +#define cpu_local_wrap_v(l) \
  344 + ({ local_t res__; \
  345 + preempt_disable(); \
  346 + res__ = (l); \
  347 + preempt_enable(); \
  348 + res__; })
  349 +#define cpu_local_wrap(l) \
  350 + ({ preempt_disable(); \
  351 + l; \
  352 + preempt_enable(); }) \
  353 +
  354 +#define cpu_local_read(l) cpu_local_wrap_v(local_read(&__get_cpu_var(l)))
  355 +#define cpu_local_set(l, i) cpu_local_wrap(local_set(&__get_cpu_var(l), (i)))
  356 +#define cpu_local_inc(l) cpu_local_wrap(local_inc(&__get_cpu_var(l)))
  357 +#define cpu_local_dec(l) cpu_local_wrap(local_dec(&__get_cpu_var(l)))
  358 +#define cpu_local_add(i, l) cpu_local_wrap(local_add((i), &__get_cpu_var(l)))
  359 +#define cpu_local_sub(i, l) cpu_local_wrap(local_sub((i), &__get_cpu_var(l)))
  360 +
  361 +#define __cpu_local_inc(l) cpu_local_inc(l)
  362 +#define __cpu_local_dec(l) cpu_local_dec(l)
  363 +#define __cpu_local_add(i, l) cpu_local_add((i), (l))
  364 +#define __cpu_local_sub(i, l) cpu_local_sub((i), (l))
5 365  
6 366 #endif /* __M32R_LOCAL_H */