1 /* $NetBSD: intrctl.c,v 1.1 2015/08/17 06:42:46 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.1 2015/08/17 06:42:46 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 119 handle = intrctl_io_alloc(intrctl_io_alloc_retry_count); 120 if (handle == NULL) 121 err(EXIT_FAILURE, "intrctl_io_alloc"); 122 123 /* header */ 124 ncpus = intrctl_io_ncpus(handle); 125 printf("interrupt id\t"); 126 for (i = 0; i < ncpus; i++) { 127 printf(" CPU#%02u\t", i); 128 } 129 printf("device name(s)\n"); 130 131 /* body */ 132 illine = intrctl_io_firstline(handle); 133 for (; illine != NULL; illine = intrctl_io_nextline(handle, illine)) { 134 printf("%s\t", illine->ill_intrid); 135 for (i = 0; i < ncpus; i++) { 136 struct intrio_list_line_cpu *illc = &illine->ill_cpu[i]; 137 printf("%8" PRIu64 "%c\t", illc->illc_count, 138 illc->illc_assigned ? '*' : ' '); 139 } 140 141 printf("%s\n", illine->ill_xname); 142 } 143 144 intrctl_io_free(handle); 145 } 146 147 static void 148 intrctl_affinity(int argc, char **argv) 149 { 150 struct intrio_set iset; 151 cpuset_t *cpuset; 152 unsigned long index; 153 int ch, error; 154 155 index = ULONG_MAX; 156 memset(&iset.intrid, 0, sizeof(iset.intrid)); 157 158 while ((ch = getopt(argc, argv, "c:i:")) != -1) { 159 switch (ch) { 160 case 'c': 161 index = strtoul(optarg, NULL, 10); 162 break; 163 case 'i': 164 if (strnlen(optarg, ARG_MAX) > INTRIDBUF) 165 usage(); 166 strlcpy(iset.intrid, optarg, INTRIDBUF); 167 break; 168 default: 169 usage(); 170 } 171 } 172 173 if (iset.intrid[0] == '\0' || index == ULONG_MAX) 174 usage(); 175 176 if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 177 err(EXIT_FAILURE, "invalid cpu index"); 178 179 cpuset = cpuset_create(); 180 if (cpuset == NULL) 181 err(EXIT_FAILURE, "create_cpuset()"); 182 183 cpuset_zero(cpuset); 184 cpuset_set(index, cpuset); 185 iset.cpuset = cpuset; 186 iset.cpuset_size = cpuset_size(cpuset); 187 error = sysctlbyname("kern.intr.affinity", NULL, NULL, &iset, sizeof(iset)); 188 cpuset_destroy(cpuset); 189 if (error < 0) 190 err(EXIT_FAILURE, "sysctl kern.intr.affinity"); 191 } 192 193 static void 194 intrctl_intr(int argc, char **argv) 195 { 196 struct intrio_set iset; 197 cpuset_t *cpuset; 198 unsigned long index; 199 int ch, error; 200 201 index = ULONG_MAX; 202 203 while ((ch = getopt(argc, argv, "c:")) != -1) { 204 switch (ch) { 205 case 'c': 206 index = strtoul(optarg, NULL, 10); 207 break; 208 default: 209 usage(); 210 } 211 } 212 213 if (index == ULONG_MAX) 214 usage(); 215 216 if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 217 err(EXIT_FAILURE, "invalid cpu index"); 218 219 cpuset = cpuset_create(); 220 if (cpuset == NULL) 221 err(EXIT_FAILURE, "create_cpuset()"); 222 223 cpuset_zero(cpuset); 224 cpuset_set(index, cpuset); 225 iset.cpuset = cpuset; 226 iset.cpuset_size = cpuset_size(cpuset); 227 error = sysctlbyname("kern.intr.intr", NULL, NULL, &iset, sizeof(iset)); 228 cpuset_destroy(cpuset); 229 if (error < 0) 230 err(EXIT_FAILURE, "sysctl kern.intr.intr"); 231 } 232 233 static void 234 intrctl_nointr(int argc, char **argv) 235 { 236 struct intrio_set iset; 237 cpuset_t *cpuset; 238 unsigned long index; 239 int ch, error; 240 241 index = ULONG_MAX; 242 243 while ((ch = getopt(argc, argv, "c:")) != -1) { 244 switch (ch) { 245 case 'c': 246 index = strtoul(optarg, NULL, 10); 247 break; 248 default: 249 usage(); 250 } 251 } 252 253 if (index == ULONG_MAX) 254 usage(); 255 256 if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF)) 257 err(EXIT_FAILURE, "invalid cpu index"); 258 259 cpuset = cpuset_create(); 260 if (cpuset == NULL) 261 err(EXIT_FAILURE, "create_cpuset()"); 262 263 cpuset_zero(cpuset); 264 cpuset_set(index, cpuset); 265 iset.cpuset = cpuset; 266 iset.cpuset_size = cpuset_size(cpuset); 267 error = sysctlbyname("kern.intr.nointr", NULL, NULL, &iset, sizeof(iset)); 268 cpuset_destroy(cpuset); 269 if (error < 0) 270 err(EXIT_FAILURE, "sysctl kern.intr.nointr"); 271 } 272