From f7a1c6f2a1e123d2811faf3a2a4e494b59d3cbdf Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Sun, 13 Dec 2020 10:36:43 +0800 Subject: [PATCH] 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: 2d367d61e8c1 (cpufreq: interactive: introduce boost cpufreq interface for task) Change-Id: I9607faa5ede3a662e7f2f55da29b08fc328f4d43 Signed-off-by: Liang Chen --- drivers/cpufreq/cpufreq_interactive.c | 90 +++++++++++++-------------- 1 file changed, 42 insertions(+), 48 deletions(-) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index f95554debb2c..7bbcdf6f64fd 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -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)