[PATCH v6 78/99] sh: intc: Convert to XArray

From: Matthew Wilcox
Date: Wed Jan 17 2018 - 15:33:11 EST


From: Matthew Wilcox <mawilcox@xxxxxxxxxxxxx>

The radix tree was being protected by a raw spinlock. I believe that
was not necessary, and the new internal regular spinlock will be
adequate for this array.

Signed-off-by: Matthew Wilcox <mawilcox@xxxxxxxxxxxxx>
---
drivers/sh/intc/core.c | 9 ++----
drivers/sh/intc/internals.h | 5 ++--
drivers/sh/intc/virq.c | 72 +++++++++++++--------------------------------
3 files changed, 25 insertions(+), 61 deletions(-)

diff --git a/drivers/sh/intc/core.c b/drivers/sh/intc/core.c
index 8e72bcbd3d6d..356a423d9dcb 100644
--- a/drivers/sh/intc/core.c
+++ b/drivers/sh/intc/core.c
@@ -30,7 +30,6 @@
#include <linux/syscore_ops.h>
#include <linux/list.h>
#include <linux/spinlock.h>
-#include <linux/radix-tree.h>
#include <linux/export.h>
#include <linux/sort.h>
#include "internals.h"
@@ -78,11 +77,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
struct intc_handle_int *hp;
struct irq_data *irq_data;
unsigned int data[2], primary;
- unsigned long flags;

- raw_spin_lock_irqsave(&intc_big_lock, flags);
- radix_tree_insert(&d->tree, enum_id, intc_irq_xlate_get(irq));
- raw_spin_unlock_irqrestore(&intc_big_lock, flags);
+ xa_store(&d->array, enum_id, intc_irq_xlate_get(irq), GFP_ATOMIC);

/*
* Prefer single interrupt source bitmap over other combinations:
@@ -196,8 +192,7 @@ int __init register_intc_controller(struct intc_desc *desc)
INIT_LIST_HEAD(&d->list);
list_add_tail(&d->list, &intc_list);

- raw_spin_lock_init(&d->lock);
- INIT_RADIX_TREE(&d->tree, GFP_ATOMIC);
+ xa_init(&d->array);

d->index = nr_intc_controllers;

diff --git a/drivers/sh/intc/internals.h b/drivers/sh/intc/internals.h
index fa73c173b56a..9b6fd07e99a6 100644
--- a/drivers/sh/intc/internals.h
+++ b/drivers/sh/intc/internals.h
@@ -5,7 +5,7 @@
#include <linux/list.h>
#include <linux/kernel.h>
#include <linux/types.h>
-#include <linux/radix-tree.h>
+#include <linux/xarray.h>
#include <linux/device.h>

#define _INTC_MK(fn, mode, addr_e, addr_d, width, shift) \
@@ -54,8 +54,7 @@ struct intc_subgroup_entry {
struct intc_desc_int {
struct list_head list;
struct device dev;
- struct radix_tree_root tree;
- raw_spinlock_t lock;
+ struct xarray array;
unsigned int index;
unsigned long *reg;
#ifdef CONFIG_SMP
diff --git a/drivers/sh/intc/virq.c b/drivers/sh/intc/virq.c
index a638c3048207..801c9c8b7556 100644
--- a/drivers/sh/intc/virq.c
+++ b/drivers/sh/intc/virq.c
@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/list.h>
-#include <linux/radix-tree.h>
#include <linux/spinlock.h>
#include <linux/export.h>
#include "internals.h"
@@ -27,10 +26,7 @@ struct intc_virq_list {
#define for_each_virq(entry, head) \
for (entry = head; entry; entry = entry->next)

-/*
- * Tags for the radix tree
- */
-#define INTC_TAG_VIRQ_NEEDS_ALLOC 0
+#define INTC_TAG_VIRQ_NEEDS_ALLOC XA_TAG_0

