Message ID | 20241227135832.188256-1-arikalo@gmail.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [v2] riscv: Fix the PAUSE Opcode for MIPS P8700. | expand |
On Fri, Dec 27, 2024 at 02:58:32PM +0100, Aleksandar Rikalo wrote: > From: Djordje Todorovic <djordje.todorovic@htecgroup.com> > > The riscv MIPS P8700 uses a different opcode for PAUSE. > It is a ‘hint’ encoding of the SLLI instruction, with rd=0, rs1=0 and > imm=5. It will behave as a NOP instruction if no additional behavior > beyond that of SLLI is implemented. > > Add ERRATA_MIPS and ERRATA_MIPS_P8700_PAUSE_OPCODE configs. > Handle errata for MIPS CPUs. > > Signed-off-by: Djordje Todorovic <djordje.todorovic@htecgroup.com> > Signed-off-by: Aleksandar Rikalo <arikalo@gmail.com> > Signed-off-by: Raj Vishwanathan4 <rvishwanathan@mips.com> > --- > arch/riscv/Kconfig.errata | 22 +++++++++++++++++ > arch/riscv/errata/Makefile | 1 + > arch/riscv/errata/mips/Makefile | 5 ++++ > arch/riscv/errata/mips/errata.c | 33 ++++++++++++++++++++++++++ > arch/riscv/include/asm/alternative.h | 3 +++ > arch/riscv/include/asm/vendorid_list.h | 1 + > arch/riscv/kernel/alternative.c | 5 ++++ > 7 files changed, 70 insertions(+) > create mode 100644 arch/riscv/errata/mips/Makefile > create mode 100644 arch/riscv/errata/mips/errata.c > > diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata > index 2acc7d876e1f..99c75fece8b9 100644 > --- a/arch/riscv/Kconfig.errata > +++ b/arch/riscv/Kconfig.errata > @@ -21,6 +21,28 @@ config ERRATA_ANDES_CMO > > If you don't know what to do here, say "Y". > > +config ERRATA_MIPS > + bool "MIPS errata" > + depends on RISCV_ALTERNATIVE > + help > + All MIPS errata Kconfig depend on this Kconfig. Disabling > + this Kconfig will disable all MIPS errata. Please say "Y" > + here if your platform uses MIPS CPU cores. > + > + Otherwise, please say "N" here to avoid unnecessary overhead. > + > +config ERRATA_MIPS_P8700_PAUSE_OPCODE > + bool "Fix the PAUSE Opcode for MIPS P8700" > + depends on ERRATA_MIPS && 64BIT > + help > + The RISCV MIPS P8700 uses a different opcode for PAUSE. > + It is a 'hint' encoding of the SLLI instruction, > + with rd=0, rs1=0 and imm=5. It will behave as a NOP > + instruction if no additional behavior beyond that of > + SLLI is implemented. > + > + If you are not using the P8700 processor, say N. > + > config ERRATA_SIFIVE > bool "SiFive errata" > depends on RISCV_ALTERNATIVE > diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile > index f0da9d7b39c3..156cafb338c1 100644 > --- a/arch/riscv/errata/Makefile > +++ b/arch/riscv/errata/Makefile > @@ -9,5 +9,6 @@ endif > endif > > obj-$(CONFIG_ERRATA_ANDES) += andes/ > +obj-$(CONFIG_ERRATA_MIPS) += mips/ > obj-$(CONFIG_ERRATA_SIFIVE) += sifive/ > obj-$(CONFIG_ERRATA_THEAD) += thead/ > diff --git a/arch/riscv/errata/mips/Makefile b/arch/riscv/errata/mips/Makefile > new file mode 100644 > index 000000000000..6278c389b801 > --- /dev/null > +++ b/arch/riscv/errata/mips/Makefile > @@ -0,0 +1,5 @@ > +ifdef CONFIG_RISCV_ALTERNATIVE_EARLY > +CFLAGS_errata.o := -mcmodel=medany > +endif > + > +obj-y += errata.o > diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c > new file mode 100644 > index 000000000000..7affc590ded5 > --- /dev/null > +++ b/arch/riscv/errata/mips/errata.c > @@ -0,0 +1,33 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Copyright (C) 2024 MIPS. > + */ > + > +#include <linux/memory.h> > +#include <linux/module.h> > + > +#include <asm/alternative.h> > +#include <asm/cacheflush.h> > +#include <asm/errata_list.h> > +#include <asm/text-patching.h> > +#include <asm/processor.h> > +#include <asm/sbi.h> > +#include <asm/vendorid_list.h> > +#include <asm/vendor_extensions.h> > + > +void __init_or_module mips_errata_patch_func(struct alt_entry *begin, > + struct alt_entry *end, > + unsigned long archid, > + unsigned long impid, > + unsigned int stage) > +{ > + if (!IS_ENABLED(CONFIG_ERRATA_MIPS)) > + return; > + > + if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE)) > + return; > + > + asm volatile(ALTERNATIVE(".4byte 0x1000000f", ".4byte 0x00501013", > + MIPS_VENDOR_ID, 0, /* patch_id */ > + CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE)); I dont think his isn't quite what you are looking for. This will end up emitting a pause instruction when this patch function is called, instead of replacing all pause instructions with this custom encoding. What you want to do here is similar to what is done in arch/riscv/include/asm/errata_list.h. A good example of this is: #define ALT_SFENCE_VMA_ASID(asid) \ asm(ALTERNATIVE("sfence.vma x0, %0", "sfence.vma", SIFIVE_VENDOR_ID, \ ERRATA_SIFIVE_CIP_1200, CONFIG_ERRATA_SIFIVE_CIP_1200) \ : : "r" (asid) : "memory") This macro is then used everywhere "sfence.vma" would normally be used. Then in sifive_errata_patch_func() in arch/riscv/errata/sifive/errata.c iterates through all alternatives, looking for any alternatives that match SIFIVE_VENDOR_ID and then perform the replacement. There seem to be three places where the pause instruction is used: - cpu_relax() in arch/riscv/include/asm/vdso/processor.h - __cmpwait() in arch/riscv/include/asm/cmpxchg.h This one is a different because it is in tools. - cpu_relax() in tools/arch/riscv/include/asm/vdso/processor.h tools is userspace code, so alternatives are not supported. Patching the pause instruction here will require a call to hwprobe. I am hesitant about this though because that would cause all microarchitectures to incur the cost of calling hwprobe, not just ones produced by MIPS. I would prefer for that to not be the default, kconfig doesn't extend to tools so some environment variable could be set for it. I am not sure what kind of precedent we want to set for this. Also, Palmer is expected to merge in my vendor-specific hwprobe framework this merge window that is included in [1]. Link https://lore.kernel.org/linux-riscv/20241113-xtheadvector-v11-0-236c22791ef9@rivosinc.com/ [1] > +} > diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h > index 3c2b59b25017..bc3ada8190a9 100644 > --- a/arch/riscv/include/asm/alternative.h > +++ b/arch/riscv/include/asm/alternative.h > @@ -48,6 +48,9 @@ struct alt_entry { > void andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, > unsigned long archid, unsigned long impid, > unsigned int stage); > +void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, > + unsigned long archid, unsigned long impid, > + unsigned int stage); > void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, > unsigned long archid, unsigned long impid, > unsigned int stage); > diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h > index 2f2bb0c84f9a..55d979a7a7c2 100644 > --- a/arch/riscv/include/asm/vendorid_list.h > +++ b/arch/riscv/include/asm/vendorid_list.h > @@ -8,5 +8,6 @@ > #define ANDES_VENDOR_ID 0x31e > #define SIFIVE_VENDOR_ID 0x489 > #define THEAD_VENDOR_ID 0x5b7 > +#define MIPS_VENDOR_ID 0x127 > > #endif > diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c > index 7eb3cb1215c6..7642704c7f18 100644 > --- a/arch/riscv/kernel/alternative.c > +++ b/arch/riscv/kernel/alternative.c > @@ -47,6 +47,11 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info > cpu_mfr_info->patch_func = andes_errata_patch_func; > break; > #endif > +#ifdef CONFIG_ERRATA_MIPS > + case MIPS_VENDOR_ID: > + cpu_mfr_info->patch_func = mips_errata_patch_func; > + break; > +#endif > #ifdef CONFIG_ERRATA_SIFIVE > case SIFIVE_VENDOR_ID: > cpu_mfr_info->patch_func = sifive_errata_patch_func; > -- > 2.25.1 > > > _______________________________________________ > linux-riscv mailing list > linux-riscv@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-riscv
diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata index 2acc7d876e1f..99c75fece8b9 100644 --- a/arch/riscv/Kconfig.errata +++ b/arch/riscv/Kconfig.errata @@ -21,6 +21,28 @@ config ERRATA_ANDES_CMO If you don't know what to do here, say "Y". +config ERRATA_MIPS + bool "MIPS errata" + depends on RISCV_ALTERNATIVE + help + All MIPS errata Kconfig depend on this Kconfig. Disabling + this Kconfig will disable all MIPS errata. Please say "Y" + here if your platform uses MIPS CPU cores. + + Otherwise, please say "N" here to avoid unnecessary overhead. + +config ERRATA_MIPS_P8700_PAUSE_OPCODE + bool "Fix the PAUSE Opcode for MIPS P8700" + depends on ERRATA_MIPS && 64BIT + help + The RISCV MIPS P8700 uses a different opcode for PAUSE. + It is a 'hint' encoding of the SLLI instruction, + with rd=0, rs1=0 and imm=5. It will behave as a NOP + instruction if no additional behavior beyond that of + SLLI is implemented. + + If you are not using the P8700 processor, say N. + config ERRATA_SIFIVE bool "SiFive errata" depends on RISCV_ALTERNATIVE diff --git a/arch/riscv/errata/Makefile b/arch/riscv/errata/Makefile index f0da9d7b39c3..156cafb338c1 100644 --- a/arch/riscv/errata/Makefile +++ b/arch/riscv/errata/Makefile @@ -9,5 +9,6 @@ endif endif obj-$(CONFIG_ERRATA_ANDES) += andes/ +obj-$(CONFIG_ERRATA_MIPS) += mips/ obj-$(CONFIG_ERRATA_SIFIVE) += sifive/ obj-$(CONFIG_ERRATA_THEAD) += thead/ diff --git a/arch/riscv/errata/mips/Makefile b/arch/riscv/errata/mips/Makefile new file mode 100644 index 000000000000..6278c389b801 --- /dev/null +++ b/arch/riscv/errata/mips/Makefile @@ -0,0 +1,5 @@ +ifdef CONFIG_RISCV_ALTERNATIVE_EARLY +CFLAGS_errata.o := -mcmodel=medany +endif + +obj-y += errata.o diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c new file mode 100644 index 000000000000..7affc590ded5 --- /dev/null +++ b/arch/riscv/errata/mips/errata.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024 MIPS. + */ + +#include <linux/memory.h> +#include <linux/module.h> + +#include <asm/alternative.h> +#include <asm/cacheflush.h> +#include <asm/errata_list.h> +#include <asm/text-patching.h> +#include <asm/processor.h> +#include <asm/sbi.h> +#include <asm/vendorid_list.h> +#include <asm/vendor_extensions.h> + +void __init_or_module mips_errata_patch_func(struct alt_entry *begin, + struct alt_entry *end, + unsigned long archid, + unsigned long impid, + unsigned int stage) +{ + if (!IS_ENABLED(CONFIG_ERRATA_MIPS)) + return; + + if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE)) + return; + + asm volatile(ALTERNATIVE(".4byte 0x1000000f", ".4byte 0x00501013", + MIPS_VENDOR_ID, 0, /* patch_id */ + CONFIG_ERRATA_MIPS_P8700_PAUSE_OPCODE)); +} diff --git a/arch/riscv/include/asm/alternative.h b/arch/riscv/include/asm/alternative.h index 3c2b59b25017..bc3ada8190a9 100644 --- a/arch/riscv/include/asm/alternative.h +++ b/arch/riscv/include/asm/alternative.h @@ -48,6 +48,9 @@ struct alt_entry { void andes_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, unsigned long archid, unsigned long impid, unsigned int stage); +void mips_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, + unsigned long archid, unsigned long impid, + unsigned int stage); void sifive_errata_patch_func(struct alt_entry *begin, struct alt_entry *end, unsigned long archid, unsigned long impid, unsigned int stage); diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h index 2f2bb0c84f9a..55d979a7a7c2 100644 --- a/arch/riscv/include/asm/vendorid_list.h +++ b/arch/riscv/include/asm/vendorid_list.h @@ -8,5 +8,6 @@ #define ANDES_VENDOR_ID 0x31e #define SIFIVE_VENDOR_ID 0x489 #define THEAD_VENDOR_ID 0x5b7 +#define MIPS_VENDOR_ID 0x127 #endif diff --git a/arch/riscv/kernel/alternative.c b/arch/riscv/kernel/alternative.c index 7eb3cb1215c6..7642704c7f18 100644 --- a/arch/riscv/kernel/alternative.c +++ b/arch/riscv/kernel/alternative.c @@ -47,6 +47,11 @@ static void riscv_fill_cpu_mfr_info(struct cpu_manufacturer_info_t *cpu_mfr_info cpu_mfr_info->patch_func = andes_errata_patch_func; break; #endif +#ifdef CONFIG_ERRATA_MIPS + case MIPS_VENDOR_ID: + cpu_mfr_info->patch_func = mips_errata_patch_func; + break; +#endif #ifdef CONFIG_ERRATA_SIFIVE case SIFIVE_VENDOR_ID: cpu_mfr_info->patch_func = sifive_errata_patch_func;