diff options
| author | Anup Patel <anup@brainfault.org> | 2018-10-02 15:15:07 -0400 |
|---|---|---|
| committer | Palmer Dabbelt <palmer@sifive.com> | 2018-10-22 20:03:37 -0400 |
| commit | 8b20d2db0a6d2761e0fc156eb74f7a55b92b3147 (patch) | |
| tree | 1a5a6b213805d6cec82f940351b7aed614fde409 | |
| parent | 4b26d22fdff1e39647cc5952b01d329e83dedfe1 (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.h | 9 | ||||
| -rw-r--r-- | arch/riscv/kernel/irq.c | 8 | ||||
| -rw-r--r-- | arch/riscv/kernel/smp.c | 39 |
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 @@ | |||
| 25 | extern unsigned long __cpuid_to_hartid_map[NR_CPUS]; | 25 | extern 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 | ||
| 28 | struct seq_file; | ||
| 29 | |||
| 28 | #ifdef CONFIG_SMP | 30 | #ifdef CONFIG_SMP |
| 29 | 31 | ||
| 32 | /* print IPI stats */ | ||
| 33 | void show_ipi_stats(struct seq_file *p, int prec); | ||
| 34 | |||
| 30 | /* SMP initialization hook for setup_arch */ | 35 | /* SMP initialization hook for setup_arch */ |
| 31 | void __init setup_smp(void); | 36 | void __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 | ||
| 55 | static inline void show_ipi_stats(struct seq_file *p, int prec) | ||
| 56 | { | ||
| 57 | } | ||
| 58 | |||
| 50 | static inline int riscv_hartid_to_cpuid(int hartid) | 59 | static 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 | ||
| 29 | int arch_show_interrupts(struct seq_file *p, int prec) | ||
| 30 | { | ||
| 31 | show_ipi_stats(p, prec); | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 27 | asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs) | 35 | asmlinkage 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. */ | ||
| 31 | static struct { | ||
| 32 | unsigned long bits ____cacheline_aligned; | ||
| 33 | } ipi_data[NR_CPUS] __cacheline_aligned; | ||
| 34 | |||
| 35 | enum ipi_message_type { | 31 | enum 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. */ | ||
| 38 | static struct { | ||
| 39 | unsigned long stats[IPI_MAX] ____cacheline_aligned; | ||
| 40 | unsigned long bits ____cacheline_aligned; | ||
| 41 | } ipi_data[NR_CPUS] __cacheline_aligned; | ||
| 42 | |||
| 41 | int riscv_hartid_to_cpuid(int hartid) | 43 | int 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) | |||
| 67 | void riscv_software_interrupt(void) | 69 | void 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 | ||
| 121 | static const char * const ipi_names[] = { | ||
| 122 | [IPI_RESCHEDULE] = "Rescheduling interrupts", | ||
| 123 | [IPI_CALL_FUNC] = "Function call interrupts", | ||
| 124 | }; | ||
| 125 | |||
| 126 | void 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 | |||
| 114 | void arch_send_call_function_ipi_mask(struct cpumask *mask) | 139 | void 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); |
