Unverified Commit 62a31d6e authored by Evan Green's avatar Evan Green Committed by Palmer Dabbelt
Browse files

RISC-V: hwprobe: Support probing of misaligned access performance

This allows userspace to select various routines to use based on the
performance of misaligned access on the target hardware.

Rather than adding DT bindings, this change taps into the alternatives
mechanism used to probe CPU errata. Add a new function pointer alongside
the vendor-specific errata_patch_func() that probes for desirable errata
(otherwise known as "features"). Unlike the errata_patch_func(), this
function is called on each CPU as it comes up, so it can save
feature information per-CPU.

The T-head C906 has fast unaligned access, both as defined by GCC [1],
and in performing a basic benchmark, which determined that byte copies
are >50% slower than a misaligned word copy of the same data size (source
for this test at [2]):

bytecopy size f000 count 50000 offset 0 took 31664899 us
wordcopy size f000 count 50000 offset 0 took 5180919 us
wordcopy size f000 count 50000 offset 1 took 13416949 us

[1] https://github.com/gcc-mirror/gcc/blob/master/gcc/config/riscv/riscv.cc#L353
[2] https://pastebin.com/EPXvDHSW



Co-developed-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: default avatarEvan Green <evan@rivosinc.com>
Reviewed-by: default avatarHeiko Stuebner <heiko.stuebner@vrull.eu>
Tested-by: default avatarHeiko Stuebner <heiko.stuebner@vrull.eu>
Reviewed-by: default avatarConor Dooley <conor.dooley@microchip.com>
Reviewed-by: default avatarPaul Walmsley <paul.walmsley@sifive.com>
Link: https://lore.kernel.org/r/20230407231103.2622178-5-evan@rivosinc.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent 00e76e2c
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -63,3 +63,24 @@ The following keys are defined:

  * :c:macro:`RISCV_HWPROBE_IMA_C`: The C extension is supported, as defined
    by version 2.2 of the RISC-V ISA manual.

* :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance
  information about the selected set of processors.

  * :c:macro:`RISCV_HWPROBE_MISALIGNED_UNKNOWN`: The performance of misaligned
    accesses is unknown.

  * :c:macro:`RISCV_HWPROBE_MISALIGNED_EMULATED`: Misaligned accesses are
    emulated via software, either in or below the kernel.  These accesses are
    always extremely slow.

  * :c:macro:`RISCV_HWPROBE_MISALIGNED_SLOW`: Misaligned accesses are supported
    in hardware, but are slower than the cooresponding aligned accesses
    sequences.

  * :c:macro:`RISCV_HWPROBE_MISALIGNED_FAST`: Misaligned accesses are supported
    in hardware and are faster than the cooresponding aligned accesses
    sequences.

  * :c:macro:`RISCV_HWPROBE_MISALIGNED_UNSUPPORTED`: Misaligned accesses are
    not supported at all and will generate a misaligned address fault.
+10 −0
Original line number Diff line number Diff line
@@ -11,7 +11,9 @@
#include <linux/uaccess.h>
#include <asm/alternative.h>
#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
#include <asm/errata_list.h>
#include <asm/hwprobe.h>
#include <asm/patch.h>
#include <asm/vendorid_list.h>

@@ -115,3 +117,11 @@ void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct al
	if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
		local_flush_icache_all();
}

void __init_or_module thead_feature_probe_func(unsigned int cpu,
					       unsigned long archid,
					       unsigned long impid)
{
	if ((archid == 0) && (impid == 0))
		per_cpu(misaligned_access_speed, cpu) = RISCV_HWPROBE_MISALIGNED_FAST;
}
+5 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#define ALT_OLD_PTR(a)			__ALT_PTR(a, old_offset)
#define ALT_ALT_PTR(a)			__ALT_PTR(a, alt_offset)

void __init probe_vendor_features(unsigned int cpu);
void __init apply_boot_alternatives(void);
void __init apply_early_boot_alternatives(void);
void apply_module_alternatives(void *start, size_t length);
@@ -55,11 +56,15 @@ void thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
			     unsigned long archid, unsigned long impid,
			     unsigned int stage);

void thead_feature_probe_func(unsigned int cpu, unsigned long archid,
			      unsigned long impid);

void riscv_cpufeature_patch_func(struct alt_entry *begin, struct alt_entry *end,
				 unsigned int stage);

#else /* CONFIG_RISCV_ALTERNATIVE */

static inline void probe_vendor_features(unsigned int cpu) { }
static inline void apply_boot_alternatives(void) { }
static inline void apply_early_boot_alternatives(void) { }
static inline void apply_module_alternatives(void *start, size_t length) { }
+2 −0
Original line number Diff line number Diff line
@@ -18,4 +18,6 @@ struct riscv_cpuinfo {

DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);

DECLARE_PER_CPU(long, misaligned_access_speed);

#endif
+1 −1
Original line number Diff line number Diff line
@@ -8,6 +8,6 @@

#include <uapi/asm/hwprobe.h>

#define RISCV_HWPROBE_MAX_KEY 4
#define RISCV_HWPROBE_MAX_KEY 5

#endif
Loading