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_SLOW_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_slow_hint_enable" 16 #define WORKLOAD_TYPE_INDEX_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index" 17 18 static const char * const workload_types[] = { 19 "idle", 20 "battery_life", 21 "sustained", 22 "bursty", 23 NULL 24 }; 25 26 static int wlt_slow; 27 static char *wlt_enable_attr; 28 29 #define WORKLOAD_TYPE_MAX_INDEX 3 30 31 void workload_hint_exit(int signum) 32 { 33 int fd; 34 35 /* Disable feature via sysfs knob */ 36 37 fd = open(wlt_enable_attr, O_RDWR); 38 if (fd < 0) { 39 perror("Unable to open workload type feature enable file"); 40 exit(1); 41 } 42 43 if (write(fd, "0\n", 2) < 0) { 44 perror("Can't disable workload hints"); 45 exit(1); 46 } 47 48 printf("Disabled workload type prediction\n"); 49 50 close(fd); 51 } 52 53 static void update_delay(char *delay_str) 54 { 55 int fd; 56 57 printf("Setting notification delay in ms to %s\n", delay_str); 58 59 fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR); 60 if (fd < 0) { 61 perror("Unable to open workload notification delay"); 62 exit(1); 63 } 64 65 if (write(fd, delay_str, strlen(delay_str)) < 0) { 66 perror("Can't set delay"); 67 exit(1); 68 } 69 70 close(fd); 71 } 72 73 int main(int argc, char **argv) 74 { 75 struct pollfd ufd; 76 char index_str[4]; 77 int fd, ret, index; 78 char delay_str[64]; 79 int delay = 0; 80 81 printf("Usage: workload_hint_test [notification delay in milli seconds][slow]\n"); 82 83 if (argc > 1) { 84 int i; 85 86 for (i = 1; i < argc; ++i) { 87 if (!strcmp(argv[i], "slow")) { 88 wlt_slow = 1; 89 continue; 90 } 91 92 ret = sscanf(argv[1], "%d", &delay); 93 if (ret < 0) { 94 printf("Invalid delay\n"); 95 exit(1); 96 } 97 98 sprintf(delay_str, "%s\n", argv[1]); 99 update_delay(delay_str); 100 } 101 } 102 103 if (signal(SIGINT, workload_hint_exit) == SIG_IGN) 104 signal(SIGINT, SIG_IGN); 105 if (signal(SIGHUP, workload_hint_exit) == SIG_IGN) 106 signal(SIGHUP, SIG_IGN); 107 if (signal(SIGTERM, workload_hint_exit) == SIG_IGN) 108 signal(SIGTERM, SIG_IGN); 109 110 if (wlt_slow) 111 wlt_enable_attr = WORKLOAD_SLOW_ENABLE_ATTRIBUTE; 112 else 113 wlt_enable_attr = WORKLOAD_ENABLE_ATTRIBUTE; 114 115 /* Enable feature via sysfs knob */ 116 fd = open(wlt_enable_attr, O_RDWR); 117 if (fd < 0) { 118 perror("Unable to open workload type feature enable file"); 119 exit(1); 120 } 121 122 if (write(fd, "1\n", 2) < 0) { 123 perror("Can't enable workload hints"); 124 exit(1); 125 } 126 127 close(fd); 128 129 printf("Enabled workload type prediction\n"); 130 131 while (1) { 132 fd = open(WORKLOAD_TYPE_INDEX_ATTRIBUTE, O_RDONLY); 133 if (fd < 0) { 134 perror("Unable to open workload type file"); 135 exit(1); 136 } 137 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 fprintf(stderr, "Failed to read from:%s\n", 145 WORKLOAD_TYPE_INDEX_ATTRIBUTE); 146 exit(1); 147 } 148 149 ufd.fd = fd; 150 ufd.events = POLLPRI; 151 152 ret = poll(&ufd, 1, -1); 153 if (ret < 0) { 154 perror("poll error"); 155 exit(1); 156 } else if (ret == 0) { 157 printf("Poll Timeout\n"); 158 } else { 159 if ((lseek(fd, 0L, SEEK_SET)) < 0) { 160 fprintf(stderr, "Failed to set pointer to beginning\n"); 161 exit(1); 162 } 163 164 if (read(fd, index_str, sizeof(index_str)) < 0) 165 exit(0); 166 167 ret = sscanf(index_str, "%d", &index); 168 if (ret < 0) 169 break; 170 171 if (wlt_slow) { 172 if (index & 0x10) 173 printf("workload type slow:%s\n", "power"); 174 else 175 printf("workload type slow:%s\n", "performance"); 176 } 177 178 index &= 0x0f; 179 if (index > WORKLOAD_TYPE_MAX_INDEX) 180 printf("Invalid workload type index\n"); 181 else 182 printf("workload type:%s\n", workload_types[index]); 183 } 184 185 close(fd); 186 } 187 } 188