From 6b4feaea251a97bf08c7d41eabdec07f63a11073 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 11 Dec 2015 15:38:40 +0100 Subject: [PATCH] clk: exynos: use irqsave version of spin_lock to avoid deadlock with irqs It is allowed to enable/disable clocks from interrupts, so common Exynos ARM clock management code for CPUfreq should use 'irqsave' version of spin_lock calls to avoid potential deadlock caused by spin_lock recursion. The same spin_lock is used by gate/mux clocks during enable/disable calls. This deadlock, can be reproduced by enabling CPUfreq (ondemand or userspace) and decoding video with s5p-mfc driver. Relevant stack trace: [ 5928.061534] BUG: spinlock recursion on CPU#0, bash/1252 [ 5928.061609] lock: 0xee80454c, .magic: dead4ead, .owner: bash/1252, .owner_cpu: 0 [ 5928.068586] CPU: 0 PID: 1252 Comm: bash Tainted: G W 4.4.0-rc4-00001-g447a7fd #678 [ 5928.077260] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 5928.083359] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 5928.091072] [] (show_stack) from [] (dump_stack+0x68/0xb8) [ 5928.098275] [] (dump_stack) from [] (do_raw_spin_lock+0x184/0x1ac) [ 5928.106177] [] (do_raw_spin_lock) from [] (_raw_spin_lock_irqsave+0x20/0x28) [ 5928.114943] [] (_raw_spin_lock_irqsave) from [] (clk_gate_endisable+0x24/0x98) [ 5928.123882] [] (clk_gate_endisable) from [] (clk_core_disable+0x60/0x84) [ 5928.132299] [] (clk_core_disable) from [] (clk_disable+0x24/0x30) [ 5928.140117] [] (clk_disable) from [] (s5p_mfc_handle_frame+0x254/0x860) [ 5928.148445] [] (s5p_mfc_handle_frame) from [] (s5p_mfc_irq+0x890/0xa24) [ 5928.156778] [] (s5p_mfc_irq) from [] (handle_irq_event_percpu+0x50/0x14c) [ 5928.165283] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [ 5928.174143] [] (handle_irq_event) from [] (handle_fasteoi_irq+0xdc/0x1a4) [ 5928.182645] [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x18/0x28) [ 5928.191236] [] (generic_handle_irq) from [] (__handle_domain_irq+0x6c/0xdc) [ 5928.199917] [] (__handle_domain_irq) from [] (gic_handle_irq+0x4c/0x98) [ 5928.208249] [] (gic_handle_irq) from [] (__irq_svc+0x54/0x90) [ 5928.215709] Exception stack(0xeddb5cb8 to 0xeddb5d00) [ 5928.220745] 5ca0: ee80454c faddfadc [ 5928.228906] 5cc0: 00000000 01000001 ee831ce0 f8114200 ee807c00 01130520 00000403 eddb5d84 [ 5928.237063] 5ce0: ee807c48 2faf0800 ee807c0c eddb5d08 c046b618 c046b634 20000053 ffffffff [ 5928.245225] [] (__irq_svc) from [] (exynos_cpuclk_notifier_cb+0x170/0x270) [ 5928.253823] [] (exynos_cpuclk_notifier_cb) from [] (notifier_call_chain+0x44/0x84) [ 5928.263106] [] (notifier_call_chain) from [] (__srcu_notifier_call_chain+0x6c/0x9c) [ 5928.272480] [] (__srcu_notifier_call_chain) from [] (srcu_notifier_call_chain+0x18/0x20) [ 5928.282288] [] (srcu_notifier_call_chain) from [] (__clk_notify+0x6c/0x74) [ 5928.290881] [] (__clk_notify) from [] (clk_propagate_rate_change+0xa0/0xac) [ 5928.299561] [] (clk_propagate_rate_change) from [] (clk_propagate_rate_change+0x90/0xac) [ 5928.309370] [] (clk_propagate_rate_change) from [] (clk_core_set_rate_nolock+0x64/0xa8) [ 5928.319091] [] (clk_core_set_rate_nolock) from [] (clk_set_rate+0x20/0x30) [ 5928.327686] [] (clk_set_rate) from [] (set_target+0xe8/0x23c) [ 5928.335152] [] (set_target) from [] (__cpufreq_driver_target+0x184/0x29c) [ 5928.343655] [] (__cpufreq_driver_target) from [] (cpufreq_set+0x44/0x64) [ 5928.352074] [] (cpufreq_set) from [] (store_scaling_setspeed+0x5c/0x74) [ 5928.360407] [] (store_scaling_setspeed) from [] (store+0x7c/0x98) [ 5928.368221] [] (store) from [] (sysfs_kf_write+0x44/0x48) [ 5928.375338] [] (sysfs_kf_write) from [] (kernfs_fop_write+0xb8/0x1bc) [ 5928.383496] [] (kernfs_fop_write) from [] (__vfs_write+0x2c/0xd4) [ 5928.391308] [] (__vfs_write) from [] (vfs_write+0xa0/0x144) [ 5928.398598] [] (vfs_write) from [] (SyS_write+0x44/0x84) [ 5928.405631] [] (SyS_write) from [] (ret_fast_syscall+0x0/0x3c) CC: stable@vger.kernel.org # v4.2+ Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki --- drivers/clk/samsung/clk-cpu.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 2fe37f708dc7..813003d6ce09 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -148,6 +148,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata, unsigned long alt_prate = clk_get_rate(cpuclk->alt_parent); unsigned long alt_div = 0, alt_div_mask = DIV_MASK; unsigned long div0, div1 = 0, mux_reg; + unsigned long flags; /* find out the divider values to use for clock data */ while ((cfg_data->prate * 1000) != ndata->new_rate) { @@ -156,7 +157,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata, cfg_data++; } - spin_lock(cpuclk->lock); + spin_lock_irqsave(cpuclk->lock, flags); /* * For the selected PLL clock frequency, get the pre-defined divider @@ -212,7 +213,7 @@ static int exynos_cpuclk_pre_rate_change(struct clk_notifier_data *ndata, DIV_MASK_ALL); } - spin_unlock(cpuclk->lock); + spin_unlock_irqrestore(cpuclk->lock, flags); return 0; } @@ -223,6 +224,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata, const struct exynos_cpuclk_cfg_data *cfg_data = cpuclk->cfg; unsigned long div = 0, div_mask = DIV_MASK; unsigned long mux_reg; + unsigned long flags; /* find out the divider values to use for clock data */ if (cpuclk->flags & CLK_CPU_NEEDS_DEBUG_ALT_DIV) { @@ -233,7 +235,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata, } } - spin_lock(cpuclk->lock); + spin_lock_irqsave(cpuclk->lock, flags); /* select mout_apll as the alternate parent */ mux_reg = readl(base + E4210_SRC_CPU); @@ -246,7 +248,7 @@ static int exynos_cpuclk_post_rate_change(struct clk_notifier_data *ndata, } exynos_set_safe_div(base, div, div_mask); - spin_unlock(cpuclk->lock); + spin_unlock_irqrestore(cpuclk->lock, flags); return 0; } -- 2.20.1