Lines Matching +full:hwlock +full:- +full:names
1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
7 * Contact: Ohad Ben-Cohen <ohad@wizery.com>
19 #include <linux/radix-tree.h>
36 * and provides easy-to-use API which makes the hwspinlock core code simple
54 * as the radix-tree API requires that users provide all synchronisation.
55 * A mutex is needed because we're using non-atomic radix tree allocations.
61 * __hwspin_trylock() - attempt to lock a specific hwspinlock
62 * @hwlock: an hwspinlock which we want to trylock
72 * user need some time-consuming or sleepable operations under the hardware
87 * Returns: %0 if we successfully locked the hwspinlock or -EBUSY if
92 int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags) in __hwspin_trylock() argument
96 if (WARN_ON(!hwlock || (!flags && mode == HWLOCK_IRQSTATE))) in __hwspin_trylock()
97 return -EINVAL; in __hwspin_trylock()
106 * 2. Make the hwspinlock SMP-safe (so we can take it from in __hwspin_trylock()
114 ret = spin_trylock_irqsave(&hwlock->lock, *flags); in __hwspin_trylock()
117 ret = spin_trylock_irq(&hwlock->lock); in __hwspin_trylock()
124 ret = spin_trylock(&hwlock->lock); in __hwspin_trylock()
130 return -EBUSY; in __hwspin_trylock()
133 ret = hwlock->bank->ops->trylock(hwlock); in __hwspin_trylock()
135 /* if hwlock is already taken, undo spin_trylock_* and exit */ in __hwspin_trylock()
139 spin_unlock_irqrestore(&hwlock->lock, *flags); in __hwspin_trylock()
142 spin_unlock_irq(&hwlock->lock); in __hwspin_trylock()
149 spin_unlock(&hwlock->lock); in __hwspin_trylock()
153 return -EBUSY; in __hwspin_trylock()
173 * __hwspin_lock_timeout() - lock an hwspinlock with timeout limit
174 * @hwlock: the hwspinlock to be locked
180 * This function locks the given @hwlock. If the @hwlock
186 * user need some time-consuming or sleepable operations under the hardware
190 * is handled with busy-waiting delays, hence shall not exceed few msecs.
203 * Returns: %0 when the @hwlock was successfully taken, and an appropriate
204 * error code otherwise (most notably -ETIMEDOUT if the @hwlock is still
209 int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to, in __hwspin_lock_timeout() argument
219 ret = __hwspin_trylock(hwlock, mode, flags); in __hwspin_lock_timeout()
220 if (ret != -EBUSY) in __hwspin_lock_timeout()
231 return -ETIMEDOUT; in __hwspin_lock_timeout()
234 return -ETIMEDOUT; in __hwspin_lock_timeout()
238 * Allow platform-specific relax handlers to prevent in __hwspin_lock_timeout()
241 if (hwlock->bank->ops->relax) in __hwspin_lock_timeout()
242 hwlock->bank->ops->relax(hwlock); in __hwspin_lock_timeout()
250 * __hwspin_unlock() - unlock a specific hwspinlock
251 * @hwlock: a previously-acquired hwspinlock which we want to unlock
257 * @hwlock must be already locked before calling this function: it is a bug
258 * to call unlock on a @hwlock that is already unlocked.
268 void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) in __hwspin_unlock() argument
270 if (WARN_ON(!hwlock || (!flags && mode == HWLOCK_IRQSTATE))) in __hwspin_unlock()
287 hwlock->bank->ops->unlock(hwlock); in __hwspin_unlock()
292 spin_unlock_irqrestore(&hwlock->lock, *flags); in __hwspin_unlock()
295 spin_unlock_irq(&hwlock->lock); in __hwspin_unlock()
302 spin_unlock(&hwlock->lock); in __hwspin_unlock()
309 * hwspin_lock_bust() - bust a specific hwspinlock
310 * @hwlock: a previously-acquired hwspinlock which we want to bust
318 * Returns: 0 on success, or -EINVAL if the hwspinlock does not exist, or
319 * the bust operation fails, and -EOPNOTSUPP if the bust operation is not
322 int hwspin_lock_bust(struct hwspinlock *hwlock, unsigned int id) in hwspin_lock_bust() argument
324 if (WARN_ON(!hwlock)) in hwspin_lock_bust()
325 return -EINVAL; in hwspin_lock_bust()
327 if (!hwlock->bank->ops->bust) { in hwspin_lock_bust()
329 return -EOPNOTSUPP; in hwspin_lock_bust()
332 return hwlock->bank->ops->bust(hwlock, id); in hwspin_lock_bust()
337 * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
338 * @hwlock_spec: hwlock specifier as found in the device tree
344 * or -EINVAL on invalid specifier cell count.
349 if (WARN_ON(hwlock_spec->args_count != 1)) in of_hwspin_lock_simple_xlate()
350 return -EINVAL; in of_hwspin_lock_simple_xlate()
352 return hwlock_spec->args[0]; in of_hwspin_lock_simple_xlate()
356 * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock
357 * @np: device node from which to request the specific hwlock
358 * @index: index of the hwlock in the list of values
365 * Returns: the global lock id number on success, -EPROBE_DEFER if the
366 * hwspinlock device is not yet registered, -EINVAL on invalid args
373 struct hwspinlock *hwlock; in of_hwspin_lock_get_id() local
379 ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index, in of_hwspin_lock_get_id()
385 ret = -ENOENT; in of_hwspin_lock_get_id()
390 ret = -EPROBE_DEFER; in of_hwspin_lock_get_id()
393 hwlock = radix_tree_deref_slot(slot); in of_hwspin_lock_get_id()
394 if (unlikely(!hwlock)) in of_hwspin_lock_get_id()
396 if (radix_tree_deref_retry(hwlock)) { in of_hwspin_lock_get_id()
401 if (device_match_of_node(hwlock->bank->dev, args.np)) { in of_hwspin_lock_get_id()
411 if (id < 0 || id >= hwlock->bank->num_locks) { in of_hwspin_lock_get_id()
412 ret = -EINVAL; in of_hwspin_lock_get_id()
415 id += hwlock->bank->base_id; in of_hwspin_lock_get_id()
424 * of_hwspin_lock_get_id_byname() - get lock id for an specified hwlock name
425 * @np: device node from which to request the specific hwlock
426 * @name: hwlock name
433 * Returns: the global lock id number on success, -EPROBE_DEFER if the
434 * hwspinlock device is not yet registered, -EINVAL on invalid args
443 return -EINVAL; in of_hwspin_lock_get_id_byname()
445 index = of_property_match_string(np, "hwlock-names", name); in of_hwspin_lock_get_id_byname()
453 static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id) in hwspin_lock_register_single() argument
460 ret = radix_tree_insert(&hwspinlock_tree, id, hwlock); in hwspin_lock_register_single()
462 if (ret == -EEXIST) in hwspin_lock_register_single()
470 /* self-sanity check which should never fail */ in hwspin_lock_register_single()
471 WARN_ON(tmp != hwlock); in hwspin_lock_register_single()
480 struct hwspinlock *hwlock = NULL; in hwspin_lock_unregister_single() local
492 hwlock = radix_tree_delete(&hwspinlock_tree, id); in hwspin_lock_unregister_single()
493 if (!hwlock) { in hwspin_lock_unregister_single()
500 return hwlock; in hwspin_lock_unregister_single()
504 * hwspin_lock_register() - register a new hw spinlock device
511 * This function should be called from the underlying platform-specific
521 struct hwspinlock *hwlock; in hwspin_lock_register() local
524 if (!bank || !ops || !dev || !num_locks || !ops->trylock || in hwspin_lock_register()
525 !ops->unlock) { in hwspin_lock_register()
527 return -EINVAL; in hwspin_lock_register()
530 bank->dev = dev; in hwspin_lock_register()
531 bank->ops = ops; in hwspin_lock_register()
532 bank->base_id = base_id; in hwspin_lock_register()
533 bank->num_locks = num_locks; in hwspin_lock_register()
536 hwlock = &bank->lock[i]; in hwspin_lock_register()
538 spin_lock_init(&hwlock->lock); in hwspin_lock_register()
539 hwlock->bank = bank; in hwspin_lock_register()
541 ret = hwspin_lock_register_single(hwlock, base_id + i); in hwspin_lock_register()
549 while (--i >= 0) in hwspin_lock_register()
556 * hwspin_lock_unregister() - unregister an hw spinlock device
559 * This function should be called from the underlying platform-specific
568 struct hwspinlock *hwlock, *tmp; in hwspin_lock_unregister() local
571 for (i = 0; i < bank->num_locks; i++) { in hwspin_lock_unregister()
572 hwlock = &bank->lock[i]; in hwspin_lock_unregister()
574 tmp = hwspin_lock_unregister_single(bank->base_id + i); in hwspin_lock_unregister()
576 return -EBUSY; in hwspin_lock_unregister()
578 /* self-sanity check that should never fail */ in hwspin_lock_unregister()
579 WARN_ON(tmp != hwlock); in hwspin_lock_unregister()
603 * devm_hwspin_lock_unregister() - unregister an hw spinlock device for
608 * This function should be called from the underlying platform-specific
629 * devm_hwspin_lock_register() - register a new hw spinlock device for
637 * This function should be called from the underlying platform-specific
654 return -ENOMEM; in devm_hwspin_lock_register()
669 * __hwspin_lock_request() - tag an hwspinlock as used and power it up
670 * @hwlock: the target hwspinlock
679 static int __hwspin_lock_request(struct hwspinlock *hwlock) in __hwspin_lock_request() argument
681 struct device *dev = hwlock->bank->dev; in __hwspin_lock_request()
686 if (!try_module_get(dev->driver->owner)) { in __hwspin_lock_request()
688 return -EINVAL; in __hwspin_lock_request()
693 if (ret < 0 && ret != -EACCES) { in __hwspin_lock_request()
696 module_put(dev->driver->owner); in __hwspin_lock_request()
703 tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock), in __hwspin_lock_request()
706 /* self-sanity check that should never fail */ in __hwspin_lock_request()
707 WARN_ON(tmp != hwlock); in __hwspin_lock_request()
713 * hwspin_lock_get_id() - retrieve id number of a given hwspinlock
714 * @hwlock: a valid hwspinlock instance
716 * Returns: the id number of a given @hwlock, or -EINVAL if @hwlock is invalid.
718 int hwspin_lock_get_id(struct hwspinlock *hwlock) in hwspin_lock_get_id() argument
720 if (!hwlock) { in hwspin_lock_get_id()
721 pr_err("invalid hwlock\n"); in hwspin_lock_get_id()
722 return -EINVAL; in hwspin_lock_get_id()
725 return hwlock_to_id(hwlock); in hwspin_lock_get_id()
730 * hwspin_lock_request() - request an hwspinlock
736 * id of a given hwlock, use hwspin_lock_get_id()).
744 struct hwspinlock *hwlock; in hwspin_lock_request() local
750 ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock, in hwspin_lock_request()
754 hwlock = NULL; in hwspin_lock_request()
762 ret = __hwspin_lock_request(hwlock); in hwspin_lock_request()
764 hwlock = NULL; in hwspin_lock_request()
768 return hwlock; in hwspin_lock_request()
773 * hwspin_lock_request_specific() - request for a specific hwspinlock
787 struct hwspinlock *hwlock; in hwspin_lock_request_specific() local
793 hwlock = radix_tree_lookup(&hwspinlock_tree, id); in hwspin_lock_request_specific()
794 if (!hwlock) { in hwspin_lock_request_specific()
800 WARN_ON(hwlock_to_id(hwlock) != id); in hwspin_lock_request_specific()
806 hwlock = NULL; in hwspin_lock_request_specific()
811 ret = __hwspin_lock_request(hwlock); in hwspin_lock_request_specific()
813 hwlock = NULL; in hwspin_lock_request_specific()
817 return hwlock; in hwspin_lock_request_specific()
822 * hwspin_lock_free() - free a specific hwspinlock
823 * @hwlock: the specific hwspinlock to free
825 * This function mark @hwlock as free again.
826 * Should only be called with an @hwlock that was retrieved from
833 int hwspin_lock_free(struct hwspinlock *hwlock) in hwspin_lock_free() argument
839 if (!hwlock) { in hwspin_lock_free()
840 pr_err("invalid hwlock\n"); in hwspin_lock_free()
841 return -EINVAL; in hwspin_lock_free()
844 dev = hwlock->bank->dev; in hwspin_lock_free()
848 ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock), in hwspin_lock_free()
851 dev_err(dev, "%s: hwlock is already free\n", __func__); in hwspin_lock_free()
853 ret = -EINVAL; in hwspin_lock_free()
861 tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock), in hwspin_lock_free()
865 WARN_ON(tmp != hwlock); in hwspin_lock_free()
867 module_put(dev->driver->owner); in hwspin_lock_free()
877 struct hwspinlock **hwlock = res; in devm_hwspin_lock_match() local
879 if (WARN_ON(!hwlock || !*hwlock)) in devm_hwspin_lock_match()
882 return *hwlock == data; in devm_hwspin_lock_match()
891 * devm_hwspin_lock_free() - free a specific hwspinlock for a managed device
893 * @hwlock: the specific hwspinlock to free
895 * This function mark @hwlock as free again.
896 * Should only be called with an @hwlock that was retrieved from
903 int devm_hwspin_lock_free(struct device *dev, struct hwspinlock *hwlock) in devm_hwspin_lock_free() argument
908 devm_hwspin_lock_match, hwlock); in devm_hwspin_lock_free()
916 * devm_hwspin_lock_request() - request an hwspinlock for a managed device
923 * id of a given hwlock, use hwspin_lock_get_id()).
931 struct hwspinlock **ptr, *hwlock; in devm_hwspin_lock_request() local
937 hwlock = hwspin_lock_request(); in devm_hwspin_lock_request()
938 if (hwlock) { in devm_hwspin_lock_request()
939 *ptr = hwlock; in devm_hwspin_lock_request()
945 return hwlock; in devm_hwspin_lock_request()
950 * devm_hwspin_lock_request_specific() - request for a specific hwspinlock for
967 struct hwspinlock **ptr, *hwlock; in devm_hwspin_lock_request_specific() local
973 hwlock = hwspin_lock_request_specific(id); in devm_hwspin_lock_request_specific()
974 if (hwlock) { in devm_hwspin_lock_request_specific()
975 *ptr = hwlock; in devm_hwspin_lock_request_specific()
981 return hwlock; in devm_hwspin_lock_request_specific()
986 MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");