diff options
Diffstat (limited to 'arch/riscv/kernel/cpu.c')
| -rw-r--r-- | arch/riscv/kernel/cpu.c | 181 | 
1 files changed, 63 insertions, 118 deletions
diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 35b854cf078e..c17dacb1141c 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -46,7 +46,7 @@ int riscv_of_processor_hartid(struct device_node *node, unsigned long *hart)  	return 0;  } -int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hart) +int __init riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hart)  {  	const char *isa; @@ -66,16 +66,53 @@ int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *har  		return -ENODEV;  	} +	if (of_property_read_string(node, "riscv,isa-base", &isa)) +		goto old_interface; + +	if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32i", 5)) { +		pr_warn("CPU with hartid=%lu does not support rv32i", *hart); +		return -ENODEV; +	} + +	if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64i", 5)) { +		pr_warn("CPU with hartid=%lu does not support rv64i", *hart); +		return -ENODEV; +	} + +	if (!of_property_present(node, "riscv,isa-extensions")) +		return -ENODEV; + +	if (of_property_match_string(node, "riscv,isa-extensions", "i") < 0 || +	    of_property_match_string(node, "riscv,isa-extensions", "m") < 0 || +	    of_property_match_string(node, "riscv,isa-extensions", "a") < 0) { +		pr_warn("CPU with hartid=%lu does not support ima", *hart); +		return -ENODEV; +	} + +	return 0; + +old_interface: +	if (!riscv_isa_fallback) { +		pr_warn("CPU with hartid=%lu is invalid: this kernel does not parse \"riscv,isa\"", +			*hart); +		return -ENODEV; +	} +  	if (of_property_read_string(node, "riscv,isa", &isa)) { -		pr_warn("CPU with hartid=%lu has no \"riscv,isa\" property\n", *hart); +		pr_warn("CPU with hartid=%lu has no \"riscv,isa-base\" or \"riscv,isa\" property\n", +			*hart);  		return -ENODEV;  	} -	if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32ima", 7)) +	if (IS_ENABLED(CONFIG_32BIT) && strncasecmp(isa, "rv32ima", 7)) { +		pr_warn("CPU with hartid=%lu does not support rv32ima", *hart);  		return -ENODEV; +	} -	if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64ima", 7)) +	if (IS_ENABLED(CONFIG_64BIT) && strncasecmp(isa, "rv64ima", 7)) { +		pr_warn("CPU with hartid=%lu does not support rv64ima", *hart);  		return -ENODEV; +	}  	return 0;  } @@ -165,132 +202,46 @@ arch_initcall(riscv_cpuinfo_init);  #ifdef CONFIG_PROC_FS -#define __RISCV_ISA_EXT_DATA(UPROP, EXTID) \ -	{							\ -		.uprop = #UPROP,				\ -		.isa_ext_id = EXTID,				\ -	} - -/* - * The canonical order of ISA extension names in the ISA string is defined in - * chapter 27 of the unprivileged specification. - * - * Ordinarily, for in-kernel data structures, this order is unimportant but - * isa_ext_arr defines the order of the ISA string in /proc/cpuinfo. - * - * The specification uses vague wording, such as should, when it comes to - * ordering, so for our purposes the following rules apply: - * - * 1. All multi-letter extensions must be separated from other extensions by an - *    underscore. - * - * 2. Additional standard extensions (starting with 'Z') must be sorted after - *    single-letter extensions and before any higher-privileged extensions. - - * 3. The first letter following the 'Z' conventionally indicates the most - *    closely related alphabetical extension category, IMAFDQLCBKJTPVH. - *    If multiple 'Z' extensions are named, they must be ordered first by - *    category, then alphabetically within a category. - * - * 3. Standard supervisor-level extensions (starting with 'S') must be listed - *    after standard unprivileged extensions.  If multiple supervisor-level - *    extensions are listed, they must be ordered alphabetically. - * - * 4. Standard machine-level extensions (starting with 'Zxm') must be listed - *    after any lower-privileged, standard extensions.  If multiple - *    machine-level extensions are listed, they must be ordered - *    alphabetically. - * - * 5. Non-standard extensions (starting with 'X') must be listed after all - *    standard extensions. If multiple non-standard extensions are listed, they - *    must be ordered alphabetically. - * - * An example string following the order is: - *    rv64imadc_zifoo_zigoo_zafoo_sbar_scar_zxmbaz_xqux_xrux - * - * New entries to this struct should follow the ordering rules described above. - */ -static struct riscv_isa_ext_data isa_ext_arr[] = { -	__RISCV_ISA_EXT_DATA(zicbom, RISCV_ISA_EXT_ZICBOM), -	__RISCV_ISA_EXT_DATA(zicboz, RISCV_ISA_EXT_ZICBOZ), -	__RISCV_ISA_EXT_DATA(zicntr, RISCV_ISA_EXT_ZICNTR), -	__RISCV_ISA_EXT_DATA(zicsr, RISCV_ISA_EXT_ZICSR), -	__RISCV_ISA_EXT_DATA(zifencei, RISCV_ISA_EXT_ZIFENCEI), -	__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), -	__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM), -	__RISCV_ISA_EXT_DATA(zba, RISCV_ISA_EXT_ZBA), -	__RISCV_ISA_EXT_DATA(zbb, RISCV_ISA_EXT_ZBB), -	__RISCV_ISA_EXT_DATA(zbs, RISCV_ISA_EXT_ZBS), -	__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA), -	__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA), -	__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF), -	__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC), -	__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL), -	__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT), -	__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT), -	__RISCV_ISA_EXT_DATA("", RISCV_ISA_EXT_MAX), -}; - -static void print_isa_ext(struct seq_file *f) +static void print_isa(struct seq_file *f)  { -	struct riscv_isa_ext_data *edata; -	int i = 0, arr_sz; - -	arr_sz = ARRAY_SIZE(isa_ext_arr) - 1; +	seq_puts(f, "isa\t\t: "); -	/* No extension support available */ -	if (arr_sz <= 0) -		return; +	if (IS_ENABLED(CONFIG_32BIT)) +		seq_write(f, "rv32", 4); +	else +		seq_write(f, "rv64", 4); -	for (i = 0; i <= arr_sz; i++) { -		edata = &isa_ext_arr[i]; -		if (!__riscv_isa_extension_available(NULL, edata->isa_ext_id)) +	for (int i = 0; i < riscv_isa_ext_count; i++) { +		if (!__riscv_isa_extension_available(NULL, riscv_isa_ext[i].id))  			continue; -		seq_printf(f, "_%s", edata->uprop); -	} -} -/* - * These are the only valid base (single letter) ISA extensions as per the spec. - * It also specifies the canonical order in which it appears in the spec. - * Some of the extension may just be a place holder for now (B, K, P, J). - * This should be updated once corresponding extensions are ratified. - */ -static const char base_riscv_exts[13] = "imafdqcbkjpvh"; +		/* Only multi-letter extensions are split by underscores */ +		if (strnlen(riscv_isa_ext[i].name, 2) != 1) +			seq_puts(f, "_"); -static void print_isa(struct seq_file *f, const char *isa) -{ -	int i; - -	seq_puts(f, "isa\t\t: "); -	/* Print the rv[64/32] part */ -	seq_write(f, isa, 4); -	for (i = 0; i < sizeof(base_riscv_exts); i++) { -		if (__riscv_isa_extension_available(NULL, base_riscv_exts[i] - 'a')) -			/* Print only enabled the base ISA extensions */ -			seq_write(f, &base_riscv_exts[i], 1); +		seq_printf(f, "%s", riscv_isa_ext[i].name);  	} -	print_isa_ext(f); +  	seq_puts(f, "\n");  }  static void print_mmu(struct seq_file *f)  { -	char sv_type[16]; +	const char *sv_type;  #ifdef CONFIG_MMU  #if defined(CONFIG_32BIT) -	strncpy(sv_type, "sv32", 5); +	sv_type = "sv32";  #elif defined(CONFIG_64BIT)  	if (pgtable_l5_enabled) -		strncpy(sv_type, "sv57", 5); +		sv_type = "sv57";  	else if (pgtable_l4_enabled) -		strncpy(sv_type, "sv48", 5); +		sv_type = "sv48";  	else -		strncpy(sv_type, "sv39", 5); +		sv_type = "sv39";  #endif  #else -	strncpy(sv_type, "none", 5); +	sv_type = "none";  #endif /* CONFIG_MMU */  	seq_printf(f, "mmu\t\t: %s\n", sv_type);  } @@ -321,27 +272,21 @@ static int c_show(struct seq_file *m, void *v)  	unsigned long cpu_id = (unsigned long)v - 1;  	struct riscv_cpuinfo *ci = per_cpu_ptr(&riscv_cpuinfo, cpu_id);  	struct device_node *node; -	const char *compat, *isa; +	const char *compat;  	seq_printf(m, "processor\t: %lu\n", cpu_id);  	seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id)); +	print_isa(m); +	print_mmu(m);  	if (acpi_disabled) {  		node = of_get_cpu_node(cpu_id, NULL); -		if (!of_property_read_string(node, "riscv,isa", &isa)) -			print_isa(m, isa); -		print_mmu(m);  		if (!of_property_read_string(node, "compatible", &compat) &&  		    strcmp(compat, "riscv"))  			seq_printf(m, "uarch\t\t: %s\n", compat);  		of_node_put(node); -	} else { -		if (!acpi_get_riscv_isa(NULL, cpu_id, &isa)) -			print_isa(m, isa); - -		print_mmu(m);  	}  	seq_printf(m, "mvendorid\t: 0x%lx\n", ci->mvendorid);  |