Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwspinlock/core: add device tree support

This patch adds a new OF-friendly API of_hwspin_lock_get_id()
for hwspinlock clients to use/request locks from a hwspinlock
device instantiated through a device-tree blob. This new API
can be used by hwspinlock clients to get the id for a specific
lock using the phandle + args specifier, so that it can be
requested using the available hwspin_lock_request_specific()
API.

Signed-off-by: Suman Anna <s-anna@ti.com>
Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
[small comment clarification]
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>

authored by

Suman Anna and committed by
Ohad Ben-Cohen
fb7737e9 0ce8cf2f

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