Skip to content

Commit d74a177

Browse files
author
Liang Chen
committed
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: 205ed4e (cpufreq: interactive: introduce boost cpufreq interface for task) Change-Id: I9607faa5ede3a662e7f2f55da29b08fc328f4d43 Signed-off-by: Liang Chen <cl@rock-chips.com>
1 parent da3b23f commit d74a177

1 file changed

Lines changed: 41 additions & 47 deletions

File tree

drivers/cpufreq/cpufreq_interactive.c

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct cpufreq_interactive_cpuinfo {
6060
int governor_enabled;
6161
int cpu;
6262
unsigned int task_boost_freq;
63+
unsigned long task_boost_util;
6364
u64 task_boos_endtime;
6465
struct irq_work irq_work;
6566
};
@@ -1341,32 +1342,6 @@ static void rockchip_cpufreq_policy_init(struct cpufreq_policy *policy)
13411342
*tunables = backup_tunables[index];
13421343
}
13431344

1344-
static void task_boost_irq_work(struct irq_work *irq_work)
1345-
{
1346-
struct cpufreq_interactive_cpuinfo *pcpu;
1347-
unsigned long flags[2];
1348-
1349-
pcpu = container_of(irq_work, struct cpufreq_interactive_cpuinfo, irq_work);
1350-
if (!down_read_trylock(&pcpu->enable_sem))
1351-
return;
1352-
1353-
if (!pcpu->governor_enabled || !pcpu->policy)
1354-
goto out;
1355-
1356-
spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]);
1357-
spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]);
1358-
if (pcpu->target_freq < pcpu->task_boost_freq) {
1359-
pcpu->target_freq = pcpu->task_boost_freq;
1360-
cpumask_set_cpu(pcpu->cpu, &speedchange_cpumask);
1361-
wake_up_process(speedchange_task);
1362-
}
1363-
spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
1364-
spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
1365-
1366-
out:
1367-
up_read(&pcpu->enable_sem);
1368-
}
1369-
13701345
static unsigned int get_freq_for_util(struct cpufreq_policy *policy, unsigned long util)
13711346
{
13721347
struct cpufreq_frequency_table *pos;
@@ -1385,51 +1360,70 @@ static unsigned int get_freq_for_util(struct cpufreq_policy *policy, unsigned lo
13851360
return freq;
13861361
}
13871362

1388-
void cpufreq_task_boost(int cpu, unsigned long util)
1363+
static void task_boost_irq_work(struct irq_work *irq_work)
13891364
{
13901365
struct cpufreq_interactive_tunables *tunables;
1391-
struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
1392-
struct cpufreq_policy *policy = pcpu->policy;
1393-
unsigned long cap, min_util;
1394-
1395-
if (!speedchange_task)
1396-
return;
1366+
struct cpufreq_interactive_cpuinfo *pcpu;
1367+
struct cpufreq_policy *policy;
1368+
unsigned long flags[2];
1369+
u64 now, prev_boos_endtime;
1370+
unsigned int boost_freq;
13971371

1372+
pcpu = container_of(irq_work, struct cpufreq_interactive_cpuinfo, irq_work);
13981373
if (!down_read_trylock(&pcpu->enable_sem))
13991374
return;
14001375

1376+
policy = pcpu->policy;
14011377
if (!pcpu->governor_enabled || !policy)
14021378
goto out;
14031379

14041380
if (policy->cur == policy->max)
14051381
goto out;
14061382

14071383
if (have_governor_per_policy())
1408-
tunables = pcpu->policy->governor_data;
1384+
tunables = policy->governor_data;
14091385
else
14101386
tunables = common_tunables;
14111387
if (!tunables)
14121388
goto out;
14131389

1414-
min_util = util + (util >> 2);
1415-
cap = capacity_curr_of(cpu);
1416-
if (min_util > cap) {
1417-
u64 now = ktime_to_us(ktime_get());
1418-
u64 prev_boos_endtime = pcpu->task_boos_endtime;
1419-
unsigned int boost_freq;
1420-
1421-
pcpu->task_boos_endtime = now + tunables->timer_rate;
1422-
boost_freq = get_freq_for_util(policy, min_util);
1423-
if ((now < prev_boos_endtime) && (boost_freq <= pcpu->task_boost_freq))
1424-
goto out;
1425-
pcpu->task_boost_freq = boost_freq;
1390+
now = ktime_to_us(ktime_get());
1391+
prev_boos_endtime = pcpu->task_boos_endtime;
1392+
pcpu->task_boos_endtime = now + tunables->timer_rate;
1393+
boost_freq = get_freq_for_util(policy, pcpu->task_boost_util);
1394+
if ((now < prev_boos_endtime) && (boost_freq <= pcpu->task_boost_freq))
1395+
goto out;
1396+
pcpu->task_boost_freq = boost_freq;
14261397

1427-
irq_work_queue(&pcpu->irq_work);
1398+
spin_lock_irqsave(&speedchange_cpumask_lock, flags[0]);
1399+
spin_lock_irqsave(&pcpu->target_freq_lock, flags[1]);
1400+
if (pcpu->target_freq < pcpu->task_boost_freq) {
1401+
pcpu->target_freq = pcpu->task_boost_freq;
1402+
cpumask_set_cpu(pcpu->cpu, &speedchange_cpumask);
1403+
wake_up_process(speedchange_task);
14281404
}
1405+
spin_unlock_irqrestore(&pcpu->target_freq_lock, flags[1]);
1406+
spin_unlock_irqrestore(&speedchange_cpumask_lock, flags[0]);
14291407

14301408
out:
14311409
up_read(&pcpu->enable_sem);
14321410
}
1411+
1412+
void cpufreq_task_boost(int cpu, unsigned long util)
1413+
{
1414+
struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
1415+
unsigned long cap, min_util;
1416+
1417+
if (!speedchange_task)
1418+
return;
1419+
1420+
min_util = util + (util >> 2);
1421+
cap = capacity_curr_of(cpu);
1422+
if (min_util > cap) {
1423+
pcpu->task_boost_util = min_util;
1424+
irq_work_queue(&pcpu->irq_work);
1425+
}
1426+
}
14331427
#endif
14341428

14351429
static int cpufreq_governor_interactive(struct cpufreq_policy *policy,

0 commit comments

Comments
 (0)