From d74a177292b31c2f043d0dce63634da3b31eb1e9 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Tue, 29 Dec 2020 18:18:24 +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: 205ed4e6e80f (cpufreq: interactive: introduce boost cpufreq interface for task) Change-Id: I9607faa5ede3a662e7f2f55da29b08fc328f4d43 Signed-off-by: Liang Chen --- drivers/cpufreq/cpufreq_interactive.c | 88 +++++++++++++-------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 83aea065e5236..d0ad77045ce38 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -60,6 +60,7 @@ struct cpufreq_interactive_cpuinfo { int governor_enabled; int cpu; unsigned int task_boost_freq; + unsigned long task_boost_util; u64 task_boos_endtime; struct irq_work irq_work; }; @@ -1341,32 +1342,6 @@ static void rockchip_cpufreq_policy_init(struct cpufreq_policy *policy) *tunables = backup_tunables[index]; } -static void task_boost_irq_work(struct irq_work *irq_work) -{ - struct cpufreq_interactive_cpuinfo *pcpu; - unsigned long flags[2]; - - pcpu = container_of(irq_work, struct cpufreq_interactive_cpuinfo, irq_work); - if (!down_read_trylock(&pcpu->enable_sem)) - return; - - if (!pcpu->governor_enabled || !pcpu->policy) - 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; @@ -1385,19 +1360,20 @@ static unsigned int get_freq_for_util(struct cpufreq_policy *policy, unsigned lo return freq; } -void cpufreq_task_boost(int cpu, unsigned long util) +static void task_boost_irq_work(struct irq_work *irq_work) { struct cpufreq_interactive_tunables *tunables; - struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu); - struct cpufreq_policy *policy = pcpu->policy; - unsigned long cap, min_util; - - if (!speedchange_task) - return; + struct cpufreq_interactive_cpuinfo *pcpu; + struct cpufreq_policy *policy; + unsigned long flags[2]; + u64 now, prev_boos_endtime; + unsigned int boost_freq; + pcpu = container_of(irq_work, struct cpufreq_interactive_cpuinfo, irq_work); if (!down_read_trylock(&pcpu->enable_sem)) return; + policy = pcpu->policy; if (!pcpu->governor_enabled || !policy) goto out; @@ -1405,31 +1381,49 @@ void cpufreq_task_boost(int cpu, unsigned long util) goto out; if (have_governor_per_policy()) - tunables = pcpu->policy->governor_data; + tunables = policy->governor_data; else tunables = common_tunables; if (!tunables) 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 + tunables->timer_rate; - boost_freq = get_freq_for_util(policy, min_util); - if ((now < prev_boos_endtime) && (boost_freq <= pcpu->task_boost_freq)) - goto out; - pcpu->task_boost_freq = boost_freq; + now = ktime_to_us(ktime_get()); + prev_boos_endtime = pcpu->task_boos_endtime; + pcpu->task_boos_endtime = now + tunables->timer_rate; + boost_freq = get_freq_for_util(policy, pcpu->task_boost_util); + if ((now < prev_boos_endtime) && (boost_freq <= pcpu->task_boost_freq)) + goto out; + pcpu->task_boost_freq = boost_freq; - irq_work_queue(&pcpu->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); } + +void cpufreq_task_boost(int cpu, unsigned long util) +{ + struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, 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->irq_work); + } +} #endif static int cpufreq_governor_interactive(struct cpufreq_policy *policy,