Skip to content

Commit 49f92d3

Browse files
alcharkKAGA-KOKO
authored andcommitted
irqchip/irq-vt8500: Use a dedicated chained handler function
Current code for the chained interrupt controller maps its interrupts on the parent but doesn't register a separate chained handler, instead needlessly calling enable_irq() on an unactivated parent interrupt, causing a boot time WARN_ON from the common code. The common handler meanwhile loops through all registered interrupt controllers in an arbitrary order and tries to handle active interrupts in each of them, which is fragile. Use common infrastructure for handling chained interrupts instead. Signed-off-by: Alexey Charkov <alchark@gmail.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/all/20250506-vt8500-intc-updates-v2-4-a3a0606cf92d@gmail.com
1 parent 54a1f3e commit 49f92d3

File tree

1 file changed

+37
-22
lines changed

1 file changed

+37
-22
lines changed

drivers/irqchip/irq-vt8500.c

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/io.h>
1616
#include <linux/irq.h>
1717
#include <linux/irqchip.h>
18+
#include <linux/irqchip/chained_irq.h>
1819
#include <linux/irqdomain.h>
1920
#include <linux/interrupt.h>
2021
#include <linux/bitops.h>
@@ -66,6 +67,8 @@ struct vt8500_irq_data {
6667
/* Global variable for accessing io-mem addresses */
6768
static struct vt8500_irq_data intc[VT8500_INTC_MAX];
6869
static u32 active_cnt = 0;
70+
/* Primary interrupt controller data */
71+
static struct vt8500_irq_data *primary_intc;
6972

7073
static void vt8500_irq_ack(struct irq_data *d)
7174
{
@@ -163,28 +166,38 @@ static const struct irq_domain_ops vt8500_irq_domain_ops = {
163166
.xlate = irq_domain_xlate_onecell,
164167
};
165168

169+
static inline void vt8500_handle_irq_common(struct vt8500_irq_data *intc)
170+
{
171+
unsigned long irqnr = readl_relaxed(intc->base) & 0x3F;
172+
unsigned long stat;
173+
174+
/*
175+
* Highest Priority register default = 63, so check that this
176+
* is a real interrupt by checking the status register
177+
*/
178+
if (irqnr == 63) {
179+
stat = readl_relaxed(intc->base + VT8500_ICIS + 4);
180+
if (!(stat & BIT(31)))
181+
return;
182+
}
183+
184+
generic_handle_domain_irq(intc->domain, irqnr);
185+
}
186+
166187
static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
167188
{
168-
u32 stat, i;
169-
int irqnr;
170-
void __iomem *base;
171-
172-
/* Loop through each active controller */
173-
for (i=0; i<active_cnt; i++) {
174-
base = intc[i].base;
175-
irqnr = readl_relaxed(base) & 0x3F;
176-
/*
177-
Highest Priority register default = 63, so check that this
178-
is a real interrupt by checking the status register
179-
*/
180-
if (irqnr == 63) {
181-
stat = readl_relaxed(base + VT8500_ICIS + 4);
182-
if (!(stat & BIT(31)))
183-
continue;
184-
}
189+
vt8500_handle_irq_common(primary_intc);
190+
}
185191

186-
generic_handle_domain_irq(intc[i].domain, irqnr);
187-
}
192+
static void vt8500_handle_irq_chained(struct irq_desc *desc)
193+
{
194+
struct irq_domain *d = irq_desc_get_handler_data(desc);
195+
struct irq_chip *chip = irq_desc_get_chip(desc);
196+
struct vt8500_irq_data *intc = d->host_data;
197+
198+
chained_irq_enter(chip, desc);
199+
vt8500_handle_irq_common(intc);
200+
chained_irq_exit(chip, desc);
188201
}
189202

190203
static int __init vt8500_irq_init(struct device_node *node,
@@ -212,8 +225,6 @@ static int __init vt8500_irq_init(struct device_node *node,
212225
goto out;
213226
}
214227

215-
set_handle_irq(vt8500_handle_irq);
216-
217228
vt8500_init_irq_hw(intc[active_cnt].base);
218229

219230
pr_info("vt8500-irq: Added interrupt controller\n");
@@ -224,10 +235,14 @@ static int __init vt8500_irq_init(struct device_node *node,
224235
if (of_irq_count(node) != 0) {
225236
for (i = 0; i < of_irq_count(node); i++) {
226237
irq = irq_of_parse_and_map(node, i);
227-
enable_irq(irq);
238+
irq_set_chained_handler_and_data(irq, vt8500_handle_irq_chained,
239+
&intc[active_cnt]);
228240
}
229241

230242
pr_info("vt8500-irq: Enabled slave->parent interrupts\n");
243+
} else {
244+
primary_intc = &intc[active_cnt];
245+
set_handle_irq(vt8500_handle_irq);
231246
}
232247
out:
233248
return 0;

0 commit comments

Comments
 (0)