summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSubramaniam Chanderashekarapuram <subramaniam.ca@ti.com>2012-08-24 20:32:48 -0500
committerXavier Boudet <x-boudet@ti.com>2012-11-05 14:24:58 +0100
commit7aec72d028f414ff2f88007dda4ea7939e5d2a79 (patch)
tree0afca174d0e7db0452201bd41a5e653d08dfb28b
parent85dab720cadfe1b313316abc354c0da6e4546053 (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.c50
-rw-r--r--include/linux/hwspinlock.h5
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 */
/**