Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * arch/arm/mach-msm/msm_mpdecision.c
- *
- * This program features:
- * -cpu auto-hotplug/unplug based on system load for MSM multicore cpus
- * -single core while screen is off
- * -extensive sysfs tuneables
- *
- * Copyright (c) 2012-2013, Dennis Rassmann <showp1984@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include "msm_mpdecision.h"
- #ifndef CONFIG_HAS_EARLYSUSPEND
- #include <linux/lcd_notify.h>
- #else
- #include <linux/earlysuspend.h>
- #endif
- #include <linux/init.h>
- #include <linux/cpufreq.h>
- #include <linux/workqueue.h>
- #include <linux/completion.h>
- #include <linux/cpu.h>
- #include <linux/cpumask.h>
- #include <asm-generic/cputime.h>
- #include <linux/hrtimer.h>
- #include <linux/delay.h>
- #include <linux/export.h>
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- #include <linux/input.h>
- #include <linux/slab.h>
- #endif
- #include "acpuclock.h"
- #define DEBUG 0
- DEFINE_PER_CPU(struct msm_mpdec_cpudata_t, msm_mpdec_cpudata);
- EXPORT_PER_CPU_SYMBOL_GPL(msm_mpdec_cpudata);
- static bool mpdec_suspended = false;
- #ifndef CONFIG_HAS_EARLYSUSPEND
- static struct notifier_block msm_mpdec_lcd_notif;
- #else
- #endif
- static struct delayed_work msm_mpdec_work;
- static struct workqueue_struct *msm_mpdec_workq;
- static DEFINE_MUTEX(mpdec_msm_cpu_lock);
- static DEFINE_MUTEX(mpdec_msm_susres_lock);
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- static struct workqueue_struct *mpdec_input_wq;
- static DEFINE_PER_CPU(struct work_struct, mpdec_input_work);
- static struct workqueue_struct *msm_mpdec_revib_workq;
- static DEFINE_PER_CPU(struct delayed_work, msm_mpdec_revib_work);
- #endif
- static struct msm_mpdec_tuners {
- unsigned int startdelay;
- unsigned int delay;
- unsigned int pause;
- bool scroff_single_core;
- unsigned long int idle_freq;
- unsigned int max_cpus;
- unsigned int min_cpus;
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- bool boost_enabled;
- unsigned int boost_time;
- unsigned long int boost_freq[4];
- #endif
- } msm_mpdec_tuners_ins = {
- .startdelay = MSM_MPDEC_STARTDELAY,
- .delay = MSM_MPDEC_DELAY,
- .pause = MSM_MPDEC_PAUSE,
- .scroff_single_core = true,
- .idle_freq = MSM_MPDEC_IDLE_FREQ,
- .max_cpus = CONFIG_NR_CPUS,
- .min_cpus = 1,
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- .boost_enabled = true,
- .boost_time = MSM_MPDEC_BOOSTTIME,
- .boost_freq = {
- MSM_MPDEC_BOOSTFREQ_CPU0,
- MSM_MPDEC_BOOSTFREQ_CPU1,
- MSM_MPDEC_BOOSTFREQ_CPU2,
- MSM_MPDEC_BOOSTFREQ_CPU3
- },
- #endif
- };
- static unsigned int NwNs_Threshold[8] = {12, 0, 20, 7, 25, 10, 0, 18};
- static unsigned int TwTs_Threshold[8] = {140, 0, 140, 190, 140, 190, 0, 190};
- extern unsigned int get_rq_info(void);
- extern unsigned long acpuclk_get_rate(int);
- unsigned int state = MSM_MPDEC_IDLE;
- bool was_paused = false;
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- bool is_screen_on = true;
- static int update_cpu_min_freq(struct cpufreq_policy *cpu_policy,
- int cpu, int new_freq);
- static void unboost_cpu(int cpu);
- #endif
- static cputime64_t mpdec_paused_until = 0;
- static unsigned long get_rate(int cpu) {
- return acpuclk_get_rate(cpu);
- }
- static int get_slowest_cpu(void) {
- int i, cpu = 0;
- unsigned long rate, slow_rate = 0;
- for (i = 1; i < CONFIG_NR_CPUS; i++) {
- if (!cpu_online(i))
- continue;
- rate = get_rate(i);
- if (slow_rate == 0) {
- cpu = i;
- slow_rate = rate;
- continue;
- }
- if ((rate <= slow_rate) && (slow_rate != 0)) {
- cpu = i;
- slow_rate = rate;
- }
- }
- return cpu;
- }
- static unsigned long get_slowest_cpu_rate(void) {
- int i = 0;
- unsigned long rate, slow_rate = 0;
- for (i = 0; i < CONFIG_NR_CPUS; i++) {
- if (!cpu_online(i))
- continue;
- rate = get_rate(i);
- if ((rate < slow_rate) && (slow_rate != 0)) {
- slow_rate = rate;
- continue;
- }
- if (slow_rate == 0) {
- slow_rate = rate;
- }
- }
- return slow_rate;
- }
- static void mpdec_cpu_up(int cpu) {
- if (!cpu_online(cpu)) {
- mutex_lock(&per_cpu(msm_mpdec_cpudata, cpu).hotplug_mutex);
- cpu_up(cpu);
- per_cpu(msm_mpdec_cpudata, cpu).on_time = ktime_to_ms(ktime_get());
- per_cpu(msm_mpdec_cpudata, cpu).online = true;
- per_cpu(msm_mpdec_cpudata, cpu).times_cpu_hotplugged += 1;
- pr_info(MPDEC_TAG"CPU[%d] off->on | Mask=[%d%d%d%d]\n",
- cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
- mutex_unlock(&per_cpu(msm_mpdec_cpudata, cpu).hotplug_mutex);
- }
- }
- EXPORT_SYMBOL_GPL(mpdec_cpu_up);
- static void mpdec_cpu_down(int cpu) {
- cputime64_t on_time = 0;
- if (cpu_online(cpu)) {
- mutex_lock(&per_cpu(msm_mpdec_cpudata, cpu).hotplug_mutex);
- cpu_down(cpu);
- on_time = (ktime_to_ms(ktime_get()) - per_cpu(msm_mpdec_cpudata, cpu).on_time);
- per_cpu(msm_mpdec_cpudata, cpu).online = false;
- per_cpu(msm_mpdec_cpudata, cpu).on_time_total += on_time;
- per_cpu(msm_mpdec_cpudata, cpu).times_cpu_unplugged += 1;
- pr_info(MPDEC_TAG"CPU[%d] on->off | Mask=[%d%d%d%d] | time online: %llu\n",
- cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3), on_time);
- mutex_unlock(&per_cpu(msm_mpdec_cpudata, cpu).hotplug_mutex);
- }
- }
- EXPORT_SYMBOL_GPL(mpdec_cpu_down);
- static int mp_decision(void) {
- static bool first_call = true;
- int new_state = MSM_MPDEC_IDLE;
- int nr_cpu_online;
- int index;
- unsigned int rq_depth;
- static cputime64_t total_time = 0;
- static cputime64_t last_time;
- cputime64_t current_time;
- cputime64_t this_time = 0;
- if (state == MSM_MPDEC_DISABLED)
- return MSM_MPDEC_DISABLED;
- current_time = ktime_to_ms(ktime_get());
- if (first_call) {
- first_call = false;
- } else {
- this_time = current_time - last_time;
- }
- total_time += this_time;
- rq_depth = get_rq_info();
- nr_cpu_online = num_online_cpus();
- if (nr_cpu_online) {
- index = (nr_cpu_online - 1) * 2;
- if ((nr_cpu_online < CONFIG_NR_CPUS) && (rq_depth >= NwNs_Threshold[index])) {
- if ((total_time >= TwTs_Threshold[index]) &&
- (nr_cpu_online < msm_mpdec_tuners_ins.max_cpus)) {
- new_state = MSM_MPDEC_UP;
- if (get_slowest_cpu_rate() <= msm_mpdec_tuners_ins.idle_freq)
- new_state = MSM_MPDEC_IDLE;
- }
- } else if ((nr_cpu_online > 1) && (rq_depth <= NwNs_Threshold[index+1])) {
- if ((total_time >= TwTs_Threshold[index+1]) &&
- (nr_cpu_online > msm_mpdec_tuners_ins.min_cpus)) {
- new_state = MSM_MPDEC_DOWN;
- if (get_slowest_cpu_rate() > msm_mpdec_tuners_ins.idle_freq)
- new_state = MSM_MPDEC_IDLE;
- }
- } else {
- new_state = MSM_MPDEC_IDLE;
- total_time = 0;
- }
- } else {
- total_time = 0;
- }
- if (new_state != MSM_MPDEC_IDLE) {
- total_time = 0;
- }
- last_time = ktime_to_ms(ktime_get());
- #if DEBUG
- pr_info(MPDEC_TAG"[DEBUG] rq: %u, new_state: %i | Mask=[%d%d%d%d]\n",
- rq_depth, new_state, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
- #endif
- return new_state;
- }
- static void msm_mpdec_work_thread(struct work_struct *work) {
- unsigned int cpu = nr_cpu_ids;
- /* Check if we are paused */
- if (mpdec_paused_until >= ktime_to_ms(ktime_get()))
- goto out;
- if (mpdec_suspended == true)
- goto out;
- if (!mutex_trylock(&mpdec_msm_cpu_lock))
- goto out;
- /* if sth messed with the cpus, update the check vars so we can proceed */
- if (was_paused) {
- for_each_possible_cpu(cpu) {
- if (cpu_online(cpu))
- per_cpu(msm_mpdec_cpudata, cpu).online = true;
- else if (!cpu_online(cpu))
- per_cpu(msm_mpdec_cpudata, cpu).online = false;
- }
- was_paused = false;
- }
- state = mp_decision();
- switch (state) {
- case MSM_MPDEC_DISABLED:
- case MSM_MPDEC_IDLE:
- break;
- case MSM_MPDEC_DOWN:
- cpu = get_slowest_cpu();
- if (cpu < nr_cpu_ids) {
- if ((per_cpu(msm_mpdec_cpudata, cpu).online == true) && (cpu_online(cpu))) {
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- unboost_cpu(cpu);
- #endif
- mpdec_cpu_down(cpu);
- } else if (per_cpu(msm_mpdec_cpudata, cpu).online != cpu_online(cpu)) {
- pr_info(MPDEC_TAG"CPU[%d] was controlled outside of mpdecision! | pausing [%d]ms\n",
- cpu, msm_mpdec_tuners_ins.pause);
- mpdec_paused_until = ktime_to_ms(ktime_get()) + msm_mpdec_tuners_ins.pause;
- was_paused = true;
- }
- }
- break;
- case MSM_MPDEC_UP:
- cpu = cpumask_next_zero(0, cpu_online_mask);
- if (cpu < nr_cpu_ids) {
- if ((per_cpu(msm_mpdec_cpudata, cpu).online == false) && (!cpu_online(cpu))) {
- mpdec_cpu_up(cpu);
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- unboost_cpu(cpu);
- #endif
- } else if (per_cpu(msm_mpdec_cpudata, cpu).online != cpu_online(cpu)) {
- pr_info(MPDEC_TAG"CPU[%d] was controlled outside of mpdecision! | pausing [%d]ms\n",
- cpu, msm_mpdec_tuners_ins.pause);
- mpdec_paused_until = ktime_to_ms(ktime_get()) + msm_mpdec_tuners_ins.pause;
- was_paused = true;
- }
- }
- break;
- default:
- pr_err(MPDEC_TAG"%s: invalid mpdec hotplug state %d\n",
- __func__, state);
- }
- mutex_unlock(&mpdec_msm_cpu_lock);
- out:
- if (state != MSM_MPDEC_DISABLED)
- queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work,
- msecs_to_jiffies(msm_mpdec_tuners_ins.delay));
- return;
- }
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- static int update_cpu_min_freq(struct cpufreq_policy *cpu_policy,
- int cpu, int new_freq) {
- int ret = 0;
- if (!cpu_policy)
- return -EINVAL;
- cpufreq_verify_within_limits(cpu_policy, new_freq, cpu_policy->max);
- cpu_policy->user_policy.min = new_freq;
- ret = cpufreq_update_policy(cpu);
- if (!ret) {
- pr_debug(MPDEC_TAG"Touch event! Setting CPU%d min frequency to %d\n",
- cpu, new_freq);
- }
- return ret;
- }
- static void unboost_cpu(int cpu) {
- struct cpufreq_policy *cpu_policy = NULL;
- if (cpu_online(cpu)) {
- if (per_cpu(msm_mpdec_cpudata, cpu).is_boosted) {
- if (mutex_trylock(&per_cpu(msm_mpdec_cpudata, cpu).unboost_mutex)) {
- cpu_policy = cpufreq_cpu_get(cpu);
- if (!cpu_policy) {
- pr_debug(MPDEC_TAG"NULL policy on cpu %d\n", cpu);
- return;
- }
- #if DEBUG
- pr_info(MPDEC_TAG"un boosted cpu%i to %lu", cpu, per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq);
- #endif
- per_cpu(msm_mpdec_cpudata, cpu).is_boosted = false;
- per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running = false;
- if ((cpu_policy->min != per_cpu(msm_mpdec_cpudata, cpu).boost_freq) &&
- (cpu_policy->min != per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq)) {
- pr_info(MPDEC_TAG"cpu%u min was changed while boosted (%lu->%u), using new min",
- cpu, per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq, cpu_policy->min);
- per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq = cpu_policy->min;
- }
- update_cpu_min_freq(cpu_policy, cpu, per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq);
- cpufreq_cpu_put(cpu_policy);
- mutex_unlock(&per_cpu(msm_mpdec_cpudata, cpu).unboost_mutex);
- }
- }
- }
- return;
- }
- static void msm_mpdec_revib_work_thread(struct work_struct *work) {
- int cpu = smp_processor_id();
- if (per_cpu(msm_mpdec_cpudata, cpu).is_boosted) {
- per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running = true;
- if (ktime_to_ms(ktime_get()) > per_cpu(msm_mpdec_cpudata, cpu).boost_until) {
- unboost_cpu(cpu);
- } else {
- queue_delayed_work_on(
- cpu,
- msm_mpdec_revib_workq,
- &per_cpu(msm_mpdec_revib_work, cpu),
- msecs_to_jiffies((per_cpu(msm_mpdec_cpudata, cpu).boost_until - ktime_to_ms(ktime_get())))
- );
- }
- } else {
- per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running = false;
- }
- return;
- }
- static void mpdec_input_callback(struct work_struct *unused) {
- struct cpufreq_policy *cpu_policy = NULL;
- int cpu = smp_processor_id();
- bool boosted = false;
- if (!per_cpu(msm_mpdec_cpudata, cpu).is_boosted) {
- if (mutex_trylock(&per_cpu(msm_mpdec_cpudata, cpu).boost_mutex)) {
- cpu_policy = cpufreq_cpu_get(cpu);
- if (!cpu_policy) {
- pr_debug(MPDEC_TAG"NULL policy on cpu %d\n", cpu);
- return;
- }
- per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq = cpu_policy->min;
- /* check if boost freq is > minfreq */
- cpufreq_verify_within_limits(cpu_policy, cpu_policy->min, per_cpu(msm_mpdec_cpudata, cpu).boost_freq);
- update_cpu_min_freq(cpu_policy, cpu, per_cpu(msm_mpdec_cpudata, cpu).boost_freq);
- #if DEBUG
- pr_info(MPDEC_TAG"boosted cpu%i to %lu", cpu, per_cpu(msm_mpdec_cpudata, cpu).boost_freq);
- #endif
- per_cpu(msm_mpdec_cpudata, cpu).is_boosted = true;
- per_cpu(msm_mpdec_cpudata, cpu).boost_until = ktime_to_ms(ktime_get()) + msm_mpdec_tuners_ins.boost_time;
- boosted = true;
- cpufreq_cpu_put(cpu_policy);
- mutex_unlock(&per_cpu(msm_mpdec_cpudata, cpu).boost_mutex);
- }
- } else {
- boosted = true;
- }
- if (boosted && !per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running) {
- per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running = true;
- queue_delayed_work_on(
- cpu,
- msm_mpdec_revib_workq,
- &per_cpu(msm_mpdec_revib_work, cpu),
- msecs_to_jiffies(msm_mpdec_tuners_ins.boost_time)
- );
- } else if (boosted && per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running) {
- per_cpu(msm_mpdec_cpudata, cpu).boost_until = ktime_to_ms(ktime_get()) + msm_mpdec_tuners_ins.boost_time;
- }
- return;
- }
- #ifdef CONFIG_BRICKED_THERMAL
- extern int bricked_thermal_throttled;
- #endif
- static void mpdec_input_event(struct input_handle *handle, unsigned int type,
- unsigned int code, int value) {
- int i = 0;
- #ifdef CONFIG_BRICKED_THERMAL
- if (bricked_thermal_throttled > 0)
- return;
- #endif
- if (!msm_mpdec_tuners_ins.boost_enabled)
- return;
- if (!is_screen_on)
- return;
- for_each_online_cpu(i) {
- queue_work_on(i, mpdec_input_wq, &per_cpu(mpdec_input_work, i));
- }
- }
- static int input_dev_filter(const char *input_dev_name) {
- if (strstr(input_dev_name, "touch") ||
- strstr(input_dev_name, "key") ||
- strstr(input_dev_name, "power") ||
- strstr(input_dev_name, "pwr") ||
- strstr(input_dev_name, "lid")) {
- return 0;
- } else {
- return 1;
- }
- }
- static int mpdec_input_connect(struct input_handler *handler,
- struct input_dev *dev, const struct input_device_id *id) {
- struct input_handle *handle;
- int error;
- if (input_dev_filter(dev->name))
- return -ENODEV;
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "mpdec";
- 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 mpdec_input_disconnect(struct input_handle *handle) {
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
- }
- static const struct input_device_id mpdec_ids[] = {
- { .driver_info = 1 },
- { },
- };
- static struct input_handler mpdec_input_handler = {
- .event = mpdec_input_event,
- .connect = mpdec_input_connect,
- .disconnect = mpdec_input_disconnect,
- .name = "mpdec_inputreq",
- .id_table = mpdec_ids,
- };
- #endif
- static void msm_mpdec_suspend(struct work_struct * msm_mpdec_suspend_work) {
- int cpu = nr_cpu_ids;
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- is_screen_on = false;
- #endif
- if (!msm_mpdec_tuners_ins.scroff_single_core) {
- pr_info(MPDEC_TAG"Screen -> off\n");
- return;
- }
- /* main work thread can sleep now */
- cancel_delayed_work_sync(&msm_mpdec_work);
- for_each_possible_cpu(cpu) {
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- unboost_cpu(cpu);
- #endif
- if ((cpu >= 1) && (cpu_online(cpu))) {
- mpdec_cpu_down(cpu);
- }
- }
- mpdec_suspended = true;
- pr_info(MPDEC_TAG"Screen -> off. Deactivated mpdecision.\n");
- }
- static DECLARE_WORK(msm_mpdec_suspend_work, msm_mpdec_suspend);
- static void msm_mpdec_resume(struct work_struct * msm_mpdec_suspend_work) {
- int cpu = nr_cpu_ids;
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- is_screen_on = true;
- #endif
- if (!mpdec_suspended)
- return;
- mpdec_suspended = false;
- if (msm_mpdec_tuners_ins.scroff_single_core) {
- /* wake up main work thread */
- was_paused = true;
- queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work, 0);
- /* restore min/max cpus limits */
- for (cpu=1; cpu<CONFIG_NR_CPUS; cpu++) {
- if (cpu < msm_mpdec_tuners_ins.min_cpus) {
- if (!cpu_online(cpu))
- mpdec_cpu_up(cpu);
- } else if (cpu > msm_mpdec_tuners_ins.max_cpus) {
- if (cpu_online(cpu))
- mpdec_cpu_down(cpu);
- }
- }
- pr_info(MPDEC_TAG"Screen -> on. Activated mpdecision. | Mask=[%d%d%d%d]\n",
- cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3));
- } else {
- pr_info(MPDEC_TAG"Screen -> on\n");
- }
- }
- static DECLARE_WORK(msm_mpdec_resume_work, msm_mpdec_resume);
- #ifndef CONFIG_HAS_EARLYSUSPEND
- static int msm_mpdec_lcd_notifier_callback(struct notifier_block *this,
- unsigned long event, void *data) {
- pr_debug("%s: event = %lu\n", __func__, event);
- switch (event) {
- case LCD_EVENT_OFF_START:
- mutex_lock(&mpdec_msm_susres_lock);
- schedule_work(&msm_mpdec_suspend_work);
- break;
- case LCD_EVENT_ON_START:
- mutex_lock(&mpdec_msm_susres_lock);
- schedule_work(&msm_mpdec_resume_work);
- break;
- case LCD_EVENT_OFF_END:
- mutex_unlock(&mpdec_msm_susres_lock);
- break;
- case LCD_EVENT_ON_END:
- mutex_unlock(&mpdec_msm_susres_lock);
- break;
- default:
- break;
- }
- return 0;
- }
- #else
- static void msm_mpdec_early_suspend(struct early_suspend *h) {
- mutex_lock(&mpdec_msm_susres_lock);
- schedule_work(&msm_mpdec_suspend_work);
- mutex_unlock(&mpdec_msm_susres_lock);
- }
- static void msm_mpdec_late_resume(struct early_suspend *h) {
- mutex_lock(&mpdec_msm_susres_lock);
- schedule_work(&msm_mpdec_resume_work);
- mutex_unlock(&mpdec_msm_susres_lock);
- }
- static struct early_suspend msm_mpdec_early_suspend_handler = {
- .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN,
- .suspend = msm_mpdec_early_suspend,
- .resume = msm_mpdec_late_resume,
- };
- #endif
- /**************************** SYSFS START ****************************/
- struct kobject *msm_mpdec_kobject;
- #define show_one(file_name, object) \
- static ssize_t show_##file_name \
- (struct kobject *kobj, struct attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%u\n", msm_mpdec_tuners_ins.object); \
- }
- show_one(startdelay, startdelay);
- show_one(delay, delay);
- show_one(pause, pause);
- show_one(scroff_single_core, scroff_single_core);
- show_one(min_cpus, min_cpus);
- show_one(max_cpus, max_cpus);
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- show_one(boost_enabled, boost_enabled);
- show_one(boost_time, boost_time);
- #endif
- #define show_one_twts(file_name, arraypos) \
- static ssize_t show_##file_name \
- (struct kobject *kobj, struct attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%u\n", TwTs_Threshold[arraypos]); \
- }
- show_one_twts(twts_threshold_0, 0);
- show_one_twts(twts_threshold_1, 1);
- show_one_twts(twts_threshold_2, 2);
- show_one_twts(twts_threshold_3, 3);
- show_one_twts(twts_threshold_4, 4);
- show_one_twts(twts_threshold_5, 5);
- show_one_twts(twts_threshold_6, 6);
- show_one_twts(twts_threshold_7, 7);
- #define store_one_twts(file_name, arraypos) \
- static ssize_t store_##file_name \
- (struct kobject *a, struct attribute *b, const char *buf, size_t count) \
- { \
- unsigned int input; \
- int ret; \
- ret = sscanf(buf, "%u", &input); \
- if (ret != 1) \
- return -EINVAL; \
- TwTs_Threshold[arraypos] = input; \
- return count; \
- } \
- define_one_global_rw(file_name);
- store_one_twts(twts_threshold_0, 0);
- store_one_twts(twts_threshold_1, 1);
- store_one_twts(twts_threshold_2, 2);
- store_one_twts(twts_threshold_3, 3);
- store_one_twts(twts_threshold_4, 4);
- store_one_twts(twts_threshold_5, 5);
- store_one_twts(twts_threshold_6, 6);
- store_one_twts(twts_threshold_7, 7);
- #define show_one_nwns(file_name, arraypos) \
- static ssize_t show_##file_name \
- (struct kobject *kobj, struct attribute *attr, char *buf) \
- { \
- return sprintf(buf, "%u\n", NwNs_Threshold[arraypos]); \
- }
- show_one_nwns(nwns_threshold_0, 0);
- show_one_nwns(nwns_threshold_1, 1);
- show_one_nwns(nwns_threshold_2, 2);
- show_one_nwns(nwns_threshold_3, 3);
- show_one_nwns(nwns_threshold_4, 4);
- show_one_nwns(nwns_threshold_5, 5);
- show_one_nwns(nwns_threshold_6, 6);
- show_one_nwns(nwns_threshold_7, 7);
- #define store_one_nwns(file_name, arraypos) \
- static ssize_t store_##file_name \
- (struct kobject *a, struct attribute *b, const char *buf, size_t count) \
- { \
- unsigned int input; \
- int ret; \
- ret = sscanf(buf, "%u", &input); \
- if (ret != 1) \
- return -EINVAL; \
- NwNs_Threshold[arraypos] = input; \
- return count; \
- } \
- define_one_global_rw(file_name);
- store_one_nwns(nwns_threshold_0, 0);
- store_one_nwns(nwns_threshold_1, 1);
- store_one_nwns(nwns_threshold_2, 2);
- store_one_nwns(nwns_threshold_3, 3);
- store_one_nwns(nwns_threshold_4, 4);
- store_one_nwns(nwns_threshold_5, 5);
- store_one_nwns(nwns_threshold_6, 6);
- store_one_nwns(nwns_threshold_7, 7);
- static ssize_t show_idle_freq (struct kobject *kobj, struct attribute *attr,
- char *buf)
- {
- return sprintf(buf, "%lu\n", msm_mpdec_tuners_ins.idle_freq);
- }
- static ssize_t show_enabled(struct kobject *a, struct attribute *b,
- char *buf)
- {
- unsigned int enabled;
- switch (state) {
- case MSM_MPDEC_DISABLED:
- enabled = 0;
- break;
- case MSM_MPDEC_IDLE:
- case MSM_MPDEC_DOWN:
- case MSM_MPDEC_UP:
- enabled = 1;
- break;
- default:
- enabled = 333;
- }
- return sprintf(buf, "%u\n", enabled);
- }
- static ssize_t store_startdelay(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- msm_mpdec_tuners_ins.startdelay = input;
- return count;
- }
- static ssize_t store_delay(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- msm_mpdec_tuners_ins.delay = input;
- return count;
- }
- static ssize_t store_pause(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- msm_mpdec_tuners_ins.pause = input;
- return count;
- }
- static ssize_t store_idle_freq(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- long unsigned int input;
- int ret;
- ret = sscanf(buf, "%lu", &input);
- if (ret != 1)
- return -EINVAL;
- msm_mpdec_tuners_ins.idle_freq = input;
- return count;
- }
- static ssize_t store_scroff_single_core(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- switch (buf[0]) {
- case '0':
- case '1':
- msm_mpdec_tuners_ins.scroff_single_core = input;
- break;
- default:
- ret = -EINVAL;
- }
- return count;
- }
- static ssize_t store_max_cpus(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret, cpu;
- ret = sscanf(buf, "%u", &input);
- if ((ret != 1) || input > CONFIG_NR_CPUS || input < msm_mpdec_tuners_ins.min_cpus)
- return -EINVAL;
- msm_mpdec_tuners_ins.max_cpus = input;
- if (num_online_cpus() > input) {
- for (cpu=CONFIG_NR_CPUS; cpu>0; cpu--) {
- if (num_online_cpus() <= input)
- break;
- if (!cpu_online(cpu))
- continue;
- mpdec_cpu_down(cpu);
- }
- pr_info(MPDEC_TAG"max_cpus set to %u. Affected CPUs were unplugged!\n", input);
- }
- return count;
- }
- static ssize_t store_min_cpus(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret, cpu;
- ret = sscanf(buf, "%u", &input);
- if ((ret != 1) || input < 1 || input > msm_mpdec_tuners_ins.max_cpus)
- return -EINVAL;
- msm_mpdec_tuners_ins.min_cpus = input;
- if (num_online_cpus() < input) {
- for (cpu=1; cpu<CONFIG_NR_CPUS; cpu++) {
- if (num_online_cpus() >= input)
- break;
- if (cpu_online(cpu))
- continue;
- mpdec_cpu_up(cpu);
- }
- pr_info(MPDEC_TAG"min_cpus set to %u. Affected CPUs were hotplugged!\n", input);
- }
- return count;
- }
- static ssize_t store_enabled(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int cpu, input, enabled;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- switch (state) {
- case MSM_MPDEC_DISABLED:
- enabled = 0;
- break;
- case MSM_MPDEC_IDLE:
- case MSM_MPDEC_DOWN:
- case MSM_MPDEC_UP:
- enabled = 1;
- break;
- default:
- enabled = 333;
- }
- if (buf[0] == enabled)
- return -EINVAL;
- switch (buf[0]) {
- case '0':
- state = MSM_MPDEC_DISABLED;
- pr_info(MPDEC_TAG"nap time... Hot plugging offline CPUs...\n");
- for (cpu = 1; cpu < CONFIG_NR_CPUS; cpu++)
- if (!cpu_online(cpu))
- mpdec_cpu_up(cpu);
- break;
- case '1':
- state = MSM_MPDEC_IDLE;
- was_paused = true;
- queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work,
- msecs_to_jiffies(msm_mpdec_tuners_ins.delay));
- pr_info(MPDEC_TAG"firing up mpdecision...\n");
- break;
- default:
- ret = -EINVAL;
- }
- return count;
- }
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- static ssize_t store_boost_enabled(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- msm_mpdec_tuners_ins.boost_enabled = input;
- return count;
- }
- static ssize_t store_boost_time(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- unsigned int input;
- int ret;
- ret = sscanf(buf, "%u", &input);
- if (ret != 1)
- return -EINVAL;
- msm_mpdec_tuners_ins.boost_time = input;
- return count;
- }
- static ssize_t show_boost_freqs(struct kobject *a, struct attribute *b,
- char *buf)
- {
- ssize_t len = 0;
- int cpu = 0;
- for_each_present_cpu(cpu) {
- len += sprintf(buf + len, "%lu\n", per_cpu(msm_mpdec_cpudata, cpu).boost_freq);
- }
- return len;
- }
- static ssize_t store_boost_freqs(struct kobject *a, struct attribute *b,
- const char *buf, size_t count)
- {
- int i = 0;
- unsigned int cpu = 0;
- long unsigned int hz = 0;
- const char *chz = NULL;
- for (i=0; i<count; i++) {
- if (buf[i] == ' ') {
- sscanf(&buf[(i-1)], "%u", &cpu);
- chz = &buf[(i+1)];
- }
- }
- sscanf(chz, "%lu", &hz);
- /* if this cpu is currently boosted, unboost */
- unboost_cpu(cpu);
- /* update boost freq */
- per_cpu(msm_mpdec_cpudata, cpu).boost_freq = hz;
- return count;
- }
- define_one_global_rw(boost_freqs);
- #endif
- define_one_global_rw(startdelay);
- define_one_global_rw(delay);
- define_one_global_rw(pause);
- define_one_global_rw(scroff_single_core);
- define_one_global_rw(idle_freq);
- define_one_global_rw(min_cpus);
- define_one_global_rw(max_cpus);
- define_one_global_rw(enabled);
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- define_one_global_rw(boost_enabled);
- define_one_global_rw(boost_time);
- #endif
- static struct attribute *msm_mpdec_attributes[] = {
- &startdelay.attr,
- &delay.attr,
- &pause.attr,
- &scroff_single_core.attr,
- &idle_freq.attr,
- &min_cpus.attr,
- &max_cpus.attr,
- &enabled.attr,
- &twts_threshold_0.attr,
- &twts_threshold_1.attr,
- &twts_threshold_2.attr,
- &twts_threshold_3.attr,
- &twts_threshold_4.attr,
- &twts_threshold_5.attr,
- &twts_threshold_6.attr,
- &twts_threshold_7.attr,
- &nwns_threshold_0.attr,
- &nwns_threshold_1.attr,
- &nwns_threshold_2.attr,
- &nwns_threshold_3.attr,
- &nwns_threshold_4.attr,
- &nwns_threshold_5.attr,
- &nwns_threshold_6.attr,
- &nwns_threshold_7.attr,
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- &boost_freqs.attr,
- &boost_enabled.attr,
- &boost_time.attr,
- #endif
- NULL
- };
- static struct attribute_group msm_mpdec_attr_group = {
- .attrs = msm_mpdec_attributes,
- .name = "conf",
- };
- /********* STATS START *********/
- static ssize_t show_time_cpus_on(struct kobject *a, struct attribute *b,
- char *buf)
- {
- ssize_t len = 0;
- int cpu = 0;
- for_each_possible_cpu(cpu) {
- if (cpu_online(cpu)) {
- len += sprintf(
- buf + len, "%i %llu\n", cpu,
- (per_cpu(msm_mpdec_cpudata, cpu).on_time_total +
- (ktime_to_ms(ktime_get()) -
- per_cpu(msm_mpdec_cpudata, cpu).on_time))
- );
- } else
- len += sprintf(buf + len, "%i %llu\n", cpu, per_cpu(msm_mpdec_cpudata, cpu).on_time_total);
- }
- return len;
- }
- define_one_global_ro(time_cpus_on);
- static ssize_t show_times_cpus_hotplugged(struct kobject *a, struct attribute *b,
- char *buf)
- {
- ssize_t len = 0;
- int cpu = 0;
- for_each_possible_cpu(cpu) {
- len += sprintf(buf + len, "%i %llu\n", cpu, per_cpu(msm_mpdec_cpudata, cpu).times_cpu_hotplugged);
- }
- return len;
- }
- define_one_global_ro(times_cpus_hotplugged);
- static ssize_t show_times_cpus_unplugged(struct kobject *a, struct attribute *b,
- char *buf)
- {
- ssize_t len = 0;
- int cpu = 0;
- for_each_possible_cpu(cpu) {
- len += sprintf(buf + len, "%i %llu\n", cpu, per_cpu(msm_mpdec_cpudata, cpu).times_cpu_unplugged);
- }
- return len;
- }
- define_one_global_ro(times_cpus_unplugged);
- static struct attribute *msm_mpdec_stats_attributes[] = {
- &time_cpus_on.attr,
- ×_cpus_hotplugged.attr,
- ×_cpus_unplugged.attr,
- NULL
- };
- static struct attribute_group msm_mpdec_stats_attr_group = {
- .attrs = msm_mpdec_stats_attributes,
- .name = "stats",
- };
- /**************************** SYSFS END ****************************/
- static int __init msm_mpdec_init(void) {
- int cpu, rc, err = 0;
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- int i;
- unsigned long int boost_freq = 0;
- #endif
- mpdec_suspended = false;
- for_each_possible_cpu(cpu) {
- mutex_init(&(per_cpu(msm_mpdec_cpudata, cpu).hotplug_mutex));
- per_cpu(msm_mpdec_cpudata, cpu).online = true;
- per_cpu(msm_mpdec_cpudata, cpu).on_time_total = 0;
- per_cpu(msm_mpdec_cpudata, cpu).times_cpu_unplugged = 0;
- per_cpu(msm_mpdec_cpudata, cpu).times_cpu_hotplugged = 0;
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- per_cpu(msm_mpdec_cpudata, cpu).norm_min_freq = CONFIG_MSM_CPU_FREQ_MIN;
- switch (cpu) {
- case 0:
- case 1:
- case 2:
- boost_freq = msm_mpdec_tuners_ins.boost_freq[cpu];
- break;
- default:
- boost_freq = msm_mpdec_tuners_ins.boost_freq[3];
- break;
- }
- per_cpu(msm_mpdec_cpudata, cpu).boost_freq = boost_freq;
- per_cpu(msm_mpdec_cpudata, cpu).is_boosted = false;
- per_cpu(msm_mpdec_cpudata, cpu).revib_wq_running = false;
- per_cpu(msm_mpdec_cpudata, cpu).boost_until = 0;
- mutex_init(&(per_cpu(msm_mpdec_cpudata, cpu).boost_mutex));
- mutex_init(&(per_cpu(msm_mpdec_cpudata, cpu).unboost_mutex));
- #endif
- }
- was_paused = true;
- msm_mpdec_workq = alloc_workqueue(
- "mpdec",
- WQ_UNBOUND | WQ_RESCUER | WQ_FREEZABLE,
- 1
- );
- if (!msm_mpdec_workq)
- return -ENOMEM;
- INIT_DELAYED_WORK(&msm_mpdec_work, msm_mpdec_work_thread);
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- mpdec_input_wq = create_workqueue("mpdeciwq");
- if (!mpdec_input_wq) {
- printk(KERN_ERR "%s: Failed to create mpdeciwq workqueue\n", __func__);
- return -EFAULT;
- }
- msm_mpdec_revib_workq = create_workqueue("mpdecribwq");
- if (!msm_mpdec_revib_workq) {
- printk(KERN_ERR "%s: Failed to create mpdecrevibwq workqueue\n", __func__);
- return -EFAULT;
- }
- for_each_possible_cpu(i) {
- INIT_WORK(&per_cpu(mpdec_input_work, i), mpdec_input_callback);
- INIT_DELAYED_WORK(&per_cpu(msm_mpdec_revib_work, i), msm_mpdec_revib_work_thread);
- }
- rc = input_register_handler(&mpdec_input_handler);
- #endif
- if (state != MSM_MPDEC_DISABLED)
- queue_delayed_work(msm_mpdec_workq, &msm_mpdec_work,
- msecs_to_jiffies(msm_mpdec_tuners_ins.startdelay));
- msm_mpdec_kobject = kobject_create_and_add("msm_mpdecision", kernel_kobj);
- if (msm_mpdec_kobject) {
- rc = sysfs_create_group(msm_mpdec_kobject,
- &msm_mpdec_attr_group);
- if (rc) {
- pr_warn(MPDEC_TAG"sysfs: ERROR, could not create sysfs group");
- }
- rc = sysfs_create_group(msm_mpdec_kobject,
- &msm_mpdec_stats_attr_group);
- if (rc) {
- pr_warn(MPDEC_TAG"sysfs: ERROR, could not create sysfs stats group");
- }
- } else
- pr_warn(MPDEC_TAG"sysfs: ERROR, could not create sysfs kobj");
- pr_info(MPDEC_TAG"%s init complete.", __func__);
- #ifndef CONFIG_HAS_EARLYSUSPEND
- msm_mpdec_lcd_notif.notifier_call = msm_mpdec_lcd_notifier_callback;
- if (lcd_register_client(&msm_mpdec_lcd_notif) != 0) {
- pr_err("%s: Failed to register lcd callback\n", __func__);
- err = -EINVAL;
- lcd_unregister_client(&msm_mpdec_lcd_notif);
- }
- #else
- register_early_suspend(&msm_mpdec_early_suspend_handler);
- #endif
- return err;
- }
- late_initcall(msm_mpdec_init);
- void msm_mpdec_exit(void) {
- #ifndef CONFIG_HAS_EARLYSUSPEND
- lcd_unregister_client(&msm_mpdec_lcd_notif);
- #else
- #ifdef CONFIG_MSM_MPDEC_INPUTBOOST_CPUMIN
- input_unregister_handler(&mpdec_input_handler);
- destroy_workqueue(msm_mpdec_revib_workq);
- destroy_workqueue(mpdec_input_wq);
- #endif
- destroy_workqueue(msm_mpdec_workq);
- #endif
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement