Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+135 -10
+60 -5
Documentation/devicetree/bindings/interrupt-controller/sifive,plic-1.0.0.yaml
··· 26 26 with priority below this threshold will not cause the PLIC to raise its 27 27 interrupt line leading to the context. 28 28 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. 32 37 33 38 While the RISC-V ISA doesn't specify a memory layout for the PLIC, the 34 39 "sifive,plic-1.0.0" device is a concrete implementation of the PLIC that ··· 54 49 oneOf: 55 50 - items: 56 51 - enum: 52 + - renesas,r9a07g043-plic 53 + - const: andestech,nceplic100 54 + - items: 55 + - enum: 57 56 - sifive,fu540-c000-plic 58 57 - starfive,jh7100-plic 59 58 - canaan,k210-plic ··· 73 64 '#address-cells': 74 65 const: 0 75 66 76 - '#interrupt-cells': 77 - const: 1 67 + '#interrupt-cells': true 78 68 79 69 interrupt-controller: true 80 70 ··· 90 82 description: 91 83 Specifies how many external interrupts are supported by this controller. 92 84 85 + clocks: true 86 + 87 + power-domains: true 88 + 89 + resets: true 90 + 93 91 required: 94 92 - compatible 95 93 - '#address-cells' ··· 104 90 - reg 105 91 - interrupts-extended 106 92 - riscv,ndev 93 + 94 + allOf: 95 + - if: 96 + properties: 97 + compatible: 98 + contains: 99 + enum: 100 + - andestech,nceplic100 101 + - thead,c900-plic 102 + 103 + then: 104 + properties: 105 + '#interrupt-cells': 106 + const: 2 107 + 108 + else: 109 + properties: 110 + '#interrupt-cells': 111 + const: 1 112 + 113 + - if: 114 + properties: 115 + compatible: 116 + contains: 117 + const: renesas,r9a07g043-plic 118 + 119 + then: 120 + properties: 121 + clocks: 122 + maxItems: 1 123 + 124 + power-domains: 125 + maxItems: 1 126 + 127 + resets: 128 + maxItems: 1 129 + 130 + required: 131 + - clocks 132 + - power-domains 133 + - resets 107 134 108 135 additionalProperties: false 109 136
+75 -5
drivers/irqchip/irq-sifive-plic.c
··· 60 60 #define PLIC_DISABLE_THRESHOLD 0x7 61 61 #define PLIC_ENABLE_THRESHOLD 0 62 62 63 + #define PLIC_QUIRK_EDGE_INTERRUPT 0 64 + 63 65 struct plic_priv { 64 66 struct cpumask lmask; 65 67 struct irq_domain *irqdomain; 66 68 void __iomem *regs; 69 + unsigned long plic_quirks; 67 70 }; 68 71 69 72 struct plic_handler { ··· 83 80 static int plic_parent_irq __ro_after_init; 84 81 static bool plic_cpuhp_setup_done __ro_after_init; 85 82 static DEFINE_PER_CPU(struct plic_handler, plic_handlers); 83 + 84 + static int plic_irq_set_type(struct irq_data *d, unsigned int type); 86 85 87 86 static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable) 88 87 { ··· 181 176 } 182 177 } 183 178 179 + static struct irq_chip plic_edge_chip = { 180 + .name = "SiFive PLIC", 181 + .irq_ack = plic_irq_eoi, 182 + .irq_mask = plic_irq_mask, 183 + .irq_unmask = plic_irq_unmask, 184 + #ifdef CONFIG_SMP 185 + .irq_set_affinity = plic_set_affinity, 186 + #endif 187 + .irq_set_type = plic_irq_set_type, 188 + }; 189 + 184 190 static struct irq_chip plic_chip = { 185 191 .name = "SiFive PLIC", 186 192 .irq_mask = plic_irq_mask, ··· 200 184 #ifdef CONFIG_SMP 201 185 .irq_set_affinity = plic_set_affinity, 202 186 #endif 187 + .irq_set_type = plic_irq_set_type, 203 188 }; 189 + 190 + static int plic_irq_set_type(struct irq_data *d, unsigned int type) 191 + { 192 + struct plic_priv *priv = irq_data_get_irq_chip_data(d); 193 + 194 + if (!test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks)) 195 + return IRQ_SET_MASK_OK_NOCOPY; 196 + 197 + switch (type) { 198 + case IRQ_TYPE_EDGE_RISING: 199 + irq_set_chip_handler_name_locked(d, &plic_edge_chip, 200 + handle_edge_irq, NULL); 201 + break; 202 + case IRQ_TYPE_LEVEL_HIGH: 203 + irq_set_chip_handler_name_locked(d, &plic_chip, 204 + handle_fasteoi_irq, NULL); 205 + break; 206 + default: 207 + return -EINVAL; 208 + } 209 + 210 + return IRQ_SET_MASK_OK; 211 + } 204 212 205 213 static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, 206 214 irq_hw_number_t hwirq) ··· 238 198 return 0; 239 199 } 240 200 201 + static int plic_irq_domain_translate(struct irq_domain *d, 202 + struct irq_fwspec *fwspec, 203 + unsigned long *hwirq, 204 + unsigned int *type) 205 + { 206 + struct plic_priv *priv = d->host_data; 207 + 208 + if (test_bit(PLIC_QUIRK_EDGE_INTERRUPT, &priv->plic_quirks)) 209 + return irq_domain_translate_twocell(d, fwspec, hwirq, type); 210 + 211 + return irq_domain_translate_onecell(d, fwspec, hwirq, type); 212 + } 213 + 241 214 static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 242 215 unsigned int nr_irqs, void *arg) 243 216 { ··· 259 206 unsigned int type; 260 207 struct irq_fwspec *fwspec = arg; 261 208 262 - ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type); 209 + ret = plic_irq_domain_translate(domain, fwspec, &hwirq, &type); 263 210 if (ret) 264 211 return ret; 265 212 ··· 273 220 } 274 221 275 222 static const struct irq_domain_ops plic_irqdomain_ops = { 276 - .translate = irq_domain_translate_onecell, 223 + .translate = plic_irq_domain_translate, 277 224 .alloc = plic_irq_domain_alloc, 278 225 .free = irq_domain_free_irqs_top, 279 226 }; ··· 334 281 return 0; 335 282 } 336 283 337 - static int __init plic_init(struct device_node *node, 338 - struct device_node *parent) 284 + static int __init __plic_init(struct device_node *node, 285 + struct device_node *parent, 286 + unsigned long plic_quirks) 339 287 { 340 288 int error = 0, nr_contexts, nr_handlers = 0, i; 341 289 u32 nr_irqs; ··· 346 292 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 347 293 if (!priv) 348 294 return -ENOMEM; 295 + 296 + priv->plic_quirks = plic_quirks; 349 297 350 298 priv->regs = of_iomap(node, 0); 351 299 if (WARN_ON(!priv->regs)) { ··· 466 410 return error; 467 411 } 468 412 413 + static int __init plic_init(struct device_node *node, 414 + struct device_node *parent) 415 + { 416 + return __plic_init(node, parent, 0); 417 + } 418 + 469 419 IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init); 470 420 IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */ 471 - IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */ 421 + 422 + static int __init plic_edge_init(struct device_node *node, 423 + struct device_node *parent) 424 + { 425 + return __plic_init(node, parent, BIT(PLIC_QUIRK_EDGE_INTERRUPT)); 426 + } 427 + 428 + IRQCHIP_DECLARE(andestech_nceplic100, "andestech,nceplic100", plic_edge_init); 429 + IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_edge_init);