aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2015-07-14 08:25:05 -0400
committerVineet Gupta <vgupta@synopsys.com>2015-08-03 23:56:33 -0400
commitae7eae9e031206bde8645d038c76ad89e7d3fbcb (patch)
tree15e37fb62b3f2467148367e7fa73a1d7147e1d17
parent8ac0665fb6ff125efc4df08772317f7311a95ce5 (diff)
ARC: LLOCK/SCOND based spin_lock
Current spin_lock uses EXchange instruction to implement the atomic test and set of lock location (reads orig value and ST 1). This however forces the cacheline into exclusive state (because of the ST) and concurrent loops in multiple cores will bounce the line around between cores. Instead, use LLOCK/SCOND to implement the atomic test and set which is better as line is in shared state while lock is spinning on LLOCK The real motivation of this change however is to make way for future changes in atomics to implement delayed retry (with backoff). Initial experiment with delayed retry in atomics combined with orig EX based spinlock was a total disaster (broke even LMBench) as struct sock has a cache line sharing an atomic_t and spinlock. The tight spinning on lock, caused the atomic retry to keep backing off such that it would never finish. Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
-rw-r--r--arch/arc/include/asm/spinlock.h76
1 files changed, 69 insertions, 7 deletions
diff --git a/arch/arc/include/asm/spinlock.h b/arch/arc/include/asm/spinlock.h
index e1651df6a93d..4f6c90a0a68a 100644
--- a/arch/arc/include/asm/spinlock.h
+++ b/arch/arc/include/asm/spinlock.h
@@ -18,9 +18,68 @@
18#define arch_spin_unlock_wait(x) \ 18#define arch_spin_unlock_wait(x) \
19 do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) 19 do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0)
20 20
21#ifdef CONFIG_ARC_HAS_LLSC
22
23static inline void arch_spin_lock(arch_spinlock_t *lock)
24{
25 unsigned int val;
26
27 smp_mb();
28
29 __asm__ __volatile__(
30 "1: llock %[val], [%[slock]] \n"
31 " breq %[val], %[LOCKED], 1b \n" /* spin while LOCKED */
32 " scond %[LOCKED], [%[slock]] \n" /* acquire */
33 " bnz 1b \n"
34 " \n"
35 : [val] "=&r" (val)
36 : [slock] "r" (&(lock->slock)),
37 [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__)
38 : "memory", "cc");
39
40 smp_mb();
41}
42
43/* 1 - lock taken successfully */
44static inline int arch_spin_trylock(arch_spinlock_t *lock)
45{
46 unsigned int val, got_it = 0;
47
48 smp_mb();
49
50 __asm__ __volatile__(
51 "1: llock %[val], [%[slock]] \n"
52 " breq %[val], %[LOCKED], 4f \n" /* already LOCKED, just bail */
53 " scond %[LOCKED], [%[slock]] \n" /* acquire */
54 " bnz 1b \n"
55 " mov %[got_it], 1 \n"
56 "4: \n"
57 " \n"
58 : [val] "=&r" (val),
59 [got_it] "+&r" (got_it)
60 : [slock] "r" (&(lock->slock)),
61 [LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__)
62 : "memory", "cc");
63
64 smp_mb();
65
66 return got_it;
67}
68
69static inline void arch_spin_unlock(arch_spinlock_t *lock)
70{
71 smp_mb();
72
73 lock->slock = __ARCH_SPIN_LOCK_UNLOCKED__;
74
75 smp_mb();
76}
77
78#else /* !CONFIG_ARC_HAS_LLSC */
79
21static inline void arch_spin_lock(arch_spinlock_t *lock) 80static inline void arch_spin_lock(arch_spinlock_t *lock)
22{ 81{
23 unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__; 82 unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
24 83
25 /* 84 /*
26 * This smp_mb() is technically superfluous, we only need the one 85 * This smp_mb() is technically superfluous, we only need the one
@@ -33,7 +92,7 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
33 __asm__ __volatile__( 92 __asm__ __volatile__(
34 "1: ex %0, [%1] \n" 93 "1: ex %0, [%1] \n"
35 " breq %0, %2, 1b \n" 94 " breq %0, %2, 1b \n"
36 : "+&r" (tmp) 95 : "+&r" (val)
37 : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__) 96 : "r"(&(lock->slock)), "ir"(__ARCH_SPIN_LOCK_LOCKED__)
38 : "memory"); 97 : "memory");
39 98
@@ -48,26 +107,27 @@ static inline void arch_spin_lock(arch_spinlock_t *lock)
48 smp_mb(); 107 smp_mb();
49} 108}
50 109
110/* 1 - lock taken successfully */
51static inline int arch_spin_trylock(arch_spinlock_t *lock) 111static inline int arch_spin_trylock(arch_spinlock_t *lock)
52{ 112{
53 unsigned int tmp = __ARCH_SPIN_LOCK_LOCKED__; 113 unsigned int val = __ARCH_SPIN_LOCK_LOCKED__;
54 114
55 smp_mb(); 115 smp_mb();
56 116
57 __asm__ __volatile__( 117 __asm__ __volatile__(
58 "1: ex %0, [%1] \n" 118 "1: ex %0, [%1] \n"
59 : "+r" (tmp) 119 : "+r" (val)
60 : "r"(&(lock->slock)) 120 : "r"(&(lock->slock))
61 : "memory"); 121 : "memory");
62 122
63 smp_mb(); 123 smp_mb();
64 124
65 return (tmp == __ARCH_SPIN_LOCK_UNLOCKED__); 125 return (val == __ARCH_SPIN_LOCK_UNLOCKED__);
66} 126}
67 127
68static inline void arch_spin_unlock(arch_spinlock_t *lock) 128static inline void arch_spin_unlock(arch_spinlock_t *lock)
69{ 129{
70 unsigned int tmp = __ARCH_SPIN_LOCK_UNLOCKED__; 130 unsigned int val = __ARCH_SPIN_LOCK_UNLOCKED__;
71 131
72 /* 132 /*
73 * RELEASE barrier: given the instructions avail on ARCv2, full barrier 133 * RELEASE barrier: given the instructions avail on ARCv2, full barrier
@@ -77,7 +137,7 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
77 137
78 __asm__ __volatile__( 138 __asm__ __volatile__(
79 " ex %0, [%1] \n" 139 " ex %0, [%1] \n"
80 : "+r" (tmp) 140 : "+r" (val)
81 : "r"(&(lock->slock)) 141 : "r"(&(lock->slock))
82 : "memory"); 142 : "memory");
83 143
@@ -88,6 +148,8 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock)
88 smp_mb(); 148 smp_mb();
89} 149}
90 150
151#endif
152
91/* 153/*
92 * Read-write spinlocks, allowing multiple readers but only one writer. 154 * Read-write spinlocks, allowing multiple readers but only one writer.
93 * 155 *