Commit f43f7b46eb101f50950cfcead0cb0b7a9c4f6823

Authored by Mathieu Desnoyers
Committed by Linus Torvalds
1 parent 5e97b9309b

local_t: alpha extension

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 329 additions and 24 deletions Side-by-side Diff

include/asm-alpha/local.h
... ... @@ -4,38 +4,116 @@
4 4 #include <linux/percpu.h>
5 5 #include <asm/atomic.h>
6 6  
7   -typedef atomic64_t local_t;
  7 +typedef struct
  8 +{
  9 + atomic_long_t a;
  10 +} local_t;
8 11  
9   -#define LOCAL_INIT(i) ATOMIC64_INIT(i)
10   -#define local_read(v) atomic64_read(v)
11   -#define local_set(v,i) atomic64_set(v,i)
  12 +#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) }
  13 +#define local_read(l) atomic_long_read(&(l)->a)
  14 +#define local_set(l,i) atomic_long_set(&(l)->a, (i))
  15 +#define local_inc(l) atomic_long_inc(&(l)->a)
  16 +#define local_dec(l) atomic_long_dec(&(l)->a)
  17 +#define local_add(i,l) atomic_long_add((i),(&(l)->a))
  18 +#define local_sub(i,l) atomic_long_sub((i),(&(l)->a))
12 19  
13   -#define local_inc(v) atomic64_inc(v)
14   -#define local_dec(v) atomic64_dec(v)
15   -#define local_add(i, v) atomic64_add(i, v)
16   -#define local_sub(i, v) atomic64_sub(i, v)
  20 +static __inline__ long local_add_return(long i, local_t * l)
  21 +{
  22 + long temp, result;
  23 + __asm__ __volatile__(
  24 + "1: ldq_l %0,%1\n"
  25 + " addq %0,%3,%2\n"
  26 + " addq %0,%3,%0\n"
  27 + " stq_c %0,%1\n"
  28 + " beq %0,2f\n"
  29 + ".subsection 2\n"
  30 + "2: br 1b\n"
  31 + ".previous"
  32 + :"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
  33 + :"Ir" (i), "m" (l->a.counter) : "memory");
  34 + return result;
  35 +}
17 36  
18   -#define __local_inc(v) ((v)->counter++)
19   -#define __local_dec(v) ((v)->counter++)
20   -#define __local_add(i,v) ((v)->counter+=(i))
21   -#define __local_sub(i,v) ((v)->counter-=(i))
  37 +static __inline__ long local_sub_return(long i, local_t * l)
  38 +{
  39 + long temp, result;
  40 + __asm__ __volatile__(
  41 + "1: ldq_l %0,%1\n"
  42 + " subq %0,%3,%2\n"
  43 + " subq %0,%3,%0\n"
  44 + " stq_c %0,%1\n"
  45 + " beq %0,2f\n"
  46 + ".subsection 2\n"
  47 + "2: br 1b\n"
  48 + ".previous"
  49 + :"=&r" (temp), "=m" (l->a.counter), "=&r" (result)
  50 + :"Ir" (i), "m" (l->a.counter) : "memory");
  51 + return result;
  52 +}
