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 		case 'e':
45 			if (param) {
46 				param = -1;
47 				cont = 0;
48 				break;
49 			}
50 			param = ret;
51 			strtol(optarg, &endptr, 10);
52 			if (*endptr != '\0') {
53 				printf(_("Bad value: %s, Integer expected\n"), optarg);
54 				exit(EXIT_FAILURE);
55 			} else {
56 				idlestate = atoi(optarg);
57 			}
58 			break;
59 		case 'D':
60 			if (param) {
61 				param = -1;
62 				cont = 0;
63 				break;
64 			}
65 			param = ret;
66 			latency = strtoull(optarg, &endptr, 10);
67 			if (*endptr != '\0') {
68 				printf(_("Bad latency value: %s\n"), optarg);
69 				exit(EXIT_FAILURE);
70 			}
71 			break;
72 		case 'E':
73 			if (param) {
74 				param = -1;
75 				cont = 0;
76 				break;
77 			}
78 			param = ret;
79 			break;
80 		case -1:
81 			cont = 0;
82 			break;
83 		}
84 	} while (cont);
85 
86 	switch (param) {
87 	case -1:
88 		printf(_("You can't specify more than one "
89 			 "output-specific argument\n"));
90 		exit(EXIT_FAILURE);
91 	case '?':
92 		printf(_("invalid or unknown argument\n"));
93 		exit(EXIT_FAILURE);
94 	}
95 
96 	get_cpustate();
97 
98 	/* Default is: set all CPUs */
99 	if (bitmask_isallclear(cpus_chosen))
100 		bitmask_setall(cpus_chosen);
101 
102 	for (cpu = bitmask_first(cpus_chosen);
103 	     cpu <= bitmask_last(cpus_chosen); cpu++) {
104 
105 		if (!bitmask_isbitset(cpus_chosen, cpu))
106 			continue;
107 
108 		if (cpupower_is_cpu_online(cpu) != 1)
109 			continue;
110 
111 		idlestates = cpuidle_state_count(cpu);
112 		if (idlestates <= 0)
113 			continue;
114 
115 		switch (param) {
116 		case 'd':
117 			ret = cpuidle_state_disable(cpu, idlestate, 1);
118 			if (ret == 0)
119 		printf(_("Idlestate %u disabled on CPU %u\n"),  idlestate, cpu);
120 			else if (ret == -1)
121 		printf(_("Idlestate %u not available on CPU %u\n"),
122 		       idlestate, cpu);
123 			else if (ret == -2)
124 		printf(_("Idlestate disabling not supported by kernel\n"));
125 			else
126 		printf(_("Idlestate %u not disabled on CPU %u\n"),
127 		       idlestate, cpu);
128 			break;
129 		case 'e':
130 			ret = cpuidle_state_disable(cpu, idlestate, 0);
131 			if (ret == 0)
132 		printf(_("Idlestate %u enabled on CPU %u\n"),  idlestate, cpu);
133 			else if (ret == -1)
134 		printf(_("Idlestate %u not available on CPU %u\n"),
135 		       idlestate, cpu);
136 			else if (ret == -2)
137 		printf(_("Idlestate enabling not supported by kernel\n"));
138 			else
139 		printf(_("Idlestate %u not enabled on CPU %u\n"),
140 		       idlestate, cpu);
141 			break;
142 		case 'D':
143 			for (idlestate = 0; idlestate < idlestates; idlestate++) {
144 				disabled = cpuidle_is_state_disabled
145 					(cpu, idlestate);
146 				state_latency = cpuidle_state_latency
147 					(cpu, idlestate);
148 				if (disabled == 1) {
149 					if (latency > state_latency){
150 						ret = cpuidle_state_disable
151 							(cpu, idlestate, 0);
152 						if (ret == 0)
153 		printf(_("Idlestate %u enabled on CPU %u\n"),  idlestate, cpu);
154 					}
155 					continue;
156 				}
157 				if (latency <= state_latency){
158 					ret = cpuidle_state_disable
159 						(cpu, idlestate, 1);
160 					if (ret == 0)
161 		printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
162 				}
163 			}
164 			break;
165 		case 'E':
166 			for (idlestate = 0; idlestate < idlestates; idlestate++) {
167 				disabled = cpuidle_is_state_disabled
168 					(cpu, idlestate);
169 				if (disabled == 1) {
170 					ret = cpuidle_state_disable
171 						(cpu, idlestate, 0);
172 					if (ret == 0)
173 		printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
174 				}
175 			}
176 			break;
177 		default:
178 			/* Not reachable with proper args checking */
179 			printf(_("Invalid or unknown argument\n"));
180 			exit(EXIT_FAILURE);
181 			break;
182 		}
183 	}
184 
185 	print_offline_cpus();
186 	return EXIT_SUCCESS;
187 }
188