xref: /netbsd-src/usr.sbin/intrctl/intrctl.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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