aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/hwspinlock.h
diff options
context:
space:
mode:
authorOhad Ben-Cohen <ohad@wizery.com>2011-02-17 12:52:03 -0500
committerTony Lindgren <tony@atomide.com>2011-02-17 12:52:03 -0500
commitbd9a4c7df256cee4e9f6a4b56baa3b89d63f0f1e (patch)
treeee6ca0aaebd8e553576a0cf3fefafa1cd3ec8e1d /include/linux/hwspinlock.h
parentd9e45731debd83e2b249be349993595907dddeae (diff)
drivers: hwspinlock: add framework
Add a platform-independent hwspinlock framework. Hardware spinlock devices are needed, e.g., in order to access data that is shared between remote processors, that otherwise have no alternative mechanism to accomplish synchronization and mutual exclusion operations. Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com> Cc: Hari Kanigeri <h-kanigeri2@ti.com> Cc: Benoit Cousson <b-cousson@ti.com> Cc: Kevin Hilman <khilman@ti.com> Cc: Grant Likely <grant.likely@secretlab.ca> Cc: Paul Walmsley <paul@pwsan.com> Cc: Russell King <linux@arm.linux.org.uk> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'include/linux/hwspinlock.h')
-rw-r--r--include/linux/hwspinlock.h292
1 files changed, 292 insertions, 0 deletions
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
new file mode 100644
index 000000000000..8390efc457eb
--- /dev/null
+++ b/include/linux/hwspinlock.h
@@ -0,0 +1,292 @@
1/*
2 * Hardware spinlock public header
3 *
4 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
5 *
6 * Contact: Ohad Ben-Cohen <ohad@wizery.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#ifndef __LINUX_HWSPINLOCK_H
19#define __LINUX_HWSPINLOCK_H
20
21#include <linux/err.h>
22#include <linux/sched.h>
23
24/* hwspinlock mode argument */
25#define HWLOCK_IRQSTATE 0x01 /* Disable interrupts, save state */
26#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
27
28struct hwspinlock;
29
30#if defined(CONFIG_HWSPINLOCK) || defined(CONFIG_HWSPINLOCK_MODULE)
31
32int hwspin_lock_register(struct hwspinlock *lock);
33struct hwspinlock *hwspin_lock_unregister(unsigned int id);
34struct hwspinlock *hwspin_lock_request(void);
35struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
36int hwspin_lock_free(struct hwspinlock *hwlock);
37int hwspin_lock_get_id(struct hwspinlock *hwlock);
38int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
39 unsigned long *);
40int __hwspin_trylock(struct hwspinlock *, int, unsigned long *);
41void __hwspin_unlock(struct hwspinlock *, int, unsigned long *);
42
43#else /* !CONFIG_HWSPINLOCK */
44
45/*
46 * We don't want these functions to fail if CONFIG_HWSPINLOCK is not
47 * enabled. We prefer to silently succeed in this case, and let the
48 * code path get compiled away. This way, if CONFIG_HWSPINLOCK is not
49 * required on a given setup, users will still work.
50 *
51 * The only exception is hwspin_lock_register/hwspin_lock_unregister, with which
52 * we _do_ want users to fail (no point in registering hwspinlock instances if
53 * the framework is not available).
54 *
55 * Note: ERR_PTR(-ENODEV) will still be considered a success for NULL-checking
56 * users. Others, which care, can still check this with IS_ERR.
57 */
58static inline struct hwspinlock *hwspin_lock_request(void)
59{
60 return ERR_PTR(-ENODEV);
61}
62
63static inline struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
64{
65 return ERR_PTR(-ENODEV);
66}
67
68static inline int hwspin_lock_free(struct hwspinlock *hwlock)
69{
70 return 0;
71}
72
73static inline
74int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to,
75 int mode, unsigned long *flags)
76{
77 return 0;
78}
79
80static inline
81int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
82{
83 return 0;
84}
85
86static inline
87void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
88{
89 return 0;
90}
91
92static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
93{
94 return 0;
95}
96
97static inline int hwspin_lock_register(struct hwspinlock *hwlock)
98{
99 return -ENODEV;
100}
101
102static inline struct hwspinlock *hwspin_lock_unregister(unsigned int id)
103{
104 return NULL;
105}
106
107#endif /* !CONFIG_HWSPINLOCK */
108
109/**
110 * hwspin_trylock_irqsave() - try to lock an hwspinlock, disable interrupts
111 * @hwlock: an hwspinlock which we want to trylock
112 * @flags: a pointer to where the caller's interrupt state will be saved at
113 *
114 * This function attempts to lock the underlying hwspinlock, and will
115 * immediately fail if the hwspinlock is already locked.
116 *
117 * Upon a successful return from this function, preemption and local
118 * interrupts are disabled (previous interrupts state is saved at @flags),
119 * so the caller must not sleep, and is advised to release the hwspinlock
120 * as soon as possible.
121 *
122 * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
123 * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
124 */
125static inline
126int hwspin_trylock_irqsave(struct hwspinlock *hwlock, unsigned long *flags)
127{
128 return __hwspin_trylock(hwlock, HWLOCK_IRQSTATE, flags);
129}
130
131/**
132 * hwspin_trylock_irq() - try to lock an hwspinlock, disable interrupts
133 * @hwlock: an hwspinlock which we want to trylock
134 *
135 * This function attempts to lock the underlying hwspinlock, and will
136 * immediately fail if the hwspinlock is already locked.
137 *
138 * Upon a successful return from this function, preemption and local
139 * interrupts are disabled, so the caller must not sleep, and is advised
140 * to release the hwspinlock as soon as possible.
141 *
142 * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
143 * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
144 */
145static inline int hwspin_trylock_irq(struct hwspinlock *hwlock)
146{
147 return __hwspin_trylock(hwlock, HWLOCK_IRQ, NULL);
148}
149
150/**
151 * hwspin_trylock() - attempt to lock a specific hwspinlock
152 * @hwlock: an hwspinlock which we want to trylock
153 *
154 * This function attempts to lock an hwspinlock, and will immediately fail
155 * if the hwspinlock is already taken.
156 *
157 * Upon a successful return from this function, preemption is disabled,
158 * so the caller must not sleep, and is advised to release the hwspinlock
159 * as soon as possible. This is required in order to minimize remote cores
160 * polling on the hardware interconnect.
161 *
162 * Returns 0 if we successfully locked the hwspinlock, -EBUSY if
163 * the hwspinlock was already taken, and -EINVAL if @hwlock is invalid.
164 */
165static inline int hwspin_trylock(struct hwspinlock *hwlock)
166{
167 return __hwspin_trylock(hwlock, 0, NULL);
168}
169
170/**
171 * hwspin_lock_timeout_irqsave() - lock hwspinlock, with timeout, disable irqs
172 * @hwlock: the hwspinlock to be locked
173 * @to: timeout value in msecs
174 * @flags: a pointer to where the caller's interrupt state will be saved at
175 *
176 * This function locks the underlying @hwlock. If the @hwlock
177 * is already taken, the function will busy loop waiting for it to
178 * be released, but give up when @timeout msecs have elapsed.
179 *
180 * Upon a successful return from this function, preemption and local interrupts
181 * are disabled (plus previous interrupt state is saved), so the caller must
182 * not sleep, and is advised to release the hwspinlock as soon as possible.
183 *
184 * Returns 0 when the @hwlock was successfully taken, and an appropriate
185 * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
186 * busy after @timeout msecs). The function will never sleep.
187 */
188static inline int hwspin_lock_timeout_irqsave(struct hwspinlock *hwlock,
189 unsigned int to, unsigned long *flags)
190{
191 return __hwspin_lock_timeout(hwlock, to, HWLOCK_IRQSTATE, flags);
192}
193
194/**
195 * hwspin_lock_timeout_irq() - lock hwspinlock, with timeout, disable irqs
196 * @hwlock: the hwspinlock to be locked
197 * @to: timeout value in msecs
198 *
199 * This function locks the underlying @hwlock. If the @hwlock
200 * is already taken, the function will busy loop waiting for it to
201 * be released, but give up when @timeout msecs have elapsed.
202 *
203 * Upon a successful return from this function, preemption and local interrupts
204 * are disabled so the caller must not sleep, and is advised to release the
205 * hwspinlock as soon as possible.
206 *
207 * Returns 0 when the @hwlock was successfully taken, and an appropriate
208 * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
209 * busy after @timeout msecs). The function will never sleep.
210 */
211static inline
212int hwspin_lock_timeout_irq(struct hwspinlock *hwlock, unsigned int to)
213{
214 return __hwspin_lock_timeout(hwlock, to, HWLOCK_IRQ, NULL);
215}
216
217/**
218 * hwspin_lock_timeout() - lock an hwspinlock with timeout limit
219 * @hwlock: the hwspinlock to be locked
220 * @to: timeout value in msecs
221 *
222 * This function locks the underlying @hwlock. If the @hwlock
223 * is already taken, the function will busy loop waiting for it to
224 * be released, but give up when @timeout msecs have elapsed.
225 *
226 * Upon a successful return from this function, preemption is disabled
227 * so the caller must not sleep, and is advised to release the hwspinlock
228 * as soon as possible.
229 * This is required in order to minimize remote cores polling on the
230 * hardware interconnect.
231 *
232 * Returns 0 when the @hwlock was successfully taken, and an appropriate
233 * error code otherwise (most notably an -ETIMEDOUT if the @hwlock is still
234 * busy after @timeout msecs). The function will never sleep.
235 */
236static inline
237int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to)
238{
239 return __hwspin_lock_timeout(hwlock, to, 0, NULL);
240}
241
242/**
243 * hwspin_unlock_irqrestore() - unlock hwspinlock, restore irq state
244 * @hwlock: a previously-acquired hwspinlock which we want to unlock
245 * @flags: previous caller's interrupt state to restore
246 *
247 * This function will unlock a specific hwspinlock, enable preemption and
248 * restore the previous state of the local interrupts. It should be used
249 * to undo, e.g., hwspin_trylock_irqsave().
250 *
251 * @hwlock must be already locked before calling this function: it is a bug
252 * to call unlock on a @hwlock that is already unlocked.
253 */
254static inline void hwspin_unlock_irqrestore(struct hwspinlock *hwlock,
255 unsigned long *flags)
256{
257 __hwspin_unlock(hwlock, HWLOCK_IRQSTATE, flags);
258}
259
260/**
261 * hwspin_unlock_irq() - unlock hwspinlock, enable interrupts
262 * @hwlock: a previously-acquired hwspinlock which we want to unlock
263 *
264 * This function will unlock a specific hwspinlock, enable preemption and
265 * enable local interrupts. Should be used to undo hwspin_lock_irq().
266 *
267 * @hwlock must be already locked (e.g. by hwspin_trylock_irq()) before
268 * calling this function: it is a bug to call unlock on a @hwlock that is
269 * already unlocked.
270 */
271static inline void hwspin_unlock_irq(struct hwspinlock *hwlock)
272{
273 __hwspin_unlock(hwlock, HWLOCK_IRQ, NULL);
274}
275
276/**
277 * hwspin_unlock() - unlock hwspinlock
278 * @hwlock: a previously-acquired hwspinlock which we want to unlock
279 *
280 * This function will unlock a specific hwspinlock and enable preemption
281 * back.
282 *
283 * @hwlock must be already locked (e.g. by hwspin_trylock()) before calling
284 * this function: it is a bug to call unlock on a @hwlock that is already
285 * unlocked.
286 */
287static inline void hwspin_unlock(struct hwspinlock *hwlock)
288{
289 __hwspin_unlock(hwlock, 0, NULL);
290}
291
292#endif /* __LINUX_HWSPINLOCK_H */