22 53  
  54 +#define local_cmpxchg(l, o, n) \
  55 + (cmpxchg_local(&((l)->a.counter), (o), (n)))
  56 +#define local_xchg(l, n) (xchg_local(&((l)->a.counter), (n)))
  57 +
  58 +/**
  59 + * local_add_unless - add unless the number is a given value
  60 + * @l: pointer of type local_t
  61 + * @a: the amount to add to l...
  62 + * @u: ...unless l is equal to u.
  63 + *
  64 + * Atomically adds @a to @l, so long as it was not @u.
  65 + * Returns non-zero if @l was not @u, and zero otherwise.
  66 + */
  67 +#define local_add_unless(l, a, u) \
  68 +({ \
  69 + long c, old; \
  70 + c = local_read(l); \
  71 + for (;;) { \
  72 + if (unlikely(c == (u))) \
  73 + break; \
  74 + old = local_cmpxchg((l), c, c + (a)); \
  75 + if (likely(old == c)) \
  76 + break; \
  77 + c = old; \
  78 + } \
  79 + c != (u); \
  80 +})
  81 +#define local_inc_not_zero(l) local_add_unless((l), 1, 0)
  82 +
  83 +#define local_add_negative(a, l) (local_add_return((a), (l)) < 0)
  84 +
  85 +#define local_dec_return(l) local_sub_return(1,(l))
  86 +
  87 +#define local_inc_return(l) local_add_return(1,(l))
  88 +
  89 +#define local_sub_and_test(i,l) (local_sub_return((i), (l)) == 0)
  90 +
  91 +#define local_inc_and_test(l) (local_add_return(1, (l)) == 0)
  92 +
  93 +#define local_dec_and_test(l) (local_sub_return(1, (l)) == 0)
  94 +
  95 +/* Verify if faster than atomic ops */
  96 +#define __local_inc(l) ((l)->a.counter++)
  97 +#define __local_dec(l) ((l)->a.counter++)
  98 +#define __local_add(i,l) ((l)->a.counter+=(i))
  99 +#define __local_sub(i,l) ((l)->a.counter-=(i))
  100 +
23 101 /* Use these for per-cpu local_t variables: on some archs they are
24 102 * much more efficient than these naive implementations. Note they take
25 103 * a variable, not an address.
26 104 */
27   -#define cpu_local_read(v) local_read(&__get_cpu_var(v))
28   -#define cpu_local_set(v, i) local_set(&__get_cpu_var(v), (i))
  105 +#define cpu_local_read(l) local_read(&__get_cpu_var(l))
  106 +#define cpu_local_set(l, i) local_set(&__get_cpu_var(l), (i))
29 107  
30   -#define cpu_local_inc(v) local_inc(&__get_cpu_var(v))
31   -#define cpu_local_dec(v) local_dec(&__get_cpu_var(v))
32   -#define cpu_local_add(i, v) local_add((i), &__get_cpu_var(v))
33   -#define cpu_local_sub(i, v) local_sub((i), &__get_cpu_var(v))
  108 +#define cpu_local_inc(l) local_inc(&__get_cpu_var(l))
  109 +#define cpu_local_dec(l) local_dec(&__get_cpu_var(l))
  110 +#define cpu_local_add(i, l) local_add((i), &__get_cpu_var(l))
  111 +#define cpu_local_sub(i, l) local_sub((i), &__get_cpu_var(l))
34 112  
35   -#define __cpu_local_inc(v) __local_inc(&__get_cpu_var(v))
36   -#define __cpu_local_dec(v) __local_dec(&__get_cpu_var(v))
37   -#define __cpu_local_add(i, v) __local_add((i), &__get_cpu_var(v))
38   -#define __cpu_local_sub(i, v) __local_sub((i), &__get_cpu_var(v))
  113 +#define __cpu_local_inc(l) __local_inc(&__get_cpu_var(l))
  114 +#define __cpu_local_dec(l) __local_dec(&__get_cpu_var(l))
  115 +#define __cpu_local_add(i, l) __local_add((i), &__get_cpu_var(l))
  116 +#define __cpu_local_sub(i, l) __local_sub((i), &__get_cpu_var(l))
