Skip to content

Commit f1ad113

Browse files
atishp04Marc Zyngier
authored andcommitted
irqchip/sifive-plic: Add support for multiple PLICs
Current, PLIC driver can support only 1 PLIC on the board. However, there can be multiple PLICs present on a two socket systems in RISC-V. Modify the driver so that each PLIC handler can have a information about individual PLIC registers and an irqdomain associated with it. Tested on two socket RISC-V system based on VCU118 FPGA connected via OmniXtend protocol. Signed-off-by: Atish Patra <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Anup Patel <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent ccbe80b commit f1ad113

File tree

1 file changed

+51
-30
lines changed

1 file changed

+51
-30
lines changed

drivers/irqchip/irq-sifive-plic.c

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,11 @@
5959
#define PLIC_DISABLE_THRESHOLD 0xf
6060
#define PLIC_ENABLE_THRESHOLD 0
6161

62-
static void __iomem *plic_regs;
62+
struct plic_priv {
63+
struct cpumask lmask;
64+
struct irq_domain *irqdomain;
65+
void __iomem *regs;
66+
};
6367

6468
struct plic_handler {
6569
bool present;
@@ -70,6 +74,7 @@ struct plic_handler {
7074
*/
7175
raw_spinlock_t enable_lock;
7276
void __iomem *enable_base;
77+
struct plic_priv *priv;
7378
};
7479
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
7580

@@ -88,49 +93,62 @@ static inline void plic_toggle(struct plic_handler *handler,
8893
}
8994

9095
static inline void plic_irq_toggle(const struct cpumask *mask,
91-
int hwirq, int enable)
96+
struct irq_data *d, int enable)
9297
{
9398
int cpu;
99+
struct plic_priv *priv = irq_get_chip_data(d->irq);
94100

95-
writel(enable, plic_regs + PRIORITY_BASE + hwirq * PRIORITY_PER_ID);
101+
writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID);
96102
for_each_cpu(cpu, mask) {
97103
struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu);
98104

99-
if (handler->present)
100-
plic_toggle(handler, hwirq, enable);
105+
if (handler->present &&
106+
cpumask_test_cpu(cpu, &handler->priv->lmask))
107+
plic_toggle(handler, d->hwirq, enable);
101108
}
102109
}
103110

104111
static void plic_irq_unmask(struct irq_data *d)
105112
{
106-
unsigned int cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
107-
cpu_online_mask);
113+
struct cpumask amask;
114+
unsigned int cpu;
115+
struct plic_priv *priv = irq_get_chip_data(d->irq);
116+
117+
cpumask_and(&amask, &priv->lmask, cpu_online_mask);
118+
cpu = cpumask_any_and(irq_data_get_affinity_mask(d),
119+
&amask);
108120
if (WARN_ON_ONCE(cpu >= nr_cpu_ids))
109121
return;
110-
plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1);
122+
plic_irq_toggle(cpumask_of(cpu), d, 1);
111123
}
112124

113125
static void plic_irq_mask(struct irq_data *d)
114126
{
115-
plic_irq_toggle(cpu_possible_mask, d->hwirq, 0);
127+
struct plic_priv *priv = irq_get_chip_data(d->irq);
128+
129+
plic_irq_toggle(&priv->lmask, d, 0);
116130
}
117131

