X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=blobdiff_plain;f=drivers%2Fcpufreq%2Fcpufreq_interactive.c;h=055e990a2f1db035cbbff273fccefe8c0dfd13c8;hp=0be66df4a6e6b5d47fb80768367fe45e7424d87c;hb=fd7cc6839d91cbb068b8912fb2f7e27d717e79c3;hpb=fa6e6c7406806f9d4119703e4c3ad661c25b99ee diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 0be66df4a6e6..055e990a2f1d 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -19,6 +19,9 @@ #include #include #include +#ifdef CONFIG_ARCH_ROCKCHIP +#include +#endif #include #include #include @@ -106,6 +109,14 @@ struct cpufreq_interactive_tunables { int boostpulse_duration_val; /* End time of boost pulse in ktime converted to usecs */ u64 boostpulse_endtime; +#ifdef CONFIG_ARCH_ROCKCHIP + /* Frequency to which a touch boost takes the cpus to */ + unsigned long touchboost_freq; + /* Duration of a touchboost pulse in usecs */ + int touchboostpulse_duration_val; + /* End time of touchboost pulse in ktime converted to usecs */ + u64 touchboostpulse_endtime; +#endif bool boosted; /* * Max additional time to wait in idle, beyond timer_rate, at speeds @@ -116,28 +127,6 @@ struct cpufreq_interactive_tunables { bool io_is_busy; }; -/* - * HACK: FIXME: Bring back cpufreq_{get,put}_global_kobject() - * definition removed by upstream commit 8eec1020f0c0 "cpufreq: - * create cpu/cpufreq at boot time" to fix build failures. - */ -static int cpufreq_global_kobject_usage; - -int cpufreq_get_global_kobject(void) -{ - if (!cpufreq_global_kobject_usage++) - return kobject_add(cpufreq_global_kobject, - &cpu_subsys.dev_root->kobj, "%s", "cpufreq"); - - return 0; -} - -void cpufreq_put_global_kobject(void) -{ - if (!--cpufreq_global_kobject_usage) - kobject_del(cpufreq_global_kobject); -} - /* For cases where we have single governor instance for system */ static struct cpufreq_interactive_tunables *common_tunables; @@ -405,7 +394,12 @@ static void cpufreq_interactive_timer(unsigned long data) pcpu->policy->cur < tunables->hispeed_freq) new_freq = tunables->hispeed_freq; } - +#ifdef CONFIG_ARCH_ROCKCHIP + if ((now < tunables->touchboostpulse_endtime) && + (new_freq < tunables->touchboost_freq)) { + new_freq = tunables->touchboost_freq; + } +#endif if (pcpu->policy->cur >= tunables->hispeed_freq && new_freq > pcpu->policy->cur && now - pcpu->pol_hispeed_val_time < @@ -511,6 +505,58 @@ static void cpufreq_interactive_idle_end(void) up_read(&pcpu->enable_sem); } +static void cpufreq_interactive_get_policy_info(struct cpufreq_policy *policy, + unsigned int *pmax_freq, + u64 *phvt, u64 *pfvt) +{ + struct cpufreq_interactive_cpuinfo *pcpu; + unsigned int max_freq = 0; + u64 hvt = ~0ULL, fvt = 0; + unsigned int i; + + for_each_cpu(i, policy->cpus) { + pcpu = &per_cpu(cpuinfo, i); + + fvt = max(fvt, pcpu->loc_floor_val_time); + if (pcpu->target_freq > max_freq) { + max_freq = pcpu->target_freq; + hvt = pcpu->loc_hispeed_val_time; + } else if (pcpu->target_freq == max_freq) { + hvt = min(hvt, pcpu->loc_hispeed_val_time); + } + } + + *pmax_freq = max_freq; + *phvt = hvt; + *pfvt = fvt; +} + +static void cpufreq_interactive_adjust_cpu(unsigned int cpu, + struct cpufreq_policy *policy) +{ + struct cpufreq_interactive_cpuinfo *pcpu; + u64 hvt, fvt; + unsigned int max_freq; + int i; + + cpufreq_interactive_get_policy_info(policy, &max_freq, &hvt, &fvt); + + for_each_cpu(i, policy->cpus) { + pcpu = &per_cpu(cpuinfo, i); + pcpu->pol_floor_val_time = fvt; + } + + if (max_freq != policy->cur) { + __cpufreq_driver_target(policy, max_freq, CPUFREQ_RELATION_H); + for_each_cpu(i, policy->cpus) { + pcpu = &per_cpu(cpuinfo, i); + pcpu->pol_hispeed_val_time = hvt; + } + } + + trace_cpufreq_interactive_setspeed(cpu, max_freq, policy->cur); +} + static int cpufreq_interactive_speedchange_task(void *data) { unsigned int cpu; @@ -539,49 +585,18 @@ static int cpufreq_interactive_speedchange_task(void *data) spin_unlock_irqrestore(&speedchange_cpumask_lock, flags); for_each_cpu(cpu, &tmp_mask) { - unsigned int j; - unsigned int max_freq = 0; - struct cpufreq_interactive_cpuinfo *pjcpu; - u64 hvt = ~0ULL, fvt = 0; - pcpu = &per_cpu(cpuinfo, cpu); - if (!down_read_trylock(&pcpu->enable_sem)) - continue; - if (!pcpu->governor_enabled) { - up_read(&pcpu->enable_sem); - continue; - } - - for_each_cpu(j, pcpu->policy->cpus) { - pjcpu = &per_cpu(cpuinfo, j); - fvt = max(fvt, pjcpu->loc_floor_val_time); - if (pjcpu->target_freq > max_freq) { - max_freq = pjcpu->target_freq; - hvt = pjcpu->loc_hispeed_val_time; - } else if (pjcpu->target_freq == max_freq) { - hvt = min(hvt, pjcpu->loc_hispeed_val_time); - } - } - for_each_cpu(j, pcpu->policy->cpus) { - pjcpu = &per_cpu(cpuinfo, j); - pjcpu->pol_floor_val_time = fvt; - } + down_write(&pcpu->policy->rwsem); - if (max_freq != pcpu->policy->cur) { - __cpufreq_driver_target(pcpu->policy, - max_freq, - CPUFREQ_RELATION_H); - for_each_cpu(j, pcpu->policy->cpus) { - pjcpu = &per_cpu(cpuinfo, j); - pjcpu->pol_hispeed_val_time = hvt; - } + if (likely(down_read_trylock(&pcpu->enable_sem))) { + if (likely(pcpu->governor_enabled)) + cpufreq_interactive_adjust_cpu(cpu, + pcpu->policy); + up_read(&pcpu->enable_sem); } - trace_cpufreq_interactive_setspeed(cpu, - pcpu->target_freq, - pcpu->policy->cur); - up_read(&pcpu->enable_sem); + up_write(&pcpu->policy->rwsem); } } @@ -601,8 +616,19 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab for_each_online_cpu(i) { pcpu = &per_cpu(cpuinfo, i); - if (tunables != pcpu->policy->governor_data) + + if (!down_read_trylock(&pcpu->enable_sem)) + continue; + + if (!pcpu->governor_enabled) { + up_read(&pcpu->enable_sem); + continue; + } + + if (tunables != pcpu->policy->governor_data) { + up_read(&pcpu->enable_sem); continue; + } spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]); if (pcpu->target_freq < tunables->hispeed_freq) { @@ -613,6 +639,8 @@ static void cpufreq_interactive_boost(struct cpufreq_interactive_tunables *tunab anyboost = 1; } spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]); + + up_read(&pcpu->enable_sem); } spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]); @@ -1121,6 +1149,150 @@ static struct notifier_block cpufreq_interactive_idle_nb = { .notifier_call = cpufreq_interactive_idle_notifier, }; +#ifdef CONFIG_ARCH_ROCKCHIP +static void cpufreq_interactive_input_event(struct input_handle *handle, + unsigned int type, + unsigned int code, + int value) +{ + u64 now, endtime; + int i; + int anyboost = 0; + unsigned long flags[2]; + struct cpufreq_interactive_cpuinfo *pcpu; + struct cpufreq_interactive_tunables *tunables; + + if ((type != EV_ABS) && (type != EV_KEY)) + return; + + trace_cpufreq_interactive_boost("touch"); + spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]); + + now = ktime_to_us(ktime_get()); + for_each_online_cpu(i) { + pcpu = &per_cpu(cpuinfo, i); + if (!pcpu->policy) + continue; + + if (have_governor_per_policy()) + tunables = pcpu->policy->governor_data; + else + tunables = common_tunables; + if (!tunables) + continue; + + endtime = now + tunables->touchboostpulse_duration_val; + if (endtime < (tunables->touchboostpulse_endtime + + 10 * USEC_PER_MSEC)) + continue; + tunables->touchboostpulse_endtime = endtime; + + spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]); + if (pcpu->target_freq < tunables->touchboost_freq) { + pcpu->target_freq = tunables->touchboost_freq; + cpumask_set_cpu(i, &speedchange_cpumask); + pcpu->loc_hispeed_val_time = + ktime_to_us(ktime_get()); + anyboost = 1; + } + + pcpu->floor_freq = tunables->touchboost_freq; + pcpu->loc_floor_val_time = ktime_to_us(ktime_get()); + + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]); + } + + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]); + + if (anyboost) + wake_up_process(speedchange_task); +} + +static int cpufreq_interactive_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(*handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "cpufreq"; + + 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 cpufreq_interactive_input_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static const struct input_device_id cpufreq_interactive_ids[] = { + { + .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) }, + }, + { + .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) }, + }, + { + .flags = INPUT_DEVICE_ID_MATCH_EVBIT, + .evbit = { BIT_MASK(EV_KEY) }, + }, + { }, +}; + +static struct input_handler cpufreq_interactive_input_handler = { + .event = cpufreq_interactive_input_event, + .connect = cpufreq_interactive_input_connect, + .disconnect = cpufreq_interactive_input_disconnect, + .name = "cpufreq_interactive", + .id_table = cpufreq_interactive_ids, +}; + +static void rockchip_cpufreq_policy_init(struct cpufreq_policy *policy) +{ + struct cpufreq_interactive_tunables *tunables = policy->governor_data; + + tunables->min_sample_time = 40 * USEC_PER_MSEC; + tunables->boostpulse_duration_val = 40 * USEC_PER_MSEC; + if (policy->cpu == 0) { + tunables->hispeed_freq = 1008000; + tunables->touchboostpulse_duration_val = 500 * USEC_PER_MSEC; + tunables->touchboost_freq = 1200000; + } else { + tunables->hispeed_freq = 816000; + } +} +#endif + static int cpufreq_governor_interactive(struct cpufreq_policy *policy, unsigned int event) { @@ -1172,9 +1344,12 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, policy->governor_data = tunables; if (!have_governor_per_policy()) { common_tunables = tunables; - WARN_ON(cpufreq_get_global_kobject()); } +#ifdef CONFIG_ARCH_ROCKCHIP + rockchip_cpufreq_policy_init(policy); +#endif + rc = sysfs_create_group(get_governor_parent_kobj(policy), get_sysfs_attr()); if (rc) { @@ -1182,7 +1357,6 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, policy->governor_data = NULL; if (!have_governor_per_policy()) { common_tunables = NULL; - cpufreq_put_global_kobject(); } return rc; } @@ -1191,6 +1365,10 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, idle_notifier_register(&cpufreq_interactive_idle_nb); cpufreq_register_notifier(&cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); +#ifdef CONFIG_ARCH_ROCKCHIP + rc = input_register_handler(&cpufreq_interactive_input_handler); +#endif + } break; @@ -1198,6 +1376,9 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, case CPUFREQ_GOV_POLICY_EXIT: if (!--tunables->usage_count) { if (policy->governor->initialized == 1) { +#ifdef CONFIG_ARCH_ROCKCHIP + input_unregister_handler(&cpufreq_interactive_input_handler); +#endif cpufreq_unregister_notifier(&cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER); idle_notifier_unregister(&cpufreq_interactive_idle_nb); @@ -1206,9 +1387,6 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, sysfs_remove_group(get_governor_parent_kobj(policy), get_sysfs_attr()); - if (!have_governor_per_policy()) - cpufreq_put_global_kobject(); - kfree(tunables); common_tunables = NULL; }