riscv: vector: Use vlenb from DT for thead

If thead,vlenb is provided in the device tree, prefer that over reading
the vlenb csr.

Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Tested-by: Yangyu Chen <cyy@cyyself.name>
Link: https://lore.kernel.org/r/20241113-xtheadvector-v11-5-236c22791ef9@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
Charlie Jenkins 2024-11-13 18:21:11 -08:00 committed by Palmer Dabbelt
parent cddd63869f
commit 377be47f90
No known key found for this signature in database
GPG Key ID: 2E1319F35FBB1889
6 changed files with 91 additions and 1 deletions

View File

@ -26,6 +26,19 @@ config RISCV_ISA_VENDOR_EXT_THEAD
extensions. Without this option enabled, T-Head vendor extensions will extensions. Without this option enabled, T-Head vendor extensions will
not be detected at boot and their presence not reported to userspace. not be detected at boot and their presence not reported to userspace.
If you don't know what to do here, say Y.
config RISCV_ISA_XTHEADVECTOR
bool "xtheadvector extension support"
depends on RISCV_ISA_VENDOR_EXT_THEAD
depends on RISCV_ISA_V
depends on FPU
default y
help
Say N here if you want to disable all xtheadvector related procedures
in the kernel. This will disable vector for any T-Head board that
contains xtheadvector rather than the standard vector.
If you don't know what to do here, say Y. If you don't know what to do here, say Y.
endmenu endmenu

View File

@ -34,6 +34,8 @@ DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
/* Per-cpu ISA extensions. */ /* Per-cpu ISA extensions. */
extern struct riscv_isainfo hart_isa[NR_CPUS]; extern struct riscv_isainfo hart_isa[NR_CPUS];
extern u32 thead_vlenb_of;
void __init riscv_user_isa_enable(void); void __init riscv_user_isa_enable(void);
#define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \ #define _RISCV_ISA_EXT_DATA(_name, _id, _subset_exts, _subset_exts_size, _validate) { \

View File

@ -13,4 +13,10 @@
extern struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_thead; extern struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_thead;
#ifdef CONFIG_RISCV_ISA_VENDOR_EXT_THEAD
void disable_xtheadvector(void);
#else
static inline void disable_xtheadvector(void) { }
#endif
#endif #endif

View File

@ -39,6 +39,8 @@ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
/* Per-cpu ISA extensions. */ /* Per-cpu ISA extensions. */
struct riscv_isainfo hart_isa[NR_CPUS]; struct riscv_isainfo hart_isa[NR_CPUS];
u32 thead_vlenb_of;
/** /**
* riscv_isa_extension_base() - Get base extension word * riscv_isa_extension_base() - Get base extension word
* *
@ -779,6 +781,46 @@ static void __init riscv_fill_vendor_ext_list(int cpu)
} }
} }
static int has_thead_homogeneous_vlenb(void)
{
int cpu;
u32 prev_vlenb = 0;
u32 vlenb;
/* Ignore thead,vlenb property if xtheavector is not enabled in the kernel */
if (!IS_ENABLED(CONFIG_RISCV_ISA_XTHEADVECTOR))
return 0;
for_each_possible_cpu(cpu) {
struct device_node *cpu_node;
cpu_node = of_cpu_device_node_get(cpu);
if (!cpu_node) {
pr_warn("Unable to find cpu node\n");
return -ENOENT;
}
if (of_property_read_u32(cpu_node, "thead,vlenb", &vlenb)) {
of_node_put(cpu_node);
if (prev_vlenb)
return -ENOENT;
continue;
}
if (prev_vlenb && vlenb != prev_vlenb) {
of_node_put(cpu_node);
return -ENOENT;
}
prev_vlenb = vlenb;
of_node_put(cpu_node);
}
thead_vlenb_of = vlenb;
return 0;
}
static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap) static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
{ {
unsigned int cpu; unsigned int cpu;
@ -832,6 +874,12 @@ static int __init riscv_fill_hwcap_from_ext_list(unsigned long *isa2hwcap)
riscv_fill_vendor_ext_list(cpu); riscv_fill_vendor_ext_list(cpu);
} }
if (riscv_isa_vendor_extension_available(THEAD_VENDOR_ID, XTHEADVECTOR) &&
has_thead_homogeneous_vlenb() < 0) {
pr_warn("Unsupported heterogeneous vlenb detected, vector extension disabled.\n");
disable_xtheadvector();
}
if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX)) if (bitmap_empty(riscv_isa, RISCV_ISA_EXT_MAX))
return -ENOENT; return -ENOENT;

View File

@ -33,7 +33,17 @@ int riscv_v_setup_vsize(void)
{ {
unsigned long this_vsize; unsigned long this_vsize;
/* There are 32 vector registers with vlenb length. */ /*
* There are 32 vector registers with vlenb length.
*
* If the thead,vlenb property was provided by the firmware, use that
* instead of probing the CSRs.
*/
if (thead_vlenb_of) {
riscv_v_vsize = thead_vlenb_of * 32;
return 0;
}
riscv_v_enable(); riscv_v_enable();
this_vsize = csr_read(CSR_VLENB) * 32; this_vsize = csr_read(CSR_VLENB) * 32;
riscv_v_disable(); riscv_v_disable();

View File

@ -5,6 +5,7 @@
#include <asm/vendor_extensions/thead.h> #include <asm/vendor_extensions/thead.h>
#include <linux/array_size.h> #include <linux/array_size.h>
#include <linux/cpumask.h>
#include <linux/types.h> #include <linux/types.h>
/* All T-Head vendor extensions supported in Linux */ /* All T-Head vendor extensions supported in Linux */
@ -16,3 +17,13 @@ struct riscv_isa_vendor_ext_data_list riscv_isa_vendor_ext_list_thead = {
.ext_data_count = ARRAY_SIZE(riscv_isa_vendor_ext_thead), .ext_data_count = ARRAY_SIZE(riscv_isa_vendor_ext_thead),
.ext_data = riscv_isa_vendor_ext_thead, .ext_data = riscv_isa_vendor_ext_thead,
}; };
void disable_xtheadvector(void)
{
int cpu;
for_each_possible_cpu(cpu)
clear_bit(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR, riscv_isa_vendor_ext_list_thead.per_hart_isa_bitmap[cpu].isa);
clear_bit(RISCV_ISA_VENDOR_EXT_XTHEADVECTOR, riscv_isa_vendor_ext_list_thead.all_harts_isa_bitmap.isa);
}