1 /* $NetBSD: cpuctl.c,v 1.15 2009/04/23 01:36:56 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Andrew Doran. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef lint 33 #include <sys/cdefs.h> 34 __RCSID("$NetBSD: cpuctl.c,v 1.15 2009/04/23 01:36:56 lukem Exp $"); 35 #endif /* not lint */ 36 37 #include <sys/param.h> 38 #include <sys/ioctl.h> 39 #include <sys/uio.h> 40 #include <sys/cpuio.h> 41 42 #include <err.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <stdarg.h> 48 #include <string.h> 49 #include <unistd.h> 50 #include <util.h> 51 #include <time.h> 52 #include <sched.h> 53 54 #include "cpuctl.h" 55 56 u_int getcpuid(char **); 57 int main(int, char **); 58 void usage(void); 59 60 void cpu_identify(char **); 61 void cpu_list(char **); 62 void cpu_offline(char **); 63 void cpu_online(char **); 64 void cpu_intr(char **); 65 void cpu_nointr(char **); 66 67 struct cmdtab { 68 const char *label; 69 int takesargs; 70 void (*func)(char **); 71 } const cpu_cmdtab[] = { 72 { "identify", 1, cpu_identify }, 73 { "list", 0, cpu_list }, 74 { "offline", 1, cpu_offline }, 75 { "online", 1, cpu_online }, 76 { "intr", 1, cpu_intr }, 77 { "nointr", 1, cpu_nointr }, 78 { NULL, 0, NULL }, 79 }; 80 81 int fd; 82 83 int 84 main(int argc, char **argv) 85 { 86 const struct cmdtab *ct; 87 88 if (argc < 2) 89 usage(); 90 91 if ((fd = open("/dev/cpuctl", O_RDWR)) < 0) 92 err(EXIT_FAILURE, "/dev/cpuctl"); 93 94 for (ct = cpu_cmdtab; ct->label != NULL; ct++) { 95 if (strcmp(argv[1], ct->label) == 0) { 96 if ((ct->takesargs == 0) ^ (argv[2] == NULL)) 97 usage(); 98 (*ct->func)(argv + 2); 99 break; 100 } 101 } 102 103 if (ct->label == NULL) 104 errx(EXIT_FAILURE, "unknown command ``%s''", argv[optind]); 105 106 close(fd); 107 exit(EXIT_SUCCESS); 108 /* NOTREACHED */ 109 } 110 111 void 112 usage(void) 113 { 114 const char *progname = getprogname(); 115 116 fprintf(stderr, "usage: %s identify cpuno\n", progname); 117 fprintf(stderr, " %s list\n", progname); 118 fprintf(stderr, " %s offline cpuno\n", progname); 119 fprintf(stderr, " %s online cpuno\n", progname); 120 fprintf(stderr, " %s intr cpuno\n", progname); 121 fprintf(stderr, " %s nointr cpuno\n", progname); 122 exit(EXIT_FAILURE); 123 /* NOTREACHED */ 124 } 125 126 void 127 cpu_online(char **argv) 128 { 129 cpustate_t cs; 130 131 cs.cs_id = getcpuid(argv); 132 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 133 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 134 cs.cs_online = true; 135 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) 136 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 137 } 138 139 void 140 cpu_offline(char **argv) 141 { 142 cpustate_t cs; 143 144 cs.cs_id = getcpuid(argv); 145 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 146 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 147 cs.cs_online = false; 148 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) 149 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 150 } 151 152 void 153 cpu_intr(char **argv) 154 { 155 cpustate_t cs; 156 157 cs.cs_id = getcpuid(argv); 158 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 159 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 160 cs.cs_intr = true; 161 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) 162 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 163 } 164 165 void 166 cpu_nointr(char **argv) 167 { 168 cpustate_t cs; 169 170 cs.cs_id = getcpuid(argv); 171 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 172 err(EXIT_FAILURE, "IOC_CPU_GETSTATE"); 173 cs.cs_intr = false; 174 if (ioctl(fd, IOC_CPU_SETSTATE, &cs) < 0) { 175 if (errno == EOPNOTSUPP) { 176 warnx("interrupt control not supported on " 177 "this platform"); 178 } else 179 err(EXIT_FAILURE, "IOC_CPU_SETSTATE"); 180 } 181 } 182 183 void 184 cpu_identify(char **argv) 185 { 186 char name[32]; 187 unsigned int id, np; 188 cpuset_t *cpuset; 189 190 np = sysconf(_SC_NPROCESSORS_CONF); 191 id = getcpuid(argv); 192 snprintf(name, sizeof(name), "cpu%u", id); 193 194 if (np != 0) { 195 cpuset = cpuset_create(); 196 if (cpuset == NULL) 197 err(EXIT_FAILURE, "cpuset_create"); 198 cpuset_zero(cpuset); 199 cpuset_set(id, cpuset); 200 if (_sched_setaffinity(0, 0, cpuset_size(cpuset), cpuset) < 0) { 201 if (errno == EPERM) { 202 printf("Cannot bind to target CPU. Output " 203 "may not accurately describe the target.\n" 204 "Run as root to allow binding.\n\n"); 205 } else { 206 err(EXIT_FAILURE, "_sched_setaffinity"); 207 } 208 } 209 cpuset_destroy(cpuset); 210 } 211 identifycpu(name); 212 } 213 214 u_int 215 getcpuid(char **argv) 216 { 217 char *argp; 218 u_int id; 219 long np; 220 221 id = (u_int)strtoul(argv[0], &argp, 0); 222 if (*argp != '\0') 223 usage(); 224 225 np = sysconf(_SC_NPROCESSORS_CONF); 226 if (id >= (u_long)np) 227 errx(EXIT_FAILURE, "Invalid CPU number"); 228 229 return id; 230 } 231 232 void 233 cpu_list(char **argv) 234 { 235 const char *state, *intr; 236 cpustate_t cs; 237 u_int cnt, i; 238 time_t lastmod; 239 char ibuf[16], *ts; 240 241 if (ioctl(fd, IOC_CPU_GETCOUNT, &cnt) < 0) 242 err(EXIT_FAILURE, "IOC_CPU_GETCOUNT"); 243 244 printf( 245 "Num HwId Unbound LWPs Interrupts Last change #Intr\n" 246 "---- ---- ------------ ---------- ------------------------ -----\n"); 247 248 for (i = 0; i < cnt; i++) { 249 cs.cs_id = i; 250 if (ioctl(fd, IOC_CPU_GETSTATE, &cs) < 0) 251 err(EXIT_FAILURE, "IOC_CPU_GETINFO"); 252 if (ioctl(fd, IOC_CPU_MAPID, &cs.cs_id) < 0) 253 err(EXIT_FAILURE, "IOC_CPU_MAPID"); 254 if (cs.cs_online) 255 state = "online"; 256 else 257 state = "offline"; 258 if (cs.cs_intr) 259 intr = "intr"; 260 else 261 intr = "nointr"; 262 if (cs.cs_intrcnt == 0) 263 strcpy(ibuf, "?"); 264 else 265 snprintf(ibuf, sizeof(ibuf), "%d", cs.cs_intrcnt - 1); 266 lastmod = (time_t)cs.cs_lastmod | 267 ((time_t)cs.cs_lastmodhi << 32); 268 ts = asctime(localtime(&lastmod)); 269 ts[strlen(ts) - 1] = '\0'; 270 printf("%-4d %-4x %-12s %-10s %s %s\n", i, cs.cs_id, state, 271 intr, ts, ibuf); 272 } 273 } 274 275 int 276 aprint_normal(const char *fmt, ...) 277 { 278 va_list ap; 279 int rv; 280 281 va_start(ap, fmt); 282 rv = vfprintf(stdout, fmt, ap); 283 va_end(ap); 284 285 return rv; 286 } 287 __strong_alias(aprint_verbose,aprint_normal) 288 __strong_alias(aprint_error,aprint_normal) 289 290 int 291 aprint_normal_dev(const char *dev, const char *fmt, ...) 292 { 293 va_list ap; 294 int rv; 295 296 printf("%s: ", dev); 297 va_start(ap, fmt); 298 rv = vfprintf(stdout, fmt, ap); 299 va_end(ap); 300 301 return rv; 302 } 303 __strong_alias(aprint_verbose_dev,aprint_normal_dev) 304 __strong_alias(aprint_error_dev,aprint_normal_dev) 305