1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2012 Regents of the University of California 4 * Copyright (C) 2017 SiFive 5 * Copyright (C) 2018 Christoph Hellwig 6 */ 7 8 #include <linux/interrupt.h> 9 #include <linux/irqchip.h> 10 #include <linux/irqdomain.h> 11 12 /* 13 * Possible interrupt causes: 14 */ 15 #define INTERRUPT_CAUSE_SOFTWARE 1 16 #define INTERRUPT_CAUSE_TIMER 5 17 #define INTERRUPT_CAUSE_EXTERNAL 9 18 19 /* 20 * The high order bit of the trap cause register is always set for 21 * interrupts, which allows us to differentiate them from exceptions 22 * quickly. The INTERRUPT_CAUSE_* macros don't contain that bit, so we 23 * need to mask it off. 24 */ 25 #define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) 26 27 asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs, unsigned long cause) 28 { 29 struct pt_regs *old_regs = set_irq_regs(regs); 30 31 irq_enter(); 32 switch (cause & ~INTERRUPT_CAUSE_FLAG) { 33 case INTERRUPT_CAUSE_TIMER: 34 riscv_timer_interrupt(); 35 break; 36 #ifdef CONFIG_SMP 37 case INTERRUPT_CAUSE_SOFTWARE: 38 /* 39 * We only use software interrupts to pass IPIs, so if a non-SMP 40 * system gets one, then we don't know what to do. 41 */ 42 riscv_software_interrupt(); 43 break; 44 #endif 45 case INTERRUPT_CAUSE_EXTERNAL: 46 handle_arch_irq(regs); 47 break; 48 default: 49 panic("unexpected interrupt cause"); 50 } 51 irq_exit(); 52 53 set_irq_regs(old_regs); 54 } 55 56 void __init init_IRQ(void) 57 { 58 irqchip_init(); 59 } 60