summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/hwspinlock.txt10
-rw-r--r--drivers/hwspinlock/hwspinlock_core.c79
-rw-r--r--include/linux/hwspinlock.h7
3 files changed, 96 insertions, 0 deletions
diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt
index 62f7d4ea6e26..61c1ee98e59f 100644
--- a/Documentation/hwspinlock.txt
+++ b/Documentation/hwspinlock.txt
@@ -48,6 +48,16 @@ independent, drivers.
48 ids for predefined purposes. 48 ids for predefined purposes.
49 Should be called from a process context (might sleep). 49 Should be called from a process context (might sleep).
50 50
51 int of_hwspin_lock_get_id(struct device_node *np, int index);
52 - retrieve the global lock id for an OF phandle-based specific lock.
53 This function provides a means for DT users of a hwspinlock module
54 to get the global lock id of a specific hwspinlock, so that it can
55 be requested using the normal hwspin_lock_request_specific() API.
56 The function returns a lock id number on success, -EPROBE_DEFER if
57 the hwspinlock device is not yet registered with the core, or other
58 error values.
59 Should be called from a process context (might sleep).
60
51 int hwspin_lock_free(struct hwspinlock *hwlock); 61 int hwspin_lock_free(struct hwspinlock *hwlock);
52 - free a previously-assigned hwspinlock; returns 0 on success, or an 62 - free a previously-assigned hwspinlock; returns 0 on success, or an
53 appropriate error code on failure (e.g. -EINVAL if the hwspinlock 63 appropriate error code on failure (e.g. -EINVAL if the hwspinlock
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index 461a0d739d75..52f708bcf77f 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -27,6 +27,7 @@
27#include <linux/hwspinlock.h> 27#include <linux/hwspinlock.h>
28#include <linux/pm_runtime.h> 28#include <linux/pm_runtime.h>
29#include <linux/mutex.h> 29#include <linux/mutex.h>
30#include <linux/of.h>
30 31
31#include "hwspinlock_internal.h" 32#include "hwspinlock_internal.h"
32 33
@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
257} 258}
258EXPORT_SYMBOL_GPL(__hwspin_unlock); 259EXPORT_SYMBOL_GPL(__hwspin_unlock);
259 260
261/**
262 * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
263 * @bank: the hwspinlock device bank
264 * @hwlock_spec: hwlock specifier as found in the device tree
265 *
266 * This is a simple translation function, suitable for hwspinlock platform
267 * drivers that only has a lock specifier length of 1.
268 *
269 * Returns a relative index of the lock within a specified bank on success,
270 * or -EINVAL on invalid specifier cell count.
271 */
272static inline int
273of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
274{
275 if (WARN_ON(hwlock_spec->args_count != 1))
276 return -EINVAL;
277
278 return hwlock_spec->args[0];
279}
280
281/**
282 * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock
283 * @np: device node from which to request the specific hwlock
284 * @index: index of the hwlock in the list of values
285 *
286 * This function provides a means for DT users of the hwspinlock module to
287 * get the global lock id of a specific hwspinlock using the phandle of the
288 * hwspinlock device, so that it can be requested using the normal
289 * hwspin_lock_request_specific() API.
290 *
291 * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock
292 * device is not yet registered, -EINVAL on invalid args specifier value or an
293 * appropriate error as returned from the OF parsing of the DT client node.
294 */
295int of_hwspin_lock_get_id(struct device_node *np, int index)
296{
297 struct of_phandle_args args;
298 struct hwspinlock *hwlock;
299 struct radix_tree_iter iter;
300 void **slot;
301 int id;
302 int ret;
303
304 ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index,
305 &args);
306 if (ret)
307 return ret;
308
309 /* Find the hwspinlock device: we need its base_id */
310 ret = -EPROBE_DEFER;
311 rcu_read_lock();
312 radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) {
313 hwlock = radix_tree_deref_slot(slot);
314 if (unlikely(!hwlock))
315 continue;
316
317 if (hwlock->bank->dev->of_node == args.np) {
318 ret = 0;
319 break;
320 }
321 }
322 rcu_read_unlock();
323 if (ret < 0)
324 goto out;
325
326 id = of_hwspin_lock_simple_xlate(&args);
327 if (id < 0 || id >= hwlock->bank->num_locks) {
328 ret = -EINVAL;
329 goto out;
330 }
331 id += hwlock->bank->base_id;
332
333out:
334 of_node_put(args.np);
335 return ret ? ret : id;
336}
337EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
338
260static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) 339static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
261{ 340{
262 struct hwspinlock *tmp; 341 struct hwspinlock *tmp;
diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h
index 3343298e40e8..859d673d98c8 100644
--- a/include/linux/hwspinlock.h
+++ b/include/linux/hwspinlock.h
@@ -26,6 +26,7 @@
26#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */ 26#define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
27 27
28struct device; 28struct device;
29struct device_node;
29struct hwspinlock; 30struct hwspinlock;
30struct hwspinlock_device; 31struct hwspinlock_device;
31struct hwspinlock_ops; 32struct hwspinlock_ops;
@@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank);
66struct hwspinlock *hwspin_lock_request(void); 67struct hwspinlock *hwspin_lock_request(void);
67struct hwspinlock *hwspin_lock_request_specific(unsigned int id); 68struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
68int hwspin_lock_free(struct hwspinlock *hwlock); 69int hwspin_lock_free(struct hwspinlock *hwlock);
70int of_hwspin_lock_get_id(struct device_node *np, int index);
69int hwspin_lock_get_id(struct hwspinlock *hwlock); 71int hwspin_lock_get_id(struct hwspinlock *hwlock);
70int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, 72int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
71 unsigned long *); 73 unsigned long *);
@@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
120{ 122{
121} 123}
122 124
125static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
126{
127 return 0;
128}
129
123static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) 130static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
124{ 131{
125 return 0; 132 return 0;