Skip to content

Commit 67862a3

Browse files
mubinsyedMarc Zyngier
authored andcommitted
irqchip/xilinx: Add support for multiple instances
Added support for cascaded interrupt controllers. Following cascaded configurations have been tested, - peripheral->xilinx-intc->xilinx-intc->gic->Cortexa53 processor on zcu102 board - peripheral->xilinx-intc->xilinx-intc->microblaze processor on kcu105 board Signed-off-by: Mubin Sayyed <[email protected]> Signed-off-by: Anirudha Sarangi <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7d4cac5 commit 67862a3

File tree

1 file changed

+67
-48
lines changed

1 file changed

+67
-48
lines changed

drivers/irqchip/irq-xilinx-intc.c

Lines changed: 67 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,31 @@ struct xintc_irq_chip {
3838
void __iomem *base;
3939
struct irq_domain *root_domain;
4040
u32 intr_mask;
41+
u32 nr_irq;
4142
};
4243

43-
static struct xintc_irq_chip *xintc_irqc;
44+
static struct xintc_irq_chip *primary_intc;
4445

45-
static void xintc_write(int reg, u32 data)
46+
static void xintc_write(struct xintc_irq_chip *irqc, int reg, u32 data)
4647
{
4748
if (static_branch_unlikely(&xintc_is_be))
48-
iowrite32be(data, xintc_irqc->base + reg);
49+
iowrite32be(data, irqc->base + reg);
4950
else
50-
iowrite32(data, xintc_irqc->base + reg);
51+
iowrite32(data, irqc->base + reg);
5152
}
5253

53-
static unsigned int xintc_read(int reg)
54+
static u32 xintc_read(struct xintc_irq_chip *irqc, int reg)
5455
{
5556
if (static_branch_unlikely(&xintc_is_be))
56-
return ioread32be(xintc_irqc->base + reg);
57+
return ioread32be(irqc->base + reg);
5758
else
58-
return ioread32(xintc_irqc->base + reg);
59+
return ioread32(irqc->base + reg);
5960
}
6061

6162
static void intc_enable_or_unmask(struct irq_data *d)
6263
{
63-
unsigned long mask = 1 << d->hwirq;
64+
struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
65+
unsigned long mask = BIT(d->hwirq);
6466

6567
pr_debug("irq-xilinx: enable_or_unmask: %ld\n", d->hwirq);
6668

@@ -69,30 +71,35 @@ static void intc_enable_or_unmask(struct irq_data *d)
6971
* acks the irq before calling the interrupt handler
7072
*/
7173
if (irqd_is_level_type(d))
72-
xintc_write(IAR, mask);
74+
xintc_write(irqc, IAR, mask);
7375

74-
xintc_write(SIE, mask);
76+
xintc_write(irqc, SIE, mask);
7577
}
7678

7779
static void intc_disable_or_mask(struct irq_data *d)
7880
{
81+
struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
82+
7983
pr_debug("irq-xilinx: disable: %ld\n", d->hwirq);
80-
xintc_write(CIE, 1 << d->hwirq);
84+
xintc_write(irqc, CIE, BIT(d->hwirq));
8185
}
8286

8387
static void intc_ack(struct irq_data *d)
8488
{
89+
struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
90+
8591
pr_debug("irq-xilinx: ack: %ld\n", d->hwirq);
86-
xintc_write(IAR, 1 << d->hwirq);
92+
xintc_write(irqc, IAR, BIT(d->hwirq));
8793
}
8894

8995
static void intc_mask_ack(struct irq_data *d)
9096
{
91-
unsigned long mask = 1 << d->hwirq;
97+
struct xintc_irq_chip *irqc = irq_data_get_irq_chip_data(d);
98+
unsigned long mask = BIT(d->hwirq);
9299

93100
pr_debug("irq-xilinx: disable_and_ack: %ld\n", d->hwirq);
94-
xintc_write(CIE, mask);
95-
xintc_write(IAR, mask);
101+
xintc_write(irqc, CIE, mask);
102+
xintc_write(irqc, IAR, mask);
96103
}
97104

