mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user