162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <stddef.h>
362306a36Sopenharmony_ci#include <asm/hwprobe.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Rather than relying on having a new enough libc to define this, just do it
762306a36Sopenharmony_ci * ourselves.  This way we don't need to be coupled to a new-enough libc to
862306a36Sopenharmony_ci * contain the call.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_cilong riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count,
1162306a36Sopenharmony_ci		   size_t cpu_count, unsigned long *cpus, unsigned int flags);
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciint main(int argc, char **argv)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct riscv_hwprobe pairs[8];
1662306a36Sopenharmony_ci	unsigned long cpus;
1762306a36Sopenharmony_ci	long out;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	/* Fake the CPU_SET ops. */
2062306a36Sopenharmony_ci	cpus = -1;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	/*
2362306a36Sopenharmony_ci	 * Just run a basic test: pass enough pairs to get up to the base
2462306a36Sopenharmony_ci	 * behavior, and then check to make sure it's sane.
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci	for (long i = 0; i < 8; i++)
2762306a36Sopenharmony_ci		pairs[i].key = i;
2862306a36Sopenharmony_ci	out = riscv_hwprobe(pairs, 8, 1, &cpus, 0);
2962306a36Sopenharmony_ci	if (out != 0)
3062306a36Sopenharmony_ci		return -1;
3162306a36Sopenharmony_ci	for (long i = 0; i < 4; ++i) {
3262306a36Sopenharmony_ci		/* Fail if the kernel claims not to recognize a base key. */
3362306a36Sopenharmony_ci		if ((i < 4) && (pairs[i].key != i))
3462306a36Sopenharmony_ci			return -2;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci		if (pairs[i].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR)
3762306a36Sopenharmony_ci			continue;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci		if (pairs[i].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA)
4062306a36Sopenharmony_ci			continue;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		return -3;
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/*
4662306a36Sopenharmony_ci	 * This should also work with a NULL CPU set, but should not work
4762306a36Sopenharmony_ci	 * with an improperly supplied CPU set.
4862306a36Sopenharmony_ci	 */
4962306a36Sopenharmony_ci	out = riscv_hwprobe(pairs, 8, 0, 0, 0);
5062306a36Sopenharmony_ci	if (out != 0)
5162306a36Sopenharmony_ci		return -4;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	out = riscv_hwprobe(pairs, 8, 0, &cpus, 0);
5462306a36Sopenharmony_ci	if (out == 0)
5562306a36Sopenharmony_ci		return -5;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	out = riscv_hwprobe(pairs, 8, 1, 0, 0);
5862306a36Sopenharmony_ci	if (out == 0)
5962306a36Sopenharmony_ci		return -6;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/*
6262306a36Sopenharmony_ci	 * Check that keys work by providing one that we know exists, and
6362306a36Sopenharmony_ci	 * checking to make sure the resultig pair is what we asked for.
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	pairs[0].key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR;
6662306a36Sopenharmony_ci	out = riscv_hwprobe(pairs, 1, 1, &cpus, 0);
6762306a36Sopenharmony_ci	if (out != 0)
6862306a36Sopenharmony_ci		return -7;
6962306a36Sopenharmony_ci	if (pairs[0].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR)
7062306a36Sopenharmony_ci		return -8;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/*
7362306a36Sopenharmony_ci	 * Check that an unknown key gets overwritten with -1,
7462306a36Sopenharmony_ci	 * but doesn't block elements after it.
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	pairs[0].key = 0x5555;
7762306a36Sopenharmony_ci	pairs[1].key = 1;
7862306a36Sopenharmony_ci	pairs[1].value = 0xAAAA;
7962306a36Sopenharmony_ci	out = riscv_hwprobe(pairs, 2, 0, 0, 0);
8062306a36Sopenharmony_ci	if (out != 0)
8162306a36Sopenharmony_ci		return -9;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (pairs[0].key != -1)
8462306a36Sopenharmony_ci		return -10;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if ((pairs[1].key != 1) || (pairs[1].value == 0xAAAA))
8762306a36Sopenharmony_ci		return -11;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	return 0;
9062306a36Sopenharmony_ci}
91