All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] hwspinlock: add summary in debugfs
@ 2026-06-22  8:51 Wolfram Sang
  2026-06-22  8:52 ` [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected() Wolfram Sang
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Wolfram Sang @ 2026-06-22  8:51 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: linux-kernel, Matthew Wilcox, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Wolfram Sang, Baolin Wang

Renesas R-Car SoCs have their spinlocks inside a unit called MFIS. Up to
R-Car Gen4, there was only one MFIS unit on the SoC. Gen5, though, has
multiple instances and, thus, multiple spinlock providers. The spinlocks
are meant for specific cases (AP<->AP, AP<->RT, AP<->SCP...). For
development on these systems, it is helpful to have an overview of
registered spinlocks in debugfs. This series adds support for that. The
first two patches update the radix-tree header to support more lock
types. The third patch fixes a missing RCU annotation for the slot
pointer. The fourth patch finally adds the desired functionality.

Because the radix tree seems to have no dedicated tree nor maintainer, I
suggest that all these patches go in via hwspinlock. This also keeps the
dependencies zero.

A branch for testing is here:

git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git renesas/mfis/hwspinlock

It has been tested on a SparrowHawk board (R-Car V4H) and an Ironhide
board (R-Car X5H).

Looking forward to comments.

Changes since v1:
* dropped patch inverting the HWSPINLOCK_UNUSED logic
* added radix tree patches to support the mutex treelock of hwspinlock
* included RCU annotation patch sent previously as independent patch
* addresses Sashiko comments in patch 4
	* ensure correct locking
	* add error codes
	* proper ppos handling
	* no leaking iterator when done
	* mark pointer dereference as protected (needs patch 2)
	* split up long lines


Wolfram Sang (4):
  radix-tree: add parameter doc for radix_tree_deref_slot_protected()
  radix-tree: allow more lock types with
    radix_tree_deref_slot_protected()
  hwspinlock: annotate slot pointer as RCU sensitive
  hwspinlock: add summary in debugfs

 drivers/hwspinlock/hwspinlock_core.c | 91 +++++++++++++++++++++++++++-
 include/linux/radix-tree.h           |  9 ++-
 2 files changed, 94 insertions(+), 6 deletions(-)

-- 
2.47.3


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected()
  2026-06-22  8:51 [PATCH v2 0/4] hwspinlock: add summary in debugfs Wolfram Sang
@ 2026-06-22  8:52 ` Wolfram Sang
  2026-06-22 10:16   ` Andy Shevchenko
  2026-06-22  8:52 ` [PATCH v2 2/4] radix-tree: allow more lock types with radix_tree_deref_slot_protected() Wolfram Sang
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Wolfram Sang @ 2026-06-22  8:52 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: linux-kernel, Matthew Wilcox, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Wolfram Sang

Add the missing documentation for the 'treelock' parameter.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
 include/linux/radix-tree.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index eae67015ce51..b8997f07b2d4 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -182,6 +182,7 @@ static inline void *radix_tree_deref_slot(void __rcu **slot)
 /**
  * radix_tree_deref_slot_protected - dereference a slot with tree lock held
  * @slot: slot pointer, returned by radix_tree_lookup_slot
+ * @treelock: pointer to the spinlock protecting the tree
  *
  * Similar to radix_tree_deref_slot.  The caller does not hold the RCU read
  * lock but it must hold the tree lock to prevent parallel updates.
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/4] radix-tree: allow more lock types with radix_tree_deref_slot_protected()
  2026-06-22  8:51 [PATCH v2 0/4] hwspinlock: add summary in debugfs Wolfram Sang
  2026-06-22  8:52 ` [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected() Wolfram Sang
@ 2026-06-22  8:52 ` Wolfram Sang
  2026-06-22 10:18   ` Andy Shevchenko
  2026-06-22  8:52 ` [PATCH v2 3/4] hwspinlock: annotate slot pointer as RCU sensitive Wolfram Sang
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Wolfram Sang @ 2026-06-22  8:52 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: linux-kernel, Matthew Wilcox, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Wolfram Sang

The 'treelock' parameter is type-checked to be of spinlock_t. The lock
to protect the tree might be something else, though. E.g. the hwspinlock
subsystem uses a mutex. 'treelock' is simply passed onto
lockdep_is_held() which supports way more lock types by using a #define
instead of an inline function. Use the same approach for
radix_tree_deref_slot_protected() to support more lock types, too.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
 include/linux/radix-tree.h | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index b8997f07b2d4..a07e5a51eaf9 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -182,18 +182,16 @@ static inline void *radix_tree_deref_slot(void __rcu **slot)
 /**
  * radix_tree_deref_slot_protected - dereference a slot with tree lock held
  * @slot: slot pointer, returned by radix_tree_lookup_slot
- * @treelock: pointer to the spinlock protecting the tree
+ * @treelock: pointer to the lock protecting the tree. Any lock type supported
+ *            by lockdep_is_held() can be used
  *
  * Similar to radix_tree_deref_slot.  The caller does not hold the RCU read
  * lock but it must hold the tree lock to prevent parallel updates.
  *
  * Return: entry stored in that slot.
  */
