aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPalmer Dabbelt <palmer@sifive.com>2018-10-22 20:39:29 -0400
committerPalmer Dabbelt <palmer@sifive.com>2018-10-22 20:41:43 -0400
commitd26c4bbf992463c043fdee4b3e5efa3f08990862 (patch)
tree6f7eb8b1da031352fc3e386dd4662fabf132b942
parenta6de21baf6373ac1ddd5c52e8fbd959f164ef9cf (diff)
parent8b20d2db0a6d2761e0fc156eb74f7a55b92b3147 (diff)
RISC-V: SMP cleanup and new features
This patch series now has evolved to contain several related changes. 1. Updated the assorted cleanup series by Palmer. The original cleanup patch series can be found here. http://lists.infradead.org/pipermail/linux-riscv/2018-August/001232.html 2. Implemented decoupling linux logical CPU ids from hart id. Some of the work has been inspired from ARM64. Tested on QEMU & HighFive Unleashed board with/without SMP enabled. 3. Included Anup's cleanup and IPI stat patch. All the patch series have been combined to avoid conflicts as a lot of common code is changed different patch sets. Atish has mostly addressed review comments and fixed checkpatch errors from Palmer's and Anup's series. Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
-rw-r--r--arch/riscv/include/asm/processor.h2
-rw-r--r--arch/riscv/include/asm/smp.h47
-rw-r--r--arch/riscv/include/asm/tlbflush.h16
-rw-r--r--arch/riscv/kernel/cpu.c87
-rw-r--r--arch/riscv/kernel/entry.S1
-rw-r--r--arch/riscv/kernel/head.S4
-rw-r--r--arch/riscv/kernel/irq.c12
-rw-r--r--arch/riscv/kernel/setup.c10
-rw-r--r--arch/riscv/kernel/smp.c82
-rw-r--r--arch/riscv/kernel/smpboot.c46
-rw-r--r--drivers/clocksource/riscv_timer.c12
-rw-r--r--drivers/irqchip/irq-sifive-plic.c10
12 files changed, 259 insertions, 70 deletions
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 3fe4af8147d2..50de774d827a 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -88,7 +88,7 @@ static inline void wait_for_interrupt(void)
88} 88}
89 89
90struct device_node; 90struct device_node;
91extern int riscv_of_processor_hart(struct device_node *node); 91int riscv_of_processor_hartid(struct device_node *node);
92 92
93extern void riscv_fill_hwcap(void); 93extern void riscv_fill_hwcap(void);
94 94
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 36016845461d..41aa73b476f4 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -14,16 +14,24 @@
14#ifndef _ASM_RISCV_SMP_H 14#ifndef _ASM_RISCV_SMP_H
15#define _ASM_RISCV_SMP_H 15#define _ASM_RISCV_SMP_H
16 16
17/* This both needs asm-offsets.h and is used when generating it. */
18#ifndef GENERATING_ASM_OFFSETS
19#include <asm/asm-offsets.h>
20#endif
21
22#include <linux/cpumask.h> 17#include <linux/cpumask.h>
23#include <linux/irqreturn.h> 18#include <linux/irqreturn.h>
19#include <linux/thread_info.h>
20
21#define INVALID_HARTID ULONG_MAX
22/*
23 * Mapping between linux logical cpu index and hartid.
24 */
25extern unsigned long __cpuid_to_hartid_map[NR_CPUS];
26#define cpuid_to_hartid_map(cpu) __cpuid_to_hartid_map[cpu]
27
28struct seq_file;
24 29
25#ifdef CONFIG_SMP 30#ifdef CONFIG_SMP
26 31
32/* print IPI stats */
33void show_ipi_stats(struct seq_file *p, int prec);
34
27/* SMP initialization hook for setup_arch */ 35/* SMP initialization hook for setup_arch */
28void __init setup_smp(void); 36void __init setup_smp(void);
29 37
@@ -33,14 +41,31 @@ void arch_send_call_function_ipi_mask(struct cpumask *mask);
33/* Hook for the generic smp_call_function_single() routine. */ 41/* Hook for the generic smp_call_function_single() routine. */
34void arch_send_call_function_single_ipi(int cpu); 42void arch_send_call_function_single_ipi(int cpu);
35 43
44int riscv_hartid_to_cpuid(int hartid);
45void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
46
36/* 47/*
37 * This is particularly ugly: it appears we can't actually get the definition 48 * Obtains the hart ID of the currently executing task. This relies on
38 * of task_struct here, but we need access to the CPU this task is running on. 49 * THREAD_INFO_IN_TASK, but we define that unconditionally.
39 * Instead of using C we're using asm-offsets.h to get the current processor
40 * ID.
41 */ 50 */
42#define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU))) 51#define raw_smp_processor_id() (current_thread_info()->cpu)
43 52
44#endif /* CONFIG_SMP */ 53#else
54
55static inline void show_ipi_stats(struct seq_file *p, int prec)
56{
57}
45 58
59static inline int riscv_hartid_to_cpuid(int hartid)
60{
61 return 0;
62}
63
64static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
65 struct cpumask *out)
66{
67 cpumask_set_cpu(cpuid_to_hartid_map(0), out);
68}
69
70#endif /* CONFIG_SMP */
46#endif /* _ASM_RISCV_SMP_H */ 71#endif /* _ASM_RISCV_SMP_H */
diff --git a/arch/riscv/include/asm/tlbflush.h b/arch/riscv/include/asm/tlbflush.h
index 85c2d8bae957..54fee0cadb1e 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -16,6 +16,7 @@
16#define _ASM_RISCV_TLBFLUSH_H 16#define _ASM_RISCV_TLBFLUSH_H
17 17
18#include <linux/mm_types.h> 18#include <linux/mm_types.h>
19#include <asm/smp.h>
19 20
20/* 21/*
21 * Flush entire local TLB. 'sfence.vma' implicitly fences with the instruction 22 * Flush entire local TLB. 'sfence.vma' implicitly fences with the instruction
@@ -49,13 +50,22 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
49 50
50#include <asm/sbi.h> 51#include <asm/sbi.h>
51 52
53static inline void remote_sfence_vma(struct cpumask *cmask, unsigned long start,
54 unsigned long size)
55{
56 struct cpumask hmask;
57
58 cpumask_clear(&hmask);
59 riscv_cpuid_to_hartid_mask(cmask, &hmask);
60 sbi_remote_sfence_vma(hmask.bits, start, size);
61}
62
52#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1) 63#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1)
53#define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0) 64#define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0)
54#define flush_tlb_range(vma, start, end) \ 65#define flush_tlb_range(vma, start, end) \
55 sbi_remote_sfence_vma(mm_cpumask((vma)->vm_mm)->bits, \ 66 remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start))
56 start, (end) - (start))
57#define flush_tlb_mm(mm) \ 67#define flush_tlb_mm(mm) \
58 sbi_remote_sfence_vma(mm_cpumask(mm)->bits, 0, -1) 68 remote_sfence_vma(mm_cpumask(mm), 0, -1)
59 69
60#endif /* CONFIG_SMP */ 70#endif /* CONFIG_SMP */
61 71
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index ca6c81e54e37..3a5a2ee31547 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -14,9 +14,13 @@
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/seq_file.h> 15#include <linux/seq_file.h>
16#include <linux/of.h> 16#include <linux/of.h>
17#include <asm/smp.h>
17 18
18/* Return -1 if not a valid hart */ 19/*
19int riscv_of_processor_hart(struct device_node *node) 20 * Returns the hart ID of the given device tree node, or -1 if the device tree
21 * node isn't a RISC-V hart.
22 */
23int riscv_of_processor_hartid(struct device_node *node)
20{ 24{
21 const char *isa, *status; 25 const char *isa, *status;
22 u32 hart; 26 u32 hart;
@@ -58,6 +62,64 @@ int riscv_of_processor_hart(struct device_node *node)
58 62
59#ifdef CONFIG_PROC_FS 63#ifdef CONFIG_PROC_FS
60 64
65static void print_isa(struct seq_file *f, const char *orig_isa)
66{
67 static const char *ext = "mafdc";
68 const char *isa = orig_isa;
69 const char *e;
70
71 /*
72 * Linux doesn't support rv32e or rv128i, and we only support booting
73 * kernels on harts with the same ISA that the kernel is compiled for.
74 */
75#if defined(CONFIG_32BIT)
76 if (strncmp(isa, "rv32i", 5) != 0)
77 return;
78#elif defined(CONFIG_64BIT)
79 if (strncmp(isa, "rv64i", 5) != 0)
80 return;
81#endif
82
83 /* Print the base ISA, as we already know it's legal. */
84 seq_puts(f, "isa\t\t: ");
85 seq_write(f, isa, 5);
86 isa += 5;
87
88 /*
89 * Check the rest of the ISA string for valid extensions, printing those
90 * we find. RISC-V ISA strings define an order, so we only print the
91 * extension bits when they're in order.
92 */
93 for (e = ext; *e != '\0'; ++e) {
94 if (isa[0] == e[0]) {
95 seq_write(f, isa, 1);
96 isa++;
97 }
98 }