From 72d840c8f7273272f8a992524b63a03a396d081f Mon Sep 17 00:00:00 2001 From: Jian Hu Date: Fri, 28 Jul 2017 14:41:05 +0800 Subject: [PATCH] pwm: fix kernel crash using spinlock_t lock PD#148269: fix kernel panic when hibenating 1.Using mutex lock instead of spinlock_t lock. 2.Clk_prepare_enable might sleep could not use spinlock_t lock. 3.Add spinlock_t lock for clock_mux. 4.Panic message: BUG: sleeping function called from invalid context at kernel/locking/mutex.c:97 in_atomic(): 1, irqs_disabled(): 128, pid: 2501, name: sh Preemption disabled at:[ 69.935889@1] [] meson_pwm_apply+0x48/0x398 Change-Id: Ib2f42c4d757d1bb4bd8e4df0f90f7924be2fa799 Signed-off-by: Jian Hu --- drivers/amlogic/pwm/pwm_meson.c | 14 +++++--------- include/linux/amlogic/pwm_meson.h | 5 +++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/drivers/amlogic/pwm/pwm_meson.c b/drivers/amlogic/pwm/pwm_meson.c index bcd477d..76e2893 100644 --- a/drivers/amlogic/pwm/pwm_meson.c +++ b/drivers/amlogic/pwm/pwm_meson.c @@ -61,8 +61,6 @@ #include #include - - struct meson_pwm_channel { unsigned int hi; unsigned int lo; @@ -75,8 +73,6 @@ struct meson_pwm_channel { struct clk *clk; }; - - struct meson_pwm *to_meson_pwm(struct pwm_chip *chip) { return container_of(chip, struct meson_pwm, chip); @@ -327,13 +323,12 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, { struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); struct meson_pwm *meson = to_meson_pwm(chip); - unsigned long flags; int err = 0; if (!state) return -EINVAL; - spin_lock_irqsave(&meson->lock, flags); + mutex_lock(&meson->lock); if (!state->enabled) { meson_pwm_disable(meson, pwm->hwpwm); @@ -373,7 +368,7 @@ static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } unlock: - spin_unlock_irqrestore(&meson->lock, flags); + mutex_unlock(&meson->lock); return err; } @@ -510,7 +505,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, channel->mux.shift = mux_reg_shifts[i]; channel->mux.mask = BIT(MISC_CLK_SEL_WIDTH) - 1; channel->mux.flags = 0; - channel->mux.lock = &meson->lock; + channel->mux.lock = &meson->pwm_lock; channel->mux.table = NULL; channel->mux.hw.init = &init; @@ -561,7 +556,8 @@ static int meson_pwm_probe(struct platform_device *pdev) if (IS_ERR(meson->base)) return PTR_ERR(meson->base); - spin_lock_init(&meson->lock); + mutex_init(&meson->lock); + spin_lock_init(&meson->pwm_lock); meson->chip.dev = &pdev->dev; meson->chip.ops = &meson_pwm_ops; meson->chip.base = -1; diff --git a/include/linux/amlogic/pwm_meson.h b/include/linux/amlogic/pwm_meson.h index 415c84e..8142869 100644 --- a/include/linux/amlogic/pwm_meson.h +++ b/include/linux/amlogic/pwm_meson.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -118,8 +119,8 @@ struct meson_pwm { struct meson_pwm_data *data; struct meson_pwm_variant variant; u32 inverter_mask; - spinlock_t lock; - + struct mutex lock; + spinlock_t pwm_lock; unsigned int clk_mask; }; -- 2.7.4