Skip to content

Commit d26c4bb

Browse files
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>
2 parents a6de21b + 8b20d2d commit d26c4bb

File tree

12 files changed

+259
-70
lines changed

12 files changed

+259
-70
lines changed

arch/riscv/include/asm/processor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static inline void wait_for_interrupt(void)
8888
}
8989

9090
struct device_node;
91-
extern int riscv_of_processor_hart(struct device_node *node);
91+
int riscv_of_processor_hartid(struct device_node *node);
9292

9393
extern void riscv_fill_hwcap(void);
9494

arch/riscv/include/asm/smp.h

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,24 @@
1414
#ifndef _ASM_RISCV_SMP_H
1515
#define _ASM_RISCV_SMP_H
1616

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-
2217
#include <linux/cpumask.h>
2318
#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+
*/
25+
extern unsigned long __cpuid_to_hartid_map[NR_CPUS];
26+
#define cpuid_to_hartid_map(cpu) __cpuid_to_hartid_map[cpu]
27+
28+
struct seq_file;
2429

2530
#ifdef CONFIG_SMP
2631

32+
/* print IPI stats */
33+
void show_ipi_stats(struct seq_file *p, int prec);
34+
2735
/* SMP initialization hook for setup_arch */
2836
void __init setup_smp(void);
2937

@@ -33,14 +41,31 @@ void arch_send_call_function_ipi_mask(struct cpumask *mask);
3341
/* Hook for the generic smp_call_function_single() routine. */
3442
void arch_send_call_function_single_ipi(int cpu);
3543

44+
int riscv_hartid_to_cpuid(int hartid);
45+
void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);
46+
3647
/*
37-
* This is particularly ugly: it appears we can't actually get the definition
38-
* of task_struct here, but we need access to the CPU this task is running on.
39-
* Instead of using C we're using asm-offsets.h to get the current processor
40-
* ID.
48+
* Obtains the hart ID of the currently executing task. This relies on
49+
* THREAD_INFO_IN_TASK, but we define that unconditionally.
4150
*/
42-
#define raw_smp_processor_id() (*((int*)((char*)get_current() + TASK_TI_CPU)))
51+
#define raw_smp_processor_id() (current_thread_info()->cpu)
4352

44-
#endif /* CONFIG_SMP */
53+
#else
54+
55+
static inline void show_ipi_stats(struct seq_file *p, int prec)
56+
{
57+
}
4558

59+
static inline int riscv_hartid_to_cpuid(int hartid)
60+
{
61+
return 0;
62+
}
63+
64+
static 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 */
4671
#endif /* _ASM_RISCV_SMP_H */

arch/riscv/include/asm/tlbflush.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define _ASM_RISCV_TLBFLUSH_H
1717

1818
#include <linux/mm_types.h>
19+
#include <asm/smp.h>
1920

2021
/*
2122
* 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,
4950

5051
#include <asm/sbi.h>
5152

53+
static 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+
5263
#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1)
5364
#define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0)
5465
#define flush_tlb_range(vma, start, end) \
55-
sbi_remote_sfence_vma(mm_cpumask((vma)->vm_mm)->bits, \
56-
start, (end) - (start))
66+
remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start))
5767
#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)
5969

6070
#endif /* CONFIG_SMP */
6171

arch/riscv/kernel/cpu.c

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414
#include <linux/init.h>
1515
#include <linux/seq_file.h>
1616
#include <linux/of.h>
17+
#include <asm/smp.h>
1718

