From fb36ab4a7cdd59d31a467bb523980a45d5b674ed Mon Sep 17 00:00:00 2001 From: franciscofranco Date: Fri, 11 Aug 2017 15:05:37 +0200 Subject: [PATCH 01/19] [PATCH] touchboost: squash the latest code from FK for Hammerhead --- drivers/input/touchscreen/touchboost.c | 87 ++++++++++---------------- include/linux/touchboost.h | 15 +++++ 2 files changed, 49 insertions(+), 53 deletions(-) create mode 100644 include/linux/touchboost.h diff --git a/drivers/input/touchscreen/touchboost.c b/drivers/input/touchscreen/touchboost.c index 8cf93163682..b3f592bed93 100644 --- a/drivers/input/touchscreen/touchboost.c +++ b/drivers/input/touchscreen/touchboost.c @@ -14,53 +14,45 @@ #include #include #include -#include #include #include #include -#include -#include -#include #include #include +#include -#define MIM_TIME_INTERVAL_US (150 * USEC_PER_MSEC) +#define MIN_TIME_INTERVAL_US (50 * USEC_PER_MSEC) + +struct touchboost_inputopen { + struct input_handle *handle; + struct work_struct inputopen_work; +} touchboost_inputopen; /* * Use this variable in your governor of choice to calculate when the cpufreq * core is allowed to ramp the cpu down after an input event. That logic is done * by you, this var only outputs the last time in us an event was captured */ -u64 last_input_time; +static u64 last_input_time = 0; -struct touchboost_inputopen { - struct input_handle *handle; - struct work_struct inputopen_work; -} touchboost_inputopen; +inline u64 get_input_time(void) +{ + return last_input_time; +} static void boost_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { u64 now; - now = ktime_to_us(ktime_get()); + if ((type == EV_ABS)) { + now = ktime_to_us(ktime_get()); - if (now - last_input_time < MIM_TIME_INTERVAL_US) - return; + if (now - last_input_time < MIN_TIME_INTERVAL_US) + return; - last_input_time = ktime_to_us(ktime_get()); -} - -static void boost_input_open(struct work_struct *w) -{ - struct touchboost_inputopen *io = - container_of(w, struct touchboost_inputopen, inputopen_work); - - int error; - - error = input_open_device(io->handle); - if (error) - input_unregister_handle(io->handle); + last_input_time = ktime_to_us(ktime_get()); + } } static int boost_input_connect(struct input_handler *handler, @@ -69,20 +61,24 @@ static int boost_input_connect(struct input_handler *handler, struct input_handle *handle; int error; - handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); - if (!handle) + handle = kzalloc(sizeof(*handle), GFP_KERNEL); + if (handle == NULL) return -ENOMEM; handle->dev = dev; handle->handler = handler; - handle->name = "touchboost"; + handle->name = handler->name; error = input_register_handle(handle); if (error) goto err; - touchboost_inputopen.handle = handle; - schedule_work(&touchboost_inputopen.inputopen_work); + error = input_open_device(handle); + if (error) { + input_unregister_handle(handle); + goto err; + } + return 0; err: @@ -98,27 +94,13 @@ static void boost_input_disconnect(struct input_handle *handle) } static const struct input_device_id boost_ids[] = { - /* multi-touch touchscreen */ { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_ABSBIT, + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, .evbit = { BIT_MASK(EV_ABS) }, + /* assumption: MT_.._X & MT_.._Y are in the same long */ .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = - BIT_MASK(ABS_MT_POSITION_X) | - BIT_MASK(ABS_MT_POSITION_Y) }, - }, - /* touchpad */ - { - .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | - INPUT_DEVICE_ID_MATCH_ABSBIT, - .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, - .absbit = { [BIT_WORD(ABS_X)] = - BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, - }, - /* Keypad */ - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_KEY) }, + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, }, { }, }; @@ -131,11 +113,10 @@ static struct input_handler boost_input_handler = { .id_table = boost_ids, }; -static int init(void) +static int __init init(void) { - INIT_WORK(&touchboost_inputopen.inputopen_work, boost_input_open); - - input_register_handler(&boost_input_handler); + if (input_register_handler(&boost_input_handler)) + pr_info("Unable to register the input handler\n"); return 0; } diff --git a/include/linux/touchboost.h b/include/linux/touchboost.h new file mode 100644 index 00000000000..1e7af26a21d --- /dev/null +++ b/include/linux/touchboost.h @@ -0,0 +1,15 @@ +/* + * linux/include/linux/touchboost.h + * + * franciscofranco.1990@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _LINUX_TOUCHBOOST_H +#define _LINUX_TOUCHBOOST_H + +u64 get_input_time(void); + +#endif From 7c6b282b6167a159dd8a65628cd620d2e52964ca Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 11 Aug 2017 15:09:25 +0200 Subject: [PATCH 02/19] enable ARCH_POWER --- kernel/sched_features.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched_features.h b/kernel/sched_features.h index 48e69155111..0d6d7348ce0 100644 --- a/kernel/sched_features.h +++ b/kernel/sched_features.h @@ -47,7 +47,7 @@ SCHED_FEAT(CACHE_HOT_BUDDY, 1) /* * Use arch dependent cpu power functions */ -SCHED_FEAT(ARCH_POWER, 0) +SCHED_FEAT(ARCH_POWER, 1) SCHED_FEAT(HRTICK, 0) SCHED_FEAT(DOUBLE_TICK, 0) From dd1e85c300acb766b171f21b2ae7fb7c6f5048be Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 10 Mar 2015 23:57:40 -0700 Subject: [PATCH 03/19] grouper: Fix pinmux init race condition Pinmux init does not complete early enough on some devices, causing the device to not boot. Signed-off-by: Sultanxda --- arch/arm/mach-tegra/board-grouper.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-tegra/board-grouper.c b/arch/arm/mach-tegra/board-grouper.c index c525ab624f1..4a9654b21ba 100644 --- a/arch/arm/mach-tegra/board-grouper.c +++ b/arch/arm/mach-tegra/board-grouper.c @@ -1084,7 +1084,6 @@ static void __init tegra_grouper_init(void) grouper_misc_init(); tegra_thermal_init(&thermal_data); tegra_clk_init_from_table(grouper_clk_init_table); - grouper_pinmux_init(); grouper_misc_reset(); grouper_booting_info(); grouper_i2c_init(); @@ -1140,11 +1139,17 @@ static void __init tegra_grouper_reserve(void) grouper_ramconsole_reserve(SZ_1M); } +static void __init tegra_grouper_init_early(void) +{ + tegra_init_early(); + grouper_pinmux_init(); +} + MACHINE_START(GROUPER, "grouper") .boot_params = 0x80000100, .map_io = tegra_map_common_io, .reserve = tegra_grouper_reserve, - .init_early = tegra_init_early, + .init_early = tegra_grouper_init_early, .init_irq = tegra_init_irq, .timer = &tegra_timer, .init_machine = tegra_grouper_init, From 5499e6a1614b1f9f5fd8500baefeddf36411b38d Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Fri, 11 Aug 2017 15:41:34 +0200 Subject: [PATCH 04/19] grouper: panel: Move screen-flicker hack to grouper board --- arch/arm/mach-tegra/board-grouper-panel.c | 8 ++++++++ drivers/video/tegra/dc/dc.c | 4 ---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-tegra/board-grouper-panel.c b/arch/arm/mach-tegra/board-grouper-panel.c index eb53370ec85..e19aa97ea01 100644 --- a/arch/arm/mach-tegra/board-grouper-panel.c +++ b/arch/arm/mach-tegra/board-grouper-panel.c @@ -217,6 +217,13 @@ static struct platform_device grouper_backlight_device = { }, }; +static int grouper_panel_prepoweroff(void) +{ + gpio_set_value(grouper_lvds_shutdown, 0); + + return 0; +} + static int grouper_panel_postpoweron(void) { if (grouper_lvds_reg == NULL) { @@ -600,6 +607,7 @@ static struct tegra_dc_out grouper_disp1_out = { .modes = grouper_panel_modes, .n_modes = ARRAY_SIZE(grouper_panel_modes), + .prepoweroff = grouper_panel_prepoweroff, .enable = grouper_panel_enable, .disable = grouper_panel_disable, .postpoweron = grouper_panel_postpoweron, diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c index e95c000bfd4..ffb18a5a7e5 100644 --- a/drivers/video/tegra/dc/dc.c +++ b/drivers/video/tegra/dc/dc.c @@ -50,7 +50,6 @@ #include "dc_reg.h" #include "dc_priv.h" #include "nvsd.h" -#include #define TEGRA_CRC_LATCHED_DELAY 34 @@ -66,7 +65,6 @@ static int no_vsync; static struct timeval t_suspend; -#define grouper_lvds_shutdown 110 static void _tegra_dc_controller_disable(struct tegra_dc *dc); @@ -2666,8 +2664,6 @@ static void _tegra_dc_controller_disable(struct tegra_dc *dc) } } - gpio_set_value(grouper_lvds_shutdown, 0); - if (dc->out_ops && dc->out_ops->disable) dc->out_ops->disable(dc); From 73d4212a8fe0ddca1635206acd050bf64c177a45 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sun, 15 Mar 2015 00:04:37 -0700 Subject: [PATCH 05/19] cpufreq: Add CPU Input Boost driver Signed-off-by: Sultanxda --- drivers/cpufreq/Kconfig | 5 + drivers/cpufreq/Makefile | 3 + drivers/cpufreq/cpu_input_boost.c | 281 ++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 drivers/cpufreq/cpu_input_boost.c diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index bc7938690ca..c49ee44cd4a 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -228,6 +228,11 @@ depends on X86 source "drivers/cpufreq/Kconfig.x86" endmenu +config CPU_INPUT_BOOST + bool "CPU Input Boost" + help + Boost the CPU on touchscreen, touchpad, and keypad input. + menu "ARM CPU frequency scaling drivers" depends on ARM source "drivers/cpufreq/Kconfig.arm" diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index a6ad8c43449..02764c9bbdc 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -3,6 +3,9 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o +# CPU Input Boost +obj-$(CONFIG_CPU_INPUT_BOOST) += cpu_input_boost.o + # CPUfreq governors obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c new file mode 100644 index 00000000000..f2d97d56dac --- /dev/null +++ b/drivers/cpufreq/cpu_input_boost.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2014-2015, Sultanxda + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "CPU-boost: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + UNBOOST, + BOOST, +}; + +struct boost_policy { + unsigned int boost_freq; + unsigned int boost_ms; + unsigned int cpu; + unsigned int cpu_boost; + struct work_struct boost_work; + struct delayed_work restore_work; +}; + +static DEFINE_PER_CPU(struct boost_policy, boost_info); +static struct workqueue_struct *boost_wq; + +static bool suspended; + +static u64 last_input_time; +#define MIN_INPUT_INTERVAL (150 * USEC_PER_MSEC) + +static unsigned int input_boost_freq; +module_param(input_boost_freq, uint, 0644); + +static unsigned int input_boost_ms; +module_param(input_boost_ms, uint, 0644); + +static void set_boost(struct boost_policy *b, unsigned int boost) +{ + b->cpu_boost = boost; + get_online_cpus(); + if (cpu_online(b->cpu)) + cpufreq_update_policy(b->cpu); + put_online_cpus(); +} + +static void boost_all_cpus(unsigned int freq, unsigned int ms) +{ + struct boost_policy *b; + unsigned int cpu; + + for_each_possible_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + b->boost_freq = freq; + b->boost_ms = ms; + queue_work(boost_wq, &b->boost_work); + } +} + +static void __cpuinit cpu_boost_main(struct work_struct *work) +{ + struct boost_policy *b = container_of(work, struct boost_policy, + boost_work); + + cancel_delayed_work_sync(&b->restore_work); + + /* Boost must be set from within work context to prevent deadlock. */ + set_boost(b, BOOST); + + queue_delayed_work(boost_wq, &b->restore_work, + msecs_to_jiffies(b->boost_ms)); +} + +static void __cpuinit cpu_restore_main(struct work_struct *work) +{ + struct boost_policy *b = container_of(work, struct boost_policy, + restore_work.work); + + set_boost(b, UNBOOST); +} + +static int cpu_do_boost(struct notifier_block *nb, unsigned long val, void *data) +{ + struct cpufreq_policy *policy = data; + struct boost_policy *b = &per_cpu(boost_info, policy->cpu); + + if (val != CPUFREQ_ADJUST) + return NOTIFY_OK; + + switch (b->cpu_boost) { + case UNBOOST: + policy->min = policy->cpuinfo.min_freq; + break; + case BOOST: + if (b->boost_freq > policy->max) + b->boost_freq = policy->max; + policy->min = b->boost_freq; + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block cpu_do_boost_nb = { + .notifier_call = cpu_do_boost, +}; + +static void cpu_boost_early_suspend(struct early_suspend *handler) +{ + struct boost_policy *b; + unsigned int cpu; + + suspended = true; + + for_each_possible_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + if (cancel_delayed_work_sync(&b->restore_work)) + set_boost(b, UNBOOST); + } +} + +static void __cpuinit cpu_boost_late_resume(struct early_suspend *handler) +{ + suspended = false; +} + +static struct early_suspend __refdata cpu_boost_early_suspend_handler = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN, + .suspend = cpu_boost_early_suspend, + .resume = cpu_boost_late_resume, +}; + +static void cpu_boost_input_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + struct boost_policy *b; + unsigned int cpu; + u64 now; + + if (suspended || !input_boost_freq || !input_boost_ms) + return; + + now = ktime_to_us(ktime_get()); + if (now - last_input_time < MIN_INPUT_INTERVAL) + return; + + /* exit if boost is pending for any cpu */ + for_each_possible_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + if (work_pending(&b->boost_work)) + return; + } + + boost_all_cpus(input_boost_freq, input_boost_ms); + last_input_time = ktime_to_us(ktime_get()); +} + +static int cpu_boost_input_connect(struct input_handler *handler, + struct input_dev *dev, const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "cpu_input_boost"; + + error = input_register_handle(handle); + if (error) + goto err2; + + error = input_open_device(handle); + if (error) + goto err1; + + return 0; +err1: + input_unregister_handle(handle); +err2: + kfree(handle); + return error; +} + +static void cpu_boost_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id cpu_boost_ids[] = { + /* multi-touch touchscreen */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .evbit = { BIT_MASK(EV_ABS) }, + .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = + BIT_MASK(ABS_MT_POSITION_X) | + BIT_MASK(ABS_MT_POSITION_Y) }, + }, + /* touchpad */ + { + .flags = INPUT_DEVICE_ID_MATCH_KEYBIT | + INPUT_DEVICE_ID_MATCH_ABSBIT, + .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, + .absbit = { [BIT_WORD(ABS_X)] = + BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, + }, + /* keypad */ + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; + +static struct input_handler cpu_boost_input_handler = { + .event = cpu_boost_input_event, + .connect = cpu_boost_input_connect, + .disconnect = cpu_boost_input_disconnect, + .name = "cpu_input_boost", + .id_table = cpu_boost_ids, +}; + +static int __init cpu_boost_init(void) +{ + struct boost_policy *b; + unsigned int cpu; + int ret; + + boost_wq = alloc_workqueue("cpu_input_boost_wq", WQ_HIGHPRI, 0); + if (!boost_wq) { + pr_err("Failed to allocate workqueue\n"); + ret = -EFAULT; + goto fail; + } + + cpufreq_register_notifier(&cpu_do_boost_nb, CPUFREQ_POLICY_NOTIFIER); + + for_each_possible_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + b->cpu = cpu; + INIT_WORK(&b->boost_work, cpu_boost_main); + INIT_DELAYED_WORK(&b->restore_work, cpu_restore_main); + } + + ret = input_register_handler(&cpu_boost_input_handler); + if (ret) { + pr_err("Failed to register input handler, err: %d\n", ret); + goto fail; + } + + register_early_suspend(&cpu_boost_early_suspend_handler); +fail: + return ret; +} +late_initcall(cpu_boost_init); + +MODULE_AUTHOR("Sultanxda "); +MODULE_DESCRIPTION("CPU Input Boost"); +MODULE_LICENSE("GPLv2"); From a0601445bb4f88431bd1f9ac2f3f4b2a342c6010 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sat, 14 Mar 2015 23:58:17 -0700 Subject: [PATCH 06/19] cpu_input_boost: Add power-saving algorithm to selectively boost CPUs Instead of boosting all CPUs, CPU input boost now checks two factors when determining the amount of CPUs to boost: the number of CPUs that are online and the current frequency of online CPUs. Each of these factors can only queue up to 2 CPUs for boosting, and a maximum of 3 out of 4 CPUs can boosted at once (or 2 CPUs on dual-core systems). A new sysfs parameter, up_threshold, has been added which can tweak the aggressiveness of the first half of the power algorithm (the current frequency of each online CPU). Online CPUs are given priority when boosting. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 108 ++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 28 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index f2d97d56dac..f22cafebe8f 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -33,24 +33,36 @@ struct boost_policy { unsigned int boost_ms; unsigned int cpu; unsigned int cpu_boost; - struct work_struct boost_work; struct delayed_work restore_work; }; static DEFINE_PER_CPU(struct boost_policy, boost_info); static struct workqueue_struct *boost_wq; +static struct work_struct boost_work; static bool suspended; static u64 last_input_time; #define MIN_INPUT_INTERVAL (150 * USEC_PER_MSEC) +#define NR_CPUS CONFIG_NR_CPUS + +/* Boost frequency in kHz */ static unsigned int input_boost_freq; module_param(input_boost_freq, uint, 0644); +/* Boost duration in millsecs */ static unsigned int input_boost_ms; module_param(input_boost_ms, uint, 0644); +/** + * Percentage threshold used to boost CPUs (default 30%). A higher + * value will cause more CPUs to be boosted -- CPUs are boosted + * when ((current_freq/max_freq) * 100) < input_boost_up_threshold + */ +static unsigned int input_boost_up_threshold = 30; +module_param(input_boost_up_threshold, uint, 0644); + static void set_boost(struct boost_policy *b, unsigned int boost) { b->cpu_boost = boost; @@ -60,31 +72,76 @@ static void set_boost(struct boost_policy *b, unsigned int boost) put_online_cpus(); } -static void boost_all_cpus(unsigned int freq, unsigned int ms) +static void __cpuinit cpu_boost_main(struct work_struct *work) { struct boost_policy *b; - unsigned int cpu; + struct cpufreq_policy *policy; + unsigned int cpu, nr_cpus_to_boost = 0, nr_online_cpus = 0; - for_each_possible_cpu(cpu) { - b = &per_cpu(boost_info, cpu); - b->boost_freq = freq; - b->boost_ms = ms; - queue_work(boost_wq, &b->boost_work); + /* Num of CPUs to be boosted based on current freq of each online CPU */ + get_online_cpus(); + for_each_online_cpu(cpu) { + nr_online_cpus++; + + /* Only allow 2 CPUs to be staged for boosting from here */ + if (nr_cpus_to_boost < 2) { + policy = cpufreq_cpu_get(cpu); + if (policy != NULL) { + if ((policy->cur * 100 / policy->max) < input_boost_up_threshold) + nr_cpus_to_boost++; + cpufreq_cpu_put(policy); + } + } } -} -static void __cpuinit cpu_boost_main(struct work_struct *work) -{ - struct boost_policy *b = container_of(work, struct boost_policy, - boost_work); + /* Num of CPUs to be boosted based on how many of them are online */ + switch (nr_online_cpus * 100 / NR_CPUS) { + case 0 ... 25: + nr_cpus_to_boost += 2; + break; + case 26 ... 75: + nr_cpus_to_boost++; + break; + } - cancel_delayed_work_sync(&b->restore_work); + if (!nr_cpus_to_boost) + goto put_cpus; - /* Boost must be set from within work context to prevent deadlock. */ - set_boost(b, BOOST); + /* Prioritize boosting of online CPUs */ + for_each_online_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + b->boost_freq = input_boost_freq; + b->boost_ms = input_boost_ms; + cancel_delayed_work_sync(&b->restore_work); + b->cpu_boost = BOOST; + cpufreq_update_policy(b->cpu); + queue_delayed_work(boost_wq, &b->restore_work, + msecs_to_jiffies(b->boost_ms)); + nr_cpus_to_boost--; + if (cpu == nr_cpus_to_boost) + goto put_cpus; + } + + /* Boost offline CPUs if we still need to boost more CPUs */ + for_each_possible_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + + /* Only boost CPUs that are not already boosted (offline CPUs) */ + if (b->cpu_boost == UNBOOST) { + b->boost_freq = input_boost_freq; + b->boost_ms = input_boost_ms; + cancel_delayed_work_sync(&b->restore_work); + b->cpu_boost = BOOST; + queue_delayed_work(boost_wq, &b->restore_work, + msecs_to_jiffies(b->boost_ms)); + nr_cpus_to_boost--; + if (cpu == nr_cpus_to_boost) + goto put_cpus; + } + } - queue_delayed_work(boost_wq, &b->restore_work, - msecs_to_jiffies(b->boost_ms)); +put_cpus: + put_online_cpus(); } static void __cpuinit cpu_restore_main(struct work_struct *work) @@ -149,8 +206,6 @@ static struct early_suspend __refdata cpu_boost_early_suspend_handler = { static void cpu_boost_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { - struct boost_policy *b; - unsigned int cpu; u64 now; if (suspended || !input_boost_freq || !input_boost_ms) @@ -160,14 +215,10 @@ static void cpu_boost_input_event(struct input_handle *handle, unsigned int type if (now - last_input_time < MIN_INPUT_INTERVAL) return; - /* exit if boost is pending for any cpu */ - for_each_possible_cpu(cpu) { - b = &per_cpu(boost_info, cpu); - if (work_pending(&b->boost_work)) - return; - } + if (unlikely(work_pending(&boost_work))) + return; - boost_all_cpus(input_boost_freq, input_boost_ms); + queue_work(boost_wq, &boost_work); last_input_time = ktime_to_us(ktime_get()); } @@ -260,10 +311,11 @@ static int __init cpu_boost_init(void) for_each_possible_cpu(cpu) { b = &per_cpu(boost_info, cpu); b->cpu = cpu; - INIT_WORK(&b->boost_work, cpu_boost_main); INIT_DELAYED_WORK(&b->restore_work, cpu_restore_main); } + INIT_WORK(&boost_work, cpu_boost_main); + ret = input_register_handler(&cpu_boost_input_handler); if (ret) { pr_err("Failed to register input handler, err: %d\n", ret); From 14849f2e9a6e66f751c35569537359a24d9f07c5 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 11 Aug 2017 15:55:20 +0200 Subject: [PATCH 07/19] tegra3_android_defconfig: Enable CPU input boosting --- arch/arm/configs/tegra3_android_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/tegra3_android_defconfig b/arch/arm/configs/tegra3_android_defconfig index e641c54a3b7..0a7de658120 100644 --- a/arch/arm/configs/tegra3_android_defconfig +++ b/arch/arm/configs/tegra3_android_defconfig @@ -516,6 +516,8 @@ CONFIG_CPU_FREQ_GOV_ONDEMAND=y CONFIG_CPU_FREQ_GOV_INTERACTIVE=y CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y CONFIG_CPU_FREQ_GOV_INTELLIACTIVE=y +CONFIG_CPU_INPUT_BOOST=y + # # ARM CPU frequency scaling drivers From 22016c9cd5e19ab956fc6f7c491c2ffcf0b66593 Mon Sep 17 00:00:00 2001 From: AndDiSa Date: Fri, 11 Aug 2017 16:08:17 +0200 Subject: [PATCH 08/19] fix compile issues --- arch/arm/mach-tegra/include/mach/dc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-tegra/include/mach/dc.h b/arch/arm/mach-tegra/include/mach/dc.h index e19344dac15..006a85469e3 100644 --- a/arch/arm/mach-tegra/include/mach/dc.h +++ b/arch/arm/mach-tegra/include/mach/dc.h @@ -383,6 +383,7 @@ struct tegra_dc_out { u8 *out_sel_configs; unsigned n_out_sel_configs; + int (*prepoweroff)(void); int (*enable)(void); int (*postpoweron)(void); int (*disable)(void); From c29939b8614e28fa5f965a070964341b13c4719c Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sun, 15 Mar 2015 02:10:18 -0700 Subject: [PATCH 09/19] cpu_input_boost: Unboost all CPUs in a single call Unboosting CPUs on a per-cpu basis now could leave some CPUs boosted, and it is unnecessary. Unboost all CPUs at once instead. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 73 ++++++++++++++----------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index f22cafebe8f..658a04f289f 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -29,16 +29,13 @@ enum { }; struct boost_policy { - unsigned int boost_freq; - unsigned int boost_ms; - unsigned int cpu; unsigned int cpu_boost; - struct delayed_work restore_work; }; static DEFINE_PER_CPU(struct boost_policy, boost_info); static struct workqueue_struct *boost_wq; static struct work_struct boost_work; +static struct delayed_work restore_work; static bool suspended; @@ -63,12 +60,20 @@ module_param(input_boost_ms, uint, 0644); static unsigned int input_boost_up_threshold = 30; module_param(input_boost_up_threshold, uint, 0644); -static void set_boost(struct boost_policy *b, unsigned int boost) +static void cpu_unboost_all(void) { - b->cpu_boost = boost; + struct boost_policy *b; + unsigned int cpu; + get_online_cpus(); - if (cpu_online(b->cpu)) - cpufreq_update_policy(b->cpu); + for_each_possible_cpu(cpu) { + b = &per_cpu(boost_info, cpu); + if (b->cpu_boost == BOOST) { + b->cpu_boost = UNBOOST; + if (cpu_online(cpu)) + cpufreq_update_policy(cpu); + } + } put_online_cpus(); } @@ -110,16 +115,12 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) /* Prioritize boosting of online CPUs */ for_each_online_cpu(cpu) { b = &per_cpu(boost_info, cpu); - b->boost_freq = input_boost_freq; - b->boost_ms = input_boost_ms; - cancel_delayed_work_sync(&b->restore_work); + cancel_delayed_work_sync(&restore_work); b->cpu_boost = BOOST; - cpufreq_update_policy(b->cpu); - queue_delayed_work(boost_wq, &b->restore_work, - msecs_to_jiffies(b->boost_ms)); + cpufreq_update_policy(cpu); nr_cpus_to_boost--; if (cpu == nr_cpus_to_boost) - goto put_cpus; + goto finish_boost; } /* Boost offline CPUs if we still need to boost more CPUs */ @@ -128,28 +129,24 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) /* Only boost CPUs that are not already boosted (offline CPUs) */ if (b->cpu_boost == UNBOOST) { - b->boost_freq = input_boost_freq; - b->boost_ms = input_boost_ms; - cancel_delayed_work_sync(&b->restore_work); + cancel_delayed_work_sync(&restore_work); b->cpu_boost = BOOST; - queue_delayed_work(boost_wq, &b->restore_work, - msecs_to_jiffies(b->boost_ms)); nr_cpus_to_boost--; if (cpu == nr_cpus_to_boost) - goto put_cpus; + goto finish_boost; } } +finish_boost: + queue_delayed_work(boost_wq, &restore_work, + msecs_to_jiffies(input_boost_ms)); put_cpus: put_online_cpus(); } static void __cpuinit cpu_restore_main(struct work_struct *work) { - struct boost_policy *b = container_of(work, struct boost_policy, - restore_work.work); - - set_boost(b, UNBOOST); + cpu_unboost_all(); } static int cpu_do_boost(struct notifier_block *nb, unsigned long val, void *data) @@ -165,9 +162,10 @@ static int cpu_do_boost(struct notifier_block *nb, unsigned long val, void *data policy->min = policy->cpuinfo.min_freq; break; case BOOST: - if (b->boost_freq > policy->max) - b->boost_freq = policy->max; - policy->min = b->boost_freq; + if (input_boost_freq > policy->max) + policy->min = policy->max; + else + policy->min = input_boost_freq; break; } @@ -187,8 +185,8 @@ static void cpu_boost_early_suspend(struct early_suspend *handler) for_each_possible_cpu(cpu) { b = &per_cpu(boost_info, cpu); - if (cancel_delayed_work_sync(&b->restore_work)) - set_boost(b, UNBOOST); + if (cancel_delayed_work_sync(&restore_work)) + cpu_unboost_all(); } } @@ -295,35 +293,28 @@ static struct input_handler cpu_boost_input_handler = { static int __init cpu_boost_init(void) { - struct boost_policy *b; - unsigned int cpu; int ret; boost_wq = alloc_workqueue("cpu_input_boost_wq", WQ_HIGHPRI, 0); if (!boost_wq) { pr_err("Failed to allocate workqueue\n"); ret = -EFAULT; - goto fail; + goto err; } cpufreq_register_notifier(&cpu_do_boost_nb, CPUFREQ_POLICY_NOTIFIER); - for_each_possible_cpu(cpu) { - b = &per_cpu(boost_info, cpu); - b->cpu = cpu; - INIT_DELAYED_WORK(&b->restore_work, cpu_restore_main); - } - + INIT_DELAYED_WORK(&restore_work, cpu_restore_main); INIT_WORK(&boost_work, cpu_boost_main); ret = input_register_handler(&cpu_boost_input_handler); if (ret) { pr_err("Failed to register input handler, err: %d\n", ret); - goto fail; + goto err; } register_early_suspend(&cpu_boost_early_suspend_handler); -fail: +err: return ret; } late_initcall(cpu_boost_init); From d1b19987e40908028265f71fcad29bae84230f5f Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Mon, 16 Mar 2015 22:48:54 -0700 Subject: [PATCH 10/19] cpu_input_boost: Automagically calculate boost freq to be used Boost frequencies to be used are now automatically calculated at init by multiplying a hardcoded fraction by the maxfreq. The main boost function will determine which boost frequency to use (high, medium, low). On dual-core systems, only the high and medium boost frequencies are used. Also fixed some derps that broke boosting on a per-cpu basis. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 124 ++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 34 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 658a04f289f..2a1354e1508 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -23,13 +23,21 @@ #include #include +/* Boost state */ enum { UNBOOST, BOOST, }; +/* Boost level */ +enum { + LOW, + MID, + HIGH, +}; + struct boost_policy { - unsigned int cpu_boost; + unsigned int boost_state; }; static DEFINE_PER_CPU(struct boost_policy, boost_info); @@ -42,11 +50,19 @@ static bool suspended; static u64 last_input_time; #define MIN_INPUT_INTERVAL (150 * USEC_PER_MSEC) -#define NR_CPUS CONFIG_NR_CPUS +#define NUM_CPUS CONFIG_NR_CPUS + +/** + * Auto boost freq calculation: + * Requested boost freqs = maxfreq * boost_factor[i] / BOOST_FACTOR_DIVISOR, + * so the lowest boost freq in this case would be maxfreq * 3 / 7 + */ +static unsigned int boost_freq[3]; +static unsigned int boost_factor[3] = {3, 4, 5}; +#define BOOST_FACTOR_DIVISOR 7 -/* Boost frequency in kHz */ -static unsigned int input_boost_freq; -module_param(input_boost_freq, uint, 0644); +/* Boost-freq level to use (high, mid, low) */ +static unsigned int boost_level; /* Boost duration in millsecs */ static unsigned int input_boost_ms; @@ -68,8 +84,8 @@ static void cpu_unboost_all(void) get_online_cpus(); for_each_possible_cpu(cpu) { b = &per_cpu(boost_info, cpu); - if (b->cpu_boost == BOOST) { - b->cpu_boost = UNBOOST; + if (b->boost_state == BOOST) { + b->boost_state = UNBOOST; if (cpu_online(cpu)) cpufreq_update_policy(cpu); } @@ -81,45 +97,59 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) { struct boost_policy *b; struct cpufreq_policy *policy; - unsigned int cpu, nr_cpus_to_boost = 0, nr_online_cpus = 0; + unsigned int cpu, num_cpus_boosted = 0, num_cpus_to_boost = 0; /* Num of CPUs to be boosted based on current freq of each online CPU */ get_online_cpus(); for_each_online_cpu(cpu) { - nr_online_cpus++; - /* Only allow 2 CPUs to be staged for boosting from here */ - if (nr_cpus_to_boost < 2) { + if (num_cpus_to_boost < 2) { policy = cpufreq_cpu_get(cpu); if (policy != NULL) { if ((policy->cur * 100 / policy->max) < input_boost_up_threshold) - nr_cpus_to_boost++; + num_cpus_to_boost++; cpufreq_cpu_put(policy); } } } /* Num of CPUs to be boosted based on how many of them are online */ - switch (nr_online_cpus * 100 / NR_CPUS) { - case 0 ... 25: - nr_cpus_to_boost += 2; + switch (num_online_cpus() * 100 / NUM_CPUS) { + case 25: + num_cpus_to_boost += 2; + break; + case 50 ... 75: + num_cpus_to_boost++; + break; + } + + if (!num_cpus_to_boost) + goto put_online_cpus; + + /* Boost freq to use based on how many CPUs to boost */ + switch (num_cpus_to_boost * 100 / NUM_CPUS) { + case 25: + boost_level = HIGH; break; - case 26 ... 75: - nr_cpus_to_boost++; + case 50: + boost_level = MID; break; + default: + boost_level = LOW; } - if (!nr_cpus_to_boost) - goto put_cpus; + if (NUM_CPUS == 2) + boost_level++; + + cancel_delayed_work_sync(&restore_work); /* Prioritize boosting of online CPUs */ for_each_online_cpu(cpu) { b = &per_cpu(boost_info, cpu); - cancel_delayed_work_sync(&restore_work); - b->cpu_boost = BOOST; + b->boost_state = BOOST; cpufreq_update_policy(cpu); - nr_cpus_to_boost--; - if (cpu == nr_cpus_to_boost) + num_cpus_boosted++; + if (num_cpus_boosted == num_cpus_to_boost) goto finish_boost; } @@ -128,11 +158,10 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) b = &per_cpu(boost_info, cpu); /* Only boost CPUs that are not already boosted (offline CPUs) */ - if (b->cpu_boost == UNBOOST) { - cancel_delayed_work_sync(&restore_work); - b->cpu_boost = BOOST; - nr_cpus_to_boost--; - if (cpu == nr_cpus_to_boost) + if (b->boost_state == UNBOOST) { + b->boost_state = BOOST; + num_cpus_boosted++; + if (num_cpus_boosted == num_cpus_to_boost) goto finish_boost; } } @@ -140,7 +169,7 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) finish_boost: queue_delayed_work(boost_wq, &restore_work, msecs_to_jiffies(input_boost_ms)); -put_cpus: +put_online_cpus: put_online_cpus(); } @@ -157,15 +186,15 @@ static int cpu_do_boost(struct notifier_block *nb, unsigned long val, void *data if (val != CPUFREQ_ADJUST) return NOTIFY_OK; - switch (b->cpu_boost) { + switch (b->boost_state) { case UNBOOST: policy->min = policy->cpuinfo.min_freq; break; case BOOST: - if (input_boost_freq > policy->max) + if (boost_freq[boost_level] > policy->max) policy->min = policy->max; else - policy->min = input_boost_freq; + policy->min = boost_freq[boost_level]; break; } @@ -206,7 +235,7 @@ static void cpu_boost_input_event(struct input_handle *handle, unsigned int type { u64 now; - if (suspended || !input_boost_freq || !input_boost_ms) + if (suspended || !input_boost_ms) return; now = ktime_to_us(ktime_get()); @@ -293,7 +322,34 @@ static struct input_handler cpu_boost_input_handler = { static int __init cpu_boost_init(void) { - int ret; + struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(0); + int maxfreq = cpufreq_quick_get_max(0); + int b_level = 0, req_freq[3]; + int curr, prev, i, ret = 0; + + if (!maxfreq) { + pr_err("Failed to get max freq, input boost disabled\n"); + goto err; + } + + for (i = 0; i < 3; i++) + req_freq[i] = maxfreq * boost_factor[i] / BOOST_FACTOR_DIVISOR; + + for (i = 0;; i++) { + if (table[i].frequency == CPUFREQ_ENTRY_INVALID) + continue; + + curr = table[i].frequency - req_freq[b_level]; + prev = table[i ? i - 1 : 0].frequency - req_freq[b_level]; + + if (curr > 0 && prev < 0) { + boost_freq[b_level] = table[i].frequency; + b_level++; + } + + if (b_level == 3) + break; + } boost_wq = alloc_workqueue("cpu_input_boost_wq", WQ_HIGHPRI, 0); if (!boost_wq) { From 5107cc627e36acf61b7817febd9cb18d84122e50 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 17 Mar 2015 19:24:00 -0700 Subject: [PATCH 11/19] cpu_input_boost: Automagically calculate boost duration Boost duration is calculated based on the number of CPUs boosted, as well as how much they are being boosted. Also allowed frequencies that are exactly the same as the requested freq to be used as the boost freq. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 2a1354e1508..37ef08b6da2 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -65,8 +65,7 @@ static unsigned int boost_factor[3] = {3, 4, 5}; static unsigned int boost_level; /* Boost duration in millsecs */ -static unsigned int input_boost_ms; -module_param(input_boost_ms, uint, 0644); +static unsigned int boost_ms; /** * Percentage threshold used to boost CPUs (default 30%). A higher @@ -141,6 +140,9 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) if (NUM_CPUS == 2) boost_level++; + /* Calculate boost duration */ + boost_ms = 3000 - ((num_cpus_to_boost * 750) + ((boost_level + 1) * 250)); + cancel_delayed_work_sync(&restore_work); /* Prioritize boosting of online CPUs */ @@ -168,7 +170,7 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) finish_boost: queue_delayed_work(boost_wq, &restore_work, - msecs_to_jiffies(input_boost_ms)); + msecs_to_jiffies(boost_ms)); put_online_cpus: put_online_cpus(); } @@ -235,7 +237,7 @@ static void cpu_boost_input_event(struct input_handle *handle, unsigned int type { u64 now; - if (suspended || !input_boost_ms) + if (suspended) return; now = ktime_to_us(ktime_get()); @@ -342,7 +344,7 @@ static int __init cpu_boost_init(void) curr = table[i].frequency - req_freq[b_level]; prev = table[i ? i - 1 : 0].frequency - req_freq[b_level]; - if (curr > 0 && prev < 0) { + if (!curr || (curr > 0 && prev < 0)) { boost_freq[b_level] = table[i].frequency; b_level++; } From c009d031009aaa4eec3b2089191bea72327eae06 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 17 Mar 2015 21:29:01 -0700 Subject: [PATCH 12/19] cpu_input_boost: Add on/off switch Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 37ef08b6da2..3bbc699f2a5 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -67,13 +67,17 @@ static unsigned int boost_level; /* Boost duration in millsecs */ static unsigned int boost_ms; +/* On/off switch */ +static unsigned int enabled; +module_param(enabled, uint, 0644); + /** * Percentage threshold used to boost CPUs (default 30%). A higher * value will cause more CPUs to be boosted -- CPUs are boosted - * when ((current_freq/max_freq) * 100) < input_boost_up_threshold + * when ((current_freq/max_freq) * 100) < up_threshold */ -static unsigned int input_boost_up_threshold = 30; -module_param(input_boost_up_threshold, uint, 0644); +static unsigned int up_threshold = 30; +module_param(up_threshold, uint, 0644); static void cpu_unboost_all(void) { @@ -105,7 +109,7 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) if (num_cpus_to_boost < 2) { policy = cpufreq_cpu_get(cpu); if (policy != NULL) { - if ((policy->cur * 100 / policy->max) < input_boost_up_threshold) + if ((policy->cur * 100 / policy->max) < up_threshold) num_cpus_to_boost++; cpufreq_cpu_put(policy); } @@ -237,7 +241,7 @@ static void cpu_boost_input_event(struct input_handle *handle, unsigned int type { u64 now; - if (suspended) + if (suspended || !enabled) return; now = ktime_to_us(ktime_get()); From d98cd1b4b867a2e293afef41f62d3cf929298517 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 17 Mar 2015 21:40:30 -0700 Subject: [PATCH 13/19] cpu_input_boost: Clean up suspend routine The boost work functions are no longer defined per-cpu, so this code is redundant. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 3bbc699f2a5..085fdef62dc 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -213,16 +213,10 @@ static struct notifier_block cpu_do_boost_nb = { static void cpu_boost_early_suspend(struct early_suspend *handler) { - struct boost_policy *b; - unsigned int cpu; - suspended = true; - for_each_possible_cpu(cpu) { - b = &per_cpu(boost_info, cpu); - if (cancel_delayed_work_sync(&restore_work)) - cpu_unboost_all(); - } + if (cancel_delayed_work_sync(&restore_work)) + cpu_unboost_all(); } static void __cpuinit cpu_boost_late_resume(struct early_suspend *handler) From c22967de16ddae78c914c4a07cb6510abe55a25d Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sun, 22 Mar 2015 17:12:20 -0700 Subject: [PATCH 14/19] cpu_input_boost: Remove useless guard during init We are guaranteed to break out of this loop before hitting the maxfreq (or hitting any invalid freqs), as long as the system has more than 3 CPU frequencies available and as long as boost_factor/BOOST_FACTOR_DIVISOR is less than 1. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 085fdef62dc..d1749ab362b 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -336,9 +336,6 @@ static int __init cpu_boost_init(void) req_freq[i] = maxfreq * boost_factor[i] / BOOST_FACTOR_DIVISOR; for (i = 0;; i++) { - if (table[i].frequency == CPUFREQ_ENTRY_INVALID) - continue; - curr = table[i].frequency - req_freq[b_level]; prev = table[i ? i - 1 : 0].frequency - req_freq[b_level]; From a0538045c841acda229b8ac8c22e4e069c40e8c9 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 24 Mar 2015 18:58:56 -0700 Subject: [PATCH 15/19] cpu_input_boost: Reduce overhead and prevent races *Instead of constantly overriding boosts every 150ms during a torrent of input events, wait for the current boost to expire before accepting a new boost *Make the workqueue non-reentrant, as running the boost workers concurrently could lead to mayhem Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 33 ++++++++++--------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index d1749ab362b..49533c795c0 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -45,11 +44,9 @@ static struct workqueue_struct *boost_wq; static struct work_struct boost_work; static struct delayed_work restore_work; +static bool boost_running; static bool suspended; -static u64 last_input_time; -#define MIN_INPUT_INTERVAL (150 * USEC_PER_MSEC) - #define NUM_CPUS CONFIG_NR_CPUS /** @@ -94,6 +91,7 @@ static void cpu_unboost_all(void) } } put_online_cpus(); + boost_running = false; } static void __cpuinit cpu_boost_main(struct work_struct *work) @@ -127,7 +125,7 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) } if (!num_cpus_to_boost) - goto put_online_cpus; + goto finish_boost; /* Boost freq to use based on how many CPUs to boost */ switch (num_cpus_to_boost * 100 / NUM_CPUS) { @@ -147,8 +145,6 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) /* Calculate boost duration */ boost_ms = 3000 - ((num_cpus_to_boost * 750) + ((boost_level + 1) * 250)); - cancel_delayed_work_sync(&restore_work); - /* Prioritize boosting of online CPUs */ for_each_online_cpu(cpu) { b = &per_cpu(boost_info, cpu); @@ -173,10 +169,10 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) } finish_boost: - queue_delayed_work(boost_wq, &restore_work, - msecs_to_jiffies(boost_ms)); -put_online_cpus: put_online_cpus(); + if (num_cpus_to_boost) + queue_delayed_work(boost_wq, &restore_work, + msecs_to_jiffies(boost_ms)); } static void __cpuinit cpu_restore_main(struct work_struct *work) @@ -233,20 +229,11 @@ static struct early_suspend __refdata cpu_boost_early_suspend_handler = { static void cpu_boost_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { - u64 now; - - if (suspended || !enabled) - return; - - now = ktime_to_us(ktime_get()); - if (now - last_input_time < MIN_INPUT_INTERVAL) - return; - - if (unlikely(work_pending(&boost_work))) + if (boost_running || !enabled || suspended) return; + boost_running = true; queue_work(boost_wq, &boost_work); - last_input_time = ktime_to_us(ktime_get()); } static int cpu_boost_input_connect(struct input_handler *handler, @@ -325,7 +312,7 @@ static int __init cpu_boost_init(void) struct cpufreq_frequency_table *table = cpufreq_frequency_get_table(0); int maxfreq = cpufreq_quick_get_max(0); int b_level = 0, req_freq[3]; - int curr, prev, i, ret = 0; + int curr, prev, i, ret = 1; if (!maxfreq) { pr_err("Failed to get max freq, input boost disabled\n"); @@ -348,7 +335,7 @@ static int __init cpu_boost_init(void) break; } - boost_wq = alloc_workqueue("cpu_input_boost_wq", WQ_HIGHPRI, 0); + boost_wq = alloc_workqueue("cpu_input_boost_wq", WQ_HIGHPRI | WQ_NON_REENTRANT, 0); if (!boost_wq) { pr_err("Failed to allocate workqueue\n"); ret = -EFAULT; From c57c5f395be8a6de6a4da2513f37e372de350f4d Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 31 Mar 2015 16:41:43 -0700 Subject: [PATCH 16/19] cpu_input_boost: Set boost_running to false if there is no boost boost_running would be remain true forever if the power algorithms decided not to boost, thus permanently disabling input boosting. Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 49533c795c0..88ce61f029f 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -173,6 +173,8 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) if (num_cpus_to_boost) queue_delayed_work(boost_wq, &restore_work, msecs_to_jiffies(boost_ms)); + else + boost_running = false; } static void __cpuinit cpu_restore_main(struct work_struct *work) From f23b690d81f1da9e369e0a391c82f56ff5da754f Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Tue, 31 Mar 2015 19:29:36 -0700 Subject: [PATCH 17/19] cpu_input_boost: Minor clean-up Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 32 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index 88ce61f029f..f1969ae3342 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -22,21 +22,19 @@ #include #include -/* Boost state */ -enum { +enum boost_status { UNBOOST, BOOST, }; -/* Boost level */ -enum { +enum boost_pwr { LOW, MID, HIGH, }; struct boost_policy { - unsigned int boost_state; + enum boost_status boost_state; }; static DEFINE_PER_CPU(struct boost_policy, boost_info); @@ -59,7 +57,7 @@ static unsigned int boost_factor[3] = {3, 4, 5}; #define BOOST_FACTOR_DIVISOR 7 /* Boost-freq level to use (high, mid, low) */ -static unsigned int boost_level; +static enum boost_pwr boost_level; /* Boost duration in millsecs */ static unsigned int boost_ms; @@ -124,8 +122,12 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) break; } - if (!num_cpus_to_boost) - goto finish_boost; + /* Nothing to boost */ + if (!num_cpus_to_boost) { + put_online_cpus(); + boost_running = false; + return; + } /* Boost freq to use based on how many CPUs to boost */ switch (num_cpus_to_boost * 100 / NUM_CPUS) { @@ -139,6 +141,7 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) boost_level = LOW; } + /* Dual-core systems need more power */ if (NUM_CPUS == 2) boost_level++; @@ -170,11 +173,8 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) finish_boost: put_online_cpus(); - if (num_cpus_to_boost) - queue_delayed_work(boost_wq, &restore_work, - msecs_to_jiffies(boost_ms)); - else - boost_running = false; + queue_delayed_work(boost_wq, &restore_work, + msecs_to_jiffies(boost_ms)); } static void __cpuinit cpu_restore_main(struct work_struct *work) @@ -231,7 +231,11 @@ static struct early_suspend __refdata cpu_boost_early_suspend_handler = { static void cpu_boost_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { - if (boost_running || !enabled || suspended) + if (boost_running) + return; + if (!enabled) + return; + if (suspended) return; boost_running = true; From 735609ad75ca88602b7daea82b0cccae76ef23e9 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sat, 11 Apr 2015 00:17:27 -0700 Subject: [PATCH 18/19] cpu_input_boost: Add back 150ms min interval between boost requests *In a case where the boost driver consistently decides not to boost, the work function can be spammed several times a second; add back the minimum 150ms interval between boosts to prevent this --- drivers/cpufreq/cpu_input_boost.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index f1969ae3342..ff9e3c167b5 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,9 @@ static struct delayed_work restore_work; static bool boost_running; static bool suspended; +static u64 last_input_time; +#define MIN_INPUT_INTERVAL (150 * USEC_PER_MSEC) + #define NUM_CPUS CONFIG_NR_CPUS /** @@ -161,8 +165,6 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) /* Boost offline CPUs if we still need to boost more CPUs */ for_each_possible_cpu(cpu) { b = &per_cpu(boost_info, cpu); - - /* Only boost CPUs that are not already boosted (offline CPUs) */ if (b->boost_state == UNBOOST) { b->boost_state = BOOST; num_cpus_boosted++; @@ -231,6 +233,8 @@ static struct early_suspend __refdata cpu_boost_early_suspend_handler = { static void cpu_boost_input_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) { + u64 now; + if (boost_running) return; if (!enabled) @@ -238,8 +242,13 @@ static void cpu_boost_input_event(struct input_handle *handle, unsigned int type if (suspended) return; + now = ktime_to_us(ktime_get()); + if (now - last_input_time < MIN_INPUT_INTERVAL) + return; + boost_running = true; queue_work(boost_wq, &boost_work); + last_input_time = ktime_to_us(ktime_get()); } static int cpu_boost_input_connect(struct input_handler *handler, From 431004939300693c0a88712612dbce9b5161d0e1 Mon Sep 17 00:00:00 2001 From: Sultanxda Date: Sat, 11 Apr 2015 00:21:13 -0700 Subject: [PATCH 19/19] cpu_input_boost: Minor clean-up of loop inside main fn Signed-off-by: Sultanxda --- drivers/cpufreq/cpu_input_boost.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpu_input_boost.c b/drivers/cpufreq/cpu_input_boost.c index ff9e3c167b5..4fdf94d6285 100644 --- a/drivers/cpufreq/cpu_input_boost.c +++ b/drivers/cpufreq/cpu_input_boost.c @@ -105,14 +105,14 @@ static void __cpuinit cpu_boost_main(struct work_struct *work) /* Num of CPUs to be boosted based on current freq of each online CPU */ get_online_cpus(); for_each_online_cpu(cpu) { - /* Only allow 2 CPUs to be staged for boosting from here */ - if (num_cpus_to_boost < 2) { - policy = cpufreq_cpu_get(cpu); - if (policy != NULL) { - if ((policy->cur * 100 / policy->max) < up_threshold) - num_cpus_to_boost++; - cpufreq_cpu_put(policy); - } + policy = cpufreq_cpu_get(cpu); + if (policy != NULL) { + if ((policy->cur * 100 / policy->max) < up_threshold) + num_cpus_to_boost++; + cpufreq_cpu_put(policy); + /* Only allow 2 CPUs to be staged for boosting from here */ + if (num_cpus_to_boost == 2) + break; } }