1 /* $NetBSD: intrctl.c,v 1.2 2016/08/03 08:34:21 knakahara Exp $ */ 2 3 /* 4 * Copyright (c) 2015 Internet Initiative Japan Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __RCSID("$NetBSD: intrctl.c,v 1.2 2016/08/03 08:34:21 knakahara Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/sysctl.h> 34 #include <sys/intrio.h> 35 #include <sys/types.h> 36 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <limits.h> 41 #include <paths.h> 42 #include <sched.h> 43 #include <stdint.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "intrctl_io.h" 50 51 __dead static void usage(void); 52 53 int verbose; 54 55 static void intrctl_list(int, char **); 56 static void intrctl_affinity(int, char **); 57 static void intrctl_intr(int, char **); 58 static void intrctl_nointr(int, char **); 59 60 static struct cmdtab { 61 const char *label; 62 void (*func)(int, char **); 63 } const intrctl_cmdtab[] = { 64 { "list", intrctl_list }, 65 { "affinity", intrctl_affinity }, 66 { "intr", intrctl_intr }, 67 { "nointr", intrctl_nointr }, 68 { NULL, NULL }, 69 }; 70 71 int 72 main(int argc, char **argv) 73 { 74 const struct cmdtab *ct; 75 char *cmdname; 76 77 if (argc < 2) 78 usage(); 79 80 cmdname = argv[1]; 81 argv += 1; 82 argc -= 1; 83 84 for (ct = intrctl_cmdtab; ct->label != NULL; ct++) { 85 if (strcmp(cmdname, ct->label) == 0) { 86 break; 87 } 88 } 89 if (ct->label == NULL) 90 errx(EXIT_FAILURE, "unknown command ``%s''", cmdname); 91 92 (*ct->func)(argc, argv); 93 exit(EXIT_SUCCESS); 94 /* NOTREACHED */ 95 } 96 97 static void 98 usage(void) 99 { 100 const char *progname = getprogname(); 101 102 fprintf(stderr, "usage: %s list\n", progname); 103 fprintf(stderr, " %s affinity -i interrupt_name -c cpu_index\n", progname); 104 fprintf(stderr, " %s intr -c cpu_index\n", progname); 105 fprintf(stderr, " %s nointr -c cpu_index\n", progname); 106 exit(EXIT_FAILURE); 107 /* NOTREACHED */ 108 } 109 110 static int intrctl_io_alloc_retry_count = 4; 111 112 static void 113 intrctl_list(int argc, char **argv) 114 { 115 struct intrio_list_line *illine; 116 int i, ncpus; 117 void *handle; 118 size_t intridlen; 119 120 handle = intrctl_io_alloc(intrctl_io_alloc_retry_count); 121 if (handle == NULL) 122 err(EXIT_FAILURE, "intrctl_io_alloc"); 123 124 /* calc columns */ 125 ncpus = intrctl_io_ncpus(handle); 126 intridlen = strlen("interrupt id"); 127 illine = intrctl_io_firstline(handle); 128 for (; illine != NULL; illine = intrctl_io_nextline(handle, illine)) { 129 size_t len = strlen(illine->ill_intrid); 130 if (intridlen < len) 131 intridlen = len; 132 } 133 134 /* header */ 135 printf("%-*s", (int)intridlen, "interrupt id"); 136 for (i = 0; i < ncpus; i++) { 137 char buf[64]; 138 snprintf(buf, sizeof(buf), "CPU%u", i); 139 printf(" %20s ", buf); 140 } 141 printf(" device name(s)\n"); 142 143 /* body */ 144 illine = intrctl_io_firstline(handle); 145 for (; illine != NULL; illine = intrctl_io_nextline(handle, illine)) { 146 printf("%-*s ", (int)intridlen, illine->ill_intrid); 147 for (i = 0; i < ncpus; i++) { 148 struct intrio_list_line_cpu *illc = &illine->ill_cpu[i]; 149 printf("%20" PRIu64 "%c ", illc->illc_count, 150 illc->illc_assigned ? '*' : ' '); 151 } 152 printf("%s\n", illine->ill_xname); 153 } 154 155 intrctl_io_free(handle); 156 } 157 158 static void 159 intrctl_affinity(int argc, char **argv) 160 { 161 struct intrio_set iset; 162 cpuset_t *cpuset; 163 unsigned long index; 164 int ch, error; 165 166 index = ULONG_MAX; 167 memset(&iset.intrid, 0, sizeof(iset.intrid)); 168 169 while ((ch = getopt(argc, argv, "c:i:")) != -1) { 170 switch (ch) { 171 case 'c': 172 index = strtoul(optarg, NULL, 10); 173 break; 174 case 'i': 175 if (strnlen(optarg, ARG_MAX) > INTRIDBUF) 176 usage(); 177 strlcpy(iset.intrid, optarg, INTRIDBUF); 178 break; 179 default: 180 usage(); 181 } 182 } 183 184 if (iset.intrid[0] == '\0' || index == ULONG_MAX) 185 usage(); 186 187 if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 188 err(EXIT_FAILURE, "invalid cpu index"); 189 190 cpuset = cpuset_create(); 191 if (cpuset == NULL) 192 err(EXIT_FAILURE, "create_cpuset()"); 193 194 cpuset_zero(cpuset); 195 cpuset_set(index, cpuset); 196 iset.cpuset = cpuset; 197 iset.cpuset_size = cpuset_size(cpuset); 198 error = sysctlbyname("kern.intr.affinity", NULL, NULL, &iset, sizeof(iset)); 199 cpuset_destroy(cpuset); 200 if (error < 0) 201 err(EXIT_FAILURE, "sysctl kern.intr.affinity"); 202 } 203 204 static void 205 intrctl_intr(int argc, char **argv) 206 { 207 struct intrio_set iset; 208 cpuset_t *cpuset; 209 unsigned long index; 210 int ch, error; 211 212 index = ULONG_MAX; 213 214 while ((ch = getopt(argc, argv, "c:")) != -1) { 215 switch (ch) { 216 case 'c': 217 index = strtoul(optarg, NULL, 10); 218 break; 219 default: 220 usage(); 221 } 222 } 223 224 if (index == ULONG_MAX) 225 usage(); 226 227 if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 228 err(EXIT_FAILURE, "invalid cpu index"); 229 230 cpuset = cpuset_create(); 231 if (cpuset == NULL) 232 err(EXIT_FAILURE, "create_cpuset()"); 233 234 cpuset_zero(cpuset); 235 cpuset_set(index, cpuset); 236 iset.cpuset = cpuset; 237 iset.cpuset_size = cpuset_size(cpuset); 238 error = sysctlbyname("kern.intr.intr", NULL, NULL, &iset, sizeof(iset)); 239 cpuset_destroy(cpuset); 240 if (error < 0) 241 err(EXIT_FAILURE, "sysctl kern.intr.intr"); 242 } 243 244 static void 245 intrctl_nointr(int argc, char **argv) 246 { 247 struct intrio_set iset; 248 cpuset_t *cpuset; 249 unsigned long index; 250 int ch, error; 251 252 index = ULONG_MAX; 253 254 while ((ch = getopt(argc, argv, "c:")) != -1) { 255 switch (ch) { 256 case 'c': 257 index = strtoul(optarg, NULL, 10); 258 break; 259 default: 260 usage(); 261 } 262 } 263 264 if (index == ULONG_MAX) 265 usage(); 266 267 if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 268 err(EXIT_FAILURE, "invalid cpu index"); 269 270 cpuset = cpuset_create(); 271 if (cpuset == NULL) 272 err(EXIT_FAILURE, "create_cpuset()"); 273 274 cpuset_zero(cpuset); 275 cpuset_set(index, cpuset); 276 iset.cpuset = cpuset; 277 iset.cpuset_size = cpuset_size(cpuset); 278 error = sysctlbyname("kern.intr.nointr", NULL, NULL, &iset, sizeof(iset)); 279 cpuset_destroy(cpuset); 280 if (error < 0) 281 err(EXIT_FAILURE, "sysctl kern.intr.nointr"); 282 } 283