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