-static inline void *radix_tree_deref_slot_protected(void __rcu **slot,
-							spinlock_t *treelock)
-{
-	return rcu_dereference_protected(*slot, lockdep_is_held(treelock));
-}
+#define radix_tree_deref_slot_protected(slot, treelock) \
+	rcu_dereference_protected(*(slot), lockdep_is_held(treelock))
 
 /**
  * radix_tree_deref_retry	- check radix_tree_deref_slot
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/4] hwspinlock: annotate slot pointer as RCU sensitive
  2026-06-22  8:51 [PATCH v2 0/4] hwspinlock: add summary in debugfs Wolfram Sang
  2026-06-22  8:52 ` [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected() Wolfram Sang
  2026-06-22  8:52 ` [PATCH v2 2/4] radix-tree: allow more lock types with radix_tree_deref_slot_protected() Wolfram Sang
@ 2026-06-22  8:52 ` Wolfram Sang
  2026-06-22 10:20   ` Andy Shevchenko
  2026-06-22  8:52 ` [PATCH v2 4/4] hwspinlock: add summary in debugfs Wolfram Sang
  2026-06-22 13:59 ` [PATCH v2 0/4] " Matthew Wilcox
  4 siblings, 1 reply; 11+ messages in thread
From: Wolfram Sang @ 2026-06-22  8:52 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: linux-kernel, Matthew Wilcox, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Wolfram Sang, Baolin Wang

Because 'slot' is used within an RCU read-lock, it must not be accessed
directly but with RCU helpers. Annotate the pointer to enforce checking
this. Sparse confirms the missing annotation:

drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in assignment (different address spaces)
drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void **slot
drivers/hwspinlock/hwspinlock_core.c:392:9:    got void [noderef] __rcu **
drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in assignment (different address spaces)
drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void **slot
drivers/hwspinlock/hwspinlock_core.c:392:9:    got void [noderef] __rcu **
drivers/hwspinlock/hwspinlock_core.c:393:48: warning: incorrect type in argument 1 (different address spaces)
drivers/hwspinlock/hwspinlock_core.c:393:48:    expected void [noderef] __rcu **slot
drivers/hwspinlock/hwspinlock_core.c:393:48:    got void **slot
drivers/hwspinlock/hwspinlock_core.c:397:30: warning: incorrect type in assignment (different address spaces)
drivers/hwspinlock/hwspinlock_core.c:397:30:    expected void **slot
drivers/hwspinlock/hwspinlock_core.c:397:30:    got void [noderef] __rcu **
drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in argument 1 (different address spaces)
drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void [noderef] __rcu **slot
drivers/hwspinlock/hwspinlock_core.c:392:9:    got void **slot
drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in assignment (different address spaces)
drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void **slot
drivers/hwspinlock/hwspinlock_core.c:392:9:    got void [noderef] __rcu **

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
 drivers/hwspinlock/hwspinlock_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index a509b73da190..c97d68050102 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -372,7 +372,7 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
 	struct of_phandle_args args;
 	struct hwspinlock *hwlock;
 	struct radix_tree_iter iter;
-	void **slot;
+	void __rcu **slot;
 	int id;
 	int ret;
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/4] hwspinlock: add summary in debugfs
  2026-06-22  8:51 [PATCH v2 0/4] hwspinlock: add summary in debugfs Wolfram Sang
                   ` (2 preceding siblings ...)
  2026-06-22  8:52 ` [PATCH v2 3/4] hwspinlock: annotate slot pointer as RCU sensitive Wolfram Sang
@ 2026-06-22  8:52 ` Wolfram Sang
  2026-06-22 10:24   ` Andy Shevchenko
  2026-06-22 13:59 ` [PATCH v2 0/4] " Matthew Wilcox
  4 siblings, 1 reply; 11+ messages in thread
From: Wolfram Sang @ 2026-06-22  8:52 UTC (permalink / raw)
  To: linux-renesas-soc
  Cc: linux-kernel, Matthew Wilcox, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Wolfram Sang, Baolin Wang

Add a subsystem entry in debugfs and place a summary file there. It
informs about registered locks, if they are in use, and to which device
they belong. The state of the lock itself is usually not accessible
without modifying the state, so there is no support for that.

Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
---
 drivers/hwspinlock/hwspinlock_core.c | 89 ++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index c97d68050102..b4789b0c2150 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/debugfs.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -21,6 +22,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/mutex.h>
 #include <linux/of.h>
+#include <linux/seq_file.h>
 
 #include "hwspinlock_internal.h"
 
@@ -888,5 +890,92 @@ struct hwspinlock *devm_hwspin_lock_request_specific(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_hwspin_lock_request_specific);
 
+#ifdef CONFIG_DEBUG_FS
+struct hwspinlock_seq_iterator {
+	void __rcu **slot;
+	struct radix_tree_iter iter;
+};
+
+static void *hwspinlock_seq_start(struct seq_file *s, loff_t *ppos)
+{
+	struct hwspinlock_seq_iterator *hwsp_seq_iter;
+
+	mutex_lock(&hwspinlock_tree_lock);
+
+	hwsp_seq_iter = kzalloc_obj(*hwsp_seq_iter);
+	if (!hwsp_seq_iter)
+		return ERR_PTR(-ENOMEM);
+
+	hwsp_seq_iter->slot = radix_tree_iter_lookup(&hwspinlock_tree,
+						     &hwsp_seq_iter->iter, *ppos);
+
+	return hwsp_seq_iter->slot ? hwsp_seq_iter : NULL;
+}
+
+static void *hwspinlock_seq_next(struct seq_file *s, void *v, loff_t *ppos)
+{
+	struct hwspinlock_seq_iterator *hwsp_seq_iter = v;
+
+	hwsp_seq_iter->slot = radix_tree_next_slot(hwsp_seq_iter->slot,
+						   &hwsp_seq_iter->iter, 0);
+	if (!hwsp_seq_iter->slot)
+		hwsp_seq_iter->slot = radix_tree_next_chunk(&hwspinlock_tree,
+							    &hwsp_seq_iter->iter, 0);
+
+	if (!hwsp_seq_iter->slot) {
+		kfree(hwsp_seq_iter);
+		++*ppos;
+		return NULL;
+	}
+
+	*ppos = hwsp_seq_iter->iter.index;
+	return hwsp_seq_iter;
+}
+
+static void hwspinlock_seq_stop(struct seq_file *s, void *v)
+{
+	mutex_unlock(&hwspinlock_tree_lock);
+}
+
+static int hwspinlock_seq_show(struct seq_file *s, void *v)
+{
+	struct hwspinlock_seq_iterator *hwsp_seq_iter = v;
+	unsigned long id = hwsp_seq_iter->iter.index;
+	struct hwspinlock *hwlock;
+	int used;
+
+	used = !radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
+	hwlock = radix_tree_deref_slot_protected(hwsp_seq_iter->slot,
+						 &hwspinlock_tree_lock);
+	seq_printf(s, "%4lu:\t%s\t%s\n", id, used ? "in use" : "free",
+		   dev_name(hwlock->bank->dev));
+	return 0;
+}
+
+static const struct seq_operations hwspinlock_sops = {
+	.start = hwspinlock_seq_start,
+	.next = hwspinlock_seq_next,
+	.stop = hwspinlock_seq_stop,
+	.show = hwspinlock_seq_show,
+};
+DEFINE_SEQ_ATTRIBUTE(hwspinlock);
+
+/*
+ * subsys_initcall() is used here but controllers may already have been
+ * registered earlier or will be later. The rationale is that debugfs is
+ * accessed only late, i.e. from userspace. So, files created here must make no
+ * assumptions about initcall ordering.
+ */
+static int __init hwspinlock_init(void)
+{
+	struct dentry *hwspinlock_debugfs = debugfs_create_dir("hwspinlock", NULL);
+
+	debugfs_create_file("hwspinlock_summary", 0444, hwspinlock_debugfs,
+			    NULL, &hwspinlock_fops);
+	return 0;
+}
+subsys_initcall(hwspinlock_init);
+#endif	/* DEBUG_FS */
+
 MODULE_DESCRIPTION("Hardware spinlock interface");
 MODULE_AUTHOR("Ohad Ben-Cohen <ohad@wizery.com>");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected()
  2026-06-22  8:52 ` [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected() Wolfram Sang
@ 2026-06-22 10:16   ` Andy Shevchenko
  0 siblings, 0 replies; 11+ messages in thread
