Skip to content

Commit ee4aae5

Browse files
author
Marc Zyngier
committed
Merge branch irq/plic-edge-fixes into irq/irqchip-next
* irq/plic-edge-fixes: : . : Work around broken PLIC implementations that deal pretty : badly with edge-triggered interrupts. Flag two implementations : as affected. : . irqchip/sifive-plic: Fix T-HEAD PLIC edge trigger handling dt-bindings: interrupt-controller: Require trigger type for T-HEAD PLIC irqchip/sifive-plic: Add support for Renesas RZ/Five SoC dt-bindings: interrupt-controller: sifive,plic: Document Renesas RZ/Five SoC Signed-off-by: Marc Zyngier <maz@kernel.org>
2 parents a111daf + 5873ba5 commit ee4aae5

File tree

2 files changed

+135
-10
lines changed

2 files changed

+135
-10
lines changed

Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ description:
2626
with priority below this threshold will not cause the PLIC to raise its
2727
interrupt line leading to the context.
2828

29-
While the PLIC supports both edge-triggered and level-triggered interrupts,
30-
interrupt handlers are oblivious to this distinction and therefore it is not
31-
specified in the PLIC device-tree binding.
29+
The PLIC supports both edge-triggered and level-triggered interrupts. For
30+
edge-triggered interrupts, the RISC-V PLIC spec allows two responses to edges
31+
seen while an interrupt handler is active; the PLIC may either queue them or
32+
ignore them. In the first case, handlers are oblivious to the trigger type, so
33+
it is not included in the interrupt specifier. In the second case, software
34+
needs to know the trigger type, so it can reorder the interrupt flow to avoid
35+
missing interrupts. This special handling is needed by at least the Renesas
36+
RZ/Five SoC (AX45MP AndesCore with a NCEPLIC100) and the T-HEAD C900 PLIC.
3237

3338
While the RISC-V ISA doesn't specify a memory layout for the PLIC, the
3439
"sifive,plic-1.0.0" device is a concrete implementation of the PLIC that
@@ -47,6 +52,10 @@ maintainers:
4752
properties:
4853
compatible:
4954
oneOf:
55+
- items:
56+
- enum:
57+
- renesas,r9a07g043-plic
58+
- const: andestech,nceplic100
5059
- items:
5160
- enum:
5261
- sifive,fu540-c000-plic
@@ -64,8 +73,7 @@ properties:
6473
'#address-cells':
6574
const: 0
6675

67-
'#interrupt-cells':
68-
const: 1
76+
'#interrupt-cells': true
6977

7078
interrupt-controller: true
7179

@@ -82,6 +90,12 @@ properties:
8290
description:
8391
Specifies how many external interrupts are supported by this controller.
8492

93+
clocks: true
94+
95+
power-domains: true
96+
97+
resets: true
98+
8599
required:
86100
- compatible
87101
- '#address-cells'
@@ -91,6 +105,47 @@ required:
91105
- interrupts-extended
92106
- riscv,ndev
93107

108+
allOf:
109+
- if:
110+
properties:
111+
compatible:
112+
contains:
113+
enum:
114+
- andestech,nceplic100
115+
- thead,c900-plic
116+
117+
then:
118+
properties:
119+
'#interrupt-cells':
120+
const: 2
121+
122+
else:
123+
properties:
124+
'#interrupt-cells':
125+
const: 1
126+
127+
- if:
128+
properties:
129+
compatible:
130+
contains:
131+
const: renesas,r9a07g043-plic
132+
133+
then:
134+
properties:
135+
clocks:
136+
maxItems: 1
137+
138+
power-domains:
139+
maxItems: 1
140+
141+
resets:
142+
maxItems: 1
143+
144+
required:
145+
- clocks
146+
- power-domains
147+
- resets
148+
94149
additionalProperties: false
95150

96151
examples:

drivers/irqchip/irq-sifive-plic.c

Lines changed: 75 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,13 @@
6060
#define PLIC_DISABLE_THRESHOLD 0x7
6161
#define PLIC_ENABLE_THRESHOLD 0
6262

63+
#define PLIC_QUIRK_EDGE_INTERRUPT 0
64+
6365
struct plic_priv {
6466
struct cpumask lmask;
6567
struct irq_domain *irqdomain;
6668
void __iomem *regs;
69+
unsigned long plic_quirks;
6770
};
6871

6972
struct plic_handler {
@@ -81,6 +84,8 @@ static int plic_parent_irq __ro_after_init;
8184
static bool plic_cpuhp_setup_done __ro_after_init;
8285
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
8386

87+
static int plic_irq_set_type(struct irq_data *d, unsigned int type);
88+
8489
static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable)
8590
{
8691
u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32);
@@ -176,6 +181,17 @@ static void plic_irq_eoi(struct irq_data *d)
176181
}
177182
}
178183

