From a54bcc81e0f39caca448189b27e277c524756edc Mon Sep 17 00:00:00 2001 From: Finley Xiao Date: Wed, 9 Aug 2017 12:36:21 +0800 Subject: [PATCH] PM / devfreq: rockchip_dmc: Fix locking when rounding rate There's no need to take the rcu read lock when rounding rate. This patch fixes the following BUG: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:620 in_atomic(): 0, irqs_disabled(): 0, pid: 153, name: kworker/u16:2 5 locks held by kworker/u16:2/153: #0: ("%s"("devfreq_wq")){......}, at: [] process_one_work+0x1c4/0x58c #1: ((&(&devfreq->work)->work)){......}, at: [] process_one_work+0x1c4/0x58c #2: (&devfreq->lock){......}, at: [] devfreq_monitor+0x28/0x8c #3: (&vop->vop_lock){......}, at: [] dmc_notifier_call+0x14/0x34 #4: (rcu_read_lock){......}, at: [] rockchip_dmcfreq_target+0x0/0x2e0 CPU: 3 PID: 153 Comm: kworker/u16:2 Not tainted 4.4.77 #2573 Hardware name: Rockchip Sheep board (DT) Workqueue: devfreq_wq devfreq_monitor Call trace: [] dump_backtrace+0x0/0x1c8 [] show_stack+0x14/0x1c [] dump_stack+0x8c/0xac [] ___might_sleep+0x11c/0x128 [] __might_sleep+0x74/0x84 [] mutex_lock_nested+0x4c/0x39c [] clk_prepare_lock+0x58/0xc8 [] clk_round_rate+0x34/0x94 [] rockchip_dmcfreq_target+0xac/0x2e0 [] update_devfreq+0x100/0x1ac [] devfreq_monitor+0x30/0x8c [] process_one_work+0x2ec/0x58c [] worker_thread+0x300/0x428 [] kthread+0x104/0x10c [] ret_from_fork+0x10/0x50 Change-Id: I31f75a55da72cab597796edd5c339222094fff97 Signed-off-by: Finley Xiao --- drivers/devfreq/rockchip_dmc.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c index fa00e367b35388..13a0a5bf2cf2e2 100644 --- a/drivers/devfreq/rockchip_dmc.c +++ b/drivers/devfreq/rockchip_dmc.c @@ -249,20 +249,21 @@ static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq, int err; rcu_read_lock(); + opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(opp)) { rcu_read_unlock(); return PTR_ERR(opp); } - temp_rate = dev_pm_opp_get_freq(opp); - target_rate = clk_round_rate(dmcfreq->dmc_clk, temp_rate); - if ((long)target_rate <= 0) - target_rate = temp_rate; target_volt = dev_pm_opp_get_voltage(opp); rcu_read_unlock(); + target_rate = clk_round_rate(dmcfreq->dmc_clk, temp_rate); + if ((long)target_rate <= 0) + target_rate = temp_rate; + if (dmcfreq->rate == target_rate) { if (dmcfreq->volt == target_volt) return 0;