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 POWER_FLOOR_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/power_limits/power_floor_enable"
14 #define POWER_FLOOR_STATUS_ATTRIBUTE  "/sys/bus/pci/devices/0000:00:04.0/power_limits/power_floor_status"
15 
16 void power_floor_exit(int signum)
17 {
18 	int fd;
19 
20 	/* Disable feature via sysfs knob */
21 
22 	fd = open(POWER_FLOOR_ENABLE_ATTRIBUTE, O_RDWR);
23 	if (fd < 0) {
24 		perror("Unable to open power floor enable file\n");
25 		exit(1);
26 	}
27 
28 	if (write(fd, "0\n", 2) < 0) {
29 		perror("Can' disable power floor notifications\n");
30 		exit(1);
31 	}
32 
33 	printf("Disabled power floor notifications\n");
34 
35 	close(fd);
36 }
37 
38 int main(int argc, char **argv)
39 {
40 	struct pollfd ufd;
41 	char status_str[3];
42 	int fd, ret;
43 
44 	if (signal(SIGINT, power_floor_exit) == SIG_IGN)
45 		signal(SIGINT, SIG_IGN);
46 	if (signal(SIGHUP, power_floor_exit) == SIG_IGN)
47 		signal(SIGHUP, SIG_IGN);
48 	if (signal(SIGTERM, power_floor_exit) == SIG_IGN)
49 		signal(SIGTERM, SIG_IGN);
50 
51 	/* Enable feature via sysfs knob */
52 	fd = open(POWER_FLOOR_ENABLE_ATTRIBUTE, O_RDWR);
53 	if (fd < 0) {
54 		perror("Unable to open power floor enable file\n");
55 		exit(1);
56 	}
57 
58 	if (write(fd, "1\n", 2) < 0) {
59 		perror("Can' enable power floor notifications\n");
60 		exit(1);
61 	}
62 
63 	close(fd);
64 
65 	printf("Enabled power floor notifications\n");
66 
67 	while (1) {
68 		fd = open(POWER_FLOOR_STATUS_ATTRIBUTE, O_RDONLY);
69 		if (fd < 0) {
70 			perror("Unable to power floor status file\n");
71 			exit(1);
72 		}
73 
74 		if ((lseek(fd, 0L, SEEK_SET)) < 0) {
75 			fprintf(stderr, "Failed to set pointer to beginning\n");
76 			exit(1);
77 		}
78 
79 		if (read(fd, status_str, sizeof(status_str)) < 0) {
80 			fprintf(stderr, "Failed to read from:%s\n",
81 			POWER_FLOOR_STATUS_ATTRIBUTE);
82 			exit(1);
83 		}
84 
85 		ufd.fd = fd;
86 		ufd.events = POLLPRI;
87 
88 		ret = poll(&ufd, 1, -1);
89 		if (ret < 0) {
90 			perror("poll error");
91 			exit(1);
92 		} else if (ret == 0) {
93 			printf("Poll Timeout\n");
94 		} else {
95 			if ((lseek(fd, 0L, SEEK_SET)) < 0) {
96 				fprintf(stderr, "Failed to set pointer to beginning\n");
97 				exit(1);
98 			}
99 
100 			if (read(fd, status_str, sizeof(status_str)) < 0)
101 				exit(0);
102 
103 			printf("power floor status: %s\n", status_str);
104 		}
105 
106 		close(fd);
107 	}
108 }
109