From: Andy Shevchenko @ 2026-06-22 10:16 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-renesas-soc, linux-kernel, Matthew Wilcox, Bjorn Andersson,
	linux-remoteproc

On Mon, Jun 22, 2026 at 10:52:00AM +0200, Wolfram Sang wrote:
> Add the missing documentation for the 'treelock' parameter.

Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] radix-tree: allow more lock types with radix_tree_deref_slot_protected()
  2026-06-22  8:52 ` [PATCH v2 2/4] radix-tree: allow more lock types with radix_tree_deref_slot_protected() Wolfram Sang
@ 2026-06-22 10:18   ` Andy Shevchenko
  0 siblings, 0 replies; 11+ messages in thread
From: Andy Shevchenko @ 2026-06-22 10:18 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-renesas-soc, linux-kernel, Matthew Wilcox, Bjorn Andersson,
	linux-remoteproc

On Mon, Jun 22, 2026 at 10:52:01AM +0200, Wolfram Sang wrote:
> The 'treelock' parameter is type-checked to be of spinlock_t. The lock
> to protect the tree might be something else, though. E.g. the hwspinlock
> subsystem uses a mutex. 'treelock' is simply passed onto
> lockdep_is_held() which supports way more lock types by using a #define
> instead of an inline function. Use the same approach for
> radix_tree_deref_slot_protected() to support more lock types, too.

