diff options
| -rw-r--r-- | Documentation/hwspinlock.txt | 10 | ||||
| -rw-r--r-- | drivers/hwspinlock/hwspinlock_core.c | 79 | ||||
| -rw-r--r-- | include/linux/hwspinlock.h | 7 |
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 | } |
| 258 | EXPORT_SYMBOL_GPL(__hwspin_unlock); | 259 | EXPORT_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 | */ | ||
| 272 | static inline int | ||
| 273 | of_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 | */ | ||
| 295 | int 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 | |||
| 333 | out: | ||
| 334 | of_node_put(args.np); | ||
| 335 | return ret ? ret : id; | ||
| 336 | } | ||
| 337 | EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id); | ||
| 338 | |||
| 260 | static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) | 339 | static 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 | ||
| 28 | struct device; | 28 | struct device; |
| 29 | struct device_node; | ||
| 29 | struct hwspinlock; | 30 | struct hwspinlock; |
| 30 | struct hwspinlock_device; | 31 | struct hwspinlock_device; |
| 31 | struct hwspinlock_ops; | 32 | struct hwspinlock_ops; |
| @@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspinlock_device *bank); | |||
| 66 | struct hwspinlock *hwspin_lock_request(void); | 67 | struct hwspinlock *hwspin_lock_request(void); |
| 67 | struct hwspinlock *hwspin_lock_request_specific(unsigned int id); | 68 | struct hwspinlock *hwspin_lock_request_specific(unsigned int id); |
| 68 | int hwspin_lock_free(struct hwspinlock *hwlock); | 69 | int hwspin_lock_free(struct hwspinlock *hwlock); |
| 70 | int of_hwspin_lock_get_id(struct device_node *np, int index); | ||
| 69 | int hwspin_lock_get_id(struct hwspinlock *hwlock); | 71 | int hwspin_lock_get_id(struct hwspinlock *hwlock); |
| 70 | int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, | 72 | int __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 | ||
| 125 | static inline int of_hwspin_lock_get_id(struct device_node *np, int index) | ||
| 126 | { | ||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 123 | static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) | 130 | static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) |
| 124 | { | 131 | { |
| 125 | return 0; | 132 | return 0; |
