Skip to content

Commit c2a658d

Browse files
AndybnACTpalmer-dabbelt
authored andcommitted
riscv: lib: vectorize copy_to_user/copy_from_user
This patch utilizes Vector to perform copy_to_user/copy_from_user. If Vector is available and the size of copy is large enough for Vector to perform better than scalar, then direct the kernel to do Vector copies for userspace. Though the best programming practice for users is to reduce the copy, this provides a faster variant when copies are inevitable. The optimal size for using Vector, copy_to_user_thres, is only a heuristic for now. We can add DT parsing if people feel the need of customizing it. The exception fixup code of the __asm_vector_usercopy must fallback to the scalar one because accessing user pages might fault, and must be sleepable. Current kernel-mode Vector does not allow tasks to be preemptible, so we must disactivate Vector and perform a scalar fallback in such case. The original implementation of Vector operations comes from https://github.com/sifive/sifive-libc, which we agree to contribute to Linux kernel. Co-developed-by: Jerry Shih <[email protected]> Signed-off-by: Jerry Shih <[email protected]> Co-developed-by: Nick Knight <[email protected]> Signed-off-by: Nick Knight <[email protected]> Suggested-by: Guo Ren <[email protected]> Signed-off-by: Andy Chiu <[email protected]> Tested-by: Björn Töpel <[email protected]> Tested-by: Lad Prabhakar <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
1 parent 7df56cb commit c2a658d

File tree

6 files changed

+125
-1
lines changed

6 files changed

+125
-1
lines changed

arch/riscv/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,14 @@ config RISCV_ISA_V_DEFAULT_ENABLE
525525

526526
If you don't know what to do here, say Y.
527527

528+
config RISCV_ISA_V_UCOPY_THRESHOLD
529+
int "Threshold size for vectorized user copies"
530+
depends on RISCV_ISA_V
531+
default 768
532+
help
533+
Prefer using vectorized copy_to_user()/copy_from_user() when the
534+
workload size exceeds this value.
535+
528536
config TOOLCHAIN_HAS_ZBB
529537
bool
530538
default y

arch/riscv/include/asm/asm-prototypes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ long long __ashlti3(long long a, int b);
1111

1212
#ifdef CONFIG_RISCV_ISA_V
1313

