#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"
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:
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;
#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"
#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_VIRQ_NEEDS_ALLOC XA_MARK_0
void intc_irq_xlate_set(unsigned int irq, intc_enum id, struct intc_desc_int *d)
{
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_mark(&d->array, enum_id,
+ INTC_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;
{
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;
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,
- INTC_TAG_VIRQ_NEEDS_ALLOC);
+ }
+ xa_set_mark(&d->array, entry->enum_id, INTC_VIRQ_NEEDS_ALLOC);
}
-
- raw_spin_unlock_irqrestore(&d->lock, flags);
}
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_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;
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], 0);
+ xa_clear_mark(&d->array, entry->enum_id, INTC_VIRQ_NEEDS_ALLOC);
}
-
- raw_spin_unlock_irqrestore(&d->lock, flags);
}
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_marked(&d->array, INTC_VIRQ_NEEDS_ALLOC))
intc_subgroup_map(d);
}