aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnup Patel <anup@brainfault.org>2018-10-02 15:15:07 -0400
committerPalmer Dabbelt <palmer@sifive.com>2018-10-22 20:03:37 -0400
commit8b20d2db0a6d2761e0fc156eb74f7a55b92b3147 (patch)
tree1a5a6b213805d6cec82f940351b7aed614fde409
parent4b26d22fdff1e39647cc5952b01d329e83dedfe1 (diff)
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>
-rw-r--r--arch/riscv/include/asm/smp.h9
-rw-r--r--arch/riscv/kernel/irq.c8
-rw-r--r--arch/riscv/kernel/smp.c39
3 files changed, 49 insertions, 7 deletions
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 47fd61dfc897..41aa73b476f4 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -25,8 +25,13 @@
25extern unsigned long __cpuid_to_hartid_map[NR_CPUS]; 25extern unsigned long __cpuid_to_hartid_map[NR_CPUS];
26#define cpuid_to_hartid_map(cpu) __cpuid_to_hartid_map[cpu] 26#define cpuid_to_hartid_map(cpu) __cpuid_to_hartid_map[cpu]
27 27
28struct seq_file;
29
28#ifdef CONFIG_SMP 30#ifdef CONFIG_SMP
29 31
32/* print IPI stats */
33void show_ipi_stats(struct seq_file *p, int prec);
34
30/* SMP initialization hook for setup_arch */ 35/* SMP initialization hook for setup_arch */
31void __init setup_smp(void); 36void __init setup_smp(void);
32 37
@@ -47,6 +52,10 @@ void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
47 52
48#else 53#else
49 54
55static inline void show_ipi_stats(struct seq_file *p, int prec)
56{
57}
58
50static inline int riscv_hartid_to_cpuid(int hartid) 59static inline int riscv_hartid_to_cpuid(int hartid)
51{ 60{
52 return 0; 61 return 0;
diff --git a/arch/riscv/kernel/irq.c b/arch/riscv/kernel/irq.c
index ca4593317e45..48e6b7db83a1 100644
--- a/arch/riscv/kernel/irq.c
+++ b/arch/riscv/kernel/irq.c
@@ -8,6 +8,8 @@
8#include <linux/interrupt.h> 8#include <linux/interrupt.h>
9#include <linux/irqchip.h> 9#include <linux/irqchip.h>
10#include <linux/irqdomain.h> 10#include <linux/irqdomain.h>
11#include <linux/seq_file.h>
12#include <asm/smp.h>
11 13
12/* 14/*
13 * Possible interrupt causes: 15 * Possible interrupt causes:
@@ -24,6 +26,12 @@
24 */ 26 */
25#define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1)) 27#define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1))
26 28
29int arch_show_interrupts(struct seq_file *p, int prec)
30{
31 show_ipi_stats(p, prec);
32 return 0;
33}
34
27asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs) 35asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs)
28{ 36{
29 struct pt_regs *old_regs = set_irq_regs(regs); 37 struct pt_regs *old_regs = set_irq_regs(regs);
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
index 4eac0094f47e..57b1383e5ef7 100644
--- a/arch/riscv/kernel/smp.c
+++ b/arch/riscv/kernel/smp.c
@@ -22,22 +22,24 @@
22#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/smp.h> 23#include <linux/smp.h>
24#include <linux/sched.h> 24#include <linux/sched.h>
25#include <linux/seq_file.h>
25 26
26#include <asm/sbi.h> 27#include <asm/sbi.h>
27#include <asm/tlbflush.h> 28#include <asm/tlbflush.h>
28#include <asm/cacheflush.h> 29#include <asm/cacheflush.h>
29 30
30/* A collection of single bit ipi messages. */
31static struct {
32 unsigned long bits ____cacheline_aligned;
33} ipi_data[NR_CPUS] __cacheline_aligned;
34
35enum ipi_message_type { 31enum ipi_message_type {
36 IPI_RESCHEDULE, 32 IPI_RESCHEDULE,
37 IPI_CALL_FUNC, 33 IPI_CALL_FUNC,
38 IPI_MAX 34 IPI_MAX
39}; 35};
40 36
37/* A collection of single bit ipi messages. */
38static struct {
39 unsigned long stats[IPI_MAX] ____cacheline_aligned;
40 unsigned long bits ____cacheline_aligned;
41} ipi_data[NR_CPUS] __cacheline_aligned;
42
41int riscv_hartid_to_cpuid(int hartid) 43int riscv_hartid_to_cpuid(int hartid)
42{ 44{
43 int i = -1; 45 int i = -1;
@@ -67,6 +69,7 @@ int setup_profiling_timer(unsigned int multiplier)
67void riscv_software_interrupt(void) 69void riscv_software_interrupt(void)
68{ 70{
69 unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; 71 unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
72 unsigned long *stats = ipi_data[smp_processor_id()].stats;
70 73
71 /* Clear pending IPI */ 74 /* Clear pending IPI */
72 csr_clear(sip, SIE_SSIE); 75 csr_clear(sip, SIE_SSIE);
@@ -81,11 +84,15 @@ void riscv_software_interrupt(void)
81 if (ops == 0) 84 if (ops == 0)
82 return; 85 return;
83 86
84 if (ops & (1 << IPI_RESCHEDULE)) 87 if (ops & (1 << IPI_RESCHEDULE)) {
88 stats[IPI_RESCHEDULE]++;
85 scheduler_ipi(); 89 scheduler_ipi();
90 }
86 91
87 if (ops & (1 << IPI_CALL_FUNC)) 92 if (ops & (1 << IPI_CALL_FUNC)) {
93 stats[IPI_CALL_FUNC]++;
88 generic_smp_call_function_interrupt(); 94 generic_smp_call_function_interrupt();
95 }
89 96
90 BUG_ON((ops >> IPI_MAX) != 0); 97 BUG_ON((ops >> IPI_MAX) != 0);
91 98
@@ -111,6 +118,24 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
111 sbi_send_ipi(cpumask_bits(&hartid_mask)); 118 sbi_send_ipi(cpumask_bits(&hartid_mask));
112} 119}
113 120
121static const char * const ipi_names[] = {
122 [IPI_RESCHEDULE] = "Rescheduling interrupts",
123 [IPI_CALL_FUNC] = "Function call interrupts",
124};
125
126void show_ipi_stats(struct seq_file *p, int prec)
127{
128 unsigned int cpu, i;
129
130 for (i = 0; i < IPI_MAX; i++) {
131 seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
132 prec >= 4 ? " " : "");
133 for_each_online_cpu(cpu)
134 seq_printf(p, "%10lu ", ipi_data[cpu].stats[i]);
135 seq_printf(p, " %s\n", ipi_names[i]);
136 }
137}
138
114void arch_send_call_function_ipi_mask(struct cpumask *mask) 139void arch_send_call_function_ipi_mask(struct cpumask *mask)
115{ 140{
116 send_ipi_message(mask, IPI_CALL_FUNC); 141 send_ipi_message(mask, IPI_CALL_FUNC);