Skip to content

Commit a4251b8

Browse files
committed
power: powersafe-toggle: First final version
4 states: 0 - Default (Kernel default) 1 - Balanced 2 - Performance (with input boost & prime allowed to scale 3.12 Ghz) 3 - Powersafe (IO_Weight, Latency adjusted accordingly & boost disabled) This module relies on cpu_input_boost for more scalability. Testing showed great performance while consuming similar amount of battery. Finetuning for display, cpufreq, governor are on the to-do-list.
1 parent 674a493 commit a4251b8

File tree

1 file changed

+254
-23
lines changed

1 file changed

+254
-23
lines changed

drivers/power/powersafe-toggle.c

Lines changed: 254 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/pm_qos.h>
1111
#include <linux/proc_fs.h>
1212
#include <linux/uaccess.h>
13+
#include <linux/fs.h>
1314

1415
#define PROC_DIR "powersafe"
1516
#define MAX_BUF_LEN 32
@@ -18,10 +19,87 @@ static struct pm_qos_request latency_req;
1819
static struct proc_dir_entry *psafe_dir;
1920

2021
/* Track states */
21-
static int latency_state = 0; // 0 = default, 1 = 100µs
22-
static int prime_state = 0; // 0 = default, 1 = 2.84GHz
22+
static int latency_state = 0; // 0 = default, 1 = 100µs
23+
static int prime_state = 0; // 0 = default, 1 = 2.84GHz
2324
static unsigned int io_weight_state = 0; // 0 = default, else custom
24-
static int master_state = 0; // 0 = default, 1 = optimized
25+
static int master_state = 0; // 0 = default, 1 = optimized
26+
static int input_boost_state = 0; // 0 = off, 1 = on
27+
28+
/* ---------- Input boost helpers ---------- */
29+
30+
static void write_sysfs(const char *path, const char *val)
31+
{
32+
struct file *f;
33+
loff_t pos = 0;
34+
mm_segment_t oldfs;
35+
36+
oldfs = get_fs();
37+
set_fs(KERNEL_DS);
38+
39+
f = filp_open(path, O_WRONLY, 0);
40+
if (!IS_ERR(f)) {
41+
kernel_write(f, val, strlen(val), &pos);
42+
filp_close(f, NULL);
43+
}
44+
45+
set_fs(oldfs);
46+
}
47+
48+
static void set_input_boost_enabled(bool enable)
49+
{
50+
struct file *f;
51+
mm_segment_t oldfs;
52+
char buf[2];
53+
54+
snprintf(buf, sizeof(buf), "%d", enable ? 1 : 0);
55+
56+
oldfs = get_fs();
57+
set_fs(KERNEL_DS);
58+
59+
f = filp_open("/sys/module/cpu_input_boost/parameters/input_boost_enabled", O_WRONLY, 0);
60+
if (!IS_ERR(f)) {
61+
kernel_write(f, buf, strlen(buf), &f->f_pos);
62+
filp_close(f, NULL);
63+
}
64+
65+
set_fs(oldfs);
66+
}
67+
68+
static void set_input_boost_param_str(const char *name, const char *val)
69+
{
70+
char path[128];
71+
snprintf(path, sizeof(path), "/sys/module/cpu_input_boost/parameters/%s", name);
72+
write_sysfs(path, val);
73+
}
74+
75+
static void set_input_boost_param_int(const char *name, int val)
76+
{
77+
char buf[32];
78+
snprintf(buf, sizeof(buf), "%d", val);
79+
set_input_boost_param_str(name, buf);
80+
}
81+
82+
/* Convenience setters */
83+
static void configure_input_boost(int input_ms, int wake_ms,
84+
int little_boost, int big_boost, int prime_boost,
85+
int little_cap, int big_cap, int prime_cap,
86+
int little_min, int big_min, int prime_min)
87+
{
88+
set_input_boost_param_int("input_boost_ms", input_ms);
89+
set_input_boost_param_int("wake_boost_ms", wake_ms);
90+
91+
set_input_boost_param_int("l_cluster_boost_freq", little_boost);
92+
set_input_boost_param_int("b_cluster_boost_freq", big_boost);
93+
set_input_boost_param_int("p_cluster_boost_freq", prime_boost);
94+
95+
set_input_boost_param_int("l_cluster_max_boost_freq", little_cap);
96+
set_input_boost_param_int("b_cluster_max_boost_freq", big_cap);
97+
set_input_boost_param_int("p_cluster_max_boost_freq", prime_cap);
98+
99+
set_input_boost_param_int("little_default_min_freq", little_min);
100+
set_input_boost_param_int("big_default_min_freq", big_min);
101+
set_input_boost_param_int("prime_default_min_freq", prime_min);
102+
}
25103

