Skip to content

Commit f4ddf8d

Browse files
committed
realtek: irq: backport upstream patches
The interrupt driver downstream patches have been sent upstream and got accepted. Backport them and make the driver free of downstream hacks. Link: openwrt#23679 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
1 parent 0a64c7a commit f4ddf8d

9 files changed

Lines changed: 870 additions & 428 deletions
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
From 167883f75f83088a2b32c85ce5e3d0cd1cef157b Mon Sep 17 00:00:00 2001
2+
From: Markus Stockhausen <markus.stockhausen@gmx.de>
3+
Date: Thu, 4 Jun 2026 20:25:05 +0200
4+
Subject: [PATCH 1/8] irqchip/irq-realtek-rtl: Add/simplify register helpers
5+
6+
The Realtek interrupt controller has two important registers that are used
7+
by the driver in several places
8+
9+
- GIMR: global interrupt mask register
10+
- IRR: Interrupt routing registers
11+
12+
The usage of these registers is very inconsistent. GIMR is addressed
13+
directly while IRR has a helper that needs a macro as an input. Harmonize
14+
this by providing consistent helpers that improve code readability.
15+
16+
The callers of these helpers use classic lock/unlock functions and
17+
sometimes use the wrong locking helper. E.g. irqsave variants are used in
18+
mask/unmask although not needed. Adapt and fix the surrounding call
19+
locations.
20+
21+
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
22+
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
23+
Link: https://patch.msgid.link/20260604182506.1113440-2-markus.stockhausen@gmx.de
24+
---
25+
drivers/irqchip/irq-realtek-rtl.c | 64 +++++++++++++++----------------
26+
1 file changed, 32 insertions(+), 32 deletions(-)
27+
28+
--- a/drivers/irqchip/irq-realtek-rtl.c
29+
+++ b/drivers/irqchip/irq-realtek-rtl.c
30+
@@ -37,10 +37,29 @@ static void __iomem *realtek_ictl_base;
31+
#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
32+
#define IRR_SHIFT(idx) ((idx * 4) % 32)
33+
34+
-static void write_irr(void __iomem *irr0, int idx, u32 value)
35+
+static inline void enable_gimr(unsigned int hw_irq)
36+
{
37+
- unsigned int offset = IRR_OFFSET(idx);
38+
- unsigned int shift = IRR_SHIFT(idx);
39+
+ u32 gimr;
40+
+
41+
+ gimr = readl(REG(RTL_ICTL_GIMR));
42+
+ gimr |= BIT(hw_irq);
43+
+ writel(gimr, REG(RTL_ICTL_GIMR));
44+
+}
45+
+
46+
+static inline void disable_gimr(unsigned int hw_irq)
47+
+{
48+
+ u32 gimr;
49+
+
50+
+ gimr = readl(REG(RTL_ICTL_GIMR));
51+
+ gimr &= ~BIT(hw_irq);
52+
+ writel(gimr, REG(RTL_ICTL_GIMR));
53+
+}
54+
+
55+
+static void write_irr(int hw_irq, u32 value)
56+
+{
57+
+ void __iomem *irr0 = REG(RTL_ICTL_IRR0);
58+
+ unsigned int offset = IRR_OFFSET(hw_irq);
59+
+ unsigned int shift = IRR_SHIFT(hw_irq);
60+
u32 irr;
61+
62+
irr = readl(irr0 + offset) & ~(0xf << shift);
63+
@@ -50,30 +69,14 @@ static void write_irr(void __iomem *irr0
64+
65+
static void realtek_ictl_unmask_irq(struct irq_data *i)
66+
{
67+
- unsigned long flags;
68+
- u32 value;
69+
-
70+
- raw_spin_lock_irqsave(&irq_lock, flags);
71+
-
72+
- value = readl(REG(RTL_ICTL_GIMR));
73+
- value |= BIT(i->hwirq);
74+
- writel(value, REG(RTL_ICTL_GIMR));
75+
-
76+
- raw_spin_unlock_irqrestore(&irq_lock, flags);
77+
+ guard(raw_spinlock)(&irq_lock);
78+
+ enable_gimr(i->hwirq);
79+
}
80+
81+
static void realtek_ictl_mask_irq(struct irq_data *i)
82+
{
83+
- unsigned long flags;
84+
- u32 value;
85+
-
86+
- raw_spin_lock_irqsave(&irq_lock, flags);
87+
-
88+
- value = readl(REG(RTL_ICTL_GIMR));
89+
- value &= ~BIT(i->hwirq);
90+
- writel(value, REG(RTL_ICTL_GIMR));
91+
-
92+
- raw_spin_unlock_irqrestore(&irq_lock, flags);
93+
+ guard(raw_spinlock)(&irq_lock);
94+
+ disable_gimr(i->hwirq);
95+
}
96+
97+
static struct irq_chip realtek_ictl_irq = {
98+
@@ -84,13 +87,10 @@ static struct irq_chip realtek_ictl_irq
99+
100+
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
101+
{
102+
- unsigned long flags;
103+
-
104+
irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
105+
106+
- raw_spin_lock_irqsave(&irq_lock, flags);
107+
- write_irr(REG(RTL_ICTL_IRR0), hw, 1);
108+
- raw_spin_unlock_irqrestore(&irq_lock, flags);
109+
+ guard(raw_spinlock_irqsave)(&irq_lock);
110+
+ write_irr(hw, 1);
111+
112+
return 0;
113+
}
114+
@@ -127,7 +127,6 @@ static int __init realtek_rtl_of_init(st
115+
{
116+
struct of_phandle_args oirq;
117+
struct irq_domain *domain;
118+
- unsigned int soc_irq;
119+
int parent_irq;
120+
121+
realtek_ictl_base = of_iomap(node, 0);
122+
@@ -135,9 +134,10 @@ static int __init realtek_rtl_of_init(st
123+
return -ENXIO;
124+
125+
/* Disable all cascaded interrupts and clear routing */
126+
- writel(0, REG(RTL_ICTL_GIMR));
127+
- for (soc_irq = 0; soc_irq < RTL_ICTL_NUM_INPUTS; soc_irq++)
128+
- write_irr(REG(RTL_ICTL_IRR0), soc_irq, 0);
129+
+ for (unsigned int hw_irq = 0; hw_irq < RTL_ICTL_NUM_INPUTS; hw_irq++) {
130+
+ disable_gimr(hw_irq);
131+
+ write_irr(hw_irq, 0);
132+
+ }
133+
134+
if (WARN_ON(!of_irq_count(node))) {
135+
/*
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
From a1a35c09241f0577cc40f65d7372fed01138619d Mon Sep 17 00:00:00 2001
2+
From: Markus Stockhausen <markus.stockhausen@gmx.de>
3+
Date: Thu, 4 Jun 2026 20:25:06 +0200
4+
Subject: [PATCH 2/8] irqchip/irq-realtek-rtl: Add multicore support
5+
6+
The Realtek interrupt driver currently supports only single core
7+
systems. So the higher end devices like RTL839x and RTL930x with
8+
dual VPEs must be driven with NR_CPU=1. Enhance the driver to
9+
support multicore (dual VPE) systems. For this:
10+
11+
- Extend the register map for multiple cores
12+
- Search for multiple CPU cores in the devicetree
13+
- Improve the register helpers to support multiple cores
14+
- Add an affinity setter
15+
- Enhance the IRQ handler for multiple cores
16+
17+
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
18+
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
19+
Link: https://patch.msgid.link/20260604182506.1113440-3-markus.stockhausen@gmx.de
20+
---
21+
drivers/irqchip/irq-realtek-rtl.c | 82 ++++++++++++++++++++-----------
22+
1 file changed, 54 insertions(+), 28 deletions(-)
23+
24+
--- a/drivers/irqchip/irq-realtek-rtl.c
25+
+++ b/drivers/irqchip/irq-realtek-rtl.c
26+
@@ -23,10 +23,10 @@
27+
28+
#define RTL_ICTL_NUM_INPUTS 32
29+
30+
-#define REG(x) (realtek_ictl_base + x)
31+
+#define REG(cpu, x) (realtek_ictl_base[cpu] + x)
32+
33+
static DEFINE_RAW_SPINLOCK(irq_lock);
34+
-static void __iomem *realtek_ictl_base;
35+
+static void __iomem *realtek_ictl_base[NR_CPUS];
36+
37+
/*
38+
* IRR0-IRR3 store 4 bits per interrupt, but Realtek uses inverted numbering,
39+
@@ -37,27 +37,27 @@ static void __iomem *realtek_ictl_base;
40+
#define IRR_OFFSET(idx) (4 * (3 - (idx * 4) / 32))
41+
#define IRR_SHIFT(idx) ((idx * 4) % 32)
42+
43+
-static inline void enable_gimr(unsigned int hw_irq)
44+
+static inline void enable_gimr(unsigned int cpu, unsigned int hw_irq)
45+
{
46+
u32 gimr;
47+
48+
- gimr = readl(REG(RTL_ICTL_GIMR));
49+
+ gimr = readl(REG(cpu, RTL_ICTL_GIMR));
50+
gimr |= BIT(hw_irq);
51+
- writel(gimr, REG(RTL_ICTL_GIMR));
52+
+ writel(gimr, REG(cpu, RTL_ICTL_GIMR));
53+
}
54+
55+
-static inline void disable_gimr(unsigned int hw_irq)
56+
+static inline void disable_gimr(unsigned int cpu, unsigned int hw_irq)
57+
{
58+
u32 gimr;
59+
60+
- gimr = readl(REG(RTL_ICTL_GIMR));
61+
+ gimr = readl(REG(cpu, RTL_ICTL_GIMR));
62+
gimr &= ~BIT(hw_irq);
63+
- writel(gimr, REG(RTL_ICTL_GIMR));
64+
+ writel(gimr, REG(cpu, RTL_ICTL_GIMR));
65+
}
66+
67+
-static void write_irr(int hw_irq, u32 value)
68+
+static void write_irr(unsigned int cpu, int hw_irq, u32 value)
69+
{
70+
- void __iomem *irr0 = REG(RTL_ICTL_IRR0);
71+
+ void __iomem *irr0 = REG(cpu, RTL_ICTL_IRR0);
72+
unsigned int offset = IRR_OFFSET(hw_irq);
73+
unsigned int shift = IRR_SHIFT(hw_irq);
74+
u32 irr;
75+
@@ -69,28 +69,51 @@ static void write_irr(int hw_irq, u32 va
76+
77+
static void realtek_ictl_unmask_irq(struct irq_data *i)
78+
{
79+
+ unsigned int cpu;
80+
+
81+
guard(raw_spinlock)(&irq_lock);
82+
- enable_gimr(i->hwirq);
83+
+ for_each_cpu(cpu, irq_data_get_effective_affinity_mask(i))
84+
+ enable_gimr(cpu, i->hwirq);
85+
}
86+
87+
static void realtek_ictl_mask_irq(struct irq_data *i)
88+
{
89+
+ unsigned int cpu;
90+
+
91+
guard(raw_spinlock)(&irq_lock);
92+
- disable_gimr(i->hwirq);
93+
+ for_each_cpu(cpu, irq_data_get_effective_affinity_mask(i))
94+
+ disable_gimr(cpu, i->hwirq);
95+
+}
96+
+
97+
+static int realtek_ictl_irq_affinity(struct irq_data *i, const struct cpumask *dest, bool force)
98+
+{
99+
+ if (!irqd_irq_masked(i))
100+
+ realtek_ictl_mask_irq(i);
101+
+
102+
+ irq_data_update_effective_affinity(i, dest);
103+
+
104+
+ if (!irqd_irq_masked(i))
105+
+ realtek_ictl_unmask_irq(i);
106+
+
107+
+ return IRQ_SET_MASK_OK;
108+
}
109+
110+
static struct irq_chip realtek_ictl_irq = {
111+
- .name = "realtek-rtl-intc",
112+
- .irq_mask = realtek_ictl_mask_irq,
113+
- .irq_unmask = realtek_ictl_unmask_irq,
114+
+ .name = "realtek-rtl-intc",
115+
+ .irq_mask = realtek_ictl_mask_irq,
116+
+ .irq_unmask = realtek_ictl_unmask_irq,
117+
+ .irq_set_affinity = realtek_ictl_irq_affinity,
118+
};
119+
120+
static int intc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
121+
{
122+
+ unsigned int cpu;
123+
+
124+
irq_set_chip_and_handler(irq, &realtek_ictl_irq, handle_level_irq);
125+
126+
guard(raw_spinlock_irqsave)(&irq_lock);
127+
- write_irr(hw, 1);
128+
+ for_each_present_cpu(cpu)
129+
+ write_irr(cpu, hw, 1);
130+
131+
return 0;
132+
}
133+
@@ -103,12 +126,13 @@ static const struct irq_domain_ops irq_d
134+
static void realtek_irq_dispatch(struct irq_desc *desc)
135+
{
136+
struct irq_chip *chip = irq_desc_get_chip(desc);
137+
+ unsigned int cpu = smp_processor_id();
138+
struct irq_domain *domain;
139+
unsigned long pending;
140+
unsigned int soc_int;
141+
142+
chained_irq_enter(chip, desc);
143+
- pending = readl(REG(RTL_ICTL_GIMR)) & readl(REG(RTL_ICTL_GISR));
144+
+ pending = readl(REG(cpu, RTL_ICTL_GIMR)) & readl(REG(cpu, RTL_ICTL_GISR));
145+
146+
if (unlikely(!pending)) {
147+
spurious_interrupt();
148+
@@ -116,7 +140,7 @@ static void realtek_irq_dispatch(struct
149+
}
150+
151+
domain = irq_desc_get_handler_data(desc);
152+
- for_each_set_bit(soc_int, &pending, 32)
153+
+ for_each_set_bit(soc_int, &pending, RTL_ICTL_NUM_INPUTS)
154+
generic_handle_domain_irq(domain, soc_int);
155+
156+
out:
157+
@@ -127,16 +151,18 @@ static int __init realtek_rtl_of_init(st
158+
{
159+
struct of_phandle_args oirq;
160+
struct irq_domain *domain;
161+
- int parent_irq;
162+
+ int cpu, parent_irq;
163+
164+
- realtek_ictl_base = of_iomap(node, 0);
165+
- if (!realtek_ictl_base)
166+
- return -ENXIO;
167+
-
168+
- /* Disable all cascaded interrupts and clear routing */
169+
- for (unsigned int hw_irq = 0; hw_irq < RTL_ICTL_NUM_INPUTS; hw_irq++) {
170+
- disable_gimr(hw_irq);
171+
- write_irr(hw_irq, 0);
172+
+ for_each_present_cpu(cpu) {
173+
+ realtek_ictl_base[cpu] = of_iomap(node, cpu);
174+
+ if (!realtek_ictl_base[cpu])
175+
+ return -ENXIO;
176+
+
177+
+ /* Disable all cascaded interrupts and clear routing */
178+
+ for (unsigned int hw_irq = 0; hw_irq < RTL_ICTL_NUM_INPUTS; hw_irq++) {
179+
+ disable_gimr(cpu, hw_irq);
180+
+ write_irr(cpu, hw_irq, 0);
181+
+ }
182+
}
183+
184+
if (WARN_ON(!of_irq_count(node))) {

0 commit comments

Comments
 (0)