diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 461a2083354d..d347e4b5cc7d 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -126,6 +126,7 @@ struct interactive_cpu { struct interactive_policy *ipolicy; struct irq_work irq_work; + struct irq_work boost_irq_work; u64 last_sample_time; unsigned long next_sample_jiffies; bool work_in_progress; @@ -148,6 +149,8 @@ struct interactive_cpu { u64 pol_hispeed_val_time; /* policy hispeed_validate_time */ u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */ int cpu; + unsigned int task_boost_freq; + u64 task_boos_endtime; }; static DEFINE_PER_CPU(struct interactive_cpu, interactive_cpu); @@ -423,6 +426,9 @@ static void eval_target_freq(struct interactive_cpu *icpu) new_freq < tunables->touchboost_freq) { new_freq = tunables->touchboost_freq; } + if ((now < icpu->task_boos_endtime) && (new_freq < icpu->task_boost_freq)) { + new_freq = icpu->task_boost_freq; + } #endif if (policy->cur >= tunables->hispeed_freq && new_freq > policy->cur && @@ -1131,6 +1137,9 @@ static inline void gov_clear_update_util(struct cpufreq_policy *policy) static void icpu_cancel_work(struct interactive_cpu *icpu) { irq_work_sync(&icpu->irq_work); +#ifdef CONFIG_ARCH_ROCKCHIP + irq_work_sync(&icpu->boost_irq_work); +#endif icpu->work_in_progress = false; del_timer_sync(&icpu->slack_timer); } @@ -1355,6 +1364,87 @@ static void rockchip_cpufreq_policy_init(struct interactive_policy *ipolicy) tunables->attr_set = attr_set; } } + +static void task_boost_irq_work(struct irq_work *irq_work) +{ + struct interactive_cpu *pcpu; + unsigned long flags[2]; + + pcpu = container_of(irq_work, struct interactive_cpu, boost_irq_work); + if (!down_read_trylock(&pcpu->enable_sem)) + return; + + if (!pcpu->ipolicy) + goto out; + + spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]); + spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]); + if (pcpu->target_freq < pcpu->task_boost_freq) { + pcpu->target_freq = pcpu->task_boost_freq; + cpumask_set_cpu(pcpu->cpu, &speedchange_cpumask); + wake_up_process(speedchange_task); + } + spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]); + spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]); + +out: + up_read(&pcpu->enable_sem); +} + +static unsigned int get_freq_for_util(struct cpufreq_policy *policy, unsigned long util) +{ + struct cpufreq_frequency_table *pos; + unsigned long max_cap, cur_cap; + unsigned int freq = 0; + + max_cap = arch_scale_cpu_capacity(NULL, policy->cpu); + cpufreq_for_each_valid_entry(pos, policy->freq_table) { + freq = pos->frequency; + + cur_cap = max_cap * freq / policy->max; + if (cur_cap > util) + break; + } + + return freq; +} + +extern unsigned long capacity_curr_of(int cpu); + +void cpufreq_task_boost(int cpu, unsigned long util) +{ + struct interactive_cpu *pcpu = &per_cpu(interactive_cpu, cpu); + struct interactive_policy *ipolicy = pcpu->ipolicy; + unsigned long cap, min_util; + + if (!down_read_trylock(&pcpu->enable_sem)) + return; + + if (!ipolicy) + goto out; + + if (ipolicy->policy->cur == ipolicy->policy->max) + goto out; + + min_util = util + (util >> 2); + cap = capacity_curr_of(cpu); + if (min_util > cap) { + u64 now = ktime_to_us(ktime_get()); + u64 prev_boos_endtime = pcpu->task_boos_endtime; + unsigned int boost_freq; + + pcpu->task_boos_endtime = now + ipolicy->tunables->sampling_rate; + boost_freq = get_freq_for_util(ipolicy->policy, min_util); + if ((now < prev_boos_endtime) && (boost_freq <= pcpu->task_boost_freq)) + goto out; + pcpu->task_boost_freq = boost_freq; + + irq_work_queue(&pcpu->boost_irq_work); + } + +out: + up_read(&pcpu->enable_sem); +} #endif int cpufreq_interactive_init(struct cpufreq_policy *policy) @@ -1583,6 +1673,9 @@ static int __init cpufreq_interactive_gov_init(void) icpu = &per_cpu(interactive_cpu, cpu); init_irq_work(&icpu->irq_work, irq_work); +#ifdef CONFIG_ARCH_ROCKCHIP + init_irq_work(&icpu->boost_irq_work, task_boost_irq_work); +#endif spin_lock_init(&icpu->load_lock); spin_lock_init(&icpu->target_freq_lock); init_rwsem(&icpu->enable_sem); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 983e756f32e9..d02619286e9b 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -949,6 +949,14 @@ static inline void sched_cpufreq_governor_change(struct cpufreq_policy *policy, struct cpufreq_governor *old_gov) { } #endif +#if defined(CONFIG_ARCH_ROCKCHIP) && defined(CONFIG_CPU_FREQ_GOV_INTERACTIVE) +void cpufreq_task_boost(int cpu, unsigned long util); +#else +static inline void cpufreq_task_boost(int cpu, unsigned long util) +{ +} +#endif + extern void arch_freq_prepare_all(void); extern unsigned int arch_freq_get_on_cpu(int cpu);