39 117  
40 118 #endif /* _ALPHA_LOCAL_H */
include/asm-alpha/system.h
... ... @@ -443,6 +443,111 @@
443 443 (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
444 444 })
445 445  
  446 +static inline unsigned long
  447 +__xchg_u8_local(volatile char *m, unsigned long val)
  448 +{
  449 + unsigned long ret, tmp, addr64;
  450 +
  451 + __asm__ __volatile__(
  452 + " andnot %4,7,%3\n"
  453 + " insbl %1,%4,%1\n"
  454 + "1: ldq_l %2,0(%3)\n"
  455 + " extbl %2,%4,%0\n"
  456 + " mskbl %2,%4,%2\n"
  457 + " or %1,%2,%2\n"
  458 + " stq_c %2,0(%3)\n"
  459 + " beq %2,2f\n"
  460 + ".subsection 2\n"
  461 + "2: br 1b\n"
  462 + ".previous"
  463 + : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
  464 + : "r" ((long)m), "1" (val) : "memory");
  465 +
  466 + return ret;
  467 +}
  468 +
  469 +static inline unsigned long
  470 +__xchg_u16_local(volatile short *m, unsigned long val)
  471 +{
  472 + unsigned long ret, tmp, addr64;
  473 +
  474 + __asm__ __volatile__(
  475 + " andnot %4,7,%3\n"
  476 + " inswl %1,%4,%1\n"
  477 + "1: ldq_l %2,0(%3)\n"
  478 + " extwl %2,%4,%0\n"
  479 + " mskwl %2,%4,%2\n"
  480 + " or %1,%2,%2\n"
  481 + " stq_c %2,0(%3)\n"
  482 + " beq %2,2f\n"
  483 + ".subsection 2\n"
  484 + "2: br 1b\n"
  485 + ".previous"
  486 + : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
  487 + : "r" ((long)m), "1" (val) : "memory");
  488 +
  489 + return ret;
  490 +}
  491 +
  492 +static inline unsigned long
  493 +__xchg_u32_local(volatile int *m, unsigned long val)
  494 +{
  495 + unsigned long dummy;
  496 +
  497 + __asm__ __volatile__(
  498 + "1: ldl_l %0,%4\n"
  499 + " bis $31,%3,%1\n"
  500 + " stl_c %1,%2\n"
  501 + " beq %1,2f\n"
  502 + ".subsection 2\n"
  503 + "2: br 1b\n"
  504 + ".previous"
  505 + : "=&r" (val), "=&r" (dummy), "=m" (*m)
  506 + : "rI" (val), "m" (*m) : "memory");
  507 +
  508 + return val;
  509 +}
  510 +
  511 +static inline unsigned long
  512 +__xchg_u64_local(volatile long *m, unsigned long val)
  513 +{
  514 + unsigned long dummy;
  515 +
  516 + __asm__ __volatile__(
  517 + "1: ldq_l %0,%4\n"
  518 + " bis $31,%3,%1\n"
  519 + " stq_c %1,%2\n"
  520 + " beq %1,2f\n"
  521 + ".subsection 2\n"
  522 + "2: br 1b\n"
  523 + ".previous"
  524 + : "=&r" (val), "=&r" (dummy), "=m" (*m)
  525 + : "rI" (val), "m" (*m) : "memory");
  526 +
  527 + return val;
  528 +}
  529 +
  530 +#define __xchg_local(ptr, x, size) \
  531 +({ \
  532 + unsigned long __xchg__res; \
  533 + volatile void *__xchg__ptr = (ptr); \
  534 + switch (size) { \
  535 + case 1: __xchg__res = __xchg_u8_local(__xchg__ptr, x); break; \
  536 + case 2: __xchg__res = __xchg_u16_local(__xchg__ptr, x); break; \
  537 + case 4: __xchg__res = __xchg_u32_local(__xchg__ptr, x); break; \
  538 + case 8: __xchg__res = __xchg_u64_local(__xchg__ptr, x); break; \
  539 + default: __xchg_called_with_bad_pointer(); __xchg__res = x; \
  540 + } \
  541 + __xchg__res; \
  542 +})
  543 +
  544 +#define xchg_local(ptr,x) \
  545 + ({ \
  546 + __typeof__(*(ptr)) _x_ = (x); \
  547 + (__typeof__(*(ptr))) __xchg_local((ptr), (unsigned long)_x_, \
  548 + sizeof(*(ptr))); \
  549 + })
  550 +
