Patch "Input: pwm-beeper - fix - scheduling while atomic" has been added to the 4.6-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
Input: pwm-beeper - fix - scheduling while atomic
to the 4.6-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
input-pwm-beeper-fix-scheduling-while-atomic.patch
and it can be found in the queue-4.6 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
f49cf3b8b4c841457244c461c66186a719e13bccMon Sep 17 00:00:00 2001
From: Manfred Schlaegl <[email protected]>
Date: Fri, 27 May 2016 16:36:36 -0700
Subject: Input: pwm-beeper - fix - scheduling while atomic
From: Manfred Schlaegl <[email protected]>
commit f49cf3b8b4c841457244c461c66186a719e13bcc upstream.
Pwm config may sleep so defer it using a worker.
On a Freescale i.MX53 based board we ran into "BUG: scheduling while atomic" because input_inject_event locks interrupts, but imx_pwm_config_v2 sleeps.
Tested on Freescale i.MX53 SoC with 4.6.0.
--- drivers/input/misc/pwm-beeper.c | 69 +++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 21 deletions(-)
drivers/input/misc/pwm-beeper.c +48 -21
@@ -20,21 +20,40 @@#include <linux/platform_device.h> #include <linux/pwm.h> #include <linux/slab.h> +#include <linux/workqueue.h> struct pwm_beeper {struct input_dev *input;struct pwm_device *pwm; +struct work_struct work;unsigned long period; };#define HZ_TO_NANOSECONDS (x) (1000000000UL/(x)) +static void __pwm_beeper_set (struct pwm_beeper *beeper) +{ +unsigned long period = beeper->period; + +if (period) { +pwm_config (beeper->pwm, period /2 , period); +pwm_enable (beeper->pwm); + }else +pwm_disable (beeper->pwm); +} + +static void pwm_beeper_work (struct work_struct *work) +{ +struct pwm_beeper *beeper = + container_of(work, struct pwm_beeper, work); + +__pwm_beeper_set (beeper); +} +static int pwm_beeper_event (struct input_dev *input,unsigned int type,unsigned int code,int value) { -int ret =0 ;struct pwm_beeper *beeper =input_get_drvdata (input); -unsigned long period;if (type !=EV_SND || value <0 )return -EINVAL ;
@@ -49,22 +68,31 @@ static int pwm_beeper_event(struct inputreturn -EINVAL ; } -if (value ==0 ) { -pwm_disable (beeper->pwm); - }else { - period =HZ_TO_NANOSECONDS (value); - ret =pwm_config (beeper->pwm, period /2 , period); -if (ret) -return ret; - ret =pwm_enable (beeper->pwm); -if (ret) -return ret; - beeper->period = period; - } +if (value ==0 ) + beeper->period =0 ; +else + beeper->period =HZ_TO_NANOSECONDS (value); + +schedule_work (&beeper->work);return 0 ; } +static void pwm_beeper_stop (struct pwm_beeper *beeper) +{ +cancel_work_sync (&beeper->work); + +if (beeper->period) +pwm_disable (beeper->pwm); +} + +static void pwm_beeper_close (struct input_dev *input) +{ +struct pwm_beeper *beeper =input_get_drvdata (input); + +pwm_beeper_stop (beeper); +} +static int pwm_beeper_probe (struct platform_device *pdev) {unsigned long pwm_id = (unsigned long )dev_get_platdata (&pdev->dev);
@@ -87,6 +115,8 @@ static int pwm_beeper_probe(struct platf goto err_free; } +INIT_WORK (&beeper->work, pwm_beeper_work); + beeper->input =input_allocate_device ();if (!beeper->input) {dev_err (&pdev->dev,"Failed to allocate input device\n" );
@@ -106,6 +136,7 @@ static int pwm_beeper_probe(struct platf beeper->input->sndbit[0 ] =BIT (SND_TONE ) |BIT (SND_BELL ); beeper->input->event = pwm_beeper_event; + beeper->input->close = pwm_beeper_close;input_set_drvdata (beeper->input, beeper);
@@ -135,7 +166,6 @@ static int pwm_beeper_remove(struct platinput_unregister_device (beeper->input); -pwm_disable (beeper->pwm);pwm_free (beeper->pwm);kfree (beeper);
@@ -147,8 +177,7 @@ static int __maybe_unused pwm_beeper_sus {struct pwm_beeper *beeper =dev_get_drvdata (dev); -if (beeper->period) -pwm_disable (beeper->pwm); +pwm_beeper_stop (beeper);return 0 ; }
@@ -157,10 +186,8 @@ static int __maybe_unused pwm_beeper_res {struct pwm_beeper *beeper =dev_get_drvdata (dev); -if (beeper->period) { -pwm_config (beeper->pwm, beeper->period /2 , beeper->period); -pwm_enable (beeper->pwm); - } +if (beeper->period) +__pwm_beeper_set (beeper);return 0 ; }
Patches currently in stable-queue which might be from [email protected] are
queue-4.6/input-pwm-beeper-fix-scheduling-while-atomic.patch