mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-30 22:26:55 +00:00
irqchip/sifive-plic: Disable S-mode IRQs if running in M-mode
When detecting a context for a privilege mode different from the current running privilege mode, we simply skip to the next context register. This means that we never clear the S-mode enable bits when running in M-mode. On canaan k210, a bunch of S-mode interrupts are enabled by the bootrom. These S-mode specific interrupts should never trigger, since we never set the mie.SEIE bit in the parent interrupt controller (riscv-intc). However, we will be able to see the mip.SEIE bit set as pending. This isn't a good default when CONFIG_RISCV_M_MODE is set, since in that case we will never enter a lower privilege mode (e.g. S-mode). Let's clear the S-mode enable bits when running the kernel in M-mode, such that we won't have a interrupt pending bit set, which we will never clear. Signed-off-by: Niklas Cassel <niklas.cassel@wdc.com> Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20220302131544.3166154-3-Niklas.Cassel@wdc.com
This commit is contained in:
parent
0d3616bbd0
commit
098fdbc353
1 changed files with 19 additions and 5 deletions
|
@ -81,17 +81,21 @@ static int plic_parent_irq __ro_after_init;
|
|||
static bool plic_cpuhp_setup_done __ro_after_init;
|
||||
static DEFINE_PER_CPU(struct plic_handler, plic_handlers);
|
||||
|
||||
static inline void plic_toggle(struct plic_handler *handler,
|
||||
int hwirq, int enable)
|
||||
static void __plic_toggle(void __iomem *enable_base, int hwirq, int enable)
|
||||
{
|
||||
u32 __iomem *reg = handler->enable_base + (hwirq / 32) * sizeof(u32);
|
||||
u32 __iomem *reg = enable_base + (hwirq / 32) * sizeof(u32);
|
||||
u32 hwirq_mask = 1 << (hwirq % 32);
|
||||
|
||||
raw_spin_lock(&handler->enable_lock);
|
||||
if (enable)
|
||||
writel(readl(reg) | hwirq_mask, reg);
|
||||
else
|
||||
writel(readl(reg) & ~hwirq_mask, reg);
|
||||
}
|
||||
|
||||
static void plic_toggle(struct plic_handler *handler, int hwirq, int enable)
|
||||
{
|
||||
raw_spin_lock(&handler->enable_lock);
|
||||
__plic_toggle(handler->enable_base, hwirq, enable);
|
||||
raw_spin_unlock(&handler->enable_lock);
|
||||
}
|
||||
|
||||
|
@ -324,8 +328,18 @@ static int __init plic_init(struct device_node *node,
|
|||
* Skip contexts other than external interrupts for our
|
||||
* privilege level.
|
||||
*/
|
||||
if (parent.args[0] != RV_IRQ_EXT)
|
||||
if (parent.args[0] != RV_IRQ_EXT) {
|
||||
/* Disable S-mode enable bits if running in M-mode. */
|
||||
if (IS_ENABLED(CONFIG_RISCV_M_MODE)) {
|
||||
void __iomem *enable_base = priv->regs +
|
||||
CONTEXT_ENABLE_BASE +
|
||||
i * CONTEXT_ENABLE_SIZE;
|
||||
|
||||
for (hwirq = 1; hwirq <= nr_irqs; hwirq++)
|
||||
__plic_toggle(enable_base, hwirq, 0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
hartid = riscv_of_parent_hartid(parent.np);
|
||||
if (hartid < 0) {
|
||||
|
|
Loading…
Reference in a new issue