mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
cpufreq: interactive: introduce boost cpufreq interface for task
boost cpufreq for a task if current capacity is not fit for the task. Change-Id: I85cfeaeb6d8fcface8f6534bb95b5baf3bfc839f Signed-off-by: Liang Chen <cl@rock-chips.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user