1 // SPDX-License-Identifier: GPL-2.0
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <limits.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <getopt.h>
10 
11 #include <cpufreq.h>
12 #include <cpuidle.h>
13 
14 #include "helpers/helpers.h"
15 
16 static struct option info_opts[] = {
17      {"disable",	required_argument,		NULL, 'd'},
18      {"enable",		required_argument,		NULL, 'e'},
19      {"disable-by-latency", required_argument,		NULL, 'D'},
20      {"enable-all",	no_argument,			NULL, 'E'},
21      { },
22 };
23 
24 
25 int cmd_idle_set(int argc, char **argv)
26 {
27 	extern char *optarg;
28 	extern int optind, opterr, optopt;
29 	int ret = 0, cont = 1, param = 0, disabled;
30 	unsigned long long latency = 0, state_latency;
31 	unsigned int cpu = 0, idlestate = 0, idlestates = 0;
32 	char *endptr;
33 
34 	do {
35 		ret = getopt_long(argc, argv, "d:e:ED:", info_opts, NULL);
36 		if (ret == -1)
37 			break;
38 		switch (ret) {
39 		case '?':
40 			param = '?';
41 			cont = 0;
42 			break;
43 		case 'd':
44 			if (param) {
45 				param = -1;
46 				cont = 0;
47 				break;
48 			}
49 			param = ret;
50 			idlestate = atoi(optarg);
51 			break;
52 		case 'e':
53 			if (param) {
54 				param = -1;
55 				cont = 0;
56 				break;
57 			}
58 			param = ret;
59 			idlestate = atoi(optarg);
60 			break;
61 		case 'D':
62 			if (param) {
63 				param = -1;
64 				cont = 0;
65 				break;
66 			}
67 			param = ret;
68 			latency = strtoull(optarg, &endptr, 10);
69 			if (*endptr != '\0') {
70 				printf(_("Bad latency value: %s\n"), optarg);
71 				exit(EXIT_FAILURE);
72 			}
73 			break;
74 		case 'E':
75 			if (param) {
76 				param = -1;
77 				cont = 0;
78 				break;
79 			}
80 			param = ret;
81 			break;
82 		case -1:
83 			cont = 0;
84 			break;
85 		}
86 	} while (cont);
87 
88 	switch (param) {
89 	case -1:
90 		printf(_("You can't specify more than one "
91 			 "output-specific argument\n"));
92 		exit(EXIT_FAILURE);
93 	case '?':
94 		printf(_("invalid or unknown argument\n"));
95 		exit(EXIT_FAILURE);
96 	}
97 
98 	get_cpustate();
99 
100 	/* Default is: set all CPUs */
101 	if (bitmask_isallclear(cpus_chosen))
102 		bitmask_setall(cpus_chosen);
103 
104 	for (cpu = bitmask_first(cpus_chosen);
105 	     cpu <= bitmask_last(cpus_chosen); cpu++) {
106 
107 		if (!bitmask_isbitset(cpus_chosen, cpu))
108 			continue;
109 
110 		if (cpupower_is_cpu_online(cpu) != 1)
111 			continue;
112 
113 		idlestates = cpuidle_state_count(cpu);
114 		if (idlestates <= 0)
115 			continue;
116 
117 		switch (param) {
118 		case 'd':
119 			ret = cpuidle_state_disable(cpu, idlestate, 1);
120 			if (ret == 0)
121 		printf(_("Idlestate %u disabled on CPU %u\n"),  idlestate, cpu);
122 			else if (ret == -1)
123 		printf(_("Idlestate %u not available on CPU %u\n"),
124 		       idlestate, cpu);
125 			else if (ret == -2)
126 		printf(_("Idlestate disabling not supported by kernel\n"));
127 			else
128 		printf(_("Idlestate %u not disabled on CPU %u\n"),
129 		       idlestate, cpu);
130 			break;
131 		case 'e':
132 			ret = cpuidle_state_disable(cpu, idlestate, 0);
133 			if (ret == 0)
134 		printf(_("Idlestate %u enabled on CPU %u\n"),  idlestate, cpu);
135 			else if (ret == -1)
136 		printf(_("Idlestate %u not available on CPU %u\n"),
137 		       idlestate, cpu);
138 			else if (ret == -2)
139 		printf(_("Idlestate enabling not supported by kernel\n"));
140 			else
141 		printf(_("Idlestate %u not enabled on CPU %u\n"),
142 		       idlestate, cpu);
143 			break;
144 		case 'D':
145 			for (idlestate = 0; idlestate < idlestates; idlestate++) {
146 				disabled = cpuidle_is_state_disabled
147 					(cpu, idlestate);
148 				state_latency = cpuidle_state_latency
149 					(cpu, idlestate);
150 				if (disabled == 1) {
151 					if (latency > state_latency){
152 						ret = cpuidle_state_disable
153 							(cpu, idlestate, 0);
154 						if (ret == 0)
155 		printf(_("Idlestate %u enabled on CPU %u\n"),  idlestate, cpu);
156 					}
157 					continue;
158 				}
159 				if (latency <= state_latency){
160 					ret = cpuidle_state_disable
161 						(cpu, idlestate, 1);
162 					if (ret == 0)
163 		printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
164 				}
165 			}
166 			break;
167 		case 'E':
168 			for (idlestate = 0; idlestate < idlestates; idlestate++) {
169 				disabled = cpuidle_is_state_disabled
170 					(cpu, idlestate);
171 				if (disabled == 1) {
172 					ret = cpuidle_state_disable
173 						(cpu, idlestate, 0);
174 					if (ret == 0)
175 		printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
176 				}
177 			}
178 			break;
179 		default:
180 			/* Not reachable with proper args checking */
181 			printf(_("Invalid or unknown argument\n"));
182 			exit(EXIT_FAILURE);
183 			break;
184 		}
185 	}
186 
187 	print_offline_cpus();
188 	return EXIT_SUCCESS;
189 }
190