void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d)
{
@@ -54,23 +50,18 @@ int intc_irq_lookup(const char *chipname, intc_enum enum_id)
int irq = -1;

list_for_each_entry(d, &intc_list, list) {
- int tagged;
-
if (strcmp(d->chip.name, chipname) != 0)
continue;

/*
* Catch early lookups for subgroup VIRQs that have not
- * yet been allocated an IRQ. This already includes a
- * fast-path out if the tree is untagged, so there is no
- * need to explicitly test the root tree.
+ * yet been allocated an IRQ.
*/
- tagged = radix_tree_tag_get(&d->tree, enum_id,
- INTC_TAG_VIRQ_NEEDS_ALLOC);
- if (unlikely(tagged))
+ if (unlikely(xa_get_tag(&d->array, enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC)))
break;

- ptr = radix_tree_lookup(&d->tree, enum_id);
+ ptr = xa_load(&d->array, enum_id);
if (ptr) {
irq = ptr - intc_irq_xlate;
break;
@@ -148,22 +139,16 @@ static void __init intc_subgroup_init_one(struct intc_desc *desc,
{
struct intc_map_entry *mapped;
unsigned int pirq;
- unsigned long flags;
int i;

- mapped = radix_tree_lookup(&d->tree, subgroup->parent_id);
- if (!mapped) {
- WARN_ON(1);
+ mapped = xa_load(&d->array, subgroup->parent_id);
+ if (WARN_ON(!mapped))
return;
- }

pirq = mapped - intc_irq_xlate;

- raw_spin_lock_irqsave(&d->lock, flags);
-
for (i = 0; i < ARRAY_SIZE(subgroup->enum_ids); i++) {
struct intc_subgroup_entry *entry;
- int err;

if (!subgroup->enum_ids[i])
continue;
@@ -176,15 +161,14 @@ static void __init intc_subgroup_init_one(struct intc_desc *desc,
entry->enum_id = subgroup->enum_ids[i];
entry->handle = intc_subgroup_data(subgroup, d, i);

- err = radix_tree_insert(&d->tree, entry->enum_id, entry);
- if (unlikely(err < 0))
+ if (xa_err(xa_store(&d->array, entry->enum_id, entry,
+ GFP_NOWAIT))) {
+ kfree(entry);
break;
-
- radix_tree_tag_set(&d->tree, entry->enum_id,
+ }
+ xa_set_tag(&d->array, entry->enum_id,
INTC_TAG_VIRQ_NEEDS_ALLOC);
}
-
- raw_spin_unlock_irqrestore(&d->lock, flags);
}

void __init intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d)
@@ -201,28 +185,16 @@ void __init intc_subgroup_init(struct intc_desc *desc, struct intc_desc_int *d)
static void __init intc_subgroup_map(struct intc_desc_int *d)
{
struct intc_subgroup_entry *entries[32];
- unsigned long flags;
unsigned int nr_found;
int i;

- raw_spin_lock_irqsave(&d->lock, flags);
-
-restart:
- nr_found = radix_tree_gang_lookup_tag_slot(&d->tree,
- (void ***)entries, 0, ARRAY_SIZE(entries),
- INTC_TAG_VIRQ_NEEDS_ALLOC);
+ nr_found = xa_extract(&d->array, (void **)entries, 0, ULONG_MAX,
+ ARRAY_SIZE(entries), INTC_TAG_VIRQ_NEEDS_ALLOC);

for (i = 0; i < nr_found; i++) {
- struct intc_subgroup_entry *entry;
- int irq;
+ struct intc_subgroup_entry *entry = entries[i];
+ int irq = irq_alloc_desc(numa_node_id());

- entry = radix_tree_deref_slot((void **)entries[i]);
- if (unlikely(!entry))
- continue;
- if (radix_tree_deref_retry(entry))
- goto restart;
-
- irq = irq_alloc_desc(numa_node_id());
if (unlikely(irq < 0)) {
pr_err("no more free IRQs, bailing..\n");
break;
@@ -250,13 +222,11 @@ static void __init intc_subgroup_map(struct intc_desc_int *d)
add_virq_to_pirq(entry->pirq, irq);
irq_set_chained_handler(entry->pirq, intc_virq_handler);

- radix_tree_tag_clear(&d->tree, entry->enum_id,
- INTC_TAG_VIRQ_NEEDS_ALLOC);
- radix_tree_replace_slot(&d->tree, (void **)entries[i],
- &intc_irq_xlate[irq]);
+ xa_store(&d->array, entry->enum_id, &intc_irq_xlate[irq],
+ GFP_NOWAIT);
+ xa_clear_tag(&d->array, entry->enum_id,
+ INTC_TAG_VIRQ_NEEDS_ALLOC);
}
-
- raw_spin_unlock_irqrestore(&d->lock, flags);
}

void __init intc_finalize(void)
@@ -264,6 +234,6 @@ void __init intc_finalize(void)
struct intc_desc_int *d;

list_for_each_entry(d, &intc_list, list)
- if (radix_tree_tagged(&d->tree, INTC_TAG_VIRQ_NEEDS_ALLOC))
+ if (xa_tagged(&d->array, INTC_TAG_VIRQ_NEEDS_ALLOC))
intc_subgroup_map(d);
}
--
2.15.1