Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 721255b

Browse files
shankerd04KAGA-KOKO
authored andcommitted
genirq: Use a maple tree for interrupt descriptor management
The current implementation uses a static bitmap for interrupt descriptor allocation and a radix tree to pointer store the pointer for lookup. However, the size of the bitmap is constrained by the build time macro MAX_SPARSE_IRQS, which may not be sufficient to support high-end servers, particularly those with GICv4.1 hardware, which require a large interrupt space to cover LPIs and vSGIs. Replace the bitmap and the radix tree with a maple tree, which not only stores pointers for lookup, but also provides a mechanism to find free ranges. That removes the build time hardcoded upper limit. Signed-off-by: Shanker Donthineni <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5e630aa commit 721255b

File tree

2 files changed

+33
-26
lines changed

2 files changed

+33
-26
lines changed

kernel/irq/internals.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include <linux/sched/clock.h>
1313

1414
#ifdef CONFIG_SPARSE_IRQ
15-
# define MAX_SPARSE_IRQS (NR_IRQS + 8196)
15+
# define MAX_SPARSE_IRQS INT_MAX
1616
#else
1717
# define MAX_SPARSE_IRQS NR_IRQS
1818
#endif

kernel/irq/irqdesc.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
#include <linux/export.h>
1313
#include <linux/interrupt.h>
1414
#include <linux/kernel_stat.h>
15-
#include <linux/radix-tree.h>
16-
#include <linux/bitmap.h>
15+
#include <linux/maple_tree.h>
1716
#include <linux/irqdomain.h>
1817
#include <linux/sysfs.h>
1918

@@ -131,17 +130,39 @@ int nr_irqs = NR_IRQS;
131130
EXPORT_SYMBOL_GPL(nr_irqs);
132131

133132
static DEFINE_MUTEX(sparse_irq_lock);
134-
static DECLARE_BITMAP(allocated_irqs, MAX_SPARSE_IRQS);
133+
static struct maple_tree sparse_irqs = MTREE_INIT_EXT(sparse_irqs,
134+
MT_FLAGS_ALLOC_RANGE |
135+
MT_FLAGS_LOCK_EXTERN |
136+
MT_FLAGS_USE_RCU,
137+
sparse_irq_lock);
135138

136139
static int irq_find_free_area(unsigned int from, unsigned int cnt)
137140
{
138-
return bitmap_find_next_zero_area(allocated_irqs, MAX_SPARSE_IRQS,
139-
from, cnt, 0);
141+
MA_STATE(mas, &sparse_irqs, 0, 0);
142+
143+
if (mas_empty_area(&mas, from, MAX_SPARSE_IRQS, cnt))
144+
return -ENOSPC;
145+
return mas.index;
140146
}
141147

142148
static unsigned int irq_find_at_or_after(unsigned int offset)
143149
{
144-
return find_next_bit(allocated_irqs, nr_irqs, offset);
150+
unsigned long index = offset;
151+
struct irq_desc *desc = mt_find(&sparse_irqs, &index, nr_irqs);
152+
153+
return desc ? irq_desc_get_irq(desc) : nr_irqs;
154+
}
155+
156+
static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
157+
{
158+
MA_STATE(mas, &sparse_irqs, irq, irq);
159+
WARN_ON(mas_store_gfp(&mas, desc, GFP_KERNEL) != 0);
160+
}
161+
162+
static void delete_irq_desc(unsigned int irq)
163+
{
164+
MA_STATE(mas, &sparse_irqs, irq, irq);
165+
mas_erase(&mas);
145166
}
146167

147168
#ifdef CONFIG_SPARSE_IRQ
@@ -355,26 +376,14 @@ static void irq_sysfs_del(struct irq_desc *desc) {}
355376

356377
#endif /* CONFIG_SYSFS */
357378

358-
static RADIX_TREE(irq_desc_tree, GFP_KERNEL);
359-
360-
static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
361-
{
362-
radix_tree_insert(&irq_desc_tree, irq, desc);
363-
}
364-
365379
struct irq_desc *irq_to_desc(unsigned int irq)
366380
{
367-
return radix_tree_lookup(&irq_desc_tree, irq);
381+
return mtree_load(&sparse_irqs, irq);
368382
}
369383
#ifdef CONFIG_KVM_BOOK3S_64_HV_MODULE
370384
EXPORT_SYMBOL_GPL(irq_to_desc);
371385
#endif
372386

373-
static void delete_irq_desc(unsigned int irq)
374-
{
375-
radix_tree_delete(&irq_desc_tree, irq);
376-
}
377-
378387
#ifdef CONFIG_SMP
379388
static void free_masks(struct irq_desc *desc)
380389
{
@@ -517,7 +526,6 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
517526
irq_sysfs_add(start + i, desc);
518527
irq_add_debugfs_entry(start + i, desc);
519528
}
520-
bitmap_set(allocated_irqs, start, cnt);
521529
return start;
522530

523531
err:
@@ -557,7 +565,6 @@ int __init early_irq_init(void)
557565

558566
for (i = 0; i < initcnt; i++) {
559567
desc = alloc_desc(i, node, 0, NULL, NULL);
560-
set_bit(i, allocated_irqs);
561568
irq_insert_desc(i, desc);
562569
}
563570
return arch_early_irq_init();
@@ -612,6 +619,7 @@ static void free_desc(unsigned int irq)
612619
raw_spin_lock_irqsave(&desc->lock, flags);
613620
desc_set_defaults(irq, desc, irq_desc_get_node(desc), NULL, NULL);
614621
raw_spin_unlock_irqrestore(&desc->lock, flags);
622+
delete_irq_desc(irq);
615623
}
616624

617625
static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
@@ -624,8 +632,8 @@ static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
624632
struct irq_desc *desc = irq_to_desc(start + i);
625633

626634
desc->owner = owner;
635+
irq_insert_desc(start + i, desc);
627636
}
628-
bitmap_set(allocated_irqs, start, cnt);
629637
return start;
630638
}
631639

@@ -637,7 +645,7 @@ static int irq_expand_nr_irqs(unsigned int nr)
637645
void irq_mark_irq(unsigned int irq)
638646
{
639647
mutex_lock(&sparse_irq_lock);
640-
bitmap_set(allocated_irqs, irq, 1);
648+
irq_insert_desc(irq, irq_desc + irq);
641649
mutex_unlock(&sparse_irq_lock);
642650
}
643651

@@ -781,7 +789,6 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
781789
for (i = 0; i < cnt; i++)
782790
free_desc(from + i);
783791

784-
bitmap_clear(allocated_irqs, from, cnt);
785792
mutex_unlock(&sparse_irq_lock);
786793
}
787794
EXPORT_SYMBOL_GPL(irq_free_descs);
@@ -844,7 +851,7 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs);
844851
* irq_get_next_irq - get next allocated irq number
845852
* @offset: where to start the search
846853
*
847-
* Returns next irq number at or after offset or nr_irqs if none is found.
854+
* Returns next irq number after offset or nr_irqs if none is found.
848855
*/
849856
unsigned int irq_get_next_irq(unsigned int offset)
850857
{

0 commit comments

Comments
 (0)