diff options
author | Christoph Hellwig <hch@lst.de> | 2018-08-04 10:23:16 +0200 |
---|---|---|
committer | Palmer Dabbelt <palmer@sifive.com> | 2018-08-13 08:31:31 -0700 |
commit | 6ea0f26a7913b2a72f9cbe84e77ad2cbeaaa9dde (patch) | |
tree | dc077f5075634c43587aa2658247e37b4004e59d /arch/riscv/kernel/irq.c | |
parent | bec2e6ac353d5c8a47c6eea639136bac3990093e (diff) | |
download | linux-6ea0f26a7913b2a72f9cbe84e77ad2cbeaaa9dde.tar.bz2 |
RISC-V: implement low-level interrupt handling
Add support for a routine that dispatches exceptions with the interrupt
flags set to either the IPI or irqdomain code (and the clock source in the
future).
Loosely based on the irq-riscv-int.c irqchip driver from the RISC-V tree.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Diffstat (limited to 'arch/riscv/kernel/irq.c')
-rw-r--r-- | arch/riscv/kernel/irq.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c index 7bcdaed15703..ab5f3e22c7cc 100644 --- a/arch/riscv/kernel/irq.c +++ b/arch/riscv/kernel/irq.c @@ -1,21 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012 Regents of the University of California * Copyright (C) 2017 SiFive - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (C) 2018 Christoph Hellwig */ #include <linux/interrupt.h> #include <linux/irqchip.h> #include <linux/irqdomain.h> +/* + * Possible interrupt causes: + */ +#define INTERRUPT_CAUSE_SOFTWARE 1 +#define INTERRUPT_CAUSE_TIMER 5 +#define INTERRUPT_CAUSE_EXTERNAL 9 + +/* + * The high order bit of the trap cause register is always set for + * interrupts, which allows us to differentiate them from exceptions + * quickly. The INTERRUPT_CAUSE_* macros don't contain that bit, so we + * need to mask it off. + */ +#define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) + +asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs, unsigned long cause) +{ + struct pt_regs *old_regs = set_irq_regs(regs); + + irq_enter(); + switch (cause & ~INTERRUPT_CAUSE_FLAG) { +#ifdef CONFIG_SMP + case INTERRUPT_CAUSE_SOFTWARE: + /* + * We only use software interrupts to pass IPIs, so if a non-SMP + * system gets one, then we don't know what to do. + */ + riscv_software_interrupt(); + break; +#endif + case INTERRUPT_CAUSE_EXTERNAL: + handle_arch_irq(regs); + break; + default: + panic("unexpected interrupt cause"); + } + irq_exit(); + + set_irq_regs(old_regs); +} + void __init init_IRQ(void) { irqchip_init(); |