From 244b2c5ca8b14627e4a17755e5922221e121c771 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 09 Oct 2024 06:15:07 +0000
Subject: [PATCH] change system file
---
kernel/drivers/hwspinlock/hwspinlock_core.c | 64 +++++++++++++++++++++----------
1 files changed, 43 insertions(+), 21 deletions(-)
diff --git a/kernel/drivers/hwspinlock/hwspinlock_core.c b/kernel/drivers/hwspinlock/hwspinlock_core.c
index 2bad40d..fd5f5c5 100644
--- a/kernel/drivers/hwspinlock/hwspinlock_core.c
+++ b/kernel/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>
@@ -22,6 +23,9 @@
#include <linux/of.h>
#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 @@
* 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
@@ -88,8 +92,8 @@
{
int ret;
- BUG_ON(!hwlock);
- BUG_ON(!flags && mode == HWLOCK_IRQSTATE);
+ if (WARN_ON(!hwlock || (!flags && mode == HWLOCK_IRQSTATE)))
+ return -EINVAL;
/*
* This spin_lock{_irq, _irqsave} serves three purposes:
@@ -112,6 +116,7 @@
ret = spin_trylock_irq(&hwlock->lock);
break;
case HWLOCK_RAW:
+ case HWLOCK_IN_ATOMIC:
ret = 1;
break;
default:
@@ -136,6 +141,7 @@
spin_unlock_irq(&hwlock->lock);
break;
case HWLOCK_RAW:
+ case HWLOCK_IN_ATOMIC:
/* Nothing to do */
break;
default:
@@ -179,11 +185,14 @@
* 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 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 @@
* 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
@@ -248,8 +264,8 @@
*/
void __hwspin_unlock(struct hwspinlock *hwlock, int mode, unsigned long *flags)
{
- BUG_ON(!hwlock);
- BUG_ON(!flags && mode == HWLOCK_IRQSTATE);
+ if (WARN_ON(!hwlock || (!flags && mode == HWLOCK_IRQSTATE)))
+ return;
/*
* We must make sure that memory operations (both reads and writes),
@@ -276,6 +292,7 @@
spin_unlock_irq(&hwlock->lock);
break;
case HWLOCK_RAW:
+ case HWLOCK_IN_ATOMIC:
/* Nothing to do */
break;
default:
@@ -332,6 +349,11 @@
&args);
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;
@@ -635,12 +657,14 @@
/* notify PM core that power is now needed */
ret = pm_runtime_get_sync(dev);
- if (ret < 0) {
+ if (ret < 0 && ret != -EACCES) {
dev_err(dev, "%s: can't power on device\n", __func__);
pm_runtime_put_noidle(dev);
module_put(dev->driver->owner);
return ret;
}
+
+ ret = 0;
/* mark hwspinlock as used, should not fail */
tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock),
@@ -798,9 +822,7 @@
}
/* notify the underlying device that power is not needed */
- ret = pm_runtime_put(dev);
- if (ret < 0)
- goto out;
+ pm_runtime_put(dev);
/* mark this hwspinlock as available */
tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock),
--
Gitblit v1.6.2