From: Matthew Wilcox <mawil...@microsoft.com>

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 <mawil...@microsoft.com>
---
 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

Reply via email to