xref: /linux/tools/testing/selftests/riscv/hwprobe/which-cpus.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2023 Ventana Micro Systems Inc.
4  *
5  * Test the RISCV_HWPROBE_WHICH_CPUS flag of hwprobe. Also provides a command
6  * line interface to get the cpu list for arbitrary hwprobe pairs.
7  */
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sched.h>
13 #include <unistd.h>
14 #include <assert.h>
15 
16 #include "hwprobe.h"
17 #include "../../kselftest.h"
18 
help(void)19 static void help(void)
20 {
21 	printf("\n"
22 	       "which-cpus: [-h] [<key=value> [<key=value> ...]]\n\n"
23 	       "   Without parameters, tests the RISCV_HWPROBE_WHICH_CPUS flag of hwprobe.\n"
24 	       "   With parameters, where each parameter is a hwprobe pair written as\n"
25 	       "   <key=value>, outputs the cpulist for cpus which all match the given set\n"
26 	       "   of pairs.  'key' and 'value' should be in numeric form, e.g. 4=0x3b\n");
27 }
28 
print_cpulist(cpu_set_t * cpus)29 static void print_cpulist(cpu_set_t *cpus)
30 {
31 	int start = 0, end = 0;
32 
33 	if (!CPU_COUNT(cpus)) {
34 		printf("cpus: None\n");
35 		return;
36 	}
37 
38 	printf("cpus:");
39 	for (int i = 0, c = 0; i < CPU_COUNT(cpus); i++, c++) {
40 		if (start != end && !CPU_ISSET(c, cpus))
41 			printf("-%d", end);
42 
43 		while (!CPU_ISSET(c, cpus))
44 			++c;
45 
46 		if (i != 0 && c == end + 1) {
47 			end = c;
48 			continue;
49 		}
50 
51 		printf("%c%d", i == 0 ? ' ' : ',', c);
52 		start = end = c;
53 	}
54 	if (start != end)
55 		printf("-%d", end);
56 	printf("\n");
57 }
58 
do_which_cpus(int argc,char ** argv,cpu_set_t * cpus)59 static void do_which_cpus(int argc, char **argv, cpu_set_t *cpus)
60 {
61 	struct riscv_hwprobe *pairs;
62 	int nr_pairs = argc - 1;
63 	char *start, *end;
64 	int rc;
65 
66 	pairs = malloc(nr_pairs * sizeof(struct riscv_hwprobe));
67 	assert(pairs);
68 
69 	for (int i = 0; i < nr_pairs; i++) {
70 		start = argv[i + 1];
71 		pairs[i].key = strtol(start, &end, 0);
72 		assert(end != start && *end == '=');
73 		start = end + 1;
74 		pairs[i].value = strtoul(start, &end, 0);
75 		assert(end != start && *end == '\0');
76 	}
77 
78 	rc = riscv_hwprobe(pairs, nr_pairs, sizeof(cpu_set_t), (unsigned long *)cpus, RISCV_HWPROBE_WHICH_CPUS);
79 	assert(rc == 0);
80 	print_cpulist(cpus);
81 	free(pairs);
82 }
83 
main(int argc,char ** argv)84 int main(int argc, char **argv)
85 {
86 	struct riscv_hwprobe pairs[2];
87 	cpu_set_t cpus_aff, cpus;
88 	__u64 ext0_all;
89 	long rc;
90 
91 	rc = sched_getaffinity(0, sizeof(cpu_set_t), &cpus_aff);
92 	assert(rc == 0);
93 
94 	if (argc > 1) {
95 		if (!strcmp(argv[1], "-h"))
96 			help();
97 		else
98 			do_which_cpus(argc, argv, &cpus_aff);
99 		return 0;
100 	}
101 
102 	ksft_print_header();
103 	ksft_set_plan(7);
104 
105 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, };
106 	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
107 	assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR &&
108 	       pairs[0].value == RISCV_HWPROBE_BASE_BEHAVIOR_IMA);
109 
110 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, };
111 	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
112 	assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_IMA_EXT_0);
113 	ext0_all = pairs[0].value;
114 
115 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
116 	CPU_ZERO(&cpus);
117 	rc = riscv_hwprobe(pairs, 1, 0, (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
118 	ksft_test_result(rc == -EINVAL, "no cpusetsize\n");
119 
120 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
121 	rc = riscv_hwprobe(pairs, 1, sizeof(cpu_set_t), NULL, RISCV_HWPROBE_WHICH_CPUS);
122 	ksft_test_result(rc == -EINVAL, "NULL cpus\n");
123 
124 	pairs[0] = (struct riscv_hwprobe){ .key = 0xbadc0de, };
125 	CPU_ZERO(&cpus);
126 	rc = riscv_hwprobe(pairs, 1, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
127 	ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == 0, "unknown key\n");
128 
129 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
130 	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
131 	CPU_ZERO(&cpus);
132 	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
133 	ksft_test_result(rc == 0, "duplicate keys\n");
134 
135 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
136 	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ext0_all, };
137 	CPU_ZERO(&cpus);
138 	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
139 	ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == sysconf(_SC_NPROCESSORS_ONLN), "set all cpus\n");
140 
141 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
142 	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ext0_all, };
143 	memcpy(&cpus, &cpus_aff, sizeof(cpu_set_t));
144 	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
145 	ksft_test_result(rc == 0 && CPU_EQUAL(&cpus, &cpus_aff), "set all affinity cpus\n");
146 
147 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, .value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA, };
148 	pairs[1] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, .value = ~ext0_all, };
149 	memcpy(&cpus, &cpus_aff, sizeof(cpu_set_t));
150 	rc = riscv_hwprobe(pairs, 2, sizeof(cpu_set_t), (unsigned long *)&cpus, RISCV_HWPROBE_WHICH_CPUS);
151 	ksft_test_result(rc == 0 && CPU_COUNT(&cpus) == 0, "clear all cpus\n");
152 
153 	ksft_finished();
154 }
155