mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user