A pity we should use a macro, but I understand why.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/4] hwspinlock: annotate slot pointer as RCU sensitive
  2026-06-22  8:52 ` [PATCH v2 3/4] hwspinlock: annotate slot pointer as RCU sensitive Wolfram Sang
@ 2026-06-22 10:20   ` Andy Shevchenko
  0 siblings, 0 replies; 11+ messages in thread
From: Andy Shevchenko @ 2026-06-22 10:20 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-renesas-soc, linux-kernel, Matthew Wilcox, Bjorn Andersson,
	linux-remoteproc, Baolin Wang

On Mon, Jun 22, 2026 at 10:52:02AM +0200, Wolfram Sang wrote:
> Because 'slot' is used within an RCU read-lock, it must not be accessed
> directly but with RCU helpers. Annotate the pointer to enforce checking
> this. Sparse confirms the missing annotation:

Very good!
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

> drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in assignment (different address spaces)
> drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void **slot
> drivers/hwspinlock/hwspinlock_core.c:392:9:    got void [noderef] __rcu **
> drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in assignment (different address spaces)
> drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void **slot
> drivers/hwspinlock/hwspinlock_core.c:392:9:    got void [noderef] __rcu **

^^^

> drivers/hwspinlock/hwspinlock_core.c:393:48: warning: incorrect type in argument 1 (different address spaces)
> drivers/hwspinlock/hwspinlock_core.c:393:48:    expected void [noderef] __rcu **slot
> drivers/hwspinlock/hwspinlock_core.c:393:48:    got void **slot
> drivers/hwspinlock/hwspinlock_core.c:397:30: warning: incorrect type in assignment (different address spaces)
> drivers/hwspinlock/hwspinlock_core.c:397:30:    expected void **slot
> drivers/hwspinlock/hwspinlock_core.c:397:30:    got void [noderef] __rcu **

> drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in argument 1 (different address spaces)
> drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void [noderef] __rcu **slot
> drivers/hwspinlock/hwspinlock_core.c:392:9:    got void **slot
> drivers/hwspinlock/hwspinlock_core.c:392:9: warning: incorrect type in assignment (different address spaces)
> drivers/hwspinlock/hwspinlock_core.c:392:9:    expected void **slot
> drivers/hwspinlock/hwspinlock_core.c:392:9:    got void [noderef] __rcu **

