aboutsummaryrefslogtreecommitdiffstats
path: root/arch/riscv/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/riscv/kernel')
-rw-r--r--arch/riscv/kernel/head.S3
-rw-r--r--arch/riscv/kernel/riscv_ksyms.c3
-rw-r--r--arch/riscv/kernel/setup.c5
-rw-r--r--arch/riscv/kernel/smp.c55
-rw-r--r--arch/riscv/kernel/sys_riscv.c33
-rw-r--r--arch/riscv/kernel/syscall_table.c2
-rw-r--r--arch/riscv/kernel/vdso/Makefile7
-rw-r--r--arch/riscv/kernel/vdso/clock_getres.S26
-rw-r--r--arch/riscv/kernel/vdso/clock_gettime.S26
-rw-r--r--arch/riscv/kernel/vdso/flush_icache.S31
-rw-r--r--arch/riscv/kernel/vdso/getcpu.S26
-rw-r--r--arch/riscv/kernel/vdso/gettimeofday.S26
-rw-r--r--arch/riscv/kernel/vdso/vdso.lds.S7
13 files changed, 243 insertions, 7 deletions
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 76af908f87c1..78f670d70133 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -152,6 +152,3 @@ END(_start)
152__PAGE_ALIGNED_BSS 152__PAGE_ALIGNED_BSS
153 /* Empty zero page */ 153 /* Empty zero page */
154 .balign PAGE_SIZE 154 .balign PAGE_SIZE
155ENTRY(empty_zero_page)
156 .fill (empty_zero_page + PAGE_SIZE) - ., 1, 0x00
157END(empty_zero_page)
diff --git a/arch/riscv/kernel/riscv_ksyms.c b/arch/riscv/kernel/riscv_ksyms.c
index 23cc81ec9e94..551734248748 100644
--- a/arch/riscv/kernel/riscv_ksyms.c
+++ b/arch/riscv/kernel/riscv_ksyms.c
@@ -12,4 +12,7 @@
12/* 12/*
13 * Assembly functions that may be used (directly or indirectly) by modules 13 * Assembly functions that may be used (directly or indirectly) by modules
14 */ 14 */
15EXPORT_SYMBOL(__clear_user);
15EXPORT_SYMBOL(__copy_user); 16EXPORT_SYMBOL(__copy_user);
17EXPORT_SYMBOL(memset);
18EXPORT_SYMBOL(memcpy);
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index de7db114c315..8fbb6749910d 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -58,7 +58,12 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
58#endif /* CONFIG_CMDLINE_BOOL */ 58#endif /* CONFIG_CMDLINE_BOOL */
59 59
60unsigned long va_pa_offset; 60unsigned long va_pa_offset;
61EXPORT_SYMBOL(va_pa_offset);
61unsigned long pfn_base; 62unsigned long pfn_base;
63EXPORT_SYMBOL(pfn_base);
64
65unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss;
66EXPORT_SYMBOL(empty_zero_page);
62 67
63/* The lucky hart to first increment this variable will boot the other cores */ 68/* The lucky hart to first increment this variable will boot the other cores */
64atomic_t hart_lottery; 69atomic_t hart_lottery;
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c
index b4a71ec5906f..6d3962435720 100644
--- a/arch/riscv/kernel/smp.c
+++ b/arch/riscv/kernel/smp.c
@@ -38,6 +38,13 @@ enum ipi_message_type {
38 IPI_MAX 38 IPI_MAX
39}; 39};
40 40
41
42/* Unsupported */
43int setup_profiling_timer(unsigned int multiplier)
44{
45 return -EINVAL;
46}
47
41irqreturn_t handle_ipi(void) 48irqreturn_t handle_ipi(void)
42{ 49{
43 unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; 50 unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
@@ -108,3 +115,51 @@ void smp_send_reschedule(int cpu)
108{ 115{
109 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); 116 send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
110} 117}
118
119/*
120 * Performs an icache flush for the given MM context. RISC-V has no direct
121 * mechanism for instruction cache shoot downs, so instead we send an IPI that
122 * informs the remote harts they need to flush their local instruction caches.
123 * To avoid pathologically slow behavior in a common case (a bunch of
124 * single-hart processes on a many-hart machine, ie 'make -j') we avoid the
125 * IPIs for harts that are not currently executing a MM context and instead
126 * schedule a deferred local instruction cache flush to be performed before
127 * execution resumes on each hart.
128 */
129void flush_icache_mm(struct mm_struct *mm, bool local)
130{
131 unsigned int cpu;
132 cpumask_t others, *mask;
133
134 preempt_disable();
135
136 /* Mark every hart's icache as needing a flush for this MM. */
137 mask = &mm->context.icache_stale_mask;
138 cpumask_setall(mask);
139 /* Flush this hart's I$ now, and mark it as flushed. */
140 cpu = smp_processor_id();
141 cpumask_clear_cpu(cpu, mask);
142 local_flush_icache_all();
143
144 /*
145 * Flush the I$ of other harts concurrently executing, and mark them as
146 * flushed.
147 */
148 cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu));
149 local |= cpumask_empty(&others);
150 if (mm != current->active_mm || !local)
151 sbi_remote_fence_i(others.bits);
152 else {
153 /*
154 * It's assumed that at least one strongly ordered operation is
155 * performed on this hart between setting a hart's cpumask bit
156 * and scheduling this MM context on that hart. Sending an SBI
157 * remote message will do this, but in the case where no
158 * messages are sent we still need to order this hart's writes
159 * with flush_icache_deferred().
160 */
161 smp_mb();
162 }
163
164 preempt_enable();
165}
diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c
index 4351be7d0533..a2ae936a093e 100644
--- a/arch/riscv/kernel/sys_riscv.c
+++ b/arch/riscv/kernel/sys_riscv.c
@@ -14,8 +14,8 @@
14 */ 14 */
15 15
16#include <linux/syscalls.h> 16#include <linux/syscalls.h>
17#include <asm/cmpxchg.h>
18#include <asm/unistd.h> 17#include <asm/unistd.h>
18#include <asm/cacheflush.h>
19 19
20static long riscv_sys_mmap(unsigned long addr, unsigned long len, 20static long riscv_sys_mmap(unsigned long addr, unsigned long len,
21 unsigned long prot, unsigned long flags, 21 unsigned long prot, unsigned long flags,
@@ -47,3 +47,34 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
47 return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); 47 return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12);
48} 48}
49#endif /* !CONFIG_64BIT */ 49#endif /* !CONFIG_64BIT */
50
51#ifdef CONFIG_SMP
52/*
53 * Allows the instruction cache to be flushed from userspace. Despite RISC-V
54 * having a direct 'fence.i' instruction available to userspace (which we
55 * can't trap!), that's not actually viable when running on Linux because the
56 * kernel might schedule a process on another hart. There is no way for
57 * userspace to handle this without invoking the kernel (as it doesn't know the
58 * thread->hart mappings), so we've defined a RISC-V specific system call to
59 * flush the instruction cache.
60 *
61 * sys_riscv_flush_icache() is defined to flush the instruction cache over an
62 * address range, with the flush applying to either all threads or just the
63 * caller. We don't currently do anything with the address range, that's just
64 * in there for forwards compatibility.
65 */
66SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end,
67 uintptr_t, flags)
68{
69 struct mm_struct *mm = current->mm;
70 bool local = (flags & SYS_RISCV_FLUSH_ICACHE_LOCAL) != 0;
71
72 /* Check the reserved flags. */
73 if (unlikely(flags & !SYS_RISCV_FLUSH_ICACHE_ALL))
74 return -EINVAL;
75
76 flush_icache_mm(mm, local);
77
78 return 0;
79}
80#endif
diff --git a/arch/riscv/kernel/syscall_table.c b/arch/riscv/kernel/syscall_table.c
index 4e30dc5fb593..a5bd6401f95e 100644
--- a/arch/riscv/kernel/syscall_table.c
+++ b/arch/riscv/kernel/syscall_table.c
@@ -15,6 +15,7 @@
15#include <linux/linkage.h> 15#include <linux/linkage.h>
16#include <linux/syscalls.h> 16#include <linux/syscalls.h>
17#include <asm-generic/syscalls.h> 17#include <asm-generic/syscalls.h>
18#include <asm/vdso.h>
18 19
19#undef __SYSCALL 20#undef __SYSCALL
20#define __SYSCALL(nr, call) [nr] = (call), 21#define __SYSCALL(nr, call) [nr] = (call),
@@ -22,4 +23,5 @@
22void *sys_call_table[__NR_syscalls] = { 23void *sys_call_table[__NR_syscalls] = {
23 [0 ... __NR_syscalls - 1] = sys_ni_syscall, 24 [0 ... __NR_syscalls - 1] = sys_ni_syscall,
24#include <asm/unistd.h> 25#include <asm/unistd.h>
26#include <asm/vdso-syscalls.h>
25}; 27};
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile
index 523d0a8ac8db..324568d33921 100644
--- a/arch/riscv/kernel/vdso/Makefile
+++ b/arch/riscv/kernel/vdso/Makefile
@@ -1,7 +1,12 @@
1# Copied from arch/tile/kernel/vdso/Makefile 1# Copied from arch/tile/kernel/vdso/Makefile
2 2
3# Symbols present in the vdso 3# Symbols present in the vdso
4vdso-syms = rt_sigreturn 4vdso-syms = rt_sigreturn
5vdso-syms += gettimeofday
6vdso-syms += clock_gettime
7vdso-syms += clock_getres
8vdso-syms += getcpu
9vdso-syms += flush_icache
5 10
6# Files to link into the vdso 11# Files to link into the vdso
7obj-vdso = $(patsubst %, %.o, $(vdso-syms)) 12obj-vdso = $(patsubst %, %.o, $(vdso-syms))
diff --git a/arch/riscv/kernel/vdso/clock_getres.S b/arch/riscv/kernel/vdso/clock_getres.S
new file mode 100644
index 000000000000..edf7e2339648
--- /dev/null
+++ b/arch/riscv/kernel/vdso/clock_getres.S
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2017 SiFive
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/linkage.h>
15#include <asm/unistd.h>
16
17 .text
18/* int __vdso_clock_getres(clockid_t clock_id, struct timespec *res); */
19ENTRY(__vdso_clock_getres)
20 .cfi_startproc
21 /* For now, just do the syscall. */
22 li a7, __NR_clock_getres
23 ecall
24 ret
25 .cfi_endproc
26ENDPROC(__vdso_clock_getres)
diff --git a/arch/riscv/kernel/vdso/clock_gettime.S b/arch/riscv/kernel/vdso/clock_gettime.S
new file mode 100644
index 000000000000..aac65676c6d5
--- /dev/null
+++ b/arch/riscv/kernel/vdso/clock_gettime.S
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2017 SiFive
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/linkage.h>
15#include <asm/unistd.h>
16
17 .text
18/* int __vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); */
19ENTRY(__vdso_clock_gettime)
20 .cfi_startproc
21 /* For now, just do the syscall. */
22 li a7, __NR_clock_gettime
23 ecall
24 ret
25 .cfi_endproc
26ENDPROC(__vdso_clock_gettime)
diff --git a/arch/riscv/kernel/vdso/flush_icache.S b/arch/riscv/kernel/vdso/flush_icache.S
new file mode 100644
index 000000000000..b0fbad74e873
--- /dev/null
+++ b/arch/riscv/kernel/vdso/flush_icache.S
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2017 SiFive
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/linkage.h>
15#include <asm/unistd.h>
16#include <asm/vdso-syscalls.h>
17
18 .text
19/* int __vdso_flush_icache(void *start, void *end, unsigned long flags); */
20ENTRY(__vdso_flush_icache)
21 .cfi_startproc
22#ifdef CONFIG_SMP
23 li a7, __NR_riscv_flush_icache
24 ecall
25#else
26 fence.i
27 li a0, 0
28#endif
29 ret
30 .cfi_endproc
31ENDPROC(__vdso_flush_icache)
diff --git a/arch/riscv/kernel/vdso/getcpu.S b/arch/riscv/kernel/vdso/getcpu.S
new file mode 100644
index 000000000000..cc7e98924484
--- /dev/null
+++ b/arch/riscv/kernel/vdso/getcpu.S
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2017 SiFive
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/linkage.h>
15#include <asm/unistd.h>
16
17 .text
18/* int __vdso_getcpu(unsigned *cpu, unsigned *node, void *unused); */
19ENTRY(__vdso_getcpu)
20 .cfi_startproc
21 /* For now, just do the syscall. */
22 li a7, __NR_getcpu
23 ecall
24 ret
25 .cfi_endproc
26ENDPROC(__vdso_getcpu)
diff --git a/arch/riscv/kernel/vdso/gettimeofday.S b/arch/riscv/kernel/vdso/gettimeofday.S
new file mode 100644
index 000000000000..da85d33e8990
--- /dev/null
+++ b/arch/riscv/kernel/vdso/gettimeofday.S
@@ -0,0 +1,26 @@
1/*
2 * Copyright (C) 2017 SiFive
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation, version 2.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/linkage.h>
15#include <asm/unistd.h>
16
17 .text
18/* int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz); */
19ENTRY(__vdso_gettimeofday)
20 .cfi_startproc
21 /* For now, just do the syscall. */
22 li a7, __NR_gettimeofday
23 ecall
24 ret
25 .cfi_endproc
26ENDPROC(__vdso_gettimeofday)
diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S
index 8c9dce95c11d..cd1d47e0724b 100644
--- a/arch/riscv/kernel/vdso/vdso.lds.S
+++ b/arch/riscv/kernel/vdso/vdso.lds.S
@@ -70,8 +70,11 @@ VERSION
70 LINUX_4.15 { 70 LINUX_4.15 {
71 global: 71 global:
72 __vdso_rt_sigreturn; 72 __vdso_rt_sigreturn;
73 __vdso_cmpxchg32; 73 __vdso_gettimeofday;
74 __vdso_cmpxchg64; 74 __vdso_clock_gettime;
75 __vdso_clock_getres;
76 __vdso_getcpu;
77 __vdso_flush_icache;
75 local: *; 78 local: *;
76 }; 79 };
77} 80}