Skip to content

Commit ff689fd

Browse files
mmindpalmer-dabbelt
authored andcommitted
riscv: add RISC-V Svpbmt extension support
Svpbmt (the S should be capitalized) is the "Supervisor-mode: page-based memory types" extension that specifies attributes for cacheability, idempotency and ordering. The relevant settings are done in special bits in PTEs: Here is the svpbmt PTE format: | 63 | 62-61 | 60-8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 N MT RSW D A G U X W R V ^ Of the Reserved bits [63:54] in a leaf PTE, the high bit is already allocated (as the N bit), so bits [62:61] are used as the MT (aka MemType) field. This field specifies one of three memory types that are close equivalents (or equivalent in effect) to the three main x86 and ARMv8 memory types - as shown in the following table. RISC-V Encoding & MemType RISC-V Description ---------- ------------------------------------------------ 00 - PMA Normal Cacheable, No change to implied PMA memory type 01 - NC Non-cacheable, idempotent, weakly-ordered Main Memory 10 - IO Non-cacheable, non-idempotent, strongly-ordered I/O memory 11 - Rsvd Reserved for future standard use As the extension will not be present on all implementations, implement a method to handle cpufeatures via alternatives to not incur runtime penalties on cpu variants not supporting specific extensions and patch relevant code parts at runtime. Co-developed-by: Wei Fu <wefu@redhat.com> Signed-off-by: Wei Fu <wefu@redhat.com> Co-developed-by: Liu Shaohua <liush@allwinnertech.com> Signed-off-by: Liu Shaohua <liush@allwinnertech.com> Co-developed-by: Guo Ren <guoren@kernel.org> Signed-off-by: Guo Ren <guoren@kernel.org> [moved to use the alternatives mechanism] Signed-off-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Philipp Tomsich <philipp.tomsich@vrull.eu> Link: https://lore.kernel.org/r/20220511192921.2223629-10-heiko@sntech.de Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
1 parent 100631b commit ff689fd

File tree

11 files changed

+189
-10
lines changed

11 files changed

+189
-10
lines changed

arch/riscv/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,19 @@ config RISCV_ISA_C
343343

344344
If you don't know what to do here, say Y.
345345

346+
config RISCV_ISA_SVPBMT
347+
bool "SVPBMT extension support"
348+
depends on 64BIT && MMU
349+
select RISCV_ALTERNATIVE
350+
default y
351+
help
352+
Adds support to dynamically detect the presence of the SVPBMT extension
353+
(Supervisor-mode: page-based memory types) and enable its usage.
354+
355+
The SVPBMT extension is only available on 64Bit cpus.
356+
357+
If you don't know what to do here, say Y.
358+
346359
config FPU
347360
bool "FPU support"
348361
default y

arch/riscv/include/asm/alternative.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
4242
unsigned long archid, unsigned long impid,
4343
unsigned int stage);
4444

45+
void riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end,
46+
unsigned int stage);
47+
4548
#else /* CONFIG_RISCV_ALTERNATIVE */
4649

4750
static inline void apply_boot_alternatives(void) { }

arch/riscv/include/asm/errata_list.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
#define ERRATA_SIFIVE_NUMBER 2
1515
#endif
1616

17+
#define CPUFEATURE_SVPBMT 0
18+
#define CPUFEATURE_NUMBER 1
19+
1720
#ifdef __ASSEMBLY__
1821

1922
#define ALT_INSN_FAULT(x) \
@@ -34,6 +37,18 @@ asm(ALTERNATIVE("sfence.vma %0", "sfence.vma", SIFIVE_VENDOR_ID, \
3437
ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \
3538
: : "r" (addr) : "memory")
3639

40+
/*
41+
* _val is marked as "will be overwritten", so need to set it to 0
42+
* in the default case.
43+
*/
44+
#define ALT_SVPBMT_SHIFT 61
45+
#define ALT_SVPBMT(_val, prot) \
46+
asm(ALTERNATIVE("li %0, 0\t\nnop", "li %0, %1\t\nslli %0,%0,%2", 0, \
47+
CPUFEATURE_SVPBMT, CONFIG_RISCV_ISA_SVPBMT) \
48+
: "=r"(_val) \
49+
: "I"(prot##_SVPBMT >> ALT_SVPBMT_SHIFT), \
50+
"I"(ALT_SVPBMT_SHIFT))
51+
3752
#endif /* __ASSEMBLY__ */
3853

3954
#endif

arch/riscv/include/asm/hwcap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ extern unsigned long elf_hwcap;
5252
*/
5353
enum riscv_isa_ext_id {
5454
RISCV_ISA_EXT_SSCOFPMF = RISCV_ISA_EXT_BASE,
55+
RISCV_ISA_EXT_SVPBMT,
5556
RISCV_ISA_EXT_ID_MAX = RISCV_ISA_EXT_MAX,
5657
};
5758

arch/riscv/include/asm/pgtable-32.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@
2424
*/
2525
#define _PAGE_PFN_MASK GENMASK(31, 10)
2626

27+
#define _PAGE_NOCACHE 0
28+
#define _PAGE_IO 0
29+
#define _PAGE_MTMASK 0
30+
31+
/* Set of bits to preserve across pte_modify() */
32+
#define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \
33+
_PAGE_WRITE | _PAGE_EXEC | \
34+
_PAGE_USER | _PAGE_GLOBAL))
35+
2736
#endif /* _ASM_RISCV_PGTABLE_32_H */