98105
static struct irq_chip intc_dev = {
@@ -103,13 +110,28 @@ static struct irq_chip intc_dev = {
103110
.irq_mask_ack = intc_mask_ack,
104111
};
105112

113+
static unsigned int xintc_get_irq_local(struct xintc_irq_chip *irqc)
114+
{
115+
unsigned int irq = 0;
116+
u32 hwirq;
117+
118+
hwirq = xintc_read(irqc, IVR);
119+
if (hwirq != -1U)
120+
irq = irq_find_mapping(irqc->root_domain, hwirq);
121+
122+
pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
123+
124+
return irq;
125+
}
126+
106127
unsigned int xintc_get_irq(void)
107128
{
108-
unsigned int hwirq, irq = -1;
129+
unsigned int irq = -1;
130+
u32 hwirq;
109131

110-
hwirq = xintc_read(IVR);
132+
hwirq = xintc_read(primary_intc, IVR);
111133
if (hwirq != -1U)
112-
irq = irq_find_mapping(xintc_irqc->root_domain, hwirq);
134+
irq = irq_find_mapping(primary_intc->root_domain, hwirq);
113135

114136
pr_debug("irq-xilinx: hwirq=%d, irq=%d\n", hwirq, irq);
115137

@@ -118,15 +140,18 @@ unsigned int xintc_get_irq(void)
118140

119141
static int xintc_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
120142
{
121-
if (xintc_irqc->intr_mask & (1 << hw)) {
143+
struct xintc_irq_chip *irqc = d->host_data;
144+
145+
if (irqc->intr_mask & BIT(hw)) {
122146
irq_set_chip_and_handler_name(irq, &intc_dev,
123-
handle_edge_irq, "edge");
147+
handle_edge_irq, "edge");
124148
irq_clear_status_flags(irq, IRQ_LEVEL);
125149
} else {
126150
irq_set_chip_and_handler_name(irq, &intc_dev,
127-
handle_level_irq, "level");
151+
handle_level_irq, "level");
128152
irq_set_status_flags(irq, IRQ_LEVEL);
129153
}
154+
irq_set_chip_data(irq, irqc);
130155
return 0;
131156
}
132157

@@ -138,12 +163,14 @@ static const struct irq_domain_ops xintc_irq_domain_ops = {
138163
static void xil_intc_irq_handler(struct irq_desc *desc)
139164
{
140165
struct irq_chip *chip = irq_desc_get_chip(desc);
166+
struct xintc_irq_chip *irqc;
141167
u32 pending;
142168

169+
irqc = irq_data_get_irq_handler_data(&desc->irq_data);
143170
chained_irq_enter(chip, desc);
144171
do {
145-
pending = xintc_get_irq();
146-
if (pending == -1U)
172+
pending = xintc_get_irq_local(irqc);
173+
if (pending == 0)
147174
break;
148175
generic_handle_irq(pending);
149176
} while (true);
@@ -153,28 +180,19 @@ static void xil_intc_irq_handler(struct irq_desc *desc)
153180
static int __init xilinx_intc_of_init(struct device_node *intc,
154181
struct device_node *parent)
155182
{
156-
u32 nr_irq;
157-
int ret, irq;
158183
struct xintc_irq_chip *irqc;
159-
160-
if (xintc_irqc) {
161-
pr_err("irq-xilinx: Multiple instances aren't supported\n");
162-
return -EINVAL;
163-
}
184+
int ret, irq;
164185

165186
irqc = kzalloc(sizeof(*irqc), GFP_KERNEL);
166187
if (!irqc)
167188
return -ENOMEM;
168-
169-
xintc_irqc = irqc;
170-
171189
irqc->base = of_iomap(intc, 0);
172190
BUG_ON(!irqc->base);
173191

174-
ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
192+
ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &irqc->nr_irq);
175193
if (ret < 0) {
176194
pr_err("irq-xilinx: unable to read xlnx,num-intr-inputs\n");
177-
goto err_alloc;
195+
goto error;
178196
}
179197

180198
ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &irqc->intr_mask);
@@ -183,34 +201,34 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
183201
irqc->intr_mask = 0;
184202
}
185203

186-
if (irqc->intr_mask >> nr_irq)
204+
if (irqc->intr_mask >> irqc->nr_irq)
187205
pr_warn("irq-xilinx: mismatch in kind-of-intr param\n");
188206

189207
pr_info("irq-xilinx: %pOF: num_irq=%d, edge=0x%x\n",
190-
intc, nr_irq, irqc->intr_mask);
208+
intc, irqc->nr_irq, irqc->intr_mask);
191209

192210

193211
/*
194212
* Disable all external interrupts until they are
195213
* explicity requested.
196214
*/
197-
xintc_write(IER, 0);
215+
xintc_write(irqc, IER, 0);
198216

199217
/* Acknowledge any pending interrupts just in case. */
200-
xintc_write(IAR, 0xffffffff);
218+
xintc_write(irqc, IAR, 0xffffffff);
201219

202220
/* Turn on the Master Enable. */
203-
xintc_write(MER, MER_HIE | MER_ME);
204-
if (!(xintc_read(MER) & (MER_HIE | MER_ME))) {
221+
xintc_write(irqc, MER, MER_HIE | MER_ME);
222+
if (xintc_read(irqc, MER) != (MER_HIE | MER_ME)) {
205223
static_branch_enable(&xintc_is_be);
206-
xintc_write(MER, MER_HIE | MER_ME);
224+
xintc_write(irqc, MER, MER_HIE | MER_ME);
207225
}
208226

209-
irqc->root_domain = irq_domain_add_linear(intc, nr_irq,
227+
irqc->root_domain = irq_domain_add_linear(intc, irqc->nr_irq,
210228
&xintc_irq_domain_ops, irqc);
211229
if (!irqc->root_domain) {
212230
pr_err("irq-xilinx: Unable to create IRQ domain\n");
213-
goto err_alloc;
231+
goto error;
214232
}
215233

216234
if (parent) {
@@ -222,16 +240,17 @@ static int __init xilinx_intc_of_init(struct device_node *intc,
222240
} else {
223241
pr_err("irq-xilinx: interrupts property not in DT\n");
224242
ret = -EINVAL;
225-
goto err_alloc;
243+
goto error;
226244
}
227245
} else {
228-
irq_set_default_host(irqc->root_domain);
246+
primary_intc = irqc;
247+
irq_set_default_host(primary_intc->root_domain);
229248
}
230249

231250
return 0;
232251

233-
err_alloc:
234-
xintc_irqc = NULL;
252+
error:
253+
iounmap(irqc->base);
235254
kfree(irqc);
236255
return ret;
237256

0 commit comments

Comments
 (0)