File Index
Files and directories
Sign in
FILE

counter_watch_events.c

File preview with syntax highlighting.

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