arch/riscv/include/asm/pgtable-64.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <linux/bits.h>
1010
#include <linux/const.h>
11+
#include <asm/errata_list.h>
1112

1213
extern bool pgtable_l4_enabled;
1314
extern bool pgtable_l5_enabled;
@@ -73,6 +74,52 @@ typedef struct {
7374
*/
7475
#define _PAGE_PFN_MASK GENMASK(53, 10)
7576

77+
/*
78+
* [62:61] Svpbmt Memory Type definitions:
79+
*
80+
* 00 - PMA Normal Cacheable, No change to implied PMA memory type
81+
* 01 - NC Non-cacheable, idempotent, weakly-ordered Main Memory
82+
* 10 - IO Non-cacheable, non-idempotent, strongly-ordered I/O memory
83+
* 11 - Rsvd Reserved for future standard use
84+
*/
85+
#define _PAGE_NOCACHE_SVPBMT (1UL << 61)
86+
#define _PAGE_IO_SVPBMT (1UL << 62)
87+
#define _PAGE_MTMASK_SVPBMT (_PAGE_NOCACHE_SVPBMT | _PAGE_IO_SVPBMT)
88+
89+
static inline u64 riscv_page_mtmask(void)
90+
{
91+
u64 val;
92+
93+
ALT_SVPBMT(val, _PAGE_MTMASK);
94+
return val;
95+
}
96+
97+
static inline u64 riscv_page_nocache(void)
98+
{
99+
u64 val;
100+
101+
ALT_SVPBMT(val, _PAGE_NOCACHE);
102+
return val;
103+
}
104+
105+
static inline u64 riscv_page_io(void)
106+
{
107+
u64 val;
108+
109+
ALT_SVPBMT(val, _PAGE_IO);
110+
return val;
111+
}
112+
113+
#define _PAGE_NOCACHE riscv_page_nocache()
114+
#define _PAGE_IO riscv_page_io()
115+
#define _PAGE_MTMASK riscv_page_mtmask()
116+
117+
/* Set of bits to preserve across pte_modify() */
118+
#define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \
119+
_PAGE_WRITE | _PAGE_EXEC | \
120+
_PAGE_USER | _PAGE_GLOBAL | \
121+
_PAGE_MTMASK))
122+
76123
static inline int pud_present(pud_t pud)
77124
{
78125
return (pud_val(pud) & _PAGE_PRESENT);

arch/riscv/include/asm/pgtable-bits.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@
2929

3030
#define _PAGE_PFN_SHIFT 10
3131

32-
/* Set of bits to preserve across pte_modify() */
33-
#define _PAGE_CHG_MASK (~(unsigned long)(_PAGE_PRESENT | _PAGE_READ | \
34-
_PAGE_WRITE | _PAGE_EXEC | \
35-
_PAGE_USER | _PAGE_GLOBAL))
3632
/*
3733
* when all of R/W/X are zero, the PTE is a pointer to the next level
3834
* of the page table; otherwise, it is a leaf PTE.

arch/riscv/include/asm/pgtable.h

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,8 @@ extern struct pt_alloc_ops pt_ops __initdata;
179179

180180
#define PAGE_TABLE __pgprot(_PAGE_TABLE)
181181

182-
/*
183-
* The RISC-V ISA doesn't yet specify how to query or modify PMAs, so we can't
184-
* change the properties of memory regions.
185-
*/
186-
#define _PAGE_IOREMAP _PAGE_KERNEL
182+
#define _PAGE_IOREMAP ((_PAGE_KERNEL & ~_PAGE_MTMASK) | _PAGE_IO)
183+
#define PAGE_KERNEL_IO __pgprot(_PAGE_IOREMAP)
187184

188185
extern pgd_t swapper_pg_dir[];
189186

@@ -523,6 +520,28 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
523520
return ptep_test_and_clear_young(vma, address, ptep);
524521
}
525522

523+
#define pgprot_noncached pgprot_noncached
524+
static inline pgprot_t pgprot_noncached(pgprot_t _prot)
525+
{
526+
unsigned long prot = pgprot_val(_prot);
527+
528+
prot &= ~_PAGE_MTMASK;
529+
prot |= _PAGE_IO;
530+
531+
return __pgprot(prot);
532+
}
533+
534+
#define pgprot_writecombine pgprot_writecombine
535+
static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
536+
{
537+
unsigned long prot = pgprot_val(_prot);
538+
539+
prot &= ~_PAGE_MTMASK;
540+
prot |= _PAGE_NOCACHE;
541+
542+
return __pgprot(prot);
543+
}
544+
526545
/*
527546
* THP functions
528547
*/

arch/riscv/kernel/alternative.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ static void __init_or_module _apply_alternatives(struct alt_entry *begin,
6363
struct alt_entry *end,
6464
unsigned int stage)
6565
{
66+
riscv_cpufeature_patch_func(begin, end, stage);
67+
6668
if (!vendor_patch_func)
6769
return;
6870

arch/riscv/kernel/cpu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ int riscv_of_parent_hartid(struct device_node *node)
8888
*/
8989
static struct riscv_isa_ext_data isa_ext_arr[] = {
9090
__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
91+
__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
9192
__RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX),
9293
};
9394

0 commit comments

Comments
 (0)