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] [<ffffff80097af728>]
	meson_pwm_apply+0x48/0x398

Change-Id: Ib2f42c4d757d1bb4bd8e4df0f90f7924be2fa799
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
This commit is contained in:
Jian Hu
2017-07-28 14:41:05 +08:00
committed by Jianxin Pan
parent 6df60b00fe
commit 72d840c8f7
2 changed files with 8 additions and 11 deletions

View File

@@ -61,8 +61,6 @@
#include <linux/amlogic/pwm_meson.h>
#include <linux/of_device.h>
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;

View File

@@ -30,6 +30,7 @@
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/time.h>
#include <linux/clk.h>
#include <linux/of_address.h>
@@ -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;
};