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 
17 static 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 
workload_hint_exit(int signum)27 void 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 
main(int argc,char ** argv)49 int 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