From b388f15fd14c3ae62deb9a059464aa99b524ea4a Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Wed, 26 Jun 2013 14:38:04 +0200 Subject: [PATCH] pwm: pwm-tiehrpwm: Use clk_enable/disable instead clk_prepare/unprepare. This was found when using pwm-led on am33xx and enable heartbeat trigger. [ 808.624876] ================================= [ 808.629443] [ INFO: inconsistent lock state ] [ 808.634021] 3.9.0 #2 Not tainted [ 808.637415] --------------------------------- [ 808.641981] inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. [ 808.648288] swapper/0 [HC0[0]:SC1[1]:HE1:SE0] takes: [ 808.653494] (prepare_lock){+.?.+.}, at: [] clk_unprepare+0x15/0x24 [ 808.661040] {SOFTIRQ-ON-W} state was registered at: [ 808.666155] [] __lock_acquire+0x411/0x824 [ 808.671465] [] lock_acquire+0x41/0x50 [ 808.676412] [] mutex_lock_nested+0x31/0x1d8 [ 808.681912] [] clk_prepare+0x15/0x28 [ 808.686764] [] _init+0x117/0x1e0 [ 808.691256] [] omap_hwmod_for_each+0x29/0x3c [ 808.696842] [] __omap_hwmod_setup_all+0x17/0x2c [ 808.702696] [] do_one_initcall+0xc3/0x10c [ 808.708017] [] kernel_init_freeable+0xa7/0x134 [ 808.713778] [] kernel_init+0x7/0x98 [ 808.718544] [] ret_from_fork+0x11/0x3c [ 808.723583] irq event stamp: 1379172 [ 808.727328] hardirqs last enabled at (1379172): [] _raw_spin_unlock_irqrestore+0x21/0x30 [ 808.736828] hardirqs last disabled at (1379171): [] _raw_spin_lock_irqsave+0x13/0x38 [ 808.745876] softirqs last enabled at (1379164): [] irq_enter+0x49/0x4c [ 808.753747] softirqs last disabled at (1379165): [] irq_exit+0x63/0x88 [ 808.761518] [ 808.761518] other info that might help us debug this: [ 808.768373] Possible unsafe locking scenario: [ 808.768373] [ 808.774578] CPU0 [ 808.777141] ---- [ 808.779705] lock(prepare_lock); [ 808.783186] [ 808.785929] lock(prepare_lock); [ 808.789595] [ 808.789595] *** DEADLOCK *** [ 808.789595] [ 808.795805] 1 lock held by swapper/0: [ 808.799643] #0: (((&heartbeat_data->timer))){+.-...}, at: [] call_timer_fn+0x0/0x90 [ 808.808814] [ 808.808814] stack backtrace: [ 808.813402] [] (unwind_backtrace+0x1/0x98) from [] (print_usage_bug.part.25+0x16d/0x1cc) [ 808.823721] [] (print_usage_bug.part.25+0x16d/0x1cc) from [] (mark_lock+0x18d/0x434) [ 808.833669] [] (mark_lock+0x18d/0x434) from [] (__lock_acquire+0x3e1/0x824) [ 808.842803] [] (__lock_acquire+0x3e1/0x824) from [] (lock_acquire+0x41/0x50) [ 808.852031] [] (lock_acquire+0x41/0x50) from [] (mutex_lock_nested+0x31/0x1d8) [ 808.861433] [] (mutex_lock_nested+0x31/0x1d8) from [] (clk_unprepare+0x15/0x24) [ 808.870930] [] (clk_unprepare+0x15/0x24) from [] (ehrpwm_pwm_disable+0x5f/0x80) [ 808.880431] [] (ehrpwm_pwm_disable+0x5f/0x80) from [] (pwm_disable+0x27/0x28) [ 808.889751] [] (pwm_disable+0x27/0x28) from [] (led_heartbeat_function+0x3f/0xb0) [ 808.899431] [] (led_heartbeat_function+0x3f/0xb0) from [] (call_timer_fn+0x45/0x90) [ 808.909288] [] (call_timer_fn+0x45/0x90) from [] (run_timer_softirq+0x105/0x17c) [ 808.918884] [] (run_timer_softirq+0x105/0x17c) from [] (__do_softirq+0xa5/0x150) [ 808.928486] [] (__do_softirq+0xa5/0x150) from [] (irq_exit+0x63/0x88) [ 808.937098] [] (irq_exit+0x63/0x88) from [] (handle_IRQ+0x21/0x54) [ 808.945415] [] (handle_IRQ+0x21/0x54) from [] (omap3_intc_handle_irq+0x5d/0x68) [ 808.954900] [] (omap3_intc_handle_irq+0x5d/0x68) from [] (__irq_svc+0x3f/0x64) [ 808.964287] Exception stack(0xc05b1f68 to 0xc05b1fb0) [ 808.969587] 1f60: 00000001 00000001 00000000 00000000 c05b0000 c0619748 [ 808.978158] 1f80: c05b0000 c05b0000 c0619748 413fc082 00000000 00000000 01000000 c05b1fb0 [ 808.986719] 1fa0: c004f989 c000d6f0 400f0033 ffffffff [ 808.992024] [] (__irq_svc+0x3f/0x64) from [] (cpu_idle+0x60/0x98) [ 809.000250] [] (cpu_idle+0x60/0x98) from [] (start_kernel+0x1e9/0x234) Remove non atomic clk api calls and use only atomic for enable/disable because can be called from atomic context (led_heartbeat_function is timer callback). Signed-off-by: Marek Belisko Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiehrpwm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 48a485c2e422..aa4c5586f53b 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -359,7 +359,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) configure_polarity(pc, pwm->hwpwm); /* Enable TBCLK before enabling PWM device */ - ret = clk_prepare_enable(pc->tbclk); + ret = clk_enable(pc->tbclk); if (ret) { pr_err("Failed to enable TBCLK for %s\n", dev_name(pc->chip.dev)); @@ -395,7 +395,7 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); /* Disabling TBCLK on PWM disable */ - clk_disable_unprepare(pc->tbclk); + clk_disable(pc->tbclk); /* Stop Time base counter */ ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); @@ -482,6 +482,12 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) return PTR_ERR(pc->tbclk); } + ret = clk_prepare(pc->tbclk); + if (ret < 0) { + dev_err(&pdev->dev, "clk_prepare() failed: %d\n", ret); + return ret; + } + ret = pwmchip_add(&pc->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); @@ -508,6 +514,7 @@ pwmss_clk_failure: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pwmchip_remove(&pc->chip); + clk_unprepare(pc->tbclk); return ret; } @@ -515,6 +522,8 @@ static int ehrpwm_pwm_remove(struct platform_device *pdev) { struct ehrpwm_pwm_chip *pc = platform_get_drvdata(pdev); + clk_unprepare(pc->tbclk); + pm_runtime_get_sync(&pdev->dev); /* * Due to hardware misbehaviour, acknowledge of the stop_req