26104
/* ---------- Latency toggle ---------- */
27105
static ssize_t latency_toggle_write(struct file *file, const char __user *buf,
@@ -131,52 +209,197 @@ static const struct file_operations io_weight_ops = {
131209
.read = io_weight_read,
132210
};
133211

212+
/* ---------- Input boost proc entries ---------- */
213+
214+
static ssize_t input_boost_state_read(struct file *file, char __user *buf,
215+
size_t count, loff_t *ppos)
216+
{
217+
char kbuf[MAX_BUF_LEN];
218+
int len;
219+
220+
if (*ppos > 0)
221+
return 0;
222+
223+
len = snprintf(kbuf, sizeof(kbuf), "%d\n", input_boost_state);
224+
if (copy_to_user(buf, kbuf, len))
225+
return -EFAULT;
226+
227+
*ppos = len;
228+
return len;
229+
}
230+
231+
static const struct file_operations input_boost_state_fops = {
232+
.owner = THIS_MODULE,
233+
.read = input_boost_state_read,
234+
.llseek = noop_llseek,
235+
};
236+
237+
static ssize_t input_boost_write(struct file *file, const char __user *ubuf,
238+
size_t count, loff_t *ppos)
239+
{
240+
char kbuf[MAX_BUF_LEN];
241+
int val;
242+
243+
if (count == 0 || count >= MAX_BUF_LEN)
244+
return -EINVAL;
245+
246+
if (copy_from_user(kbuf, ubuf, count))
247+
return -EFAULT;
248+
249+
kbuf[count] = '\0';
250+
251+
if (kstrtoint(kbuf, 10, &val))
252+
return -EINVAL;
253+
254+
if (val == 0 || val == 1) {
255+
input_boost_state = val;
256+
set_input_boost_enabled(val);
257+
pr_info("powersafe: input boost manually %s\n", val ? "enabled" : "disabled");
258+
return count;
259+
}
260+
261+
return -EINVAL;
262+
}
263+
264+
static const struct file_operations input_boost_fops = {
265+
.owner = THIS_MODULE,
266+
.write = input_boost_write,
267+
.llseek = noop_llseek,
268+
};
269+
134270
/* ---------- Master toggle ---------- */
135-
static ssize_t master_toggle_write(struct file *file, const char __user *buf,
271+
static ssize_t master_toggle_write(struct file *file, const char __user *ubuf,
136272
size_t count, loff_t *ppos)
137273
{
138274
char kbuf[MAX_BUF_LEN];
275+
int new_state;
139276
struct cpufreq_policy *policy;
140277

141-
if (copy_from_user(kbuf, buf, count))
278+
if (count == 0 || count >= MAX_BUF_LEN)
279+
return -EINVAL;
280+
281+
if (copy_from_user(kbuf, ubuf, count))
142282
return -EFAULT;
143283

144-
if (kbuf[0] == '1') {
145-
/* Optimized profile */
146-
pm_qos_update_request(&latency_req, 100);
284+
kbuf[count] = '\0';
285+
286+
if (kstrtoint(kbuf, 10, &new_state))
287+
return -EINVAL;
288+
289+
switch (new_state) {
290+
case 0: /* Default */
291+
pm_qos_update_request(&latency_req, PM_QOS_DEFAULT_VALUE);
292+
latency_state = 0;
293+
io_weight_state = 0;
294+
prime_state = 0;
295+
296+
/* Restore prime max to default */
297+
policy = cpufreq_cpu_get(7);
298+
if (policy) {
299+
policy->max = policy->cpuinfo.max_freq;
300+
cpufreq_update_policy(policy->cpu);
301+
cpufreq_cpu_put(policy);
302+
}
303+
304+
/* Input boost off, baseline mins */
305+
input_boost_state = 0;
306+
set_input_boost_enabled(false);
307+
configure_input_boost(
308+
0, 0,
309+
0, 0, 0,
310+
0, 0, 0,
311+
600000, 825600, 844800
312+
);
313+
314+
pr_info("powersafe: state=0 (default)\n");
315+
break;
316+
317+
case 1: /* Balanced */
318+
pm_qos_update_request(&latency_req, 200);
147319
latency_state = 1;
320+
io_weight_state = 250;
321+
prime_state = 0;
148322

323+
/* Prime left at default */
149324
policy = cpufreq_cpu_get(7);
150325
if (policy) {
151-
policy->max = 2841600;
326+
policy->max = policy->cpuinfo.max_freq;
152327
cpufreq_update_policy(policy->cpu);
153328
cpufreq_cpu_put(policy);
154329
}
155-
prime_state = 1;
156330

331+
/* Input boost moderate */
332+
input_boost_state = 1;
333+
set_input_boost_enabled(true);
334+
configure_input_boost(
335+
58, 0,
336+
1708800, 1056000, 1401600,
337+
1804800, 2246400, 2553600,
338+
1171200, 825600, 844800
339+
);
340+
341+
pr_info("powersafe: state=1 (balanced)\n");
342+
break;
343+
344+
case 2: /* Performance + prime boost */
345+
pm_qos_update_request(&latency_req, 100);
346+
latency_state = 1;
157347
io_weight_state = 500;
158-
pr_info("powersafe-toggle: io.weight set to 500\n");
348+
prime_state = 1;
159349

160-
master_state = 1;
161-
} else {
162-
/* Default profile: restore system defaults */
163-
pm_qos_update_request(&latency_req, PM_QOS_DEFAULT_VALUE);
164-
latency_state = 0;
350+
/* Prime boosted to 3.12 GHz */
351+
policy = cpufreq_cpu_get(7);
352+
if (policy) {
353+
policy->max = 3120000;
354+
cpufreq_update_policy(policy->cpu);
355+
cpufreq_cpu_put(policy);
356+
}
357+
358+
/* Input boost aggressive */
359+
input_boost_state = 1;
360+
set_input_boost_enabled(true);
361+
configure_input_boost(
362+
100, 1000,
363+
1708800, 2016000, 2841600,
364+
1804800, 2246400, 3120000,
365+
1171200, 1324800, 1804800
366+
);
367+
368+
pr_info("powersafe: state=2 (performance, prime boost)\n");
369+
break;
370+
371+
case 3: /* Powersafe */
372+
pm_qos_update_request(&latency_req, 400);
373+
latency_state = 1;
374+
io_weight_state = 100;
375+
prime_state = 0;
165376

377+
/* Prime back to default */
166378
policy = cpufreq_cpu_get(7);
167379
if (policy) {
168380
policy->max = policy->cpuinfo.max_freq;
169381
cpufreq_update_policy(policy->cpu);
170382
cpufreq_cpu_put(policy);
171383
}
172-
prime_state = 0;
173384

174-
io_weight_state = 0;
175-
pr_info("powersafe-toggle: io.weight reset to default\n");
385+
/* Input boost disabled, conservative mins */
386+
input_boost_state = 0;
387+
set_input_boost_enabled(false);
388+
configure_input_boost(
389+
0, 0,
390+
0, 0, 0,
391+
0, 0, 0,
392+
600000, 825600, 844800
393+
);
394+
395+
pr_info("powersafe: state=3 (powersafe)\n");
396+
break;
176397

177-
master_state = 0;
398+
default:
399+
return -EINVAL;
178400
}
179401

402+
master_state = new_state;
180403
return count;
181404
}
182405

@@ -201,24 +424,32 @@ static int __init powersafe_init(void)
201424
if (!psafe_dir)
202425
return -ENOMEM;
203426

427+
/* Existing entries */
204428
proc_create("latency_toggle", 0666, psafe_dir, &latency_toggle_ops);
205429
proc_create("prime_freq_boost", 0666, psafe_dir, &prime_freq_boost_ops);
206430
proc_create("io_weight", 0666, psafe_dir, &io_weight_ops);
207431
proc_create("master_toggle", 0666, psafe_dir, &master_toggle_ops);
208432

433+
/* New input boost entries */
434+
proc_create("input_boost_state", 0444, psafe_dir, &input_boost_state_fops);
435+
proc_create("input_boost", 0222, psafe_dir, &input_boost_fops);
436+
209437
pm_qos_add_request(&latency_req, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
210438

211-
pr_info("powersafe-toggle loaded\n");
439+
pr_info("powersafe-toggle loaded (with input boost)\n");
212440
return 0;
213441
}
214442

215443
static void __exit powersafe_exit(void)
216444
{
217445
pm_qos_remove_request(&latency_req);
446+
218447
remove_proc_entry("latency_toggle", psafe_dir);
219448
remove_proc_entry("prime_freq_boost", psafe_dir);
220449
remove_proc_entry("io_weight", psafe_dir);
221450
remove_proc_entry("master_toggle", psafe_dir);
451+
remove_proc_entry("input_boost_state", psafe_dir);
452+
remove_proc_entry("input_boost", psafe_dir);
222453
remove_proc_entry(PROC_DIR, NULL);
223454

224455
pr_info("powersafe-toggle unloaded\n");
@@ -227,5 +458,5 @@ static void __exit powersafe_exit(void)
227458
module_init(powersafe_init);
228459
module_exit(powersafe_exit);
229460
MODULE_LICENSE("GPL");
230-
MODULE_AUTHOR("Manuel & Copilot");
231-
MODULE_DESCRIPTION("Eff-CPU Runtime Toggle Module with Master Switch and Read Handlers");
461+
MODULE_AUTHOR("dtrail & Copilot");
462+
MODULE_DESCRIPTION("Powersafe Toggle Module with Master Switch, Input Boost, and Read Handlers");

0 commit comments

Comments
 (0)