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