diff options
| -rw-r--r-- | arch/riscv/Kconfig | 1 | ||||
| -rw-r--r-- | arch/riscv/include/asm/alternative.h | 2 | ||||
| -rw-r--r-- | arch/riscv/include/asm/cpufeature.h | 2 | ||||
| -rw-r--r-- | arch/riscv/include/asm/hwcap.h | 2 | ||||
| -rw-r--r-- | arch/riscv/include/asm/pgtable-64.h | 12 | ||||
| -rw-r--r-- | arch/riscv/kernel/alternative.c | 24 | ||||
| -rw-r--r-- | arch/riscv/kernel/cpufeature.c | 62 | ||||
| -rw-r--r-- | arch/riscv/mm/init.c | 9 |
8 files changed, 98 insertions, 16 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 6d4b8dae6f20..67e72bf4f91a 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -218,6 +218,7 @@ config RISCV select PCI_ECAM if (ACPI && PCI) select PCI_MSI if PCI select RELOCATABLE if !MMU && !PHYS_RAM_BASE_FIXED + select RISCV_ALTERNATIVE_EARLY if 64BIT select RISCV_APLIC select RISCV_IMSIC select RISCV_INTC diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h index 688c7d1a9ae3..6be7b2b6ade9 100644 --- a/arch/riscv/include/asm/alternative.h +++ b/arch/riscv/include/asm/alternative.h @@ -33,7 +33,7 @@ void __init apply_early_boot_alternatives(void); void apply_module_alternatives(void *start, size_t length); void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len, - int patch_offset); + int patch_offset, bool early); struct alt_entry { s32 old_offset; /* offset relative to original instruction or data */ diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index 25c5da5120b5..99799cc6c198 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -36,6 +36,8 @@ extern const struct seq_operations cpuinfo_op; /* Per-cpu ISA extensions. */ extern struct riscv_isainfo hart_isa[NR_CPUS]; +extern DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX); + extern u32 thead_vlenb_of; void __init riscv_user_isa_enable(void); diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index b103aaeafa47..b5952db9259f 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -124,6 +124,8 @@ #define RISCV_ISA_EXT_ZICCIF 114 #define RISCV_ISA_EXT_ZA64RS 115 #define RISCV_ISA_EXT_ZIC64B 116 +#define RISCV_ISA_EXT_SV48 117 +#define RISCV_ISA_EXT_SV57 118 #define RISCV_ISA_EXT_XLINUXENVCFG 127 diff --git a/arch/riscv/include/asm/pgtable-64.h b/arch/riscv/include/asm/pgtable-64.h index 72b8c63469fa..7407e36fbf7d 100644 --- a/arch/riscv/include/asm/pgtable-64.h +++ b/arch/riscv/include/asm/pgtable-64.h @@ -13,6 +13,7 @@ extern bool _pgtable_l4_enabled; extern bool _pgtable_l5_enabled; +#ifdef USE_EARLY_PGTABLE_LEVELS static __always_inline bool pgtable_l5_enabled(void) { return _pgtable_l5_enabled; @@ -22,6 +23,17 @@ static __always_inline bool pgtable_l4_enabled(void) { return _pgtable_l4_enabled; } +#else +static __always_inline bool pgtable_l5_enabled(void) +{ + return riscv_has_extension_likely(RISCV_ISA_EXT_SV57); +} + +static __always_inline bool pgtable_l4_enabled(void) +{ + return riscv_has_extension_likely(RISCV_ISA_EXT_SV48); +} +#endif #define PGDIR_SHIFT_L3 30 #define PGDIR_SHIFT_L4 39 diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c index c0c9306022c5..bbb215349452 100644 --- a/arch/riscv/kernel/alternative.c +++ b/arch/riscv/kernel/alternative.c @@ -75,7 +75,8 @@ static u32 riscv_instruction_at(void *p) } static void riscv_alternative_fix_auipc_jalr(void *ptr, u32 auipc_insn, - u32 jalr_insn, int patch_offset) + u32 jalr_insn, int patch_offset, + bool early) { u32 call[2] = { auipc_insn, jalr_insn }; s32 imm; @@ -88,10 +89,15 @@ static void riscv_alternative_fix_auipc_jalr(void *ptr, u32 auipc_insn, riscv_insn_insert_utype_itype_imm(&call[0], &call[1], imm); /* patch the call place again */ - patch_text_nosync(ptr, call, sizeof(u32) * 2); + if (early) { + memcpy(ptr, call, sizeof(call)); + } else { + patch_text_nosync(ptr, call, sizeof(call)); + } } -static void riscv_alternative_fix_jal(void *ptr, u32 jal_insn, int patch_offset) +static void riscv_alternative_fix_jal(void *ptr, u32 jal_insn, int patch_offset, + bool early) { s32 imm; @@ -103,11 +109,14 @@ static void riscv_alternative_fix_jal(void *ptr, u32 jal_insn, int patch_offset) riscv_insn_insert_jtype_imm(&jal_insn, imm); /* patch the call place again */ - patch_text_nosync(ptr, &jal_insn, sizeof(u32)); + if (early) + memcpy(ptr, &jal_insn, sizeof(u32)); + else + patch_text_nosync(ptr, &jal_insn, sizeof(u32)); } void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len, - int patch_offset) + int patch_offset, bool early) { int num_insn = len / sizeof(u32); int i; @@ -131,7 +140,8 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len, continue; riscv_alternative_fix_auipc_jalr(alt_ptr + i * sizeof(u32), - insn, insn2, patch_offset); + insn, insn2, patch_offset, + early); i++; } @@ -144,7 +154,7 @@ void riscv_alternative_fix_offsets(void *alt_ptr, unsigned int len, continue; riscv_alternative_fix_jal(alt_ptr + i * sizeof(u32), - insn, patch_offset); + insn, patch_offset, early); } } } diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 263597b08968..72bce616491f 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -39,7 +39,7 @@ static bool any_cpu_has_zicbom; unsigned long elf_hwcap __read_mostly; /* Host ISA bitmap */ -static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly; +DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly; /* Per-cpu ISA extensions. */ struct riscv_isainfo hart_isa[NR_CPUS]; @@ -666,6 +666,8 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), __RISCV_ISA_EXT_DATA(svrsw60t59b, RISCV_ISA_EXT_SVRSW60T59B), __RISCV_ISA_EXT_DATA(svvptc, RISCV_ISA_EXT_SVVPTC), + __RISCV_ISA_EXT_DATA(sv48, RISCV_ISA_EXT_SV48), + __RISCV_ISA_EXT_DATA(sv57, RISCV_ISA_EXT_SV57), }; const size_t riscv_isa_ext_count = ARRAY_SIZE(riscv_isa_ext); @@ -964,6 +966,13 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) set_bit(RISCV_ISA_EXT_ZIHPM, source_isa); } +#ifndef CONFIG_32BIT + if (_pgtable_l4_enabled) + set_bit(RISCV_ISA_EXT_SV48, source_isa); + if (_pgtable_l5_enabled) + set_bit(RISCV_ISA_EXT_SV57, source_isa); +#endif + /* * "V" in ISA strings is ambiguous in practice: it should mean * just the standard V-1.0 but vendors aren't well behaved. @@ -1124,6 +1133,13 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap) riscv_isa_set_ext(ext, source_isa); } +#ifndef CONFIG_32BIT + if (_pgtable_l4_enabled) + set_bit(RISCV_ISA_EXT_SV48, source_isa); + if (_pgtable_l5_enabled) + set_bit(RISCV_ISA_EXT_SV57, source_isa); +#endif + riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap); riscv_fill_cpu_vendor_ext(cpu_node, cpu); @@ -1190,6 +1206,12 @@ void __init riscv_fill_hwcap(void) isa2hwcap[RISCV_ISA_EXT_B] = COMPAT_HWCAP_ISA_B; isa2hwcap[RISCV_ISA_EXT_V] = COMPAT_HWCAP_ISA_V; + /* + * riscv_isa may have been touched by "early" ISA parsing, so zero it + * here to get a fresh slate. + */ + bitmap_zero(riscv_isa, RISCV_ISA_EXT_MAX); + if (!acpi_disabled) { riscv_fill_hwcap_from_isa_string(isa2hwcap); } else { @@ -1305,6 +1327,17 @@ static bool riscv_cpufeature_patch_check(u16 id, u16 value) return false; } +static bool __init_or_module riscv_is_isa_ext_early_id(u16 id) +{ + switch (id) { + case RISCV_ISA_EXT_SV48: + case RISCV_ISA_EXT_SV57: + return true; + } + + return false; +} + void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end, unsigned int stage) @@ -1312,9 +1345,7 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *alt; void *oldptr, *altptr; u16 id, value, vendor; - - if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) - return; + bool early = stage == RISCV_ALTERNATIVES_EARLY_BOOT; for (alt = begin; alt < end; alt++) { id = PATCH_ID_CPUFEATURE_ID(alt->patch_id); @@ -1329,6 +1360,8 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, * vendor extension. */ if (id < RISCV_ISA_EXT_MAX) { + if (early && !riscv_is_isa_ext_early_id(id)) + continue; /* * This patch should be treated as errata so skip * processing here. @@ -1343,6 +1376,8 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, if (!riscv_cpufeature_patch_check(id, value)) continue; } else if (id >= RISCV_VENDOR_EXT_ALTERNATIVES_BASE) { + if (early) + continue; if (!__riscv_isa_vendor_extension_available(VENDOR_EXT_ALL_CPUS, vendor, id - RISCV_VENDOR_EXT_ALTERNATIVES_BASE)) continue; @@ -1354,9 +1389,20 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, oldptr = ALT_OLD_PTR(alt); altptr = ALT_ALT_PTR(alt); - mutex_lock(&text_mutex); - patch_text_nosync(oldptr, altptr, alt->alt_len); - riscv_alternative_fix_offsets(oldptr, alt->alt_len, oldptr - altptr); - mutex_unlock(&text_mutex); + if (early) { + /* oldptr is writable through the MMU-off kernel mapping. */ + memcpy(oldptr, altptr, alt->alt_len); + riscv_alternative_fix_offsets(oldptr, alt->alt_len, + oldptr - altptr, true); + } else { + mutex_lock(&text_mutex); + patch_text_nosync(oldptr, altptr, alt->alt_len); + riscv_alternative_fix_offsets(oldptr, alt->alt_len, + oldptr - altptr, false); + mutex_unlock(&text_mutex); + } } + + if (early) + local_flush_icache_all(); } diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c index 8e8352d80a90..19e8ebf95c0c 100644 --- a/arch/riscv/mm/init.c +++ b/arch/riscv/mm/init.c @@ -6,6 +6,11 @@ * Nick Kossifidis <mick@ics.forth.gr> */ +#ifdef CONFIG_64BIT +/* riscv_has_extension_likely() cannot be used this early */ +#define USE_EARLY_PGTABLE_LEVELS +#endif + #include <linux/init.h> #include <linux/mm.h> #include <linux/memblock.h> @@ -892,6 +897,10 @@ out: memset(early_p4d, 0, PAGE_SIZE); memset(early_pud, 0, PAGE_SIZE); memset(early_pmd, 0, PAGE_SIZE); + if (pgtable_l4_enabled()) + set_bit(RISCV_ISA_EXT_SV48, riscv_isa); + if (pgtable_l5_enabled()) + set_bit(RISCV_ISA_EXT_SV57, riscv_isa); } #endif |