14+
#ifdef CONFIG_MMU
15+
asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n);
16+
#endif /* CONFIG_MMU */
17+
1418
void xor_regs_2_(unsigned long bytes, unsigned long *__restrict p1,
1519
const unsigned long *__restrict p2);
1620
void xor_regs_3_(unsigned long bytes, unsigned long *__restrict p1,

arch/riscv/lib/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ lib-y += memmove.o
66
lib-y += strcmp.o
77
lib-y += strlen.o
88
lib-y += strncmp.o
9-
lib-$(CONFIG_MMU) += uaccess.o
9+
ifeq ($(CONFIG_MMU), y)
10+
lib-y += uaccess.o
11+
lib-$(CONFIG_RISCV_ISA_V) += uaccess_vector.o
12+
endif
1013
lib-$(CONFIG_64BIT) += tishift.o
1114
lib-$(CONFIG_RISCV_ISA_ZICBOZ) += clear_page.o
1215

1316
obj-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
1417
lib-$(CONFIG_RISCV_ISA_V) += xor.o
18+
lib-$(CONFIG_RISCV_ISA_V) += riscv_v_helpers.o

arch/riscv/lib/riscv_v_helpers.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Copyright (C) 2023 SiFive
4+
* Author: Andy Chiu <[email protected]>
5+
*/
6+
#include <linux/linkage.h>
7+
#include <asm/asm.h>
8+
9+
#include <asm/vector.h>
10+
#include <asm/simd.h>
11+
12+
#ifdef CONFIG_MMU
13+
#include <asm/asm-prototypes.h>
14+
#endif
15+
16+
#ifdef CONFIG_MMU
17+
size_t riscv_v_usercopy_threshold = CONFIG_RISCV_ISA_V_UCOPY_THRESHOLD;
18+
int __asm_vector_usercopy(void *dst, void *src, size_t n);
19+
int fallback_scalar_usercopy(void *dst, void *src, size_t n);
20+
asmlinkage int enter_vector_usercopy(void *dst, void *src, size_t n)
21+
{
22+
size_t remain, copied;
23+
24+
/* skip has_vector() check because it has been done by the asm */
25+
if (!may_use_simd())
26+
goto fallback;
27+
28+
kernel_vector_begin();
29+
remain = __asm_vector_usercopy(dst, src, n);
30+
kernel_vector_end();
31+
32+
if (remain) {
33+
copied = n - remain;
34+
dst += copied;
35+
src += copied;
36+
n = remain;
37+
goto fallback;
38+
}
39+
40+
return remain;
41+
42+
fallback:
43+
return fallback_scalar_usercopy(dst, src, n);
44+
}
45+
#endif

arch/riscv/lib/uaccess.S

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <asm/asm.h>
44
#include <asm/asm-extable.h>
55
#include <asm/csr.h>
6+
#include <asm/hwcap.h>
7+
#include <asm/alternative-macros.h>
68

79
.macro fixup op reg addr lbl
810
100:
@@ -11,6 +13,13 @@
1113
.endm
1214

1315
SYM_FUNC_START(__asm_copy_to_user)
16+
#ifdef CONFIG_RISCV_ISA_V
17+
ALTERNATIVE("j fallback_scalar_usercopy", "nop", 0, RISCV_ISA_EXT_v, CONFIG_RISCV_ISA_V)
18+
REG_L t0, riscv_v_usercopy_threshold
19+
bltu a2, t0, fallback_scalar_usercopy
20+
tail enter_vector_usercopy
21+
#endif
22+
SYM_FUNC_START(fallback_scalar_usercopy)
1423

1524
/* Enable access to user memory */
1625
li t6, SR_SUM
@@ -181,6 +190,7 @@ SYM_FUNC_START(__asm_copy_to_user)
181190
sub a0, t5, a0
182191
ret
183192
SYM_FUNC_END(__asm_copy_to_user)
193+
SYM_FUNC_END(fallback_scalar_usercopy)
184194
EXPORT_SYMBOL(__asm_copy_to_user)
185195
SYM_FUNC_ALIAS(__asm_copy_from_user, __asm_copy_to_user)
186196
EXPORT_SYMBOL(__asm_copy_from_user)

arch/riscv/lib/uaccess_vector.S

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
3+
#include <linux/linkage.h>
4+
#include <asm-generic/export.h>
5+
#include <asm/asm.h>
6+
#include <asm/asm-extable.h>
7+
#include <asm/csr.h>
8+
9+
#define pDst a0
10+
#define pSrc a1
11+
#define iNum a2
12+
13+
#define iVL a3
14+
15+
#define ELEM_LMUL_SETTING m8
16+
#define vData v0
17+
18+
.macro fixup op reg addr lbl
19+
100:
20+
\op \reg, \addr
21+
_asm_extable 100b, \lbl
22+
.endm
23+
24+
SYM_FUNC_START(__asm_vector_usercopy)
25+
/* Enable access to user memory */
26+
li t6, SR_SUM
27+
csrs CSR_STATUS, t6
28+
29+
loop:
30+
vsetvli iVL, iNum, e8, ELEM_LMUL_SETTING, ta, ma
31+
fixup vle8.v vData, (pSrc), 10f
32+
sub iNum, iNum, iVL
33+
add pSrc, pSrc, iVL
34+
fixup vse8.v vData, (pDst), 11f
35+
add pDst, pDst, iVL
36+
bnez iNum, loop
37+
38+
/* Exception fixup for vector load is shared with normal exit */
39+
10:
40+
/* Disable access to user memory */
41+
csrc CSR_STATUS, t6
42+
mv a0, iNum
43+
ret
44+
45+
/* Exception fixup code for vector store. */
46+
11:
47+
/* Undo the subtraction after vle8.v */
48+
add iNum, iNum, iVL
49+
/* Make sure the scalar fallback skip already processed bytes */
50+
csrr t2, CSR_VSTART
51+
sub iNum, iNum, t2
52+
j 10b
53+
SYM_FUNC_END(__asm_vector_usercopy)

0 commit comments

Comments
 (0)