diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-17 11:53:53 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-17 11:53:53 -0700 |
commit | 57ab5f740202babe93c8796013c5cfdfd6d08d7d (patch) | |
tree | 77ad80291bdaa8e95f2a26956a2d7d8625f049fa /drivers | |
parent | fdcec00405fae0befdd7bbcbe738b7325e5746fb (diff) | |
parent | 360aa640a59f269b784848c0b2d6d462952750d9 (diff) |
Merge tag 'hwlock-v5.3' of git://github.com/andersson/remoteproc
Pull hwspinlock updates from Bjorn Andersson:
"This contains support for hardware spinlock TI K3 AM65x and J721E
family of SoCs, support for using hwspinlocks from atomic context and
better error reporting when dealing with hardware disabled in
DeviceTree"
* tag 'hwlock-v5.3' of git://github.com/andersson/remoteproc:
hwspinlock: add the 'in_atomic' API
hwspinlock: document the hwspinlock 'raw' API
hwspinlock: stm32: implement the relax() ops
hwspinlock: ignore disabled device
hwspinlock/omap: Add a trace during probe
hwspinlock/omap: Add support for TI K3 SoCs
dt-bindings: hwlock: Update OMAP binding for TI K3 SoCs
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hwspinlock/Kconfig | 2 | ||||
-rw-r--r-- | drivers/hwspinlock/hwspinlock_core.c | 48 | ||||
-rw-r--r-- | drivers/hwspinlock/omap_hwspinlock.c | 4 | ||||
-rw-r--r-- | drivers/hwspinlock/stm32_hwspinlock.c | 7 |
4 files changed, 47 insertions, 14 deletions
diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index 7869c67e5b6b..37740e992cfa 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -9,7 +9,7 @@ menuconfig HWSPINLOCK config HWSPINLOCK_OMAP tristate "OMAP Hardware Spinlock device" depends on HWSPINLOCK - depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX + depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX || ARCH_K3 help Say y here to support the OMAP Hardware Spinlock device (firstly introduced in OMAP4). diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 2bad40d42210..8862445aa858 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -9,6 +9,7 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ +#include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/spinlock.h> @@ -23,6 +24,9 @@ #include "hwspinlock_internal.h" +/* retry delay used in atomic context */ +#define HWSPINLOCK_RETRY_DELAY_US 100 + /* radix tree tags */ #define HWSPINLOCK_UNUSED (0) /* tags an hwspinlock as unused */ @@ -68,11 +72,11 @@ static DEFINE_MUTEX(hwspinlock_tree_lock); * user need some time-consuming or sleepable operations under the hardware * lock, they need one sleepable lock (like mutex) to protect the operations. * - * If the mode is not HWLOCK_RAW, upon a successful return from this function, - * preemption (and possibly interrupts) is disabled, so the caller must not - * sleep, and is advised to release the hwspinlock as soon as possible. This is - * required in order to minimize remote cores polling on the hardware - * interconnect. + * If the mode is neither HWLOCK_IN_ATOMIC nor HWLOCK_RAW, upon a successful + * return from this function, preemption (and possibly interrupts) is disabled, + * so the caller must not sleep, and is advised to release the hwspinlock as + * soon as possible. This is required in order to minimize remote cores polling + * on the hardware interconnect. * * The user decides whether local interrupts are disabled or not, and if yes, * whether he wants their previous state to be saved. It is up to the user @@ -112,6 +116,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags) ret = spin_trylock_irq(&hwlock->lock); break; case HWLOCK_RAW: + case HWLOCK_IN_ATOMIC: ret = 1; break; default: @@ -136,6 +141,7 @@ int __hwspin_trylock(struct hwspinlock *hwlock, int mode, unsigned long *flags) spin_unlock_irq(&hwlock->lock); break; case HWLOCK_RAW: + case HWLOCK_IN_ATOMIC: /* Nothing to do */ break; default: @@ -179,11 +185,14 @@ EXPORT_SYMBOL_GPL(__hwspin_trylock); * user need some time-consuming or sleepable operations under the hardware * lock, they need one sleepable lock (like mutex) to protect the operations. * - * If the mode is not HWLOCK_RAW, upon a successful return from this function, - * preemption is disabled (and possibly local interrupts, too), so the caller - * must not sleep, and is advised to release the hwspinlock as soon as possible. - * This is required in order to minimize remote cores polling on the - * hardware interconnect. + * If the mode is HWLOCK_IN_ATOMIC (called from an atomic context) the timeout + * is handled with busy-waiting delays, hence shall not exceed few msecs. + * + * If the mode is neither HWLOCK_IN_ATOMIC nor HWLOCK_RAW, upon a successful + * return from this function, preemption (and possibly interrupts) is disabled, + * so the caller must not sleep, and is advised to release the hwspinlock as + * soon as possible. This is required in order to minimize remote cores polling + * on the hardware interconnect. * * The user decides whether local interrupts are disabled or not, and if yes, * whether he wants their previous state to be saved. It is up to the user @@ -198,7 +207,7 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to, int mode, unsigned long *flags) { int ret; - unsigned long expire; + unsigned long expire, atomic_delay = 0; expire = msecs_to_jiffies(to) + jiffies; @@ -212,8 +221,15 @@ int __hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int to, * The lock is already taken, let's check if the user wants * us to try again */ - if (time_is_before_eq_jiffies(expire)) - return -ETIMEDOUT; + if (mode == HWLOCK_IN_ATOMIC) { + udelay(HWSPINLOCK_RETRY_DELAY_US); + atomic_delay += HWSPINLOCK_RETRY_DELAY_US; + if (atomic_delay > to * 1000) + return -ETIMEDOUT; + } else { + if (time_is_before_eq_jiffies(expire)) + return -ETIMEDOUT; + } /* * Allow platform-specific relax handlers to prevent @@ -276,6 +292,7 @@ void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags) spin_unlock_irq(&hwlock->lock); break; case HWLOCK_RAW: + case HWLOCK_IN_ATOMIC: /* Nothing to do */ break; default: @@ -333,6 +350,11 @@ int of_hwspin_lock_get_id(struct device_node *np, int index) if (ret) return ret; + if (!of_device_is_available(args.np)) { + ret = -ENOENT; + goto out; + } + /* Find the hwspinlock device: we need its base_id */ ret = -EPROBE_DEFER; rcu_read_lock(); diff --git a/drivers/hwspinlock/omap_hwspinlock.c b/drivers/hwspinlock/omap_hwspinlock.c index 625844e0abef..14e1a532ebb5 100644 --- a/drivers/hwspinlock/omap_hwspinlock.c +++ b/drivers/hwspinlock/omap_hwspinlock.c @@ -140,6 +140,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) if (ret) goto reg_fail; + dev_dbg(&pdev->dev, "Registered %d locks with HwSpinlock core\n", + num_locks); + return 0; reg_fail: @@ -171,6 +174,7 @@ static int omap_hwspinlock_remove(struct platform_device *pdev) static const struct of_device_id omap_hwspinlock_of_match[] = { { .compatible = "ti,omap4-hwspinlock", }, + { .compatible = "ti,am654-hwspinlock", }, { /* end */ }, }; MODULE_DEVICE_TABLE(of, omap_hwspinlock_of_match); diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c index 441839288893..c8eacf4f9692 100644 --- a/drivers/hwspinlock/stm32_hwspinlock.c +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -5,6 +5,7 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/hwspinlock.h> #include <linux/io.h> #include <linux/kernel.h> @@ -42,9 +43,15 @@ static void stm32_hwspinlock_unlock(struct hwspinlock *lock) writel(STM32_MUTEX_COREID, lock_addr); } +static void stm32_hwspinlock_relax(struct hwspinlock *lock) +{ + ndelay(50); +} + static const struct hwspinlock_ops stm32_hwspinlock_ops = { .trylock = stm32_hwspinlock_trylock, .unlock = stm32_hwspinlock_unlock, + .relax = stm32_hwspinlock_relax, }; static int stm32_hwspinlock_probe(struct platform_device *pdev) |