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>
This commit is contained in:
Christoph Hellwig 2018-08-04 10:23:16 +02:00 committed by Palmer Dabbelt
parent bec2e6ac35
commit 6ea0f26a79
No known key found for this signature in database
GPG key ID: EF4CA1502CCBAB41
2 changed files with 45 additions and 11 deletions

View file

@ -168,8 +168,8 @@ ENTRY(handle_exception)
/* Handle interrupts */ /* Handle interrupts */
move a0, sp /* pt_regs */ move a0, sp /* pt_regs */
REG_L a1, handle_arch_irq move a1, s4 /* scause */
jr a1 tail do_IRQ
1: 1:
/* Exceptions run with interrupts enabled */ /* Exceptions run with interrupts enabled */
csrs sstatus, SR_SIE csrs sstatus, SR_SIE

View file

@ -1,21 +1,55 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2012 Regents of the University of California * Copyright (C) 2012 Regents of the University of California
* Copyright (C) 2017 SiFive * Copyright (C) 2017 SiFive
* * Copyright (C) 2018 Christoph Hellwig
* 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.
*/ */
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqchip.h> #include <linux/irqchip.h>
#include <linux/irqdomain.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) void __init init_IRQ(void)
{ {
irqchip_init(); irqchip_init();