^^^

No need to have dups per a couple of cases, though.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/4] hwspinlock: add summary in debugfs
  2026-06-22  8:52 ` [PATCH v2 4/4] hwspinlock: add summary in debugfs Wolfram Sang
@ 2026-06-22 10:24   ` Andy Shevchenko
  0 siblings, 0 replies; 11+ messages in thread
From: Andy Shevchenko @ 2026-06-22 10:24 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-renesas-soc, linux-kernel, Matthew Wilcox, Bjorn Andersson,
	linux-remoteproc, Baolin Wang

On Mon, Jun 22, 2026 at 10:52:03AM +0200, Wolfram Sang wrote:
> Add a subsystem entry in debugfs and place a summary file there. It
> informs about registered locks, if they are in use, and to which device
> they belong. The state of the lock itself is usually not accessible
> without modifying the state, so there is no support for that.

...

> +#ifdef CONFIG_DEBUG_FS

Do we really need this? IIRC the compiler would be able to eliminate a dead
code for the cases CONFIG_DEBUG_FS=n.

> +#endif	/* DEBUG_FS */

Otherwise LGTM,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 0/4] hwspinlock: add summary in debugfs
  2026-06-22  8:51 [PATCH v2 0/4] hwspinlock: add summary in debugfs Wolfram Sang
                   ` (3 preceding siblings ...)
  2026-06-22  8:52 ` [PATCH v2 4/4] hwspinlock: add summary in debugfs Wolfram Sang
@ 2026-06-22 13:59 ` Matthew Wilcox
  2026-06-22 16:20   ` Wolfram Sang
  4 siblings, 1 reply; 11+ messages in thread
From: Matthew Wilcox @ 2026-06-22 13:59 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-renesas-soc, linux-kernel, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Baolin Wang

On Mon, Jun 22, 2026 at 10:51:59AM +0200, Wolfram Sang wrote:
> Renesas R-Car SoCs have their spinlocks inside a unit called MFIS. Up to
> R-Car Gen4, there was only one MFIS unit on the SoC. Gen5, though, has
> multiple instances and, thus, multiple spinlock providers. The spinlocks
> are meant for specific cases (AP<->AP, AP<->RT, AP<->SCP...). For
> development on these systems, it is helpful to have an overview of
> registered spinlocks in debugfs. This series adds support for that. The
> first two patches update the radix-tree header to support more lock
> types. The third patch fixes a missing RCU annotation for the slot
> pointer. The fourth patch finally adds the desired functionality.
> 
> Because the radix tree seems to have no dedicated tree nor maintainer, I
> suggest that all these patches go in via hwspinlock. This also keeps the
> dependencies zero.

The radix tree is deprecated.  I don't want to add any new functionality
to it.  Here's a replacement patch to convert hwspinlock to use an
XArray instead of a radix tree.  Compile tested only.

From 8ec88ed466e8153f546f7e8e69193cd5389488ee Mon Sep 17 00:00:00 2001
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
Date: Mon, 22 Jun 2026 09:38:30 -0400
Subject: [PATCH] hwspinlock: Convert to XArray

The radix tree is deprecated.  The XArray uses the same data structure
with a nicer interface.  The hwspinlock_tree_lock is not needed as the
spinlock built into the XArray is sufficient for all these cases.

hwspin_lock_register_single() used to always return 0.  Its caller
thinks it can return an errno, so I believe this to be a bug and so I
have restored its ability to return an error.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 drivers/hwspinlock/hwspinlock_core.c | 133 ++++++++++-----------------
 1 file changed, 50 insertions(+), 83 deletions(-)

diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c
index cc8e952a6772..1dd68b8410dd 100644
--- a/drivers/hwspinlock/hwspinlock_core.c
+++ b/drivers/hwspinlock/hwspinlock_core.c
@@ -16,7 +16,7 @@
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/jiffies.h>
-#include <linux/radix-tree.h>
+#include <linux/xarray.h>
 #include <linux/hwspinlock.h>
 #include <linux/pm_runtime.h>
 #include <linux/mutex.h>
