blob: fa889b64bd112699cbf03d2bfa7a3d0627d35217 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14/*
15 * Part of this this code is based on the standard ARM spinlock
16 * implementation (asm/spinlock.h) found in the 2.6.29 kernel.
17 */
18
19#ifndef __ASM__ARCH_QC_REMOTE_SPINLOCK_H
20#define __ASM__ARCH_QC_REMOTE_SPINLOCK_H
21
22#include <linux/types.h>
23
24/* Remote spinlock definitions. */
25
26struct dek_spinlock {
27 volatile uint8_t self_lock;
28 volatile uint8_t other_lock;
29 volatile uint8_t next_yield;
30 uint8_t pad;
31};
32
33typedef union {
34 volatile uint32_t lock;
35 struct dek_spinlock dek;
36} raw_remote_spinlock_t;
37
38typedef raw_remote_spinlock_t *_remote_spinlock_t;
39
40#define remote_spinlock_id_t const char *
41
42static inline void __raw_remote_ex_spin_lock(raw_remote_spinlock_t *lock)
43{
44 unsigned long tmp;
45
46 __asm__ __volatile__(
47"1: ldrex %0, [%1]\n"
48" teq %0, #0\n"
49" strexeq %0, %2, [%1]\n"
50" teqeq %0, #0\n"
51" bne 1b"
52 : "=&r" (tmp)
53 : "r" (&lock->lock), "r" (1)
54 : "cc");
55
56 smp_mb();
57}
58
59static inline int __raw_remote_ex_spin_trylock(raw_remote_spinlock_t *lock)
60{
61 unsigned long tmp;
62
63 __asm__ __volatile__(
64" ldrex %0, [%1]\n"
65" teq %0, #0\n"
66" strexeq %0, %2, [%1]\n"
67 : "=&r" (tmp)
68 : "r" (&lock->lock), "r" (1)
69 : "cc");
70
71 if (tmp == 0) {
72 smp_mb();
73 return 1;
74 }
75 return 0;
76}
77
78static inline void __raw_remote_ex_spin_unlock(raw_remote_spinlock_t *lock)
79{
80 smp_mb();
81
82 __asm__ __volatile__(
83" str %1, [%0]\n"
84 :
85 : "r" (&lock->lock), "r" (0)
86 : "cc");
87}
88
89static inline void __raw_remote_swp_spin_lock(raw_remote_spinlock_t *lock)
90{
91 unsigned long tmp;
92
93 __asm__ __volatile__(
94"1: swp %0, %2, [%1]\n"
95" teq %0, #0\n"
96" bne 1b"
97 : "=&r" (tmp)
98 : "r" (&lock->lock), "r" (1)
99 : "cc");
100
101 smp_mb();
102}
103
104static inline int __raw_remote_swp_spin_trylock(raw_remote_spinlock_t *lock)
105{
106 unsigned long tmp;
107
108 __asm__ __volatile__(
109" swp %0, %2, [%1]\n"
110 : "=&r" (tmp)
111 : "r" (&lock->lock), "r" (1)
112 : "cc");
113
114 if (tmp == 0) {
115 smp_mb();
116 return 1;
117 }
118 return 0;
119}
120
121static inline void __raw_remote_swp_spin_unlock(raw_remote_spinlock_t *lock)
122{
123 smp_mb();
124
125 __asm__ __volatile__(
126" str %1, [%0]"
127 :
128 : "r" (&lock->lock), "r" (0)
129 : "cc");
130}
131
132#define DEK_LOCK_REQUEST 1
133#define DEK_LOCK_YIELD (!DEK_LOCK_REQUEST)
134#define DEK_YIELD_TURN_SELF 0
135static inline void __raw_remote_dek_spin_lock(raw_remote_spinlock_t *lock)
136{
137 lock->dek.self_lock = DEK_LOCK_REQUEST;
138
139 while (lock->dek.other_lock) {
140
141 if (lock->dek.next_yield == DEK_YIELD_TURN_SELF)
142 lock->dek.self_lock = DEK_LOCK_YIELD;
143
144 while (lock->dek.other_lock)
145 ;
146
147 lock->dek.self_lock = DEK_LOCK_REQUEST;
148 }
149 lock->dek.next_yield = DEK_YIELD_TURN_SELF;
150
151 smp_mb();
152}
153
154static inline int __raw_remote_dek_spin_trylock(raw_remote_spinlock_t *lock)
155{
156 lock->dek.self_lock = DEK_LOCK_REQUEST;
157
158 if (lock->dek.other_lock) {
159 lock->dek.self_lock = DEK_LOCK_YIELD;
160 return 0;
161 }
162
163 lock->dek.next_yield = DEK_YIELD_TURN_SELF;
164
165 smp_mb();
166 return 1;
167}
168
169static inline void __raw_remote_dek_spin_unlock(raw_remote_spinlock_t *lock)
170{
171 smp_mb();
172
173 lock->dek.self_lock = DEK_LOCK_YIELD;
174}
175
176#ifdef CONFIG_MSM_SMD
177int _remote_spin_lock_init(remote_spinlock_id_t, _remote_spinlock_t *lock);
178#else
179static inline
180int _remote_spin_lock_init(remote_spinlock_id_t id, _remote_spinlock_t *lock)
181{
182 return -EINVAL;
183}
184#endif
185
186#if defined(CONFIG_MSM_REMOTE_SPINLOCK_DEKKERS)
187/* Use Dekker's algorithm when LDREX/STREX and SWP are unavailable for
188 * shared memory */
189#define _remote_spin_lock(lock) __raw_remote_dek_spin_lock(*lock)
190#define _remote_spin_unlock(lock) __raw_remote_dek_spin_unlock(*lock)
191#define _remote_spin_trylock(lock) __raw_remote_dek_spin_trylock(*lock)
192#elif defined(CONFIG_MSM_REMOTE_SPINLOCK_SWP)
193/* Use SWP-based locks when LDREX/STREX are unavailable for shared memory. */
194#define _remote_spin_lock(lock) __raw_remote_swp_spin_lock(*lock)
195#define _remote_spin_unlock(lock) __raw_remote_swp_spin_unlock(*lock)
196#define _remote_spin_trylock(lock) __raw_remote_swp_spin_trylock(*lock)
197#else
198/* Use LDREX/STREX for shared memory locking, when available */
199#define _remote_spin_lock(lock) __raw_remote_ex_spin_lock(*lock)
200#define _remote_spin_unlock(lock) __raw_remote_ex_spin_unlock(*lock)
201#define _remote_spin_trylock(lock) __raw_remote_ex_spin_trylock(*lock)
202#endif
203
204/* Remote mutex definitions. */
205
206typedef struct {
207 _remote_spinlock_t r_spinlock;
208 uint32_t delay_us;
209} _remote_mutex_t;
210
211struct remote_mutex_id {
212 remote_spinlock_id_t r_spinlock_id;
213 uint32_t delay_us;
214};
215
216#ifdef CONFIG_MSM_SMD
217int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock);
218void _remote_mutex_lock(_remote_mutex_t *lock);
219void _remote_mutex_unlock(_remote_mutex_t *lock);
220int _remote_mutex_trylock(_remote_mutex_t *lock);
221#else
222static inline
223int _remote_mutex_init(struct remote_mutex_id *id, _remote_mutex_t *lock)
224{
225 return -EINVAL;
226}
227static inline void _remote_mutex_lock(_remote_mutex_t *lock) {}
228static inline void _remote_mutex_unlock(_remote_mutex_t *lock) {}
229static inline int _remote_mutex_trylock(_remote_mutex_t *lock)
230{
231 return 0;
232}
233#endif
234
235#endif /* __ASM__ARCH_QC_REMOTE_SPINLOCK_H */