18-
/* Return -1 if not a valid hart */
19-
int riscv_of_processor_hart(struct device_node *node)
19+
/*
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+
*/
23+
int riscv_of_processor_hartid(struct device_node *node)
2024
{
2125
const char *isa, *status;
2226
u32 hart;
@@ -58,6 +62,64 @@ int riscv_of_processor_hart(struct device_node *node)
5862

5963
#ifdef CONFIG_PROC_FS
6064

65+
static 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+
}
99+
seq_puts(f, "\n");
100+
101+
/*
102+
* If we were given an unsupported ISA in the device tree then print
103+
* a bit of info describing what went wrong.
104+
*/
105+
if (isa[0] != '\0')
106+
pr_info("unsupported ISA \"%s\" in device tree", orig_isa);
107+
}
108+
109+
static void print_mmu(struct seq_file *f, const char *mmu_type)
110+
{
111+
#if defined(CONFIG_32BIT)
112+
if (strcmp(mmu_type, "riscv,sv32") != 0)
113+
return;
114+
#elif defined(CONFIG_64BIT)
115+
if (strcmp(mmu_type, "riscv,sv39") != 0 &&
116+
strcmp(mmu_type, "riscv,sv48") != 0)
117+
return;
118+
#endif
119+
120+
seq_printf(f, "mmu\t\t: %s\n", mmu_type+6);
121+
}
122+
61123
static void *c_start(struct seq_file *m, loff_t *pos)
62124
{
63125
*pos = cpumask_next(*pos - 1, cpu_online_mask);
@@ -78,21 +140,20 @@ static void c_stop(struct seq_file *m, void *v)
78140

79141
static int c_show(struct seq_file *m, void *v)
80142
{
81-
unsigned long hart_id = (unsigned long)v - 1;
82-
struct device_node *node = of_get_cpu_node(hart_id, NULL);
143+
unsigned long cpu_id = (unsigned long)v - 1;
144+
struct device_node *node = of_get_cpu_node(cpuid_to_hartid_map(cpu_id),
145+
NULL);
83146
const char *compat, *isa, *mmu;
84147

85-
seq_printf(m, "hart\t: %lu\n", hart_id);
86-
if (!of_property_read_string(node, "riscv,isa", &isa)
87-
&& isa[0] == 'r'
88-
&& isa[1] == 'v')
89-
seq_printf(m, "isa\t: %s\n", isa);
90-
if (!of_property_read_string(node, "mmu-type", &mmu)
91-
&& !strncmp(mmu, "riscv,", 6))
92-
seq_printf(m, "mmu\t: %s\n", mmu+6);
148+
seq_printf(m, "processor\t: %lu\n", cpu_id);
149+
seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
150+
if (!of_property_read_string(node, "riscv,isa", &isa))
151+
print_isa(m, isa);
152+
if (!of_property_read_string(node, "mmu-type", &mmu))
153+
print_mmu(m, mmu);
93154
if (!of_property_read_string(node, "compatible", &compat)
94155
&& strcmp(compat, "riscv"))
95-
seq_printf(m, "uarch\t: %s\n", compat);
156+
seq_printf(m, "uarch\t\t: %s\n", compat);
96157
seq_puts(m, "\n");
97158

98159
return 0;

arch/riscv/kernel/entry.S

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ ENTRY(handle_exception)
168168

169169
/* Handle interrupts */
170170
move a0, sp /* pt_regs */
171-
move a1, s4 /* scause */
172171
tail do_IRQ
173172
1:
174173
/* Exceptions run with interrupts enabled */

arch/riscv/kernel/head.S

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ ENTRY(_start)
4747
/* Save hart ID and DTB physical address */
4848
mv s0, a0
4949
mv s1, a1
50+
la a2, boot_cpu_hartid
51+
REG_S a0, (a2)
5052

5153
/* Initialize page tables and relocate to virtual addresses */
5254
la sp, init_thread_union + THREAD_SIZE
@@ -55,7 +57,7 @@ ENTRY(_start)
5557

5658
/* Restore C environment */
5759
la tp, init_task
58-
sw s0, TASK_TI_CPU(tp)
60+
sw zero, TASK_TI_CPU(tp)
5961

6062
la sp, init_thread_union
6163
li a0, ASM_THREAD_SIZE

arch/riscv/kernel/irq.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <linux/interrupt.h>
99
#include <linux/irqchip.h>
1010
#include <linux/irqdomain.h>
11+
#include <linux/seq_file.h>
12+
#include <asm/smp.h>
1113

1214
/*
1315
* Possible interrupt causes:
@@ -24,12 +26,18 @@
2426
*/
2527
#define INTERRUPT_CAUSE_FLAG (1UL << (__riscv_xlen - 1))
2628

27-
asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs, unsigned long cause)
29+
int arch_show_interrupts(struct seq_file *p, int prec)
30+
{
31+
show_ipi_stats(p, prec);
32+
return 0;
33+
}
34+
35+
asmlinkage void __irq_entry do_IRQ(struct pt_regs *regs)
2836
{
2937
struct pt_regs *old_regs = set_irq_regs(regs);
3038

3139
irq_enter();
32-
switch (cause & ~INTERRUPT_CAUSE_FLAG) {
40+
switch (regs->scause & ~INTERRUPT_CAUSE_FLAG) {
3341
case INTERRUPT_CAUSE_TIMER:
3442
riscv_timer_interrupt();
3543
break;

arch/riscv/kernel/setup.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,16 @@ EXPORT_SYMBOL(empty_zero_page);
8181

8282
/* The lucky hart to first increment this variable will boot the other cores */
8383
atomic_t hart_lottery;
84+
unsigned long boot_cpu_hartid;
85+
86+
unsigned long __cpuid_to_hartid_map[NR_CPUS] = {
87+
[0 ... NR_CPUS-1] = INVALID_HARTID
88+
};
89+
90+
void __init smp_setup_processor_id(void)
91+
{
92+
cpuid_to_hartid_map(0) = boot_cpu_hartid;
93+
}
8494

8595
#ifdef CONFIG_BLK_DEV_INITRD
8696
static void __init setup_initrd(void)

0 commit comments

Comments
 (0)