Commit 462a94fb authored by Paul Walmsley's avatar Paul Walmsley
Browse files

riscv: hwprobe: add support for RISCV_HWPROBE_KEY_IMA_EXT_1



We've run out of bits to describe RISC-V ISA extensions in our initial
hwprobe key, RISCV_HWPROBE_KEY_IMA_EXT_0.  So, let's add
RISCV_HWPROBE_KEY_IMA_EXT_1, along with the framework to set the
appropriate hwprobe tuple, and add testing for it.

Based on a suggestion from Andrew Jones <andrew.jones@oss.qualcomm.com>,
also fix the documentation for RISCV_HWPROBE_KEY_IMA_EXT_0.

Reviewed-by: default avatarAndrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: default avatarPaul Walmsley <pjw@kernel.org>
parent 2af7c9cf
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -67,7 +67,7 @@ The following keys are defined:
      programs (it may still be executed in userspace via a
      kernel-controlled mechanism such as the vDSO).

* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing the extensions
* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing extensions
  that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`:
  base system behavior.

@@ -387,3 +387,7 @@ The following keys are defined:

* :c:macro:`RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE`: An unsigned int which
  represents the size of the Zicbop block in bytes.

* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_1`: A bitmask containing additional
  extensions that are compatible with the
  :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
+2 −1
Original line number Diff line number Diff line
@@ -8,7 +8,7 @@

#include <uapi/asm/hwprobe.h>

#define RISCV_HWPROBE_MAX_KEY 15
#define RISCV_HWPROBE_MAX_KEY		16

