Home | History | Annotate | Line # | Download | only in intrctl
      1  1.12  jmcneill /*	$NetBSD: intrctl.c,v 1.12 2021/02/22 11:33:34 jmcneill Exp $	*/
      2   1.1  knakahar 
      3   1.1  knakahar /*
      4   1.1  knakahar  * Copyright (c) 2015 Internet Initiative Japan Inc.
      5   1.1  knakahar  * All rights reserved.
      6   1.1  knakahar  *
      7   1.1  knakahar  * Redistribution and use in source and binary forms, with or without
      8   1.1  knakahar  * modification, are permitted provided that the following conditions
      9   1.1  knakahar  * are met:
     10   1.1  knakahar  * 1. Redistributions of source code must retain the above copyright
     11   1.1  knakahar  *    notice, this list of conditions and the following disclaimer.
     12   1.1  knakahar  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1  knakahar  *    notice, this list of conditions and the following disclaimer in the
     14   1.1  knakahar  *    documentation and/or other materials provided with the distribution.
     15   1.1  knakahar  *
     16   1.1  knakahar  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17   1.1  knakahar  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18   1.1  knakahar  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19   1.1  knakahar  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20   1.1  knakahar  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21   1.1  knakahar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22   1.1  knakahar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23   1.1  knakahar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24   1.1  knakahar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25   1.1  knakahar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26   1.1  knakahar  * POSSIBILITY OF SUCH DAMAGE.
     27   1.1  knakahar  */
     28   1.1  knakahar 
     29   1.1  knakahar #include <sys/cdefs.h>
     30  1.12  jmcneill __RCSID("$NetBSD: intrctl.c,v 1.12 2021/02/22 11:33:34 jmcneill Exp $");
     31   1.1  knakahar 
     32   1.1  knakahar #include <sys/param.h>
     33   1.1  knakahar #include <sys/sysctl.h>
     34   1.1  knakahar #include <sys/intrio.h>
     35   1.1  knakahar #include <sys/types.h>
     36   1.1  knakahar 
     37   1.1  knakahar #include <err.h>
     38   1.1  knakahar #include <errno.h>
     39   1.1  knakahar #include <fcntl.h>
     40   1.1  knakahar #include <limits.h>
     41   1.1  knakahar #include <paths.h>
     42   1.1  knakahar #include <sched.h>
     43   1.1  knakahar #include <stdint.h>
     44   1.1  knakahar #include <stdio.h>
     45   1.1  knakahar #include <stdlib.h>
     46   1.1  knakahar #include <string.h>
     47   1.1  knakahar #include <unistd.h>
     48   1.1  knakahar 
     49   1.1  knakahar #include "intrctl_io.h"
     50   1.1  knakahar 
     51   1.1  knakahar __dead static void	usage(void);
     52   1.1  knakahar 
     53   1.1  knakahar int		verbose;
     54   1.1  knakahar 
     55   1.1  knakahar static void	intrctl_list(int, char **);
     56   1.1  knakahar static void	intrctl_affinity(int, char **);
     57   1.1  knakahar static void	intrctl_intr(int, char **);
     58   1.1  knakahar static void	intrctl_nointr(int, char **);
     59   1.1  knakahar 
     60   1.1  knakahar static struct cmdtab {
     61   1.1  knakahar 	const char	*label;
     62   1.1  knakahar 	void	(*func)(int, char **);
     63   1.1  knakahar } const intrctl_cmdtab[] = {
     64   1.1  knakahar 	{ "list", intrctl_list },
     65   1.1  knakahar 	{ "affinity", intrctl_affinity },
     66   1.1  knakahar 	{ "intr", intrctl_intr },
     67   1.1  knakahar 	{ "nointr", intrctl_nointr },
     68   1.1  knakahar 	{ NULL, NULL },
     69   1.1  knakahar };
     70   1.1  knakahar 
     71   1.1  knakahar int
     72   1.1  knakahar main(int argc, char **argv)
     73   1.1  knakahar {
     74   1.1  knakahar 	const struct cmdtab *ct;
     75   1.1  knakahar 	char *cmdname;
     76   1.1  knakahar 
     77   1.1  knakahar 	if (argc < 2)
     78   1.1  knakahar 		usage();
     79   1.1  knakahar 
     80   1.1  knakahar 	cmdname = argv[1];
     81   1.1  knakahar 	argv += 1;
     82   1.1  knakahar 	argc -= 1;
     83   1.1  knakahar 
     84   1.1  knakahar 	for (ct = intrctl_cmdtab; ct->label != NULL; ct++) {
     85   1.1  knakahar 		if (strcmp(cmdname, ct->label) == 0) {
     86   1.1  knakahar 			break;
     87   1.1  knakahar 		}
     88   1.1  knakahar 	}
     89   1.1  knakahar 	if (ct->label == NULL)
     90   1.1  knakahar 		errx(EXIT_FAILURE, "unknown command ``%s''", cmdname);
     91   1.1  knakahar 
     92   1.1  knakahar 	(*ct->func)(argc, argv);
     93   1.1  knakahar 	exit(EXIT_SUCCESS);
     94   1.1  knakahar 	/* NOTREACHED */
     95   1.1  knakahar }
     96   1.1  knakahar 
     97   1.1  knakahar static void
     98   1.1  knakahar usage(void)
     99   1.1  knakahar {
    100   1.1  knakahar 	const char *progname = getprogname();
    101   1.1  knakahar 
    102  1.11       wiz 	fprintf(stderr, "usage: %s list [-cz] [-w secs]\n", progname);
    103  1.10       mrg 	fprintf(stderr, "       %s affinity -i interrupt_name -c cpu_index\n",
    104  1.10       mrg 	    progname);
    105   1.1  knakahar 	fprintf(stderr, "       %s intr -c cpu_index\n", progname);
    106   1.1  knakahar 	fprintf(stderr, "       %s nointr -c cpu_index\n", progname);
    107   1.1  knakahar 	exit(EXIT_FAILURE);
    108   1.1  knakahar 	/* NOTREACHED */
    109   1.1  knakahar }
    110   1.1  knakahar 
    111   1.1  knakahar static int intrctl_io_alloc_retry_count = 4;
    112   1.1  knakahar 
    113  1.12  jmcneill static bool
    114  1.12  jmcneill intrctl_list_line_allcpus(struct intrio_list_line *illine, int ncpus)
    115  1.12  jmcneill {
    116  1.12  jmcneill 	struct intrio_list_line_cpu *illc;
    117  1.12  jmcneill 	int i;
    118  1.12  jmcneill 
    119  1.12  jmcneill 	for (i = 0; i < ncpus; i++) {
    120  1.12  jmcneill 		illc = &illine->ill_cpu[i];
    121  1.12  jmcneill 		if (illc->illc_assigned == false) {
    122  1.12  jmcneill 			return false;
    123  1.12  jmcneill 		}
    124  1.12  jmcneill 	}
    125  1.12  jmcneill 
    126  1.12  jmcneill 	return true;
    127  1.12  jmcneill }
    128  1.12  jmcneill 
    129   1.1  knakahar static void
    130  1.10       mrg intrctl_list_one(bool compact, bool skipzero)
    131   1.1  knakahar {
    132   1.3       ryo 	char buf[64];
    133   1.1  knakahar 	struct intrio_list_line *illine;
    134   1.3       ryo 	int i, ncpus, *cpucol;
    135   1.1  knakahar 	void *handle;
    136   1.2  knakahar 	size_t intridlen;
    137   1.1  knakahar 
    138   1.1  knakahar 	handle = intrctl_io_alloc(intrctl_io_alloc_retry_count);
    139   1.1  knakahar 	if (handle == NULL)
    140   1.1  knakahar 		err(EXIT_FAILURE, "intrctl_io_alloc");
    141   1.1  knakahar 
    142   1.2  knakahar 	/* calc columns */
    143   1.2  knakahar 	ncpus = intrctl_io_ncpus(handle);
    144   1.2  knakahar 	intridlen = strlen("interrupt id");
    145   1.3       ryo 	for (illine = intrctl_io_firstline(handle); illine != NULL;
    146   1.3       ryo 	    illine = intrctl_io_nextline(handle, illine)) {
    147   1.2  knakahar 		size_t len = strlen(illine->ill_intrid);
    148   1.2  knakahar 		if (intridlen < len)
    149   1.2  knakahar 			intridlen = len;
    150   1.2  knakahar 	}
    151   1.2  knakahar 
    152   1.3       ryo 	cpucol = malloc(sizeof(*cpucol) * (size_t)ncpus);
    153   1.3       ryo 	if (cpucol == NULL)
    154   1.3       ryo 		err(EXIT_FAILURE, "malloc");
    155   1.3       ryo 	for (i = 0; i < ncpus; i++) {
    156   1.3       ryo 		snprintf(buf, sizeof(buf), "CPU%u", i);
    157   1.3       ryo 		cpucol[i] = strlen(buf);
    158   1.3       ryo 	}
    159   1.3       ryo 	for (illine = intrctl_io_firstline(handle); illine != NULL;
    160   1.3       ryo 	    illine = intrctl_io_nextline(handle, illine)) {
    161   1.3       ryo 		for (i = 0; i < ncpus; i++) {
    162   1.3       ryo 			int len;
    163   1.3       ryo 			snprintf(buf, sizeof(buf), "%" PRIu64,
    164   1.3       ryo 			    illine->ill_cpu[i].illc_count);
    165   1.3       ryo 			len = (int)strlen(buf);
    166   1.3       ryo 			if (cpucol[i] < len)
    167   1.3       ryo 				cpucol[i] = len;
    168   1.3       ryo 		}
    169   1.3       ryo 	}
    170   1.3       ryo 
    171   1.1  knakahar 	/* header */
    172   1.7       ryo 	printf("%-*s ", (int)intridlen, "interrupt id");
    173   1.4  jdolecek 	if (compact) {
    174   1.7       ryo 		printf("%20s ", "total");
    175   1.7       ryo 		printf("%5s ", "aff");
    176   1.4  jdolecek 	} else {
    177   1.4  jdolecek 		for (i = 0; i < ncpus; i++) {
    178   1.4  jdolecek 			snprintf(buf, sizeof(buf), "CPU%u", i);
    179   1.4  jdolecek 			printf("%*s  ", cpucol[i], buf);
    180   1.4  jdolecek 		}
    181   1.1  knakahar 	}
    182   1.3       ryo 	printf("device name(s)\n");
    183   1.1  knakahar 
    184   1.1  knakahar 	/* body */
    185   1.3       ryo 	for (illine = intrctl_io_firstline(handle); illine != NULL;
    186   1.3       ryo 	    illine = intrctl_io_nextline(handle, illine)) {
    187   1.4  jdolecek 		struct intrio_list_line_cpu *illc;
    188   1.4  jdolecek 
    189  1.10       mrg 		if (skipzero) {
    190  1.10       mrg 			bool is_zero = true;
    191  1.10       mrg 
    192  1.10       mrg 			for (i = 0; i < ncpus; i++) {
    193  1.10       mrg 				illc = &illine->ill_cpu[i];
    194  1.10       mrg 				if (illc->illc_count != 0) {
    195  1.10       mrg 					is_zero = false;
    196  1.10       mrg 					break;
    197  1.10       mrg 				}
    198  1.10       mrg 			}
    199  1.10       mrg 			if (is_zero)
    200  1.10       mrg 				continue;
    201  1.10       mrg 		}
    202  1.10       mrg 
    203   1.4  jdolecek 		printf("%-*s ", (int)intridlen, illine->ill_intrid);
    204   1.4  jdolecek 		if (compact) {
    205   1.4  jdolecek 			uint64_t total = 0;
    206  1.12  jmcneill 			bool allcpus = ncpus > 1 &&
    207  1.12  jmcneill 			    intrctl_list_line_allcpus(illine, ncpus);
    208   1.8  jdolecek 			char *affinity = NULL, *oaffinity = NULL;
    209   1.4  jdolecek 			for (i = 0; i < ncpus; i++) {
    210   1.4  jdolecek 				illc = &illine->ill_cpu[i];
    211   1.4  jdolecek 				total += illc->illc_count;
    212  1.12  jmcneill 				if (allcpus && i != 0 && i != ncpus - 1) {
    213  1.12  jmcneill 					continue;
    214  1.12  jmcneill 				}
    215   1.4  jdolecek 				if (illc->illc_assigned) {
    216  1.12  jmcneill 					const char *sep = allcpus ? "-" : ", ";
    217   1.4  jdolecek 					asprintf(&affinity, "%s%s%d",
    218   1.4  jdolecek 					    oaffinity ? oaffinity : "",
    219  1.12  jmcneill 					    oaffinity ? sep : "",
    220   1.4  jdolecek 					    i);
    221   1.4  jdolecek 					if (oaffinity)
    222   1.4  jdolecek 						free(oaffinity);
    223   1.4  jdolecek 					oaffinity = affinity;
    224   1.4  jdolecek 				}
    225   1.4  jdolecek 			}
    226   1.4  jdolecek 			printf("%20" PRIu64 " ", total);
    227   1.5  jdolecek 			printf("%5s ", affinity ? affinity : "none");
    228   1.8  jdolecek 			if (affinity)
    229   1.8  jdolecek 				free(affinity);
    230   1.4  jdolecek 		} else {
    231   1.4  jdolecek 			for (i = 0; i < ncpus; i++) {
    232   1.4  jdolecek 				illc = &illine->ill_cpu[i];
    233   1.4  jdolecek 				printf("%*" PRIu64 "%c ", cpucol[i], illc->illc_count,
    234   1.4  jdolecek 				    illc->illc_assigned ? '*' : ' ');
    235   1.4  jdolecek 			}
    236   1.1  knakahar 		}
    237   1.1  knakahar 		printf("%s\n", illine->ill_xname);
    238   1.1  knakahar 	}
    239   1.1  knakahar 
    240   1.3       ryo 	free(cpucol);
    241   1.1  knakahar 	intrctl_io_free(handle);
    242   1.1  knakahar }
    243   1.1  knakahar 
    244   1.1  knakahar static void
    245   1.9       mrg intrctl_list(int argc, char **argv)
    246   1.9       mrg {
    247   1.9       mrg 	int seconds = 0;
    248   1.9       mrg 	bool compact = false;
    249  1.10       mrg 	bool skipzero = false;
    250   1.9       mrg 	int ch;
    251   1.9       mrg 
    252  1.10       mrg 	while ((ch = getopt(argc, argv, "cw:z")) != -1) {
    253   1.9       mrg 		switch (ch) {
    254   1.9       mrg 		case 'c':
    255   1.9       mrg 			compact = true;
    256   1.9       mrg 			break;
    257  1.10       mrg 		case 'z':
    258  1.10       mrg 			skipzero = true;
    259  1.10       mrg 			break;
    260   1.9       mrg 		case 'w':
    261   1.9       mrg 			seconds = atoi(optarg);
    262   1.9       mrg 			if (seconds < 0)
    263   1.9       mrg 				errx(1, "seconds must be positive.");
    264   1.9       mrg 			break;
    265   1.9       mrg 		default:
    266   1.9       mrg 			usage();
    267   1.9       mrg 		}
    268   1.9       mrg 	}
    269   1.9       mrg 
    270  1.10       mrg 	for (;;) {
    271  1.10       mrg 		intrctl_list_one(compact, skipzero);
    272  1.10       mrg 		if (seconds == 0)
    273  1.10       mrg 			break;
    274   1.9       mrg 		sleep(seconds);
    275  1.10       mrg 	}
    276   1.9       mrg }
    277   1.9       mrg 
    278   1.9       mrg static void
    279   1.1  knakahar intrctl_affinity(int argc, char **argv)
    280   1.1  knakahar {
    281   1.1  knakahar 	struct intrio_set iset;
    282   1.1  knakahar 	cpuset_t *cpuset;
    283   1.1  knakahar 	unsigned long index;
    284   1.1  knakahar 	int ch, error;
    285   1.1  knakahar 
    286   1.1  knakahar 	index = ULONG_MAX;
    287   1.1  knakahar 	memset(&iset.intrid, 0, sizeof(iset.intrid));
    288   1.1  knakahar 
    289   1.1  knakahar 	while ((ch = getopt(argc, argv, "c:i:")) != -1) {
    290   1.1  knakahar 		switch (ch) {
    291   1.1  knakahar 		case 'c':
    292   1.1  knakahar 			index = strtoul(optarg, NULL, 10);
    293   1.1  knakahar 			break;
    294   1.1  knakahar 		case 'i':
    295   1.1  knakahar 			if (strnlen(optarg, ARG_MAX) > INTRIDBUF)
    296   1.1  knakahar 				usage();
    297   1.1  knakahar 			strlcpy(iset.intrid, optarg, INTRIDBUF);
    298   1.1  knakahar 			break;
    299   1.1  knakahar 		default:
    300   1.1  knakahar 			usage();
    301   1.1  knakahar 		}
    302   1.1  knakahar 	}
    303   1.1  knakahar 
    304   1.1  knakahar 	if (iset.intrid[0] == '\0' || index == ULONG_MAX)
    305   1.1  knakahar 		usage();
    306   1.1  knakahar 
    307   1.1  knakahar 	if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF))
    308   1.1  knakahar 		err(EXIT_FAILURE, "invalid cpu index");
    309   1.1  knakahar 
    310   1.1  knakahar 	cpuset = cpuset_create();
    311   1.1  knakahar 	if (cpuset == NULL)
    312   1.1  knakahar 		err(EXIT_FAILURE, "create_cpuset()");
    313   1.1  knakahar 
    314   1.1  knakahar 	cpuset_zero(cpuset);
    315   1.1  knakahar 	cpuset_set(index, cpuset);
    316   1.1  knakahar 	iset.cpuset = cpuset;
    317   1.1  knakahar 	iset.cpuset_size = cpuset_size(cpuset);
    318   1.1  knakahar 	error = sysctlbyname("kern.intr.affinity", NULL, NULL, &iset, sizeof(iset));
    319   1.1  knakahar 	cpuset_destroy(cpuset);
    320   1.1  knakahar 	if (error < 0)
    321   1.1  knakahar 		err(EXIT_FAILURE, "sysctl kern.intr.affinity");
    322   1.1  knakahar }
    323   1.1  knakahar 
    324   1.1  knakahar static void
    325   1.1  knakahar intrctl_intr(int argc, char **argv)
    326   1.1  knakahar {
    327   1.1  knakahar 	struct intrio_set iset;
    328   1.1  knakahar 	cpuset_t *cpuset;
    329   1.1  knakahar 	unsigned long index;
    330   1.1  knakahar 	int ch, error;
    331   1.1  knakahar 
    332   1.1  knakahar 	index = ULONG_MAX;
    333   1.1  knakahar 
    334   1.1  knakahar 	while ((ch = getopt(argc, argv, "c:")) != -1) {
    335   1.1  knakahar 		switch (ch) {
    336   1.1  knakahar 		case 'c':
    337   1.1  knakahar 			index = strtoul(optarg, NULL, 10);
    338   1.1  knakahar 			break;
    339   1.1  knakahar 		default:
    340   1.1  knakahar 			usage();
    341   1.1  knakahar 		}
    342   1.1  knakahar 	}
    343   1.1  knakahar 
    344   1.1  knakahar 	if (index == ULONG_MAX)
    345   1.1  knakahar 		usage();
    346   1.1  knakahar 
    347   1.1  knakahar 	if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF))
    348   1.1  knakahar 		err(EXIT_FAILURE, "invalid cpu index");
    349   1.1  knakahar 
    350   1.1  knakahar 	cpuset = cpuset_create();
    351   1.1  knakahar 	if (cpuset == NULL)
    352   1.1  knakahar 		err(EXIT_FAILURE, "create_cpuset()");
    353   1.1  knakahar 
    354   1.1  knakahar 	cpuset_zero(cpuset);
    355   1.1  knakahar 	cpuset_set(index, cpuset);
    356   1.1  knakahar 	iset.cpuset = cpuset;
    357   1.1  knakahar 	iset.cpuset_size = cpuset_size(cpuset);
    358   1.1  knakahar 	error = sysctlbyname("kern.intr.intr", NULL, NULL, &iset, sizeof(iset));
    359   1.1  knakahar 	cpuset_destroy(cpuset);
    360   1.1  knakahar 	if (error < 0)
    361   1.1  knakahar 		err(EXIT_FAILURE, "sysctl kern.intr.intr");
    362   1.1  knakahar }
    363   1.1  knakahar 
    364   1.1  knakahar static void
    365   1.1  knakahar intrctl_nointr(int argc, char **argv)
    366   1.1  knakahar {
    367   1.1  knakahar 	struct intrio_set iset;
    368   1.1  knakahar 	cpuset_t *cpuset;
    369   1.1  knakahar 	unsigned long index;
    370   1.1  knakahar 	int ch, error;
    371   1.1  knakahar 
    372   1.1  knakahar 	index = ULONG_MAX;
    373   1.1  knakahar 
    374   1.1  knakahar 	while ((ch = getopt(argc, argv, "c:")) != -1) {
    375   1.1  knakahar 		switch (ch) {
    376   1.1  knakahar 		case 'c':
    377   1.1  knakahar 			index = strtoul(optarg, NULL, 10);
    378   1.1  knakahar 			break;
    379   1.1  knakahar 		default:
    380   1.1  knakahar 			usage();
    381   1.1  knakahar 		}
    382   1.1  knakahar 	}
    383   1.1  knakahar 
    384   1.1  knakahar 	if (index == ULONG_MAX)
    385   1.1  knakahar 		usage();
    386   1.1  knakahar 
    387   1.1  knakahar 	if (index >= (u_long)sysconf(_SC_NPROCESSORS_CONF))
    388   1.1  knakahar 		err(EXIT_FAILURE, "invalid cpu index");
    389   1.1  knakahar 
    390   1.1  knakahar 	cpuset = cpuset_create();
    391   1.1  knakahar 	if (cpuset == NULL)
    392   1.1  knakahar 		err(EXIT_FAILURE, "create_cpuset()");
    393   1.1  knakahar 
    394   1.1  knakahar 	cpuset_zero(cpuset);
    395   1.1  knakahar 	cpuset_set(index, cpuset);
    396   1.1  knakahar 	iset.cpuset = cpuset;
    397   1.1  knakahar 	iset.cpuset_size = cpuset_size(cpuset);
    398   1.1  knakahar 	error = sysctlbyname("kern.intr.nointr", NULL, NULL, &iset, sizeof(iset));
    399   1.1  knakahar 	cpuset_destroy(cpuset);
    400   1.1  knakahar 	if (error < 0)
    401   1.1  knakahar 		err(EXIT_FAILURE, "sysctl kern.intr.nointr");
    402   1.1  knakahar }
    403