irq-sifive-plic.c (10953B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2017 SiFive 4 * Copyright (C) 2018 Christoph Hellwig 5 */ 6#define pr_fmt(fmt) "plic: " fmt 7#include <linux/cpu.h> 8#include <linux/interrupt.h> 9#include <linux/io.h> 10#include <linux/irq.h> 11#include <linux/irqchip.h> 12#include <linux/irqchip/chained_irq.h> 13#include <linux/irqdomain.h> 14#include <linux/module.h> 15#include <linux/of.h> 16#include <linux/of_address.h> 17#include <linux/of_irq.h> 18#include <linux/platform_device.h> 19#include <linux/spinlock.h> 20#include <asm/smp.h> 21 22/* 23 * This driver implements a version of the RISC-V PLIC with the actual layout 24 * specified in chapter 8 of the SiFive U5 Coreplex Series Manual: 25 * 26 * https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf 27 * 28 * The largest number supported by devices marked as 'sifive,plic-1.0.0', is 29 * 1024, of which device 0 is defined as non-existent by the RISC-V Privileged 30 * Spec. 31 */ 32 33#define MAX_DEVICES 1024 34#define MAX_CONTEXTS 15872 35 36/* 37 * Each interrupt source has a priority register associated with it. 38 * We always hardwire it to one in Linux. 39 */ 40#define PRIORITY_BASE 0 41#define PRIORITY_PER_ID 4 42 43/* 44 * Each hart context has a vector of interrupt enable bits associated with it. 45 * There's one bit for each interrupt source. 46 */ 47#define CONTEXT_ENABLE_BASE 0x2000 48#define CONTEXT_ENABLE_SIZE 0x80 49 50/* 51 * Each hart context has a set of control registers associated with it. Right 52 * now there's only two: a source priority threshold over which the hart will 53 * take an interrupt, and a register to claim interrupts. 54 */ 55#define CONTEXT_BASE 0x200000 56#define CONTEXT_SIZE 0x1000 57#define CONTEXT_THRESHOLD 0x00 58#define CONTEXT_CLAIM 0x04 59 60#define PLIC_DISABLE_THRESHOLD 0x7 61#define PLIC_ENABLE_THRESHOLD 0 62 63struct plic_priv { 64 struct cpumask lmask; 65 struct irq_domain *irqdomain; 66 void __iomem *regs; 67}; 68 69struct plic_handler { 70 bool present; 71 void __iomem *hart_base; 72 /* 73 * Protect mask operations on the registers given that we can't 74 * assume atomic memory operations work on them. 75 */ 76 raw_spinlock_t enable_lock; 77 void __iomem *enable_base; 78 struct plic_priv *priv; 79}; 80static int plic_parent_irq __ro_after_init; 81static bool plic_cpuhp_setup_done __ro_after_init; 82static DEFINE_PER_CPU(struct plic_handler, plic_handlers); 83 84static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable) 85{ 86 u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32); 87 u32 hwirq_mask = 1 << (hwirq % 32); 88 89 if (enable) 90 writel(readl(reg) | hwirq_mask, reg); 91 else 92 writel(readl(reg) & ~hwirq_mask, reg); 93} 94 95static void plic_toggle(struct plic_handler *handler, int hwirq, int enable) 96{ 97 raw_spin_lock(&handler->enable_lock); 98 __plic_toggle(handler->enable_base, hwirq, enable); 99 raw_spin_unlock(&handler->enable_lock); 100} 101 102static inline void plic_irq_toggle(const struct cpumask *mask, 103 struct irq_data *d, int enable) 104{ 105 int cpu; 106 struct plic_priv *priv = irq_data_get_irq_chip_data(d); 107 108 writel(enable, priv->regs + PRIORITY_BASE + d->hwirq * PRIORITY_PER_ID); 109 for_each_cpu(cpu, mask) { 110 struct plic_handler *handler = per_cpu_ptr(&plic_handlers, cpu); 111 112 if (handler->present && 113 cpumask_test_cpu(cpu, &handler->priv->lmask)) 114 plic_toggle(handler, d->hwirq, enable); 115 } 116} 117 118static void plic_irq_unmask(struct irq_data *d) 119{ 120 struct cpumask amask; 121 unsigned int cpu; 122 struct plic_priv *priv = irq_data_get_irq_chip_data(d); 123 124 cpumask_and(&amask, &priv->lmask, cpu_online_mask); 125 cpu = cpumask_any_and(irq_data_get_affinity_mask(d), 126 &amask); 127 if (WARN_ON_ONCE(cpu >= nr_cpu_ids)) 128 return; 129 plic_irq_toggle(cpumask_of(cpu), d, 1); 130} 131 132static void plic_irq_mask(struct irq_data *d) 133{ 134 struct plic_priv *priv = irq_data_get_irq_chip_data(d); 135 136 plic_irq_toggle(&priv->lmask, d, 0); 137} 138 139#ifdef CONFIG_SMP 140static int plic_set_affinity(struct irq_data *d, 141 const struct cpumask *mask_val, bool force) 142{ 143 unsigned int cpu; 144 struct cpumask amask; 145 struct plic_priv *priv = irq_data_get_irq_chip_data(d); 146 147 cpumask_and(&amask, &priv->lmask, mask_val); 148 149 if (force) 150 cpu = cpumask_first(&amask); 151 else 152 cpu = cpumask_any_and(&amask, cpu_online_mask); 153 154 if (cpu >= nr_cpu_ids) 155 return -EINVAL; 156 157 plic_irq_toggle(&priv->lmask, d, 0); 158 plic_irq_toggle(cpumask_of(cpu), d, !irqd_irq_masked(d)); 159 160 irq_data_update_effective_affinity(d, cpumask_of(cpu)); 161 162 return IRQ_SET_MASK_OK_DONE; 163} 164#endif 165 166static void plic_irq_eoi(struct irq_data *d) 167{ 168 struct plic_handler *handler = this_cpu_ptr(&plic_handlers); 169 170 if (irqd_irq_masked(d)) { 171 plic_irq_unmask(d); 172 writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); 173 plic_irq_mask(d); 174 } else { 175 writel(d->hwirq, handler->hart_base + CONTEXT_CLAIM); 176 } 177} 178 179static struct irq_chip plic_chip = { 180 .name = "SiFive PLIC", 181 .irq_mask = plic_irq_mask, 182 .irq_unmask = plic_irq_unmask, 183 .irq_eoi = plic_irq_eoi, 184#ifdef CONFIG_SMP 185 .irq_set_affinity = plic_set_affinity, 186#endif 187}; 188 189static int plic_irqdomain_map(struct irq_domain *d, unsigned int irq, 190 irq_hw_number_t hwirq) 191{ 192 struct plic_priv *priv = d->host_data; 193 194 irq_domain_set_info(d, irq, hwirq, &plic_chip, d->host_data, 195 handle_fasteoi_irq, NULL, NULL); 196 irq_set_noprobe(irq); 197 irq_set_affinity(irq, &priv->lmask); 198 return 0; 199} 200 201static int plic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq, 202 unsigned int nr_irqs, void *arg) 203{ 204 int i, ret; 205 irq_hw_number_t hwirq; 206 unsigned int type; 207 struct irq_fwspec *fwspec = arg; 208 209 ret = irq_domain_translate_onecell(domain, fwspec, &hwirq, &type); 210 if (ret) 211 return ret; 212 213 for (i = 0; i < nr_irqs; i++) { 214 ret = plic_irqdomain_map(domain, virq + i, hwirq + i); 215 if (ret) 216 return ret; 217 } 218 219 return 0; 220} 221 222static const struct irq_domain_ops plic_irqdomain_ops = { 223 .translate = irq_domain_translate_onecell, 224 .alloc = plic_irq_domain_alloc, 225 .free = irq_domain_free_irqs_top, 226}; 227 228/* 229 * Handling an interrupt is a two-step process: first you claim the interrupt 230 * by reading the claim register, then you complete the interrupt by writing 231 * that source ID back to the same claim register. This automatically enables 232 * and disables the interrupt, so there's nothing else to do. 233 */ 234static void plic_handle_irq(struct irq_desc *desc) 235{ 236 struct plic_handler *handler = this_cpu_ptr(&plic_handlers); 237 struct irq_chip *chip = irq_desc_get_chip(desc); 238 void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; 239 irq_hw_number_t hwirq; 240 241 WARN_ON_ONCE(!handler->present); 242 243 chained_irq_enter(chip, desc); 244 245 while ((hwirq = readl(claim))) { 246 int err = generic_handle_domain_irq(handler->priv->irqdomain, 247 hwirq); 248 if (unlikely(err)) 249 pr_warn_ratelimited("can't find mapping for hwirq %lu\n", 250 hwirq); 251 } 252 253 chained_irq_exit(chip, desc); 254} 255 256static void plic_set_threshold(struct plic_handler *handler, u32 threshold) 257{ 258 /* priority must be > threshold to trigger an interrupt */ 259 writel(threshold, handler->hart_base + CONTEXT_THRESHOLD); 260} 261 262static int plic_dying_cpu(unsigned int cpu) 263{ 264 if (plic_parent_irq) 265 disable_percpu_irq(plic_parent_irq); 266 267 return 0; 268} 269 270static int plic_starting_cpu(unsigned int cpu) 271{ 272 struct plic_handler *handler = this_cpu_ptr(&plic_handlers); 273 274 if (plic_parent_irq) 275 enable_percpu_irq(plic_parent_irq, 276 irq_get_trigger_type(plic_parent_irq)); 277 else 278 pr_warn("cpu%d: parent irq not available\n", cpu); 279 plic_set_threshold(handler, PLIC_ENABLE_THRESHOLD); 280 281 return 0; 282} 283 284static int __init plic_init(struct device_node *node, 285 struct device_node *parent) 286{ 287 int error = 0, nr_contexts, nr_handlers = 0, i; 288 u32 nr_irqs; 289 struct plic_priv *priv; 290 struct plic_handler *handler; 291 292 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 293 if (!priv) 294 return -ENOMEM; 295 296 priv->regs = of_iomap(node, 0); 297 if (WARN_ON(!priv->regs)) { 298 error = -EIO; 299 goto out_free_priv; 300 } 301 302 error = -EINVAL; 303 of_property_read_u32(node, "riscv,ndev", &nr_irqs); 304 if (WARN_ON(!nr_irqs)) 305 goto out_iounmap; 306 307 nr_contexts = of_irq_count(node); 308 if (WARN_ON(!nr_contexts)) 309 goto out_iounmap; 310 311 error = -ENOMEM; 312 priv->irqdomain = irq_domain_add_linear(node, nr_irqs + 1, 313 &plic_irqdomain_ops, priv); 314 if (WARN_ON(!priv->irqdomain)) 315 goto out_iounmap; 316 317 for (i = 0; i < nr_contexts; i++) { 318 struct of_phandle_args parent; 319 irq_hw_number_t hwirq; 320 int cpu, hartid; 321 322 if (of_irq_parse_one(node, i, &parent)) { 323 pr_err("failed to parse parent for context %d.\n", i); 324 continue; 325 } 326 327 /* 328 * Skip contexts other than external interrupts for our 329 * privilege level. 330 */ 331 if (parent.args[0] != RV_IRQ_EXT) { 332 /* Disable S-mode enable bits if running in M-mode. */ 333 if (IS_ENABLED(CONFIG_RISCV_M_MODE)) { 334 void __iomem *enable_base = priv->regs + 335 CONTEXT_ENABLE_BASE + 336 i * CONTEXT_ENABLE_SIZE; 337 338 for (hwirq = 1; hwirq <= nr_irqs; hwirq++) 339 __plic_toggle(enable_base, hwirq, 0); 340 } 341 continue; 342 } 343 344 hartid = riscv_of_parent_hartid(parent.np); 345 if (hartid < 0) { 346 pr_warn("failed to parse hart ID for context %d.\n", i); 347 continue; 348 } 349 350 cpu = riscv_hartid_to_cpuid(hartid); 351 if (cpu < 0) { 352 pr_warn("Invalid cpuid for context %d\n", i); 353 continue; 354 } 355 356 /* Find parent domain and register chained handler */ 357 if (!plic_parent_irq && irq_find_host(parent.np)) { 358 plic_parent_irq = irq_of_parse_and_map(node, i); 359 if (plic_parent_irq) 360 irq_set_chained_handler(plic_parent_irq, 361 plic_handle_irq); 362 } 363 364 /* 365 * When running in M-mode we need to ignore the S-mode handler. 366 * Here we assume it always comes later, but that might be a 367 * little fragile. 368 */ 369 handler = per_cpu_ptr(&plic_handlers, cpu); 370 if (handler->present) { 371 pr_warn("handler already present for context %d.\n", i); 372 plic_set_threshold(handler, PLIC_DISABLE_THRESHOLD); 373 goto done; 374 } 375 376 cpumask_set_cpu(cpu, &priv->lmask); 377 handler->present = true; 378 handler->hart_base = priv->regs + CONTEXT_BASE + 379 i * CONTEXT_SIZE; 380 raw_spin_lock_init(&handler->enable_lock); 381 handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE + 382 i * CONTEXT_ENABLE_SIZE; 383 handler->priv = priv; 384done: 385 for (hwirq = 1; hwirq <= nr_irqs; hwirq++) 386 plic_toggle(handler, hwirq, 0); 387 nr_handlers++; 388 } 389 390 /* 391 * We can have multiple PLIC instances so setup cpuhp state only 392 * when context handler for current/boot CPU is present. 393 */ 394 handler = this_cpu_ptr(&plic_handlers); 395 if (handler->present && !plic_cpuhp_setup_done) { 396 cpuhp_setup_state(CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, 397 "irqchip/sifive/plic:starting", 398 plic_starting_cpu, plic_dying_cpu); 399 plic_cpuhp_setup_done = true; 400 } 401 402 pr_info("%pOFP: mapped %d interrupts with %d handlers for" 403 " %d contexts.\n", node, nr_irqs, nr_handlers, nr_contexts); 404 return 0; 405 406out_iounmap: 407 iounmap(priv->regs); 408out_free_priv: 409 kfree(priv); 410 return error; 411} 412 413IRQCHIP_DECLARE(sifive_plic, "sifive,plic-1.0.0", plic_init); 414IRQCHIP_DECLARE(riscv_plic0, "riscv,plic0", plic_init); /* for legacy systems */ 415IRQCHIP_DECLARE(thead_c900_plic, "thead,c900-plic", plic_init); /* for firmware driver */