@@ -27,34 +27,21 @@
 /* retry delay used in atomic context */
 #define HWSPINLOCK_RETRY_DELAY_US	100
 
-/* radix tree tags */
-#define HWSPINLOCK_UNUSED	(0) /* tags an hwspinlock as unused */
+/* XArray search mark */
+#define HWSPINLOCK_UNUSED	XA_MARK_0 /* marks a hwspinlock as unused */
 
 /*
- * A radix tree is used to maintain the available hwspinlock instances.
+ * An XArray is used to maintain the available hwspinlock instances.
  * The tree associates hwspinlock pointers with their integer key id,
  * and provides easy-to-use API which makes the hwspinlock core code simple
  * and easy to read.
  *
- * Radix trees are quick on lookups, and reasonably efficient in terms of
+ * XArrays are quick on lookups, and reasonably efficient in terms of
  * storage, especially with high density usages such as this framework
  * requires (a continuous range of integer keys, beginning with zero, is
- * used as the ID's of the hwspinlock instances).
- *
- * The radix tree API supports tagging items in the tree, which this
- * framework uses to mark unused hwspinlock instances (see the
- * HWSPINLOCK_UNUSED tag above). As a result, the process of querying the
- * tree, looking for an unused hwspinlock instance, is now reduced to a
- * single radix tree API call.
- */
-static RADIX_TREE(hwspinlock_tree, GFP_KERNEL);
-
-/*
- * Synchronization of access to the tree is achieved using this mutex,
- * as the radix-tree API requires that users provide all synchronisation.
- * A mutex is needed because we're using non-atomic radix tree allocations.
+ * used as the ID of the hwspinlock instances).
  */
