|
44 | 44 | * Each hart context has a vector of interrupt enable bits associated with it. |
45 | 45 | * There's one bit for each interrupt source. |
46 | 46 | */ |
47 | | -#define ENABLE_BASE 0x2000 |
48 | | -#define ENABLE_PER_HART 0x80 |
| 47 | +#define CONTEXT_ENABLE_BASE 0x2000 |
| 48 | +#define CONTEXT_ENABLE_SIZE 0x80 |
49 | 49 |
|
50 | 50 | /* |
51 | 51 | * Each hart context has a set of control registers associated with it. Right |
52 | 52 | * now there's only two: a source priority threshold over which the hart will |
53 | 53 | * take an interrupt, and a register to claim interrupts. |
54 | 54 | */ |
55 | 55 | #define CONTEXT_BASE 0x200000 |
56 | | -#define CONTEXT_PER_HART 0x1000 |
| 56 | +#define CONTEXT_SIZE 0x1000 |
57 | 57 | #define CONTEXT_THRESHOLD 0x00 |
58 | 58 | #define CONTEXT_CLAIM 0x04 |
59 | 59 |
|
@@ -81,17 +81,21 @@ static int plic_parent_irq __ro_after_init; |
81 | 81 | static bool plic_cpuhp_setup_done __ro_after_init; |
82 | 82 | static DEFINE_PER_CPU(struct plic_handler, plic_handlers); |
83 | 83 |
|
84 | | -static inline void plic_toggle(struct plic_handler *handler, |
85 | | - int hwirq, int enable) |
| 84 | +static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable) |
86 | 85 | { |
87 | | - u32 __iomem *reg = handler->enable_base + (hwirq / 32) * sizeof(u32); |
| 86 | + u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32); |
88 | 87 | u32 hwirq_mask = 1 << (hwirq % 32); |
89 | 88 |
|
90 | | - raw_spin_lock(&handler->enable_lock); |
91 | 89 | if (enable) |
92 | 90 | writel(readl(reg) | hwirq_mask, reg); |
93 | 91 | else |
94 | 92 | writel(readl(reg) & ~hwirq_mask, reg); |
| 93 | +} |
| 94 | + |
| 95 | +static 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); |
95 | 99 | raw_spin_unlock(&handler->enable_lock); |
96 | 100 | } |
97 | 101 |
|
@@ -324,8 +328,18 @@ static int __init plic_init(struct device_node *node, |
324 | 328 | * Skip contexts other than external interrupts for our |
325 | 329 | * privilege level. |
326 | 330 | */ |
327 | | - if (parent.args[0] != RV_IRQ_EXT) |
| 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 | + } |
328 | 341 | continue; |
| 342 | + } |
329 | 343 |
|
330 | 344 | hartid = riscv_of_parent_hartid(parent.np); |
331 | 345 | if (hartid < 0) { |
@@ -361,11 +375,11 @@ static int __init plic_init(struct device_node *node, |
361 | 375 |
|
362 | 376 | cpumask_set_cpu(cpu, &priv->lmask); |
363 | 377 | handler->present = true; |
364 | | - handler->hart_base = |
365 | | - priv->regs + CONTEXT_BASE + i * CONTEXT_PER_HART; |
| 378 | + handler->hart_base = priv->regs + CONTEXT_BASE + |
| 379 | + i * CONTEXT_SIZE; |
366 | 380 | raw_spin_lock_init(&handler->enable_lock); |
367 | | - handler->enable_base = |
368 | | - priv->regs + ENABLE_BASE + i * ENABLE_PER_HART; |
| 381 | + handler->enable_base = priv->regs + CONTEXT_ENABLE_BASE + |
| 382 | + i * CONTEXT_ENABLE_SIZE; |
369 | 383 | handler->priv = priv; |
370 | 384 | done: |
371 | 385 | for (hwirq = 1; hwirq <= nr_irqs; hwirq++) |
|
0 commit comments