linux/arch/riscv/kernel/irq.c
Anup Patel 8b20d2db0a
RISC-V: Show IPI stats
This patch provides arch_show_interrupts() implementation to
show IPI stats via /proc/interrupts.

Now the contents of /proc/interrupts" will look like below:
           CPU0       CPU1       CPU2       CPU3
  8:         17          7          6         14  SiFive PLIC   8  virtio0
 10:         10         10          9         11  SiFive PLIC  10  ttyS0
IPI0:       170        673        251         79  Rescheduling interrupts
IPI1:         1         12         27          1  Function call interrupts

Signed-off-by: Anup Patel <anup@brainfault.org>
[Atish - Fixed checkpatch errors]
Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Palmer Dabbelt <palmer@sifive.com>

Changes since v2:
 - Remove use of IPI_CALL_WAKEUP because it's being removed

Changes since v1:
 - Add stub inline show_ipi_stats() function for !CONFIG_SMP
 - Make ipi_names[] dynamically sized at compile time
 - Minor beautification of ipi_names[] using tabs

Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
2018-10-22 17:03:37 -07:00

68 lines
1.5 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2012 Regents of the University of California
* Copyright (C) 2017 SiFive
* Copyright (C) 2018 Christoph Hellwig
*/
#include <linux/interrupt.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/seq_file.h>
#include <asm/smp.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))
int arch_show_interrupts(struct seq_file *p, int prec)
{
show_ipi_stats(p, prec);
return 0;
}
asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs)
{
struct pt_regs *old_regs = set_irq_regs(regs);
irq_enter();
switch (regs->scause & ~INTERRUPT_CAUSE_FLAG) {
case INTERRUPT_CAUSE_TIMER:
riscv_timer_interrupt();
break;
#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();
}