184+
static struct irq_chip plic_edge_chip = {
185+
.name = "SiFive PLIC",
186+
.irq_ack = plic_irq_eoi,
187+
.irq_mask = plic_irq_mask,
188+
.irq_unmask = plic_irq_unmask,
189+
#ifdef CONFIG_SMP
190+
.irq_set_affinity = plic_set_affinity,
191+
#endif
192+
.irq_set_type = plic_irq_set_type,
193+
};
194+
179195
static struct irq_chip plic_chip = {
180196
.name = "SiFive PLIC",
181197
.irq_mask = plic_irq_mask,
@@ -184,8 +200,32 @@ static struct irq_chip plic_chip = {
184200
#ifdef CONFIG_SMP
185201
.irq_set_affinity = plic_set_affinity,
186202
#endif
203+
.irq_set_type = plic_irq_set_type,
187204
};
188205

206+
static int plic_irq_set_type(struct irq_data *d, unsigned int type)
207+
{
208+
struct plic_priv *priv = irq_data_get_irq_chip_data(d);
209+
210+
if (!test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
211+
return IRQ_SET_MASK_OK_NOCOPY;
212+
213+
switch (type) {
214+
case IRQ_TYPE_EDGE_RISING:
215+
irq_set_chip_handler_name_locked(d, &plic_edge_chip,
216+
handle_edge_irq, NULL);
217+
break;
218+
case IRQ_TYPE_LEVEL_HIGH:
219+
irq_set_chip_handler_name_locked(d, &plic_chip,
220+
handle_fasteoi_irq, NULL);
221+
break;
222+
default:
223+
return -EINVAL;
224+
}
225+
226+
return IRQ_SET_MASK_OK;
227+
}
228+
189229
static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
190230
irq_hw_number_t hwirq)
191231
{
@@ -198,6 +238,19 @@ static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq,
198238
return 0;
199239
}
200240

241+
static int plic_irq_domain_translate(struct irq_domain *d,
242+
struct irq_fwspec *fwspec,
243+
unsigned long *hwirq,
244+
unsigned int *type)
245+
{
246+
struct plic_priv *priv = d->host_data;
247+
248+
if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks))
249+
return irq_domain_translate_twocell(d, fwspec, hwirq, type);
250+
251+
return irq_domain_translate_onecell(d, fwspec, hwirq, type);
252+
}
253+
201254
static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
202255
unsigned int nr_irqs, void *arg)
203256
{
@@ -206,7 +259,7 @@ static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
206259
unsigned int type;
207260
struct irq_fwspec *fwspec = arg;
208261

209-
ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type);
262+
ret = plic_irq_domain_translate(domain, fwspec, &hwirq, &type);
210263
if (ret)
211264
return ret;
212265

@@ -220,7 +273,7 @@ static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
220273
}
221274

222275
static const struct irq_domain_ops plic_irqdomain_ops = {
223-
.translate = irq_domain_translate_onecell,
276+
.translate = plic_irq_domain_translate,
224277
.alloc = plic_irq_domain_alloc,
225278
.free = irq_domain_free_irqs_top,
226279
};
@@ -281,8 +334,9 @@ static int plic_starting_cpu(unsigned int cpu)
281334
return 0;
282335
}
283336

284-
static int __init plic_init(struct device_node *node,
285-
struct device_node *parent)
337+
static int __init __plic_init(struct device_node *node,
338+
struct device_node *parent,
339+
unsigned long plic_quirks)
286340
{
287341
int error = 0, nr_contexts, nr_handlers = 0, i;
288342
u32 nr_irqs;
@@ -293,6 +347,8 @@ static int __init plic_init(struct device_node *node,
293347
if (!priv)
294348
return -ENOMEM;
295349

350+
priv->plic_quirks = plic_quirks;
351+
296352
priv->regs = of_iomap(node, 0);
297353
if (WARN_ON(!priv->regs)) {
298354
error = -EIO;
@@ -410,6 +466,20 @@ static int __init plic_init(struct device_node *node,
410466
return error;
411467
}
412468

469+
static int __init plic_init(struct device_node *node,
470+
struct device_node *parent)
471+
{
472+
return __plic_init(node, parent, 0);
473+
}
474+
413475
IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init);
414476
IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */
415-
IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */
477+
478+
static int __init plic_edge_init(struct device_node *node,
479+
struct device_node *parent)
480+
{
481+
return __plic_init(node, parent, BIT(PLIC_QUIRK_EDGE_INTERRUPT));
482+
}
483+
484+
IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init);
485+
IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_edge_init);

0 commit comments

Comments
 (0)