arch/riscv/kernel/cpufeature.c

Source file repositories/reference/linux-study-clean/arch/riscv/kernel/cpufeature.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/kernel/cpufeature.c
Extension
.c
Size
39469 bytes
Lines
1276
Domain
Architecture Layer
Bucket
arch/riscv
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (max_loop_count-- < 0) {
			pr_err("Failed to reach a stable ISA state\n");
			return;
		}
		bitmap_copy(prev_resolved_isa, resolved_isa, RISCV_ISA_EXT_MAX);
		for_each_set_bit(bit, source_isa, RISCV_ISA_EXT_MAX) {
			ext = riscv_get_isa_ext_data(bit);

			if (ext && ext->validate) {
				ret = ext->validate(ext, resolved_isa);
				if (ret == -EPROBE_DEFER) {
					loop = true;
					continue;
				} else if (ret) {
					/* Disable the extension entirely */
					clear_bit(bit, source_isa);
					continue;
				}
			}

			set_bit(bit, resolved_isa);
			/* No need to keep it in source isa now that it is enabled */
			clear_bit(bit, source_isa);

			/* Single letter extensions get set in hwcap */
			if (bit < RISCV_ISA_EXT_BASE)
				*this_hwcap |= isa2hwcap[bit];
		}
	} while (loop && !bitmap_equal(prev_resolved_isa, resolved_isa, RISCV_ISA_EXT_MAX));
}

static void __init match_isa_ext(const char *name, const char *name_end, unsigned long *bitmap)
{
	for (int i = 0; i < riscv_isa_ext_count; i++) {
		const struct riscv_isa_ext_data *ext = &riscv_isa_ext[i];

		if ((name_end - name == strlen(ext->name)) &&
		    !strncasecmp(name, ext->name, name_end - name)) {
			riscv_isa_set_ext(ext, bitmap);
			break;
		}
	}
}

static void __init riscv_parse_isa_string(const char *isa, unsigned long *bitmap)
{
	/*
	 * For all possible cpus, we have already validated in
	 * the boot process that they at least contain "rv" and
	 * whichever of "32"/"64" this kernel supports, and so this
	 * section can be skipped.
	 */
	isa += 4;

	while (*isa) {
		const char *ext = isa++;
		const char *ext_end = isa;
		bool ext_err = false;

		switch (*ext) {
		case 'x':
		case 'X':
			if (acpi_disabled)
				pr_warn_once("Vendor extensions are ignored in riscv,isa. Use riscv,isa-extensions instead.");
			/*
			 * To skip an extension, we find its end.
			 * As multi-letter extensions must be split from other multi-letter
			 * extensions with an "_", the end of a multi-letter extension will
			 * either be the null character or the "_" at the start of the next
			 * multi-letter extension.
			 */
			for (; *isa && *isa != '_'; ++isa)
				;
			ext_err = true;
			break;
		case 's':
			/*
			 * Workaround for invalid single-letter 's' & 'u' (QEMU).
			 * No need to set the bit in riscv_isa as 's' & 'u' are
			 * not valid ISA extensions. It works unless the first
			 * multi-letter extension in the ISA string begins with
			 * "Su" and is not prefixed with an underscore.
			 */
			if (ext[-1] != '_' && ext[1] == 'u') {
				++isa;
				ext_err = true;
				break;
			}
			fallthrough;
		case 'S':

Annotation

Implementation Notes