brintos

brintos / linux-shallow public Read only

0
0
Text · 11.2 KiB · 107631e Raw
407 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Counter Watch Events - Test various counter watch events in a userspace application4 *5 * Copyright (C) STMicroelectronics 2023 - All Rights Reserved6 * Author: Fabrice Gasnier <fabrice.gasnier@foss.st.com>.7 */8 9#include <errno.h>10#include <fcntl.h>11#include <getopt.h>12#include <linux/counter.h>13#include <linux/kernel.h>14#include <stdlib.h>15#include <stdio.h>16#include <string.h>17#include <sys/ioctl.h>18#include <unistd.h>19 20static struct counter_watch simple_watch[] = {21	{22		/* Component data: Count 0 count */23		.component.type = COUNTER_COMPONENT_COUNT,24		.component.scope = COUNTER_SCOPE_COUNT,25		.component.parent = 0,26		/* Event type: overflow or underflow */27		.event = COUNTER_EVENT_OVERFLOW_UNDERFLOW,28		/* Device event channel 0 */29		.channel = 0,30	},31};32 33static const char * const counter_event_type_name[] = {34	"COUNTER_EVENT_OVERFLOW",35	"COUNTER_EVENT_UNDERFLOW",36	"COUNTER_EVENT_OVERFLOW_UNDERFLOW",37	"COUNTER_EVENT_THRESHOLD",38	"COUNTER_EVENT_INDEX",39	"COUNTER_EVENT_CHANGE_OF_STATE",40	"COUNTER_EVENT_CAPTURE",41};42 43static const char * const counter_component_type_name[] = {44	"COUNTER_COMPONENT_NONE",45	"COUNTER_COMPONENT_SIGNAL",46	"COUNTER_COMPONENT_COUNT",47	"COUNTER_COMPONENT_FUNCTION",48	"COUNTER_COMPONENT_SYNAPSE_ACTION",49	"COUNTER_COMPONENT_EXTENSION",50};51 52static const char * const counter_scope_name[] = {53	"COUNTER_SCOPE_DEVICE",54	"COUNTER_SCOPE_SIGNAL",55	"COUNTER_SCOPE_COUNT",56};57 58static void print_watch(struct counter_watch *watch, int nwatch)59{60	int i;61 62	/* prints the watch array in C-like structure */63	printf("watch[%d] = {\n", nwatch);64	for (i = 0; i < nwatch; i++) {65		printf(" [%d] =\t{\n"66		       "\t\t.component.type = %s\n"67		       "\t\t.component.scope = %s\n"68		       "\t\t.component.parent = %d\n"69		       "\t\t.component.id = %d\n"70		       "\t\t.event = %s\n"71		       "\t\t.channel = %d\n"72		       "\t},\n",73		       i,74		       counter_component_type_name[watch[i].component.type],75		       counter_scope_name[watch[i].component.scope],76		       watch[i].component.parent,77		       watch[i].component.id,78		       counter_event_type_name[watch[i].event],79		       watch[i].channel);80	}81	printf("};\n");82}83 84static void print_usage(void)85{86	fprintf(stderr, "Usage:\n\n"87		"counter_watch_events [options] [-w <watchoptions>]\n"88		"counter_watch_events [options] [-w <watch1 options>] [-w <watch2 options>]...\n"89		"\n"90		"When no --watch option has been provided, simple watch example is used:\n"91		"counter_watch_events [options] -w comp_count,scope_count,evt_ovf_udf\n"92		"\n"93		"Test various watch events for given counter device.\n"94		"\n"95		"Options:\n"96		"  -d, --debug                Prints debug information\n"97		"  -h, --help                 Prints usage\n"98		"  -n, --device-num <n>       Use /dev/counter<n> [default: /dev/counter0]\n"99		"  -l, --loop <n>             Loop for <n> events [default: 0 (forever)]\n"100		"  -w, --watch <watchoptions> comma-separated list of watch options\n"101		"\n"102		"Watch options:\n"103		"  scope_device               (COUNTER_SCOPE_DEVICE) [default: scope_device]\n"104		"  scope_signal               (COUNTER_SCOPE_SIGNAL)\n"105		"  scope_count                (COUNTER_SCOPE_COUNT)\n"106		"\n"107		"  comp_none                  (COUNTER_COMPONENT_NONE) [default: comp_none]\n"108		"  comp_signal                (COUNTER_COMPONENT_SIGNAL)\n"109		"  comp_count                 (COUNTER_COMPONENT_COUNT)\n"110		"  comp_function              (COUNTER_COMPONENT_FUNCTION)\n"111		"  comp_synapse_action        (COUNTER_COMPONENT_SYNAPSE_ACTION)\n"112		"  comp_extension             (COUNTER_COMPONENT_EXTENSION)\n"113		"\n"114		"  evt_ovf                    (COUNTER_EVENT_OVERFLOW) [default: evt_ovf]\n"115		"  evt_udf                    (COUNTER_EVENT_UNDERFLOW)\n"116		"  evt_ovf_udf                (COUNTER_EVENT_OVERFLOW_UNDERFLOW)\n"117		"  evt_threshold              (COUNTER_EVENT_THRESHOLD)\n"118		"  evt_index                  (COUNTER_EVENT_INDEX)\n"119		"  evt_change_of_state        (COUNTER_EVENT_CHANGE_OF_STATE)\n"120		"  evt_capture                (COUNTER_EVENT_CAPTURE)\n"121		"\n"122		"  chan=<n>                   channel <n> for this watch [default: 0]\n"123		"  id=<n>                     component id <n> for this watch [default: 0]\n"124		"  parent=<n>                 component parent <n> for this watch [default: 0]\n"125		"\n"126		"Example with two watched events:\n\n"127		"counter_watch_events -d \\\n"128		"\t-w comp_count,scope_count,evt_ovf_udf \\\n"129		"\t-w comp_extension,scope_count,evt_capture,id=7,chan=3\n"130		);131}132 133static const struct option longopts[] = {134	{ "debug",		no_argument,       0, 'd' },135	{ "help",		no_argument,       0, 'h' },136	{ "device-num",		required_argument, 0, 'n' },137	{ "loop",		required_argument, 0, 'l' },138	{ "watch",		required_argument, 0, 'w' },139	{ },140};141 142/* counter watch subopts */143enum {144	WATCH_SCOPE_DEVICE,145	WATCH_SCOPE_SIGNAL,146	WATCH_SCOPE_COUNT,147	WATCH_COMPONENT_NONE,148	WATCH_COMPONENT_SIGNAL,149	WATCH_COMPONENT_COUNT,150	WATCH_COMPONENT_FUNCTION,151	WATCH_COMPONENT_SYNAPSE_ACTION,152	WATCH_COMPONENT_EXTENSION,153	WATCH_EVENT_OVERFLOW,154	WATCH_EVENT_UNDERFLOW,155	WATCH_EVENT_OVERFLOW_UNDERFLOW,156	WATCH_EVENT_THRESHOLD,157	WATCH_EVENT_INDEX,158	WATCH_EVENT_CHANGE_OF_STATE,159	WATCH_EVENT_CAPTURE,160	WATCH_CHANNEL,161	WATCH_ID,162	WATCH_PARENT,163	WATCH_SUBOPTS_MAX,164};165 166static char * const counter_watch_subopts[WATCH_SUBOPTS_MAX + 1] = {167	/* component.scope */168	[WATCH_SCOPE_DEVICE] = "scope_device",169	[WATCH_SCOPE_SIGNAL] = "scope_signal",170	[WATCH_SCOPE_COUNT] = "scope_count",171	/* component.type */172	[WATCH_COMPONENT_NONE] = "comp_none",173	[WATCH_COMPONENT_SIGNAL] = "comp_signal",174	[WATCH_COMPONENT_COUNT] = "comp_count",175	[WATCH_COMPONENT_FUNCTION] = "comp_function",176	[WATCH_COMPONENT_SYNAPSE_ACTION] = "comp_synapse_action",177	[WATCH_COMPONENT_EXTENSION] = "comp_extension",178	/* event */179	[WATCH_EVENT_OVERFLOW] = "evt_ovf",180	[WATCH_EVENT_UNDERFLOW] = "evt_udf",181	[WATCH_EVENT_OVERFLOW_UNDERFLOW] = "evt_ovf_udf",182	[WATCH_EVENT_THRESHOLD] = "evt_threshold",183	[WATCH_EVENT_INDEX] = "evt_index",184	[WATCH_EVENT_CHANGE_OF_STATE] = "evt_change_of_state",185	[WATCH_EVENT_CAPTURE] = "evt_capture",186	/* channel, id, parent */187	[WATCH_CHANNEL] = "chan",188	[WATCH_ID] = "id",189	[WATCH_PARENT] = "parent",190	/* Empty entry ends the opts array */191	NULL192};193 194int main(int argc, char **argv)195{196	int c, fd, i, ret, rc = 0, debug = 0, loop = 0, dev_num = 0, nwatch = 0;197	struct counter_event event_data;198	char *device_name = NULL, *subopts, *value;199	struct counter_watch *watches;200 201	/*202	 * 1st pass:203	 * - list watch events number to allocate the watch array.204	 * - parse normal options (other than watch options)205	 */206	while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) {207		switch (c) {208		case 'd':209			debug = 1;210			break;211		case 'h':212			print_usage();213			return EXIT_SUCCESS;214		case 'n':215			dev_num = strtoul(optarg, NULL, 10);216			if (errno) {217				perror("strtol failed: --device-num <n>\n");218				return EXIT_FAILURE;219			}220			break;221		case 'l':222			loop = strtol(optarg, NULL, 10);223			if (errno) {224				perror("strtol failed: --loop <n>\n");225				return EXIT_FAILURE;226			}227			break;228		case 'w':229			nwatch++;230			break;231		default:232			return EXIT_FAILURE;233		}234	}235 236	if (nwatch) {237		watches = calloc(nwatch, sizeof(*watches));238		if (!watches) {239			perror("Error allocating watches\n");240			return EXIT_FAILURE;241		}242	} else {243		/* default to simple watch example */244		watches = simple_watch;245		nwatch = ARRAY_SIZE(simple_watch);246	}247 248	/* 2nd pass: parse watch sub-options to fill in watch array */249	optind = 1;250	i = 0;251	while ((c = getopt_long(argc, argv, "dhn:l:w:", longopts, NULL)) != -1) {252		switch (c) {253		case 'w':254			subopts = optarg;255			while (*subopts != '\0') {256				ret = getsubopt(&subopts, counter_watch_subopts, &value);257				switch (ret) {258				case WATCH_SCOPE_DEVICE:259				case WATCH_SCOPE_SIGNAL:260				case WATCH_SCOPE_COUNT:261					/* match with counter_scope */262					watches[i].component.scope = ret;263					break;264				case WATCH_COMPONENT_NONE:265				case WATCH_COMPONENT_SIGNAL:266				case WATCH_COMPONENT_COUNT:267				case WATCH_COMPONENT_FUNCTION:268				case WATCH_COMPONENT_SYNAPSE_ACTION:269				case WATCH_COMPONENT_EXTENSION:270					/* match counter_component_type: subtract enum value */271					ret -= WATCH_COMPONENT_NONE;272					watches[i].component.type = ret;273					break;274				case WATCH_EVENT_OVERFLOW:275				case WATCH_EVENT_UNDERFLOW:276				case WATCH_EVENT_OVERFLOW_UNDERFLOW:277				case WATCH_EVENT_THRESHOLD:278				case WATCH_EVENT_INDEX:279				case WATCH_EVENT_CHANGE_OF_STATE:280				case WATCH_EVENT_CAPTURE:281					/* match counter_event_type: subtract enum value */282					ret -= WATCH_EVENT_OVERFLOW;283					watches[i].event = ret;284					break;285				case WATCH_CHANNEL:286					if (!value) {287						fprintf(stderr, "Invalid chan=<number>\n");288						rc = EXIT_FAILURE;289						goto err_free_watches;290					}291					watches[i].channel = strtoul(value, NULL, 10);292					if (errno) {293						perror("strtoul failed: chan=<number>\n");294						rc = EXIT_FAILURE;295						goto err_free_watches;296					}297					break;298				case WATCH_ID:299					if (!value) {300						fprintf(stderr, "Invalid id=<number>\n");301						rc = EXIT_FAILURE;302						goto err_free_watches;303					}304					watches[i].component.id = strtoul(value, NULL, 10);305					if (errno) {306						perror("strtoul failed: id=<number>\n");307						rc = EXIT_FAILURE;308						goto err_free_watches;309					}310					break;311				case WATCH_PARENT:312					if (!value) {313						fprintf(stderr, "Invalid parent=<number>\n");314						rc = EXIT_FAILURE;315						goto err_free_watches;316					}317					watches[i].component.parent = strtoul(value, NULL, 10);318					if (errno) {319						perror("strtoul failed: parent=<number>\n");320						rc = EXIT_FAILURE;321						goto err_free_watches;322					}323					break;324				default:325					fprintf(stderr, "Unknown suboption '%s'\n", value);326					rc = EXIT_FAILURE;327					goto err_free_watches;328				}329			}330			i++;331			break;332		}333	}334 335	if (debug)336		print_watch(watches, nwatch);337 338	ret = asprintf(&device_name, "/dev/counter%d", dev_num);339	if (ret < 0) {340		fprintf(stderr, "asprintf failed\n");341		rc = EXIT_FAILURE;342		goto err_free_watches;343	}344 345	if (debug)346		printf("Opening %s\n", device_name);347 348	fd = open(device_name, O_RDWR);349	if (fd == -1) {350		fprintf(stderr, "Unable to open %s: %s\n", device_name, strerror(errno));351		free(device_name);352		rc = EXIT_FAILURE;353		goto err_free_watches;354	}355	free(device_name);356 357	for (i = 0; i < nwatch; i++) {358		ret = ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + i);359		if (ret == -1) {360			fprintf(stderr, "Error adding watches[%d]: %s\n", i,361				strerror(errno));362			rc = EXIT_FAILURE;363			goto err_close;364		}365	}366 367	ret = ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL);368	if (ret == -1) {369		perror("Error enabling events");370		rc = EXIT_FAILURE;371		goto err_close;372	}373 374	for (i = 0; loop <= 0 || i < loop; i++) {375		ret = read(fd, &event_data, sizeof(event_data));376		if (ret == -1) {377			perror("Failed to read event data");378			rc = EXIT_FAILURE;379			goto err_close;380		}381 382		if (ret != sizeof(event_data)) {383			fprintf(stderr, "Failed to read event data (got: %d)\n", ret);384			rc = EXIT_FAILURE;385			goto err_close;386		}387 388		printf("Timestamp: %llu\tData: %llu\t event: %s\tch: %d\n",389		       event_data.timestamp, event_data.value,390		       counter_event_type_name[event_data.watch.event],391		       event_data.watch.channel);392 393		if (event_data.status) {394			fprintf(stderr, "Error %d: %s\n", event_data.status,395				strerror(event_data.status));396		}397	}398 399err_close:400	close(fd);401err_free_watches:402	if (watches != simple_watch)403		free(watches);404 405	return rc;406}407