cpufreq: interactive: fix deadlock

up_read() may wakeup some tasks, so do not call up_read() in scheduler,
or it will cause deadlock as below:

Thread #4 5 (Name: cpu3, state: debug-request) (Suspended : Container)
	queued_spin_lock_slowpath() at qspinlock.c:369 0xffffff8008119120
	queued_spin_lock() at qspinlock.h:88 0xffffff8008f0a470
	do_raw_spin_lock() at spinlock.h:180 0xffffff8008f0a470
	__raw_spin_lock() at spinlock_api_smp.h:143 0xffffff8008f0a470
	_raw_spin_lock() at spinlock.c:144 0xffffff8008f0a470
	rq_lock() at sched.h:1,244 0xffffff80080f2f4c
	ttwu_queue() at core.c:2,442 0xffffff80080f2f4c
	try_to_wake_up() at core.c:2,658 0xffffff80080eb998
	wake_up_q() at core.c:450 0xffffff80080eb6a8
	rwsem_wake() at rwsem-xadd.c:703 0xffffff800811a44c
	__up_read() at rwsem.h:107 0xffffff8008118930
	up_read() at rwsem.c:122 0xffffff8008118930
	cpufreq_task_boost() at cpufreq_interactive.c:1,449 0xffffff8008a4bdb4
	enqueue_task_fair() at fair.c:5,285 0xffffff80080f7814
	enqueue_task() at core.c:1,324 0xffffff80080ec15c
	activate_task() at core.c:1,346 0xffffff80080ec15c
	ttwu_activate() at core.c:2,240 0xffffff80080f2fc0
	ttwu_do_activate() at core.c:2,299 0xffffff80080f2fc0
	ttwu_queue() at core.c:2,444 0xffffff80080f2fc0
	try_to_wake_up() at core.c:2,658 0xffffff80080eb998
	wake_up_q() at core.c:450 0xffffff80080eb6a8
	futex_wake() at futex.c:1,636 0xffffff8008159e78
	do_futex() at futex.c:3,714 0xffffff8008158fb0
	__do_sys_futex() at futex.c:3,770 0xffffff800815bd98
	__se_sys_futex() at futex.c:3,738 0xffffff800815bd98
	__arm64_sys_futex() at futex.c:3,738 0xffffff800815bd98
	__invoke_syscall() at syscall.c:36 0xffffff8008098d6c
	invoke_syscall() at syscall.c:48 0xffffff8008098d6c
	el0_svc_common() at syscall.c:117 0xffffff8008098d6c
	el0_svc_handler() at syscall.c:163 0xffffff8008098ccc
	el0_svc() at entry.S:940 0xffffff8008083d08

Fixes: 2d367d61e8 (cpufreq: interactive: introduce boost cpufreq interface for task)

Change-Id: I9607faa5ede3a662e7f2f55da29b08fc328f4d43
Signed-off-by: Liang Chen <cl@rock-chips.com>
This commit is contained in:
Liang Chen
2020-12-13 10:36:43 +08:00
committed by Tao Huang
parent d811fd17a0
commit f7a1c6f2a1

View File

@@ -150,6 +150,7 @@ struct interactive_cpu {
u64 loc_hispeed_val_time; /* per-cpu hispeed_validate_time */
int cpu;
unsigned int task_boost_freq;
unsigned long task_boost_util;
u64 task_boos_endtime;
};
@@ -1365,32 +1366,6 @@ static void rockchip_cpufreq_policy_init(struct interactive_policy *ipolicy)
}
}
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;
@@ -1409,45 +1384,64 @@ static unsigned int get_freq_for_util(struct cpufreq_policy *policy, unsigned lo
return freq;
}
extern unsigned long capacity_curr_of(int cpu);
void cpufreq_task_boost(int cpu, unsigned long util)
static void task_boost_irq_work(struct irq_work *irq_work)
{
struct interactive_cpu *pcpu = &per_cpu(interactive_cpu, cpu);
struct interactive_policy *ipolicy = pcpu->ipolicy;
unsigned long cap, min_util;
if (!speedchange_task)
return;
struct interactive_cpu *pcpu;
struct interactive_policy *ipolicy;
unsigned long flags[2];
u64 now, prev_boos_endtime;
unsigned int boost_freq;
pcpu = container_of(irq_work, struct interactive_cpu, boost_irq_work);
if (!down_read_trylock(&pcpu->enable_sem))
return;
ipolicy = pcpu->ipolicy;
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;
now = ktime_to_us(ktime_get());
prev_boos_endtime = pcpu->task_boos_endtime;;
pcpu->task_boos_endtime = now + ipolicy->tunables->sampling_rate;
boost_freq = get_freq_for_util(ipolicy->policy, pcpu->task_boost_util);
if ((now < prev_boos_endtime) && (boost_freq <= pcpu->task_boost_freq))
goto out;
pcpu->task_boost_freq = 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);
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);
}
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);
unsigned long cap, min_util;
if (!speedchange_task)
return;
min_util = util + (util >> 2);
cap = capacity_curr_of(cpu);
if (min_util > cap) {
pcpu->task_boost_util = min_util;
irq_work_queue(&pcpu->boost_irq_work);
}
}
#endif
int cpufreq_interactive_init(struct cpufreq_policy *policy)