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
16void 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
38int 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