446 551 #define tas(ptr) (xchg((ptr),1))
447 552  
448 553  
... ... @@ -593,6 +698,128 @@
593 698 __typeof__(*(ptr)) _o_ = (o); \
594 699 __typeof__(*(ptr)) _n_ = (n); \
595 700 (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
  701 + (unsigned long)_n_, sizeof(*(ptr))); \
  702 + })
  703 +
  704 +static inline unsigned long
  705 +__cmpxchg_u8_local(volatile char *m, long old, long new)
  706 +{
  707 + unsigned long prev, tmp, cmp, addr64;
  708 +
  709 + __asm__ __volatile__(
  710 + " andnot %5,7,%4\n"
  711 + " insbl %1,%5,%1\n"
  712 + "1: ldq_l %2,0(%4)\n"
  713 + " extbl %2,%5,%0\n"
  714 + " cmpeq %0,%6,%3\n"
  715 + " beq %3,2f\n"
  716 + " mskbl %2,%5,%2\n"
  717 + " or %1,%2,%2\n"
  718 + " stq_c %2,0(%4)\n"
  719 + " beq %2,3f\n"
  720 + "2:\n"
  721 + ".subsection 2\n"
  722 + "3: br 1b\n"
  723 + ".previous"
  724 + : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
  725 + : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
  726 +
  727 + return prev;
  728 +}
  729 +
  730 +static inline unsigned long
  731 +__cmpxchg_u16_local(volatile short *m, long old, long new)
  732 +{
  733 + unsigned long prev, tmp, cmp, addr64;
  734 +
  735 + __asm__ __volatile__(
  736 + " andnot %5,7,%4\n"
  737 + " inswl %1,%5,%1\n"
  738 + "1: ldq_l %2,0(%4)\n"
  739 + " extwl %2,%5,%0\n"
  740 + " cmpeq %0,%6,%3\n"
  741 + " beq %3,2f\n"
  742 + " mskwl %2,%5,%2\n"
  743 + " or %1,%2,%2\n"
  744 + " stq_c %2,0(%4)\n"
  745 + " beq %2,3f\n"
  746 + "2:\n"
  747 + ".subsection 2\n"
  748 + "3: br 1b\n"
  749 + ".previous"
  750 + : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
  751 + : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
  752 +
  753 + return prev;
  754 +}
  755 +
  756 +static inline unsigned long
  757 +__cmpxchg_u32_local(volatile int *m, int old, int new)
  758 +{
  759 + unsigned long prev, cmp;
  760 +
  761 + __asm__ __volatile__(
  762 + "1: ldl_l %0,%5\n"
  763 + " cmpeq %0,%3,%1\n"
  764 + " beq %1,2f\n"
  765 + " mov %4,%1\n"
  766 + " stl_c %1,%2\n"
  767 + " beq %1,3f\n"
  768 + "2:\n"
  769 + ".subsection 2\n"
  770 + "3: br 1b\n"
  771 + ".previous"
  772 + : "=&r"(prev), "=&r"(cmp), "=m"(*m)
  773 + : "r"((long) old), "r"(new), "m"(*m) : "memory");
  774 +
  775 + return prev;
  776 +}
  777 +
  778 +static inline unsigned long
  779 +__cmpxchg_u64_local(volatile long *m, unsigned long old, unsigned long new)
  780 +{
  781 + unsigned long prev, cmp;
  782 +
  783 + __asm__ __volatile__(
  784 + "1: ldq_l %0,%5\n"
  785 + " cmpeq %0,%3,%1\n"
  786 + " beq %1,2f\n"
  787 + " mov %4,%1\n"
  788 + " stq_c %1,%2\n"
  789 + " beq %1,3f\n"
  790 + "2:\n"
  791 + ".subsection 2\n"
  792 + "3: br 1b\n"
  793 + ".previous"
  794 + : "=&r"(prev), "=&r"(cmp), "=m"(*m)
  795 + : "r"((long) old), "r"(new), "m"(*m) : "memory");
  796 +
  797 + return prev;
  798 +}
  799 +
  800 +static __always_inline unsigned long
  801 +__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
  802 + int size)
  803 +{
  804 + switch (size) {
  805 + case 1:
  806 + return __cmpxchg_u8_local(ptr, old, new);
  807 + case 2:
  808 + return __cmpxchg_u16_local(ptr, old, new);
  809 + case 4:
  810 + return __cmpxchg_u32_local(ptr, old, new);
  811 + case 8:
  812 + return __cmpxchg_u64_local(ptr, old, new);
  813 + }
  814 + __cmpxchg_called_with_bad_pointer();
  815 + return old;
  816 +}
  817 +
  818 +#define cmpxchg_local(ptr,o,n) \
  819 + ({ \
  820 + __typeof__(*(ptr)) _o_ = (o); \
  821 + __typeof__(*(ptr)) _n_ = (n); \
  822 + (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \
596 823 (unsigned long)_n_, sizeof(*(ptr))); \
597 824 })
598 825