counter_watch_events.c 11 KB

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