1 1.12 jmcneill /* $NetBSD: intrctl.c,v 1.12 2021/02/22 11:33:34 jmcneill Exp $ */ 2 1.1 knakahar 3 1.1 knakahar /* 4 1.1 knakahar * Copyright (c) 2015 Internet Initiative Japan Inc. 5 1.1 knakahar * All rights reserved. 6 1.1 knakahar * 7 1.1 knakahar * Redistribution and use in source and binary forms, with or without 8 1.1 knakahar * modification, are permitted provided that the following conditions 9 1.1 knakahar * are met: 10 1.1 knakahar * 1. Redistributions of source code must retain the above copyright 11 1.1 knakahar * notice, this list of conditions and the following disclaimer. 12 1.1 knakahar * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 knakahar * notice, this list of conditions and the following disclaimer in the 14 1.1 knakahar * documentation and/or other materials provided with the distribution. 15 1.1 knakahar * 16 1.1 knakahar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 knakahar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 knakahar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 knakahar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 knakahar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 knakahar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 knakahar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 knakahar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 knakahar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 knakahar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 knakahar * POSSIBILITY OF SUCH DAMAGE. 27 1.1 knakahar */ 28 1.1 knakahar 29 1.1 knakahar #include <sys/cdefs.h> 30 1.12 jmcneill __RCSID("$NetBSD: intrctl.c,v 1.12 2021/02/22 11:33:34 jmcneill Exp $"); 31 1.1 knakahar 32 1.1 knakahar #include <sys/param.h> 33 1.1 knakahar #include <sys/sysctl.h> 34 1.1 knakahar #include <sys/intrio.h> 35 1.1 knakahar #include <sys/types.h> 36 1.1 knakahar 37 1.1 knakahar #include <err.h> 38 1.1 knakahar #include <errno.h> 39 1.1 knakahar #include <fcntl.h> 40 1.1 knakahar #include <limits.h> 41 1.1 knakahar #include <paths.h> 42 1.1 knakahar #include <sched.h> 43 1.1 knakahar #include <stdint.h> 44 1.1 knakahar #include <stdio.h> 45 1.1 knakahar #include <stdlib.h> 46 1.1 knakahar #include <string.h> 47 1.1 knakahar #include <unistd.h> 48 1.1 knakahar 49 1.1 knakahar #include "intrctl_io.h" 50 1.1 knakahar 51 1.1 knakahar __dead static void usage(void); 52 1.1 knakahar 53 1.1 knakahar int verbose; 54 1.1 knakahar 55 1.1 knakahar static void intrctl_list(int, char **); 56 1.1 knakahar static void intrctl_affinity(int, char **); 57 1.1 knakahar static void intrctl_intr(int, char **); 58 1.1 knakahar static void intrctl_nointr(int, char **); 59 1.1 knakahar 60 1.1 knakahar static struct cmdtab { 61 1.1 knakahar const char *label; 62 1.1 knakahar void (*func)(int, char **); 63 1.1 knakahar } const intrctl_cmdtab[] = { 64 1.1 knakahar { "list", intrctl_list }, 65 1.1 knakahar { "affinity", intrctl_affinity }, 66 1.1 knakahar { "intr", intrctl_intr }, 67 1.1 knakahar { "nointr", intrctl_nointr }, 68 1.1 knakahar { NULL, NULL }, 69 1.1 knakahar }; 70 1.1 knakahar 71 1.1 knakahar int 72 1.1 knakahar main(int argc, char **argv) 73 1.1 knakahar { 74 1.1 knakahar const struct cmdtab *ct; 75 1.1 knakahar char *cmdname; 76 1.1 knakahar 77 1.1 knakahar if (argc < 2) 78 1.1 knakahar usage(); 79 1.1 knakahar 80 1.1 knakahar cmdname = argv[1]; 81 1.1 knakahar argv += 1; 82 1.1 knakahar argc -= 1; 83 1.1 knakahar 84 1.1 knakahar for (ct = intrctl_cmdtab; ct->label != NULL; ct++) { 85 1.1 knakahar if (strcmp(cmdname, ct->label) == 0) { 86 1.1 knakahar break; 87 1.1 knakahar } 88 1.1 knakahar } 89 1.1 knakahar if (ct->label == NULL) 90 1.1 knakahar errx(EXIT_FAILURE, "unknown command ``%s''", cmdname); 91 1.1 knakahar 92 1.1 knakahar (*ct->func)(argc, argv); 93 1.1 knakahar exit(EXIT_SUCCESS); 94 1.1 knakahar /* NOTREACHED */ 95 1.1 knakahar } 96 1.1 knakahar 97 1.1 knakahar static void 98 1.1 knakahar usage(void) 99 1.1 knakahar { 100 1.1 knakahar const char *progname = getprogname(); 101 1.1 knakahar 102 1.11 wiz fprintf(stderr, "usage: %s list [-cz] [-w secs]\n", progname); 103 1.10 mrg fprintf(stderr, " %s affinity -i interrupt_name -c cpu_index\n", 104 1.10 mrg progname); 105 1.1 knakahar fprintf(stderr, " %s intr -c cpu_index\n", progname); 106 1.1 knakahar fprintf(stderr, " %s nointr -c cpu_index\n", progname); 107 1.1 knakahar exit(EXIT_FAILURE); 108 1.1 knakahar /* NOTREACHED */ 109 1.1 knakahar } 110 1.1 knakahar 111 1.1 knakahar static int intrctl_io_alloc_retry_count = 4; 112 1.1 knakahar 113 1.12 jmcneill static bool 114 1.12 jmcneill intrctl_list_line_allcpus(struct intrio_list_line *illine, int ncpus) 115 1.12 jmcneill { 116 1.12 jmcneill struct intrio_list_line_cpu *illc; 117 1.12 jmcneill int i; 118 1.12 jmcneill 119 1.12 jmcneill for (i = 0; i < ncpus; i++) { 120 1.12 jmcneill illc = &illine->ill_cpu[i]; 121 1.12 jmcneill if (illc->illc_assigned == false) { 122 1.12 jmcneill return false; 123 1.12 jmcneill } 124 1.12 jmcneill } 125 1.12 jmcneill 126 1.12 jmcneill return true; 127 1.12 jmcneill } 128 1.12 jmcneill 129 1.1 knakahar static void 130 1.10 mrg intrctl_list_one(bool compact, bool skipzero) 131 1.1 knakahar { 132 1.3 ryo char buf[64]; 133 1.1 knakahar struct intrio_list_line *illine; 134 1.3 ryo int i, ncpus, *cpucol; 135 1.1 knakahar void *handle; 136 1.2 knakahar size_t intridlen; 137 1.1 knakahar 138 1.1 knakahar handle = intrctl_io_alloc(intrctl_io_alloc_retry_count); 139 1.1 knakahar if (handle == NULL) 140 1.1 knakahar err(EXIT_FAILURE, "intrctl_io_alloc"); 141 1.1 knakahar 142 1.2 knakahar /* calc columns */ 143 1.2 knakahar ncpus = intrctl_io_ncpus(handle); 144 1.2 knakahar intridlen = strlen("interrupt id"); 145 1.3 ryo for (illine = intrctl_io_firstline(handle); illine != NULL; 146 1.3 ryo illine = intrctl_io_nextline(handle, illine)) { 147 1.2 knakahar size_t len = strlen(illine->ill_intrid); 148 1.2 knakahar if (intridlen < len) 149 1.2 knakahar intridlen = len; 150 1.2 knakahar } 151 1.2 knakahar 152 1.3 ryo cpucol = malloc(sizeof(*cpucol) * (size_t)ncpus); 153 1.3 ryo if (cpucol == NULL) 154 1.3 ryo err(EXIT_FAILURE, "malloc"); 155 1.3 ryo for (i = 0; i < ncpus; i++) { 156 1.3 ryo snprintf(buf, sizeof(buf), "CPU%u", i); 157 1.3 ryo cpucol[i] = strlen(buf); 158 1.3 ryo } 159 1.3 ryo for (illine = intrctl_io_firstline(handle); illine != NULL; 160 1.3 ryo illine = intrctl_io_nextline(handle, illine)) { 161 1.3 ryo for (i = 0; i < ncpus; i++) { 162 1.3 ryo int len; 163 1.3 ryo snprintf(buf, sizeof(buf), "%" PRIu64, 164 1.3 ryo illine->ill_cpu[i].illc_count); 165 1.3 ryo len = (int)strlen(buf); 166 1.3 ryo if (cpucol[i] < len) 167 1.3 ryo cpucol[i] = len; 168 1.3 ryo } 169 1.3 ryo } 170 1.3 ryo 171 1.1 knakahar /* header */ 172 1.7 ryo printf("%-*s ", (int)intridlen, "interrupt id"); 173 1.4 jdolecek if (compact) { 174 1.7 ryo printf("%20s ", "total"); 175 1.7 ryo printf("%5s ", "aff"); 176 1.4 jdolecek } else { 177 1.4 jdolecek for (i = 0; i < ncpus; i++) { 178 1.4 jdolecek snprintf(buf, sizeof(buf), "CPU%u", i); 179 1.4 jdolecek printf("%*s ", cpucol[i], buf); 180 1.4 jdolecek } 181 1.1 knakahar } 182 1.3 ryo printf("device name(s)\n"); 183 1.1 knakahar 184 1.1 knakahar /* body */ 185 1.3 ryo for (illine = intrctl_io_firstline(handle); illine != NULL; 186 1.3 ryo illine = intrctl_io_nextline(handle, illine)) { 187 1.4 jdolecek struct intrio_list_line_cpu *illc; 188 1.4 jdolecek 189 1.10 mrg if (skipzero) { 190 1.10 mrg bool is_zero = true; 191 1.10 mrg 192 1.10 mrg for (i = 0; i < ncpus; i++) { 193 1.10 mrg illc = &illine->ill_cpu[i]; 194 1.10 mrg if (illc->illc_count != 0) { 195 1.10 mrg is_zero = false; 196 1.10 mrg break; 197 1.10 mrg } 198 1.10 mrg } 199 1.10 mrg if (is_zero) 200 1.10 mrg continue; 201 1.10 mrg } 202 1.10 mrg 203 1.4 jdolecek printf("%-*s ", (int)intridlen, illine->ill_intrid); 204 1.4 jdolecek if (compact) { 205 1.4 jdolecek uint64_t total = 0; 206 1.12 jmcneill bool allcpus = ncpus > 1 && 207 1.12 jmcneill intrctl_list_line_allcpus(illine, ncpus); 208 1.8 jdolecek char *affinity = NULL, *oaffinity = NULL; 209 1.4 jdolecek for (i = 0; i < ncpus; i++) { 210 1.4 jdolecek illc = &illine->ill_cpu[i]; 211 1.4 jdolecek total += illc->illc_count; 212 1.12 jmcneill if (allcpus && i != 0 && i != ncpus - 1) { 213 1.12 jmcneill continue; 214 1.12 jmcneill } 215 1.4 jdolecek if (illc->illc_assigned) { 216 1.12 jmcneill const char *sep = allcpus ? "-" : ", "; 217 1.4 jdolecek asprintf(&affinity, "%s%s%d", 218 1.4 jdolecek oaffinity ? oaffinity : "", 219 1.12 jmcneill oaffinity ? sep : "", 220 1.4 jdolecek i); 221 1.4 jdolecek if (oaffinity) 222 1.4 jdolecek free(oaffinity); 223 1.4 jdolecek oaffinity = affinity; 224 1.4 jdolecek } 225 1.4 jdolecek } 226 1.4 jdolecek printf("%20" PRIu64 " ", total); 227 1.5 jdolecek printf("%5s ", affinity ? affinity : "none"); 228 1.8 jdolecek if (affinity) 229 1.8 jdolecek free(affinity); 230 1.4 jdolecek } else { 231 1.4 jdolecek for (i = 0; i < ncpus; i++) { 232 1.4 jdolecek illc = &illine->ill_cpu[i]; 233 1.4 jdolecek printf("%*" PRIu64 "%c ", cpucol[i], illc->illc_count, 234 1.4 jdolecek illc->illc_assigned ? '*' : ' '); 235 1.4 jdolecek } 236 1.1 knakahar } 237 1.1 knakahar printf("%s\n", illine->ill_xname); 238 1.1 knakahar } 239 1.1 knakahar 240 1.3 ryo free(cpucol); 241 1.1 knakahar intrctl_io_free(handle); 242 1.1 knakahar } 243 1.1 knakahar 244 1.1 knakahar static void 245 1.9 mrg intrctl_list(int argc, char **argv) 246 1.9 mrg { 247 1.9 mrg int seconds = 0; 248 1.9 mrg bool compact = false; 249 1.10 mrg bool skipzero = false; 250 1.9 mrg int ch; 251 1.9 mrg 252 1.10 mrg while ((ch = getopt(argc, argv, "cw:z")) != -1) { 253 1.9 mrg switch (ch) { 254 1.9 mrg case 'c': 255 1.9 mrg compact = true; 256 1.9 mrg break; 257 1.10 mrg case 'z': 258 1.10 mrg skipzero = true; 259 1.10 mrg break; 260 1.9 mrg case 'w': 261 1.9 mrg seconds = atoi(optarg); 262 1.9 mrg if (seconds < 0) 263 1.9 mrg errx(1, "seconds must be positive."); 264 1.9 mrg break; 265 1.9 mrg default: 266 1.9 mrg usage(); 267 1.9 mrg } 268 1.9 mrg } 269 1.9 mrg 270 1.10 mrg for (;;) { 271 1.10 mrg intrctl_list_one(compact, skipzero); 272 1.10 mrg if (seconds == 0) 273 1.10 mrg break; 274 1.9 mrg sleep(seconds); 275 1.10 mrg } 276 1.9 mrg } 277 1.9 mrg 278 1.9 mrg static void 279 1.1 knakahar intrctl_affinity(int argc, char **argv) 280 1.1 knakahar { 281 1.1 knakahar struct intrio_set iset; 282 1.1 knakahar cpuset_t *cpuset; 283 1.1 knakahar unsigned long index; 284 1.1 knakahar int ch, error; 285 1.1 knakahar 286 1.1 knakahar index = ULONG_MAX; 287 1.1 knakahar memset(&iset.intrid, 0, sizeof(iset.intrid)); 288 1.1 knakahar 289 1.1 knakahar while ((ch = getopt(argc, argv, "c:i:")) != -1) { 290 1.1 knakahar switch (ch) { 291 1.1 knakahar case 'c': 292 1.1 knakahar index = strtoul(optarg, NULL, 10); 293 1.1 knakahar break; 294 1.1 knakahar case 'i': 295 1.1 knakahar if (strnlen(optarg, ARG_MAX) > INTRIDBUF) 296 1.1 knakahar usage(); 297 1.1 knakahar strlcpy(iset.intrid, optarg, INTRIDBUF); 298 1.1 knakahar break; 299 1.1 knakahar default: 300 1.1 knakahar usage(); 301 1.1 knakahar } 302 1.1 knakahar } 303 1.1 knakahar 304 1.1 knakahar if (iset.intrid[0] == '\0' || index == ULONG_MAX) 305 1.1 knakahar usage(); 306 1.1 knakahar 307 1.1 knakahar if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 308 1.1 knakahar err(EXIT_FAILURE, "invalid cpu index"); 309 1.1 knakahar 310 1.1 knakahar cpuset = cpuset_create(); 311 1.1 knakahar if (cpuset == NULL) 312 1.1 knakahar err(EXIT_FAILURE, "create_cpuset()"); 313 1.1 knakahar 314 1.1 knakahar cpuset_zero(cpuset); 315 1.1 knakahar cpuset_set(index, cpuset); 316 1.1 knakahar iset.cpuset = cpuset; 317 1.1 knakahar iset.cpuset_size = cpuset_size(cpuset); 318 1.1 knakahar error = sysctlbyname("kern.intr.affinity", NULL, NULL, &iset, sizeof(iset)); 319 1.1 knakahar cpuset_destroy(cpuset); 320 1.1 knakahar if (error < 0) 321 1.1 knakahar err(EXIT_FAILURE, "sysctl kern.intr.affinity"); 322 1.1 knakahar } 323 1.1 knakahar 324 1.1 knakahar static void 325 1.1 knakahar intrctl_intr(int argc, char **argv) 326 1.1 knakahar { 327 1.1 knakahar struct intrio_set iset; 328 1.1 knakahar cpuset_t *cpuset; 329 1.1 knakahar unsigned long index; 330 1.1 knakahar int ch, error; 331 1.1 knakahar 332 1.1 knakahar index = ULONG_MAX; 333 1.1 knakahar 334 1.1 knakahar while ((ch = getopt(argc, argv, "c:")) != -1) { 335 1.1 knakahar switch (ch) { 336 1.1 knakahar case 'c': 337 1.1 knakahar index = strtoul(optarg, NULL, 10); 338 1.1 knakahar break; 339 1.1 knakahar default: 340 1.1 knakahar usage(); 341 1.1 knakahar } 342 1.1 knakahar } 343 1.1 knakahar 344 1.1 knakahar if (index == ULONG_MAX) 345 1.1 knakahar usage(); 346 1.1 knakahar 347 1.1 knakahar if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 348 1.1 knakahar err(EXIT_FAILURE, "invalid cpu index"); 349 1.1 knakahar 350 1.1 knakahar cpuset = cpuset_create(); 351 1.1 knakahar if (cpuset == NULL) 352 1.1 knakahar err(EXIT_FAILURE, "create_cpuset()"); 353 1.1 knakahar 354 1.1 knakahar cpuset_zero(cpuset); 355 1.1 knakahar cpuset_set(index, cpuset); 356 1.1 knakahar iset.cpuset = cpuset; 357 1.1 knakahar iset.cpuset_size = cpuset_size(cpuset); 358 1.1 knakahar error = sysctlbyname("kern.intr.intr", NULL, NULL, &iset, sizeof(iset)); 359 1.1 knakahar cpuset_destroy(cpuset); 360 1.1 knakahar if (error < 0) 361 1.1 knakahar err(EXIT_FAILURE, "sysctl kern.intr.intr"); 362 1.1 knakahar } 363 1.1 knakahar 364 1.1 knakahar static void 365 1.1 knakahar intrctl_nointr(int argc, char **argv) 366 1.1 knakahar { 367 1.1 knakahar struct intrio_set iset; 368 1.1 knakahar cpuset_t *cpuset; 369 1.1 knakahar unsigned long index; 370 1.1 knakahar int ch, error; 371 1.1 knakahar 372 1.1 knakahar index = ULONG_MAX; 373 1.1 knakahar 374 1.1 knakahar while ((ch = getopt(argc, argv, "c:")) != -1) { 375 1.1 knakahar switch (ch) { 376 1.1 knakahar case 'c': 377 1.1 knakahar index = strtoul(optarg, NULL, 10); 378 1.1 knakahar break; 379 1.1 knakahar default: 380 1.1 knakahar usage(); 381 1.1 knakahar } 382 1.1 knakahar } 383 1.1 knakahar 384 1.1 knakahar if (index == ULONG_MAX) 385 1.1 knakahar usage(); 386 1.1 knakahar 387 1.1 knakahar if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 388 1.1 knakahar err(EXIT_FAILURE, "invalid cpu index"); 389 1.1 knakahar 390 1.1 knakahar cpuset = cpuset_create(); 391 1.1 knakahar if (cpuset == NULL) 392 1.1 knakahar err(EXIT_FAILURE, "create_cpuset()"); 393 1.1 knakahar 394 1.1 knakahar cpuset_zero(cpuset); 395 1.1 knakahar cpuset_set(index, cpuset); 396 1.1 knakahar iset.cpuset = cpuset; 397 1.1 knakahar iset.cpuset_size = cpuset_size(cpuset); 398 1.1 knakahar error = sysctlbyname("kern.intr.nointr", NULL, NULL, &iset, sizeof(iset)); 399 1.1 knakahar cpuset_destroy(cpuset); 400 1.1 knakahar if (error < 0) 401 1.1 knakahar err(EXIT_FAILURE, "sysctl kern.intr.nointr"); 402 1.1 knakahar } 403