static inline bool riscv_hwprobe_key_is_valid(__s64 key)
{
@@ -20,6 +20,7 @@ static inline bool hwprobe_key_is_bitmask(__s64 key)
	switch (key) {
	case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
	case RISCV_HWPROBE_KEY_IMA_EXT_0:
	case RISCV_HWPROBE_KEY_IMA_EXT_1:
	case RISCV_HWPROBE_KEY_CPUPERF_0:
	case RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0:
	case RISCV_HWPROBE_KEY_VENDOR_EXT_MIPS_0:
+1 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ struct riscv_hwprobe {
#define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0	13
#define RISCV_HWPROBE_KEY_VENDOR_EXT_MIPS_0	14
#define RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE	15
#define RISCV_HWPROBE_KEY_IMA_EXT_1		16
/* Increase RISCV_HWPROBE_MAX_KEY when adding items. */

/* Flags */
+100 −69
Original line number Diff line number Diff line
@@ -24,6 +24,14 @@
#include <vdso/vsyscall.h>


#define EXT_KEY(isa_arg, ext, pv, missing)					\
	do {										\
		if (__riscv_isa_extension_available(isa_arg, RISCV_ISA_EXT_##ext))	\
			pv |= RISCV_HWPROBE_EXT_##ext;				\
		else									\
			missing |= RISCV_HWPROBE_EXT_##ext;				\
	} while (false)

static void hwprobe_arch_id(struct riscv_hwprobe *pair,
			    const struct cpumask *cpus)
{
@@ -93,90 +101,109 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
	for_each_cpu(cpu, cpus) {
		struct riscv_isainfo *isainfo = &hart_isa[cpu];

#define EXT_KEY(ext)									\
	do {										\
		if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext))	\
			pair->value |= RISCV_HWPROBE_EXT_##ext;				\
		else									\
			missing |= RISCV_HWPROBE_EXT_##ext;				\
	} while (false)

		/*
		 * Only use EXT_KEY() for extensions which can be exposed to userspace,
		 * regardless of the kernel's configuration, as no other checks, besides
		 * presence in the hart_isa bitmap, are made.
		 */
		EXT_KEY(ZAAMO);
		EXT_KEY(ZABHA);
		EXT_KEY(ZACAS);
		EXT_KEY(ZALASR);
		EXT_KEY(ZALRSC);
		EXT_KEY(ZAWRS);
		EXT_KEY(ZBA);
		EXT_KEY(ZBB);
		EXT_KEY(ZBC);
		EXT_KEY(ZBKB);
		EXT_KEY(ZBKC);
		EXT_KEY(ZBKX);
		EXT_KEY(ZBS);
		EXT_KEY(ZCA);
		EXT_KEY(ZCB);
		EXT_KEY(ZCLSD);
		EXT_KEY(ZCMOP);
		EXT_KEY(ZICBOM);
		EXT_KEY(ZICBOP);
		EXT_KEY(ZICBOZ);
		EXT_KEY(ZICNTR);
		EXT_KEY(ZICOND);
		EXT_KEY(ZIHINTNTL);
		EXT_KEY(ZIHINTPAUSE);
		EXT_KEY(ZIHPM);
		EXT_KEY(ZILSD);
		EXT_KEY(ZIMOP);
		EXT_KEY(ZKND);
		EXT_KEY(ZKNE);
		EXT_KEY(ZKNH);
		EXT_KEY(ZKSED);
		EXT_KEY(ZKSH);
		EXT_KEY(ZKT);
		EXT_KEY(ZTSO);
		EXT_KEY(isainfo->isa, ZAAMO, pair->value, missing);
		EXT_KEY(isainfo->isa, ZABHA, pair->value, missing);
		EXT_KEY(isainfo->isa, ZACAS, pair->value, missing);
		EXT_KEY(isainfo->isa, ZALASR, pair->value, missing);
		EXT_KEY(isainfo->isa, ZALRSC, pair->value, missing);
		EXT_KEY(isainfo->isa, ZAWRS, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBA, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBB, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBC, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBKB, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBKC, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBKX, pair->value, missing);
		EXT_KEY(isainfo->isa, ZBS, pair->value, missing);
		EXT_KEY(isainfo->isa, ZCA, pair->value, missing);
		EXT_KEY(isainfo->isa, ZCB, pair->value, missing);
		EXT_KEY(isainfo->isa, ZCLSD, pair->value, missing);
		EXT_KEY(isainfo->isa, ZCMOP, pair->value, missing);
		EXT_KEY(isainfo->isa, ZICBOM, pair->value, missing);
		EXT_KEY(isainfo->isa, ZICBOP, pair->value, missing);
		EXT_KEY(isainfo->isa, ZICBOZ, pair->value, missing);
		EXT_KEY(isainfo->isa, ZICNTR, pair->value, missing);
		EXT_KEY(isainfo->isa, ZICOND, pair->value, missing);
		EXT_KEY(isainfo->isa, ZIHINTNTL, pair->value, missing);
		EXT_KEY(isainfo->isa, ZIHINTPAUSE, pair->value, missing);
		EXT_KEY(isainfo->isa, ZIHPM, pair->value, missing);
		EXT_KEY(isainfo->isa, ZILSD, pair->value, missing);
		EXT_KEY(isainfo->isa, ZIMOP, pair->value, missing);
		EXT_KEY(isainfo->isa, ZKND, pair->value, missing);
		EXT_KEY(isainfo->isa, ZKNE, pair->value, missing);
		EXT_KEY(isainfo->isa, ZKNH, pair->value, missing);
		EXT_KEY(isainfo->isa, ZKSED, pair->value, missing);
		EXT_KEY(isainfo->isa, ZKSH, pair->value, missing);
		EXT_KEY(isainfo->isa, ZKT, pair->value, missing);
		EXT_KEY(isainfo->isa, ZTSO, pair->value, missing);

		/*
		 * All the following extensions must depend on the kernel
		 * support of V.
		 */
		if (has_vector()) {
			EXT_KEY(ZVBB);
			EXT_KEY(ZVBC);
			EXT_KEY(ZVE32F);
			EXT_KEY(ZVE32X);
			EXT_KEY(ZVE64D);
			EXT_KEY(ZVE64F);
			EXT_KEY(ZVE64X);
			EXT_KEY(ZVFBFMIN);
			EXT_KEY(ZVFBFWMA);
			EXT_KEY(ZVFH);
			EXT_KEY(ZVFHMIN);
			EXT_KEY(ZVKB);
			EXT_KEY(ZVKG);
			EXT_KEY(ZVKNED);
			EXT_KEY(ZVKNHA);
			EXT_KEY(ZVKNHB);
			EXT_KEY(ZVKSED);
			EXT_KEY(ZVKSH);
			EXT_KEY(ZVKT);
		}

		EXT_KEY(ZCD);
		EXT_KEY(ZCF);
		EXT_KEY(ZFA);
		EXT_KEY(ZFBFMIN);
		EXT_KEY(ZFH);
		EXT_KEY(ZFHMIN);
			EXT_KEY(isainfo->isa, ZVBB, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVBC, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVE32F, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVE32X, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVE64D, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVE64F, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVE64X, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVFBFMIN, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVFBFWMA, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVFH, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVFHMIN, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKB, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKG, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKNED, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKNHA, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKNHB, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKSED, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKSH, pair->value, missing);
			EXT_KEY(isainfo->isa, ZVKT, pair->value, missing);
		}

		EXT_KEY(isainfo->isa, ZCD, pair->value, missing);
		EXT_KEY(isainfo->isa, ZCF, pair->value, missing);
		EXT_KEY(isainfo->isa, ZFA, pair->value, missing);
		EXT_KEY(isainfo->isa, ZFBFMIN, pair->value, missing);
		EXT_KEY(isainfo->isa, ZFH, pair->value, missing);
		EXT_KEY(isainfo->isa, ZFHMIN, pair->value, missing);

		if (IS_ENABLED(CONFIG_RISCV_ISA_SUPM))
			EXT_KEY(SUPM);
#undef EXT_KEY
			EXT_KEY(isainfo->isa, SUPM, pair->value, missing);
	}

	/* Now turn off reporting features if any CPU is missing it. */
	pair->value &= ~missing;
}

static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
			     const struct cpumask *cpus)
{
	int cpu;
	u64 missing = 0;

	pair->value = 0;

	/*
	 * Loop through and record extensions that 1) anyone has, and 2) anyone
	 * doesn't have.
	 */
	for_each_cpu(cpu, cpus) {
		/* struct riscv_isainfo *isainfo = &hart_isa[cpu]; */

		/*
		 * Only use EXT_KEY() for extensions which can be
		 * exposed to userspace, regardless of the kernel's
		 * configuration, as no other checks, besides presence
		 * in the hart_isa bitmap, are made.
		 */
		/* Nothing here yet */
	}

	/* Now turn off reporting features if any CPU is missing it. */
@@ -287,6 +314,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
		hwprobe_isa_ext0(pair, cpus);
		break;

	case RISCV_HWPROBE_KEY_IMA_EXT_1:
		hwprobe_isa_ext1(pair, cpus);
		break;

	case RISCV_HWPROBE_KEY_CPUPERF_0:
	case RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF:
		pair->value = hwprobe_misaligned(cpus);
+13 −5
Original line number Diff line number Diff line
@@ -83,9 +83,9 @@ static void do_which_cpus(int argc, char **argv, cpu_set_t *cpus)

int main(int argc, char **argv)
{
	struct riscv_hwprobe pairs[2];
	struct riscv_hwprobe pairs[3];
	cpu_set_t cpus_aff, cpus;
	__u64 ext0_all;
	__u64 ext0_all, ext1_all;
	long rc;

	rc = sched_getaffinity(0, sizeof(cpu_set_t), &cpus_aff);
@@ -112,6 +112,11 @@ int main(int argc, char **argv)
	assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_IMA_EXT_0);
	ext0_all = pairs[0].value;

	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_1, };
	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
	assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_IMA_EXT_1);
	ext1_all = pairs[0].value;

	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
	CPU_ZERO(&cpus);
	rc = riscv_hwprobe(pairs, 1, 0, (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
@@ -134,20 +139,23 @@ int main(int argc, char **argv)

	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ext0_all, };
	pairs[2] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_1, .value = ext1_all, };
	CPU_ZERO(&cpus);
	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
	rc = riscv_hwprobe(pairs, 3, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
	ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == sysconf(_SC_NPROCESSORS_ONLN), "set all cpus\n");

	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ext0_all, };
	pairs[2] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_1, .value = ext1_all, };
	memcpy(&cpus, &cpus_aff, sizeof(cpu_set_t));
	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
	rc = riscv_hwprobe(pairs, 3, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
	ksft_test_result(rc == 0 && CPU_EQUAL(&cpus, &cpus_aff), "set all affinity cpus\n");

	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ~ext0_all, };
	pairs[2] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_1, .value = ~ext1_all, };
	memcpy(&cpus, &cpus_aff, sizeof(cpu_set_t));
	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
	rc = riscv_hwprobe(pairs, 3, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
	ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == 0, "clear all cpus\n");

	ksft_finished();