118132
#ifdef CONFIG_SMP
119133
static int plic_set_affinity(struct irq_data *d,
120134
const struct cpumask *mask_val, bool force)
121135
{
122136
unsigned int cpu;
137+
struct cpumask amask;
138+
struct plic_priv *priv = irq_get_chip_data(d->irq);
139+
140+
cpumask_and(&amask, &priv->lmask, mask_val);
123141

124142
if (force)
125-
cpu = cpumask_first(mask_val);
143+
cpu = cpumask_first(&amask);
126144
else
127-
cpu = cpumask_any_and(mask_val, cpu_online_mask);
145+
cpu = cpumask_any_and(&amask, cpu_online_mask);
128146

129147
if (cpu >= nr_cpu_ids)
130148
return -EINVAL;
131149

132-
plic_irq_toggle(cpu_possible_mask, d->hwirq, 0);
133-
plic_irq_toggle(cpumask_of(cpu), d->hwirq, 1);
150+
plic_irq_toggle(&priv->lmask, d, 0);
151+
plic_irq_toggle(cpumask_of(cpu), d, 1);
134152

135153
irq_data_update_effective_affinity(d, cpumask_of(cpu));
136154

@@ -191,8 +209,6 @@ static const struct irq_domain_ops plic_irqdomain_ops = {
191209
.free = irq_domain_free_irqs_top,
192210
};
193211

194-
static struct irq_domain *plic_irqdomain;
195-
196212
/*
197213
* Handling an interrupt is a two-step process: first you claim the interrupt
198214
* by reading the claim register, then you complete the interrupt by writing
@@ -209,7 +225,7 @@ static void plic_handle_irq(struct pt_regs *regs)
209225

210226
csr_clear(CSR_IE, IE_EIE);
211227
while ((hwirq = readl(claim))) {
212-
int irq = irq_find_mapping(plic_irqdomain, hwirq);
228+
int irq = irq_find_mapping(handler->priv->irqdomain, hwirq);
213229

214230
if (unlikely(irq <= 0))
215231
pr_warn_ratelimited("can't find mapping for hwirq %lu\n",
@@ -265,15 +281,17 @@ static int __init plic_init(struct device_node *node,
265281
{
266282
int error = 0, nr_contexts, nr_handlers = 0, i;
267283
u32 nr_irqs;
284+
struct plic_priv *priv;
268285

269-
if (plic_regs) {
270-
pr_warn("PLIC already present.\n");
271-
return -ENXIO;
272-
}
286+
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
287+
if (!priv)
288+
return -ENOMEM;
273289

274-
plic_regs = of_iomap(node, 0);
275-
if (WARN_ON(!plic_regs))
276-
return -EIO;
290+
priv->regs = of_iomap(node, 0);
291+
if (WARN_ON(!priv->regs)) {
292+
error = -EIO;
293+
goto out_free_priv;
294+
}
277295

278296
error = -EINVAL;
279297
of_property_read_u32(node, "riscv,ndev", &nr_irqs);
@@ -287,9 +305,9 @@ static int __init plic_init(struct device_node *node,
287305
goto out_iounmap;
288306

289307
error = -ENOMEM;
290-
plic_irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
291-
&plic_irqdomain_ops, NULL);
292-
if (WARN_ON(!plic_irqdomain))
308+
priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1,
309+
&plic_irqdomain_ops, priv);
310+
if (WARN_ON(!priv->irqdomain))
293311
goto out_iounmap;
294312

295313
for (i = 0; i < nr_contexts; i++) {
@@ -334,13 +352,14 @@ static int __init plic_init(struct device_node *node,
334352
goto done;
335353
}
336354

355+
cpumask_set_cpu(cpu, &priv->lmask);
337356
handler->present = true;
338357
handler->hart_base =
339-
plic_regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
358+
priv->regs + CONTEXT_BASE + i * CONTEXT_PER_HART;
340359
raw_spin_lock_init(&handler->enable_lock);
341360
handler->enable_base =
342-
plic_regs + ENABLE_BASE + i * ENABLE_PER_HART;
343-
361+
priv->regs + ENABLE_BASE + i * ENABLE_PER_HART;
362+
handler->priv = priv;
344363
done:
345364
for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
346365
plic_toggle(handler, hwirq, 0);
@@ -356,7 +375,9 @@ static int __init plic_init(struct device_node *node,
356375
return 0;
357376

358377
out_iounmap:
359-
iounmap(plic_regs);
378+
iounmap(priv->regs);
379+
out_free_priv:
380+
kfree(priv);
360381
return error;
361382
}
362383

0 commit comments

Comments
 (0)