Skip to content

Commit bc06a9e

Browse files
shankerd04KAGA-KOKO
authored andcommitted
genirq: Use hlist for managing resend handlers
The current implementation utilizes a bitmap for managing interrupt resend handlers, which is allocated based on the SPARSE_IRQ/NR_IRQS macros. However, this method may not efficiently utilize memory during runtime, particularly when IRQ_BITMAP_BITS is large. Address this issue by using an hlist to manage interrupt resend handlers instead of relying on a static bitmap memory allocation. Additionally, a new function, clear_irq_resend(), is introduced and called from irq_shutdown to ensure a graceful teardown of the interrupt. Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20230519134902.1495562-2-sdonthineni@nvidia.com
1 parent d15121b commit bc06a9e

File tree

5 files changed

+38
-17
lines changed

5 files changed

+38
-17
lines changed

include/linux/irqdesc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ struct irq_desc {
102102
int parent_irq;
103103
struct module *owner;
104104
const char *name;
105+
#ifdef CONFIG_HARDIRQS_SW_RESEND
106+
struct hlist_node resend_node;
107+
#endif
105108
} ____cacheline_internodealigned_in_smp;
106109

107110
#ifdef CONFIG_SPARSE_IRQ

kernel/irq/chip.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ static void __irq_disable(struct irq_desc *desc, bool mask);
306306
void irq_shutdown(struct irq_desc *desc)
307307
{
308308
if (irqd_is_started(&desc->irq_data)) {
309+
clear_irq_resend(desc);
309310
desc->depth = 1;
310311
if (desc->irq_data.chip->irq_shutdown) {
311312
desc->irq_data.chip->irq_shutdown(&desc->irq_data);

kernel/irq/internals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@ irqreturn_t handle_irq_event(struct irq_desc *desc);
113113

114114
/* Resending of interrupts :*/
115115
int check_irq_resend(struct irq_desc *desc, bool inject);
116+
void clear_irq_resend(struct irq_desc *desc);
117+
void irq_resend_init(struct irq_desc *desc);
116118
bool irq_wait_for_poll(struct irq_desc *desc);
117119
void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action);
118120

kernel/irq/irqdesc.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags,
415415
desc_set_defaults(irq, desc, node, affinity, owner);
416416
irqd_set(&desc->irq_data, flags);
417417
kobject_init(&desc->kobj, &irq_kobj_type);
418+
irq_resend_init(desc);
418419

419420
return desc;
420421

@@ -581,6 +582,7 @@ int __init early_irq_init(void)
581582
mutex_init(&desc[i].request_mutex);
582583
init_waitqueue_head(&desc[i].wait_for_threads);
583584
desc_set_defaults(i, &desc[i], node, NULL, NULL);
585+
irq_resend_init(desc);
584586
}
585587
return arch_early_irq_init();
586588
}

kernel/irq/resend.c

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,36 +21,34 @@
2121

2222
#ifdef CONFIG_HARDIRQS_SW_RESEND
2323

24-
/* Bitmap to handle software resend of interrupts: */
25-
static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);
24+
/* hlist_head to handle software resend of interrupts: */
25+
static HLIST_HEAD(irq_resend_list);
26+
static DEFINE_RAW_SPINLOCK(irq_resend_lock);
2627

2728
/*
2829
* Run software resends of IRQ's
2930
*/
3031
static void resend_irqs(struct tasklet_struct *unused)
3132
{
3233
struct irq_desc *desc;
33-
int irq;
34-
35-
while (!bitmap_empty(irqs_resend, nr_irqs)) {
36-
irq = find_first_bit(irqs_resend, nr_irqs);
37-
clear_bit(irq, irqs_resend);
38-
desc = irq_to_desc(irq);
39-
if (!desc)
40-
continue;
41-
local_irq_disable();
34+
35+
raw_spin_lock_irq(&irq_resend_lock);
36+
while (!hlist_empty(&irq_resend_list)) {
37+
desc = hlist_entry(irq_resend_list.first, struct irq_desc,
38+
resend_node);
39+
hlist_del_init(&desc->resend_node);
40+
raw_spin_unlock(&irq_resend_lock);
4241
desc->handle_irq(desc);
43-
local_irq_enable();
42+
raw_spin_lock(&irq_resend_lock);
4443
}
44+
raw_spin_unlock_irq(&irq_resend_lock);
4545
}
4646

4747
/* Tasklet to handle resend: */
4848
static DECLARE_TASKLET(resend_tasklet, resend_irqs);
4949

5050
static int irq_sw_resend(struct irq_desc *desc)
5151
{
52-
unsigned int irq = irq_desc_get_irq(desc);
53-
5452
/*
5553
* Validate whether this interrupt can be safely injected from
5654
* non interrupt context
@@ -70,16 +68,31 @@ static int irq_sw_resend(struct irq_desc *desc)
7068
*/
7169
if (!desc->parent_irq)
7270
return -EINVAL;
73-
irq = desc->parent_irq;
7471
}
7572

76-
/* Set it pending and activate the softirq: */
77-
set_bit(irq, irqs_resend);
73+
/* Add to resend_list and activate the softirq: */
74+
raw_spin_lock(&irq_resend_lock);
75+
hlist_add_head(&desc->resend_node, &irq_resend_list);
76+
raw_spin_unlock(&irq_resend_lock);
7877
tasklet_schedule(&resend_tasklet);
7978
return 0;
8079
}
8180

81+
void clear_irq_resend(struct irq_desc *desc)
82+
{
83+
raw_spin_lock(&irq_resend_lock);
84+
hlist_del_init(&desc->resend_node);
85+
raw_spin_unlock(&irq_resend_lock);
86+
}
87+
88+
void irq_resend_init(struct irq_desc *desc)
89+
{
90+
INIT_HLIST_NODE(&desc->resend_node);
91+
}
8292
#else
93+
void clear_irq_resend(struct irq_desc *desc) {}
94+
void irq_resend_init(struct irq_desc *desc) {}
95+
8396
static int irq_sw_resend(struct irq_desc *desc)
8497
{
8598
return -EINVAL;

0 commit comments

Comments
 (0)