1 // SPDX-License-Identifier: GPL-2.0-only
3 * Counter Watch Events - Test various counter watch events in a userspace application
5 * Copyright (C) STMicroelectronics 2023 - All Rights Reserved
6 * Author: Fabrice Gasnier <fabrice.gasnier@foss.st.com>.
12 #include <linux/counter.h>
13 #include <linux/kernel.h>
17 #include <sys/ioctl.h>
20 static struct counter_watch simple_watch
[] = {
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 */
33 static 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",
43 static 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",
52 static const char * const counter_scope_name
[] = {
53 "COUNTER_SCOPE_DEVICE",
54 "COUNTER_SCOPE_SIGNAL",
55 "COUNTER_SCOPE_COUNT",
58 static void print_watch(struct counter_watch
*watch
, int nwatch
)
62 /* prints the watch array in C-like structure */
63 printf("watch[%d] = {\n", nwatch
);
64 for (i
= 0; i
< nwatch
; i
++) {
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"
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
],
84 static void print_usage(void)
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"
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"
93 "Test various watch events for given counter device.\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"
103 " scope_device (COUNTER_SCOPE_DEVICE) [default: scope_device]\n"
104 " scope_signal (COUNTER_SCOPE_SIGNAL)\n"
105 " scope_count (COUNTER_SCOPE_COUNT)\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"
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"
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"
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"
133 static 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' },
142 /* counter watch subopts */
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
,
158 WATCH_EVENT_CHANGE_OF_STATE
,
166 static 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",
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",
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",
189 [WATCH_PARENT
] = "parent",
190 /* Empty entry ends the opts array */
194 int main(int argc
, char **argv
)
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
;
203 * - list watch events number to allocate the watch array.
204 * - parse normal options (other than watch options)
206 while ((c
= getopt_long(argc
, argv
, "dhn:l:w:", longopts
, NULL
)) != -1) {
215 dev_num
= strtoul(optarg
, NULL
, 10);
217 perror("strtol failed: --device-num <n>\n");
222 loop
= strtol(optarg
, NULL
, 10);
224 perror("strtol failed: --loop <n>\n");
237 watches
= calloc(nwatch
, sizeof(*watches
));
239 perror("Error allocating watches\n");
243 /* default to simple watch example */
244 watches
= simple_watch
;
245 nwatch
= ARRAY_SIZE(simple_watch
);
248 /* 2nd pass: parse watch sub-options to fill in watch array */
251 while ((c
= getopt_long(argc
, argv
, "dhn:l:w:", longopts
, NULL
)) != -1) {
255 while (*subopts
!= '\0') {
256 ret
= getsubopt(&subopts
, counter_watch_subopts
, &value
);
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
;
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
;
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
;
287 fprintf(stderr
, "Invalid chan=<number>\n");
289 goto err_free_watches
;
291 watches
[i
].channel
= strtoul(value
, NULL
, 10);
293 perror("strtoul failed: chan=<number>\n");
295 goto err_free_watches
;
300 fprintf(stderr
, "Invalid id=<number>\n");
302 goto err_free_watches
;
304 watches
[i
].component
.id
= strtoul(value
, NULL
, 10);
306 perror("strtoul failed: id=<number>\n");
308 goto err_free_watches
;
313 fprintf(stderr
, "Invalid parent=<number>\n");
315 goto err_free_watches
;
317 watches
[i
].component
.parent
= strtoul(value
, NULL
, 10);
319 perror("strtoul failed: parent=<number>\n");
321 goto err_free_watches
;
325 fprintf(stderr
, "Unknown suboption '%s'\n", value
);
327 goto err_free_watches
;
336 print_watch(watches
, nwatch
);
338 ret
= asprintf(&device_name
, "/dev/counter%d", dev_num
);
340 fprintf(stderr
, "asprintf failed\n");
342 goto err_free_watches
;
346 printf("Opening %s\n", device_name
);
348 fd
= open(device_name
, O_RDWR
);
350 fprintf(stderr
, "Unable to open %s: %s\n", device_name
, strerror(errno
));
353 goto err_free_watches
;
357 for (i
= 0; i
< nwatch
; i
++) {
358 ret
= ioctl(fd
, COUNTER_ADD_WATCH_IOCTL
, watches
+ i
);
360 fprintf(stderr
, "Error adding watches[%d]: %s\n", i
,
367 ret
= ioctl(fd
, COUNTER_ENABLE_EVENTS_IOCTL
);
369 perror("Error enabling events");
374 for (i
= 0; loop
<= 0 || i
< loop
; i
++) {
375 ret
= read(fd
, &event_data
, sizeof(event_data
));
377 perror("Failed to read event data");
382 if (ret
!= sizeof(event_data
)) {
383 fprintf(stderr
, "Failed to read event data (got: %d)\n", ret
);
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
);
393 if (event_data
.status
) {
394 fprintf(stderr
, "Error %d: %s\n", event_data
.status
,
395 strerror(event_data
.status
));
402 if (watches
!= simple_watch
)