-static DEFINE_MUTEX(hwspinlock_tree_lock);
+static DEFINE_XARRAY(hwspinlocks);
 
 
 /**
@@ -369,10 +356,9 @@ of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
  */
 int of_hwspin_lock_get_id(struct device_node *np, int index)
 {
+	XA_STATE(xas, &hwspinlocks, 0);
 	struct of_phandle_args args;
 	struct hwspinlock *hwlock;
-	struct radix_tree_iter iter;
-	void **slot;
 	int id;
 	int ret;
 
@@ -389,15 +375,9 @@ int of_hwspin_lock_get_id(struct device_node *np, int index)
 	/* Find the hwspinlock device: we need its base_id */
 	ret = -EPROBE_DEFER;
 	rcu_read_lock();
-	radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) {
-		hwlock = radix_tree_deref_slot(slot);
-		if (unlikely(!hwlock))
-			continue;
-		if (radix_tree_deref_retry(hwlock)) {
-			slot = radix_tree_iter_retry(&iter);
+	xas_for_each(&xas, hwlock, ULONG_MAX) {
+		if (xas_retry(&xas, hwlock))
 			continue;
-		}
-
 		if (device_match_of_node(hwlock->bank->dev, args.np)) {
 			ret = 0;
 			break;
@@ -452,51 +432,47 @@ EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id_byname);
 
 static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
 {
-	struct hwspinlock *tmp;
+	XA_STATE(xas, &hwspinlocks, id);
+	struct hwspinlock *existing;
 	int ret;
 
-	mutex_lock(&hwspinlock_tree_lock);
-
-	ret = radix_tree_insert(&hwspinlock_tree, id, hwlock);
-	if (ret) {
-		if (ret == -EEXIST)
-			pr_err("hwspinlock id %d already exists!\n", id);
-		goto out;
+	xas_lock(&xas);
+	existing = xas_load(&xas);
+	if (existing) {
+		pr_err("hwspinlock id %d already exists!\n", id);
+		xas_set_err(&xas, -EBUSY);
 	}
+	xas_store(&xas, hwlock);
 
 	/* mark this hwspinlock as available */
-	tmp = radix_tree_tag_set(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
+	xas_set_mark(&xas, HWSPINLOCK_UNUSED);
+	ret = xas_error(&xas);
+	xas_unlock(&xas);
 
-	/* self-sanity check which should never fail */
-	WARN_ON(tmp != hwlock);
-
-out:
-	mutex_unlock(&hwspinlock_tree_lock);
-	return 0;
+	return ret;
 }
 
 static struct hwspinlock *hwspin_lock_unregister_single(unsigned int id)
 {
+	XA_STATE(xas, &hwspinlocks, id);
 	struct hwspinlock *hwlock = NULL;
-	int ret;
+	bool marked;
 
-	mutex_lock(&hwspinlock_tree_lock);
+	xas_lock(&xas);
 
-	/* make sure the hwspinlock is not in use (tag is set) */
-	ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
-	if (ret == 0) {
+	/* make sure the hwspinlock is not in use (mark is set) */
+	marked = xas_get_mark(&xas, HWSPINLOCK_UNUSED);
+	if (!marked) {
 		pr_err("hwspinlock %d still in use (or not present)\n", id);
 		goto out;
 	}
 
-	hwlock = radix_tree_delete(&hwspinlock_tree, id);
-	if (!hwlock) {
-		pr_err("failed to delete hwspinlock %d\n", id);
-		goto out;
-	}
+	hwlock = xas_store(&xas, NULL);
+	if (!hwlock)
+		pr_err("hwspinlock %d already deleted\n", id);
 
 out:
-	mutex_unlock(&hwspinlock_tree_lock);
+	xas_unlock(&xas);
 	return hwlock;
 }
 
@@ -667,19 +643,20 @@ EXPORT_SYMBOL_GPL(devm_hwspin_lock_register);
 
 /**
  * __hwspin_lock_request() - tag an hwspinlock as used and power it up
+ * @xas: XArray state
  * @hwlock: the target hwspinlock
  *
  * This is an internal function that prepares an hwspinlock instance
  * before it is given to the user. The function assumes that
- * hwspinlock_tree_lock is taken.
+ * the xarray lock is held.
  *
  * Returns: %0 or positive to indicate success, and a negative value to
  * indicate an error (with the appropriate error code)
  */
-static int __hwspin_lock_request(struct hwspinlock *hwlock)
+static int __hwspin_lock_request(struct xa_state *xas,
+		struct hwspinlock *hwlock)
 {
 	struct device *dev = hwlock->bank->dev;
-	struct hwspinlock *tmp;
 	int ret;
 
 	/* prevent underlying implementation from being removed */
@@ -697,16 +674,9 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock)
 		return ret;
 	}
 
-	ret = 0;
+	xas_clear_mark(xas, HWSPINLOCK_UNUSED);
 
-	/* mark hwspinlock as used, should not fail */
-	tmp = radix_tree_tag_clear(&hwspinlock_tree, hwlock_to_id(hwlock),
-							HWSPINLOCK_UNUSED);
-
-	/* self-sanity check that should never fail */
-	WARN_ON(tmp != hwlock);
-
-	return ret;
+	return 0;
 }
 
 /**
@@ -724,13 +694,14 @@ static int __hwspin_lock_request(struct hwspinlock *hwlock)
  */
 struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
 {
+	XA_STATE(xas, &hwspinlocks, id);
 	struct hwspinlock *hwlock;
 	int ret;
 
-	mutex_lock(&hwspinlock_tree_lock);
+	xas_lock(&xas);
 
 	/* make sure this hwspinlock exists */
-	hwlock = radix_tree_lookup(&hwspinlock_tree, id);
+	hwlock = xas_load(&xas);
 	if (!hwlock) {
 		pr_warn("hwspinlock %u does not exist\n", id);
 		goto out;
@@ -740,7 +711,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
 	WARN_ON(hwlock_to_id(hwlock) != id);
 
 	/* make sure this hwspinlock is unused */
-	ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED);
+	ret = xas_get_mark(&xas, HWSPINLOCK_UNUSED);
 	if (ret == 0) {
 		pr_warn("hwspinlock %u is already in use\n", id);
 		hwlock = NULL;
@@ -748,12 +719,12 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id)
 	}
 
 	/* mark as used and power up */
-	ret = __hwspin_lock_request(hwlock);
+	ret = __hwspin_lock_request(&xas, hwlock);
 	if (ret < 0)
 		hwlock = NULL;
 
 out:
-	mutex_unlock(&hwspinlock_tree_lock);
+	xas_unlock(&xas);
 	return hwlock;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
@@ -772,8 +743,8 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific);
  */
 int hwspin_lock_free(struct hwspinlock *hwlock)
 {
+	XA_STATE(xas, &hwspinlocks, 0);
 	struct device *dev;
-	struct hwspinlock *tmp;
 	int ret;
 
 	if (!hwlock) {
@@ -782,11 +753,11 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
 	}
 
 	dev = hwlock->bank->dev;
-	mutex_lock(&hwspinlock_tree_lock);
+	xas_lock(&xas);
+	xas_set(&xas, hwlock_to_id(hwlock));
 
 	/* make sure the hwspinlock is used */
-	ret = radix_tree_tag_get(&hwspinlock_tree, hwlock_to_id(hwlock),
-							HWSPINLOCK_UNUSED);
+	ret = xas_get_mark(&xas, HWSPINLOCK_UNUSED);
 	if (ret == 1) {
 		dev_err(dev, "%s: hwlock is already free\n", __func__);
 		dump_stack();
@@ -798,16 +769,12 @@ int hwspin_lock_free(struct hwspinlock *hwlock)
 	pm_runtime_put(dev);
 
 	/* mark this hwspinlock as available */
-	tmp = radix_tree_tag_set(&hwspinlock_tree, hwlock_to_id(hwlock),
-							HWSPINLOCK_UNUSED);
-
-	/* sanity check (this shouldn't happen) */
-	WARN_ON(tmp != hwlock);
+	xas_set_mark(&xas, HWSPINLOCK_UNUSED);
 
 	module_put(dev->driver->owner);
 
 out:
-	mutex_unlock(&hwspinlock_tree_lock);
+	xas_unlock(&xas);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(hwspin_lock_free);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 0/4] hwspinlock: add summary in debugfs
  2026-06-22 13:59 ` [PATCH v2 0/4] " Matthew Wilcox
@ 2026-06-22 16:20   ` Wolfram Sang
  0 siblings, 0 replies; 11+ messages in thread
From: Wolfram Sang @ 2026-06-22 16:20 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: linux-renesas-soc, linux-kernel, Andy Shevchenko, Bjorn Andersson,
	linux-remoteproc, Baolin Wang

On Mon, Jun 22, 2026 at 02:59:23PM +0100, Matthew Wilcox wrote:
> On Mon, Jun 22, 2026 at 10:51:59AM +0200, Wolfram Sang wrote:
> > Renesas R-Car SoCs have their spinlocks inside a unit called MFIS. Up to
> > R-Car Gen4, there was only one MFIS unit on the SoC. Gen5, though, has
> > multiple instances and, thus, multiple spinlock providers. The spinlocks
> > are meant for specific cases (AP<->AP, AP<->RT, AP<->SCP...). For
> > development on these systems, it is helpful to have an overview of
> > registered spinlocks in debugfs. This series adds support for that. The
> > first two patches update the radix-tree header to support more lock
> > types. The third patch fixes a missing RCU annotation for the slot
> > pointer. The fourth patch finally adds the desired functionality.
> > 
> > Because the radix tree seems to have no dedicated tree nor maintainer, I
> > suggest that all these patches go in via hwspinlock. This also keeps the
> > dependencies zero.
> 
> The radix tree is deprecated.  I don't want to add any new functionality
> to it.  Here's a replacement patch to convert hwspinlock to use an
> XArray instead of a radix tree.  Compile tested only.

Wow, thanks a ton! I have a conference coming up but I still hope to be
able to test your patch this week. We will see...


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-06-22 16:20 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-22  8:51 [PATCH v2 0/4] hwspinlock: add summary in debugfs Wolfram Sang
2026-06-22  8:52 ` [PATCH v2 1/4] radix-tree: add parameter doc for radix_tree_deref_slot_protected() Wolfram Sang
2026-06-22 10:16   ` Andy Shevchenko
2026-06-22  8:52 ` [PATCH v2 2/4] radix-tree: allow more lock types with radix_tree_deref_slot_protected() Wolfram Sang
2026-06-22 10:18   ` Andy Shevchenko
2026-06-22  8:52 ` [PATCH v2 3/4] hwspinlock: annotate slot pointer as RCU sensitive Wolfram Sang
2026-06-22 10:20   ` Andy Shevchenko
2026-06-22  8:52 ` [PATCH v2 4/4] hwspinlock: add summary in debugfs Wolfram Sang
2026-06-22 10:24   ` Andy Shevchenko
2026-06-22 13:59 ` [PATCH v2 0/4] " Matthew Wilcox
2026-06-22 16:20   ` Wolfram Sang

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.