diff options
author | Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com> | 2012-08-24 20:32:48 -0500 |
---|---|---|
committer | Xavier Boudet <x-boudet@ti.com> | 2012-11-05 14:24:58 +0100 |
commit | 7aec72d028f414ff2f88007dda4ea7939e5d2a79 (patch) | |
tree | 0afca174d0e7db0452201bd41a5e653d08dfb28b | |
parent | 85dab720cadfe1b313316abc354c0da6e4546053 (diff) |
hwspinlock: provide implementation to reset a spinlock
hwspinlocks shared between the mpu and a remote processor can be
left in a locked state in the event of a device exception on the
remote processor have taken a hwspinlock.
The mpu being the master of the remote processor, is the best
choice to try and unlock the hwspinlock.
A new API __hwspin_lock_reset is added to allow the mpu to unlock
or reset a hwspinlock.
Change-Id: Id28e03e3ce54741f522b066ba487bf78e740c041
Signed-off-by: Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
-rw-r--r-- | drivers/hwspinlock/hwspinlock_core.c | 50 | ||||
-rw-r--r-- | include/linux/hwspinlock.h | 5 |
2 files changed, 55 insertions, 0 deletions
diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index f7fd79df6057..e731501ebd5b 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -629,6 +629,56 @@ out: } EXPORT_SYMBOL_GPL(hwspin_lock_free); +/** + * __hwspin_lock_reset() - reset/unlock a specific hwspinlock + * @id: index of the specific hwspinlock that needs to be reset + * + * This function resets a specific hwspinlock. This _should_ + * only be called in very special circumstances to unlock and + * to avoid a deadlock by an user who would want to acquire the + * lock but cannot. + * + * An example would be a case where a remote processor has crashed + * holding a lock. + */ +void __hwspin_lock_reset(int id) +{ + struct hwspinlock *hwlock; + + mutex_lock(&hwspinlock_tree_lock); + + /* make sure this hwspinlock exists */ + hwlock = radix_tree_lookup(&hwspinlock_tree, id); + if (!hwlock) { + pr_warn("hwspinlock %u does not exist\n", id); + goto out; + } + + /* sanity check (this shouldn't happen) */ + if (hwlock_to_id(hwlock) != id) { + pr_warn("id %u does not match hwspinlock id %u\n", id, + hwlock_to_id(hwlock)); + goto out; + } + + /* + * We must make sure that memory operations (both reads and writes), + * done before unlocking the hwspinlock, will not be reordered + * after the lock is released. + * + * That's the purpose of this explicit memory barrier. + */ + mb(); + pr_warn("hwspinlock %u forced to unlock\n", id); + + hwlock->bank->ops->unlock(hwlock); + +out: + mutex_unlock(&hwspinlock_tree_lock); + +} +EXPORT_SYMBOL_GPL(__hwspin_lock_reset); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Hardware spinlock interface"); MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>"); diff --git a/include/linux/hwspinlock.h b/include/linux/hwspinlock.h index 3c87cc106905..42430b18b366 100644 --- a/include/linux/hwspinlock.h +++ b/include/linux/hwspinlock.h @@ -78,6 +78,7 @@ int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int, unsigned long *); int __hwspin_trylock(struct hwspinlock *, int, unsigned long *); void __hwspin_unlock(struct hwspinlock *, int, unsigned long *); +void __hwspin_lock_reset(int id); #else /* !CONFIG_HWSPINLOCK */ @@ -133,6 +134,10 @@ static inline int hwspin_lock_get_id(struct hwspinlock *hwlock) return 0; } +static inline void __hwspin_lock_reset(int id) +{ +} + #endif /* !CONFIG_HWSPINLOCK */ /** |