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 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 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 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 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