1// SPDX-License-Identifier: GPL-2.0
2
3#define _GNU_SOURCE
4
5#include <stdio.h>
6#include <string.h>
7#include <stdlib.h>
8#include <unistd.h>
9#include <fcntl.h>
10#include <poll.h>
11#include <signal.h>
12
13#define WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/notification_delay_ms"
14#define WORKLOAD_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_hint_enable"
15#define WORKLOAD_TYPE_INDEX_ATTRIBUTE  "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index"
16
17static const char * const workload_types[] = {
18	"idle",
19	"battery_life",
20	"sustained",
21	"bursty",
22	NULL
23};
24
25#define WORKLOAD_TYPE_MAX_INDEX	3
26
27void workload_hint_exit(int signum)
28{
29	int fd;
30
31	/* Disable feature via sysfs knob */
32
33	fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
34	if (fd < 0) {
35		perror("Unable to open workload type feature enable file\n");
36		exit(1);
37	}
38
39	if (write(fd, "0\n", 2) < 0) {
40		perror("Can' disable workload hints\n");
41		exit(1);
42	}
43
44	printf("Disabled workload type prediction\n");
45
46	close(fd);
47}
48
49int main(int argc, char **argv)
50{
51	struct pollfd ufd;
52	char index_str[4];
53	int fd, ret, index;
54	char delay_str[64];
55	int delay = 0;
56
57	printf("Usage: workload_hint_test [notification delay in milli seconds]\n");
58
59	if (argc > 1) {
60		ret = sscanf(argv[1], "%d", &delay);
61		if (ret < 0) {
62			printf("Invalid delay\n");
63			exit(1);
64		}
65
66		printf("Setting notification delay to %d ms\n", delay);
67		if (delay < 0)
68			exit(1);
69
70		sprintf(delay_str, "%s\n", argv[1]);
71
72		sprintf(delay_str, "%s\n", argv[1]);
73		fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
74		if (fd < 0) {
75			perror("Unable to open workload notification delay\n");
76			exit(1);
77		}
78
79		if (write(fd, delay_str, strlen(delay_str)) < 0) {
80			perror("Can't set delay\n");
81			exit(1);
82		}
83
84		close(fd);
85	}
86
87	if (signal(SIGINT, workload_hint_exit) == SIG_IGN)
88		signal(SIGINT, SIG_IGN);
89	if (signal(SIGHUP, workload_hint_exit) == SIG_IGN)
90		signal(SIGHUP, SIG_IGN);
91	if (signal(SIGTERM, workload_hint_exit) == SIG_IGN)
92		signal(SIGTERM, SIG_IGN);
93
94	/* Enable feature via sysfs knob */
95	fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
96	if (fd < 0) {
97		perror("Unable to open workload type feature enable file\n");
98		exit(1);
99	}
100
101	if (write(fd, "1\n", 2) < 0) {
102		perror("Can' enable workload hints\n");
103		exit(1);
104	}
105
106	close(fd);
107
108	printf("Enabled workload type prediction\n");
109
110	while (1) {
111		fd = open(WORKLOAD_TYPE_INDEX_ATTRIBUTE, O_RDONLY);
112		if (fd < 0) {
113			perror("Unable to open workload type file\n");
114			exit(1);
115		}
116
117		if ((lseek(fd, 0L, SEEK_SET)) < 0) {
118			fprintf(stderr, "Failed to set pointer to beginning\n");
119			exit(1);
120		}
121
122		if (read(fd, index_str, sizeof(index_str)) < 0) {
123			fprintf(stderr, "Failed to read from:%s\n",
124			WORKLOAD_TYPE_INDEX_ATTRIBUTE);
125			exit(1);
126		}
127
128		ufd.fd = fd;
129		ufd.events = POLLPRI;
130
131		ret = poll(&ufd, 1, -1);
132		if (ret < 0) {
133			perror("poll error");
134			exit(1);
135		} else if (ret == 0) {
136			printf("Poll Timeout\n");
137		} else {
138			if ((lseek(fd, 0L, SEEK_SET)) < 0) {
139				fprintf(stderr, "Failed to set pointer to beginning\n");
140				exit(1);
141			}
142
143			if (read(fd, index_str, sizeof(index_str)) < 0)
144				exit(0);
145
146			ret = sscanf(index_str, "%d", &index);
147			if (ret < 0)
148				break;
149			if (index > WORKLOAD_TYPE_MAX_INDEX)
150				printf("Invalid workload type index\n");
151			else
152				printf("workload type:%s\n", workload_types[index]);
153		}
154
155		close(fd);
156	}
157}
158