linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA
@ 2019-03-26 12:44 Fabrice Gasnier
  2019-03-27 12:51 ` Mukesh Ojha
  2019-03-30 16:38 ` Jonathan Cameron
  0 siblings, 2 replies; 4+ messages in thread
From: Fabrice Gasnier @ 2019-03-26 12:44 UTC (permalink / raw)
  To: jic23
  Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
	mcoquelin.stm32, knaack.h, fabrice.gasnier, linux-stm32,
	linux-arm-kernel

Enabling CONFIG_DEBUG_ATOMIC_SLEEP=y triggers this BUG message:
BUG: sleeping function called from invalid context at kernel/irq/chip.c...

Call stack is as follows:
- __might_sleep
- handle_nested_irq          <-- Expects threaded irq
- iio_trigger_poll_chained
- stm32_adc_dma_buffer_done
- vchan_complete
- tasklet_action_common
- tasklet_action
- __do_softirq               <-- DMA completion raises a tasklet
- irq_exit
- __handle_domain_irq        <-- DMA IRQ
- gic_handle_irq

IIO expects threaded interrupt context when calling:
- iio_trigger_poll_chained()
Or it expects interrupt context when calling:
- iio_trigger_poll()

This patch triggers an IRQ upon stm32_adc_dma_buffer_done() DMA callback
call, so the IIO trigger poll API gets called from IRQ context.

Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
 drivers/iio/adc/Kconfig     |  1 +
 drivers/iio/adc/stm32-adc.c | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 76db6e5..059407a 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -775,6 +775,7 @@ config STM32_ADC_CORE
 	select MFD_STM32_TIMERS
 	select IIO_STM32_TIMER_TRIGGER
 	select IIO_TRIGGERED_BUFFER
+	select IRQ_WORK
 	help
 	  Select this option to enable the core driver for STMicroelectronics
 	  STM32 analog-to-digital converter (ADC).
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 205e169..1aa3189 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -20,6 +20,7 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/irq_work.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
@@ -297,6 +298,7 @@ struct stm32_adc_cfg {
  * @smpr_val:		sampling time settings (e.g. smpr1 / smpr2)
  * @cal:		optional calibration data on some devices
  * @chan_name:		channel name array
+ * @work:		irq work used to call trigger poll routine
  */
 struct stm32_adc {
 	struct stm32_adc_common	*common;
@@ -320,6 +322,7 @@ struct stm32_adc {
 	u32			smpr_val[2];
 	struct stm32_adc_calib	cal;
 	char			chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
+	struct irq_work		work;
 };
 
 struct stm32_adc_diff_channel {
@@ -1473,11 +1476,32 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc)
 	return 0;
 }
 
+static void stm32_adc_dma_irq_work(struct irq_work *work)
+{
+	struct stm32_adc *adc = container_of(work, struct stm32_adc, work);
+	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
+
+	/*
+	 * iio_trigger_poll calls generic_handle_irq(). So, it requires hard
+	 * irq context, and cannot be called directly from dma callback,
+	 * dma cb has to schedule this work instead.
+	 */
+	iio_trigger_poll(indio_dev->trig);
+}
+
 static void stm32_adc_dma_buffer_done(void *data)
 {
 	struct iio_dev *indio_dev = data;
+	struct stm32_adc *adc = iio_priv(indio_dev);
 
-	iio_trigger_poll_chained(indio_dev->trig);
+	/*
+	 * Invoques iio_trigger_poll() from hard irq context: We can't
+	 * call iio_trigger_poll() nor iio_trigger_poll_chained()
+	 * directly from DMA callback (under tasklet e.g. softirq).
+	 * They require respectively HW IRQ and threaded IRQ context
+	 * as it might sleep.
+	 */
+	irq_work_queue(&adc->work);
 }
 
 static int stm32_adc_dma_start(struct iio_dev *indio_dev)
@@ -1585,8 +1609,10 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
 	if (!adc->dma_chan)
 		stm32_adc_conv_irq_disable(adc);
 
-	if (adc->dma_chan)
+	if (adc->dma_chan) {
 		dmaengine_terminate_all(adc->dma_chan);
+		irq_work_sync(&adc->work);
+	}
 
 	if (stm32_adc_set_trig(indio_dev, NULL))
 		dev_err(&indio_dev->dev, "Can't clear trigger\n");
@@ -1872,6 +1898,8 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev)
 	if (ret)
 		goto err_free;
 
+	init_irq_work(&adc->work, stm32_adc_dma_irq_work);
+
 	return 0;
 
 err_free:
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA
  2019-03-26 12:44 [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA Fabrice Gasnier
@ 2019-03-27 12:51 ` Mukesh Ojha
  2019-03-27 13:22   ` Mukesh Ojha
  2019-03-30 16:38 ` Jonathan Cameron
  1 sibling, 1 reply; 4+ messages in thread
From: Mukesh Ojha @ 2019-03-27 12:51 UTC (permalink / raw)
  To: Fabrice Gasnier, jic23
  Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
	mcoquelin.stm32, knaack.h, linux-stm32, linux-arm-kernel


On 3/26/2019 6:14 PM, Fabrice Gasnier wrote:
> Enabling CONFIG_DEBUG_ATOMIC_SLEEP=y triggers this BUG message:
> BUG: sleeping function called from invalid context at kernel/irq/chip.c...
>
> Call stack is as follows:
> - __might_sleep
> - handle_nested_irq          <-- Expects threaded irq
> - iio_trigger_poll_chained
> - stm32_adc_dma_buffer_done
> - vchan_complete
> - tasklet_action_common
> - tasklet_action
> - __do_softirq               <-- DMA completion raises a tasklet
> - irq_exit
> - __handle_domain_irq        <-- DMA IRQ
> - gic_handle_irq
>
> IIO expects threaded interrupt context when calling:
> - iio_trigger_poll_chained()
> Or it expects interrupt context when calling:
> - iio_trigger_poll()
>
> This patch triggers an IRQ upon stm32_adc_dma_buffer_done() DMA callback
> call, so the IIO trigger poll API gets called from IRQ context.
>
> Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
>
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

Reviewed-by: Mukesh Ojha <mojha@codeaurora.org>

-Mukesh


> ---
>   drivers/iio/adc/Kconfig     |  1 +
>   drivers/iio/adc/stm32-adc.c | 32 ++++++++++++++++++++++++++++++--
>   2 files changed, 31 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 76db6e5..059407a 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -775,6 +775,7 @@ config STM32_ADC_CORE
>   	select MFD_STM32_TIMERS
>   	select IIO_STM32_TIMER_TRIGGER
>   	select IIO_TRIGGERED_BUFFER
> +	select IRQ_WORK
>   	help
>   	  Select this option to enable the core driver for STMicroelectronics
>   	  STM32 analog-to-digital converter (ADC).
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index 205e169..1aa3189 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -20,6 +20,7 @@
>   #include <linux/interrupt.h>
>   #include <linux/io.h>
>   #include <linux/iopoll.h>
> +#include <linux/irq_work.h>
>   #include <linux/module.h>
>   #include <linux/platform_device.h>
>   #include <linux/pm_runtime.h>
> @@ -297,6 +298,7 @@ struct stm32_adc_cfg {
>    * @smpr_val:		sampling time settings (e.g. smpr1 / smpr2)
>    * @cal:		optional calibration data on some devices
>    * @chan_name:		channel name array
> + * @work:		irq work used to call trigger poll routine
>    */
>   struct stm32_adc {
>   	struct stm32_adc_common	*common;
> @@ -320,6 +322,7 @@ struct stm32_adc {
>   	u32			smpr_val[2];
>   	struct stm32_adc_calib	cal;
>   	char			chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
> +	struct irq_work		work;
>   };
>   
>   struct stm32_adc_diff_channel {
> @@ -1473,11 +1476,32 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc)
>   	return 0;
>   }
>   
> +static void stm32_adc_dma_irq_work(struct irq_work *work)
> +{
> +	struct stm32_adc *adc = container_of(work, struct stm32_adc, work);
> +	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +
> +	/*
> +	 * iio_trigger_poll calls generic_handle_irq(). So, it requires hard
> +	 * irq context, and cannot be called directly from dma callback,
> +	 * dma cb has to schedule this work instead.
> +	 */
> +	iio_trigger_poll(indio_dev->trig);
> +}
> +
>   static void stm32_adc_dma_buffer_done(void *data)
>   {
>   	struct iio_dev *indio_dev = data;
> +	struct stm32_adc *adc = iio_priv(indio_dev);
>   
> -	iio_trigger_poll_chained(indio_dev->trig);
> +	/*
> +	 * Invoques iio_trigger_poll() from hard irq context: We can't
> +	 * call iio_trigger_poll() nor iio_trigger_poll_chained()
> +	 * directly from DMA callback (under tasklet e.g. softirq).
> +	 * They require respectively HW IRQ and threaded IRQ context
> +	 * as it might sleep.
> +	 */
> +	irq_work_queue(&adc->work);
>   }
>   
>   static int stm32_adc_dma_start(struct iio_dev *indio_dev)
> @@ -1585,8 +1609,10 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
>   	if (!adc->dma_chan)
>   		stm32_adc_conv_irq_disable(adc);
>   
> -	if (adc->dma_chan)
> +	if (adc->dma_chan) {
>   		dmaengine_terminate_all(adc->dma_chan);
> +		irq_work_sync(&adc->work);
> +	}
>   
>   	if (stm32_adc_set_trig(indio_dev, NULL))
>   		dev_err(&indio_dev->dev, "Can't clear trigger\n");
> @@ -1872,6 +1898,8 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev)
>   	if (ret)
>   		goto err_free;
>   
> +	init_irq_work(&adc->work, stm32_adc_dma_irq_work);
> +
>   	return 0;
>   
>   err_free:

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA
  2019-03-27 12:51 ` Mukesh Ojha
@ 2019-03-27 13:22   ` Mukesh Ojha
  0 siblings, 0 replies; 4+ messages in thread
From: Mukesh Ojha @ 2019-03-27 13:22 UTC (permalink / raw)
  To: Fabrice Gasnier, jic23
  Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
	mcoquelin.stm32, knaack.h, linux-stm32, linux-arm-kernel


On 3/27/2019 6:21 PM, Mukesh Ojha wrote:
>
> On 3/26/2019 6:14 PM, Fabrice Gasnier wrote:
>> Enabling CONFIG_DEBUG_ATOMIC_SLEEP=y triggers this BUG message:
>> BUG: sleeping function called from invalid context at 
>> kernel/irq/chip.c...
>>
>> Call stack is as follows:
>> - __might_sleep
>> - handle_nested_irq          <-- Expects threaded irq
>> - iio_trigger_poll_chained
>> - stm32_adc_dma_buffer_done
>> - vchan_complete
>> - tasklet_action_common
>> - tasklet_action
>> - __do_softirq               <-- DMA completion raises a tasklet
>> - irq_exit
>> - __handle_domain_irq        <-- DMA IRQ
>> - gic_handle_irq
>>
>> IIO expects threaded interrupt context when calling:
>> - iio_trigger_poll_chained()
>> Or it expects interrupt context when calling:
>> - iio_trigger_poll()
>>
>> This patch triggers an IRQ upon stm32_adc_dma_buffer_done() DMA callback
>> call, so the IIO trigger poll API gets called from IRQ context.
>>
>> Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> Reviewed-by: Mukesh Ojha <mojha@codeaurora.org>
>
> -Mukesh
>
>
>> ---
>>   drivers/iio/adc/Kconfig     |  1 +
>>   drivers/iio/adc/stm32-adc.c | 32 ++++++++++++++++++++++++++++++--
>>   2 files changed, 31 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 76db6e5..059407a 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -775,6 +775,7 @@ config STM32_ADC_CORE
>>       select MFD_STM32_TIMERS
>>       select IIO_STM32_TIMER_TRIGGER
>>       select IIO_TRIGGERED_BUFFER
>> +    select IRQ_WORK
>>       help
>>         Select this option to enable the core driver for 
>> STMicroelectronics
>>         STM32 analog-to-digital converter (ADC).
>> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
>> index 205e169..1aa3189 100644
>> --- a/drivers/iio/adc/stm32-adc.c
>> +++ b/drivers/iio/adc/stm32-adc.c
>> @@ -20,6 +20,7 @@
>>   #include <linux/interrupt.h>
>>   #include <linux/io.h>
>>   #include <linux/iopoll.h>
>> +#include <linux/irq_work.h>
>>   #include <linux/module.h>
>>   #include <linux/platform_device.h>
>>   #include <linux/pm_runtime.h>
>> @@ -297,6 +298,7 @@ struct stm32_adc_cfg {
>>    * @smpr_val:        sampling time settings (e.g. smpr1 / smpr2)
>>    * @cal:        optional calibration data on some devices
>>    * @chan_name:        channel name array
>> + * @work:        irq work used to call trigger poll routine
>>    */
>>   struct stm32_adc {
>>       struct stm32_adc_common    *common;
>> @@ -320,6 +322,7 @@ struct stm32_adc {
>>       u32            smpr_val[2];
>>       struct stm32_adc_calib    cal;
>>       char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
>> +    struct irq_work        work;
>>   };
>>     struct stm32_adc_diff_channel {
>> @@ -1473,11 +1476,32 @@ static unsigned int 
>> stm32_adc_dma_residue(struct stm32_adc *adc)
>>       return 0;
>>   }
>>   +static void stm32_adc_dma_irq_work(struct irq_work *work)
>> +{
>> +    struct stm32_adc *adc = container_of(work, struct stm32_adc, work);
>> +    struct iio_dev *indio_dev = iio_priv_to_dev(adc);
>> +
>> +    /*
>> +     * iio_trigger_poll calls generic_handle_irq(). So, it requires 
>> hard
>> +     * irq context, and cannot be called directly from dma callback,
>> +     * dma cb has to schedule this work instead.
>> +     */
>> +    iio_trigger_poll(indio_dev->trig);
>> +}
>> +
>>   static void stm32_adc_dma_buffer_done(void *data)
>>   {
>>       struct iio_dev *indio_dev = data;
>> +    struct stm32_adc *adc = iio_priv(indio_dev);
>>   -    iio_trigger_poll_chained(indio_dev->trig);
>> +    /*
>> +     * Invoques iio_trigger_poll() from hard irq context: We can't


s/Invoques/invoke


overlooked this last time.
Take mine Review tag if you make above change.
Reviewed-by: Mukesh Ojha <mojha@codeaurora.org>

-Mukesh


>> +     * call iio_trigger_poll() nor iio_trigger_poll_chained()
>> +     * directly from DMA callback (under tasklet e.g. softirq).
>> +     * They require respectively HW IRQ and threaded IRQ context
>> +     * as it might sleep.
>> +     */
>> +    irq_work_queue(&adc->work);
>>   }
>>     static int stm32_adc_dma_start(struct iio_dev *indio_dev)
>> @@ -1585,8 +1609,10 @@ static void 
>> __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
>>       if (!adc->dma_chan)
>>           stm32_adc_conv_irq_disable(adc);
>>   -    if (adc->dma_chan)
>> +    if (adc->dma_chan) {
>>           dmaengine_terminate_all(adc->dma_chan);
>> +        irq_work_sync(&adc->work);
>> +    }
>>         if (stm32_adc_set_trig(indio_dev, NULL))
>>           dev_err(&indio_dev->dev, "Can't clear trigger\n");
>> @@ -1872,6 +1898,8 @@ static int stm32_adc_dma_request(struct iio_dev 
>> *indio_dev)
>>       if (ret)
>>           goto err_free;
>>   +    init_irq_work(&adc->work, stm32_adc_dma_irq_work);
>> +
>>       return 0;
>>     err_free:

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA
  2019-03-26 12:44 [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA Fabrice Gasnier
  2019-03-27 12:51 ` Mukesh Ojha
@ 2019-03-30 16:38 ` Jonathan Cameron
  1 sibling, 0 replies; 4+ messages in thread
From: Jonathan Cameron @ 2019-03-30 16:38 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: lars, alexandre.torgue, linux-iio, pmeerw, linux-kernel,
	mcoquelin.stm32, knaack.h, linux-stm32, linux-arm-kernel

On Tue, 26 Mar 2019 13:44:04 +0100
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> Enabling CONFIG_DEBUG_ATOMIC_SLEEP=y triggers this BUG message:
> BUG: sleeping function called from invalid context at kernel/irq/chip.c...
> 
> Call stack is as follows:
> - __might_sleep
> - handle_nested_irq          <-- Expects threaded irq
> - iio_trigger_poll_chained
> - stm32_adc_dma_buffer_done
> - vchan_complete
> - tasklet_action_common
> - tasklet_action
> - __do_softirq               <-- DMA completion raises a tasklet
> - irq_exit
> - __handle_domain_irq        <-- DMA IRQ
> - gic_handle_irq
> 
> IIO expects threaded interrupt context when calling:
> - iio_trigger_poll_chained()
> Or it expects interrupt context when calling:
> - iio_trigger_poll()
> 
> This patch triggers an IRQ upon stm32_adc_dma_buffer_done() DMA callback
> call, so the IIO trigger poll API gets called from IRQ context.
> 
> Fixes: 2763ea0585c9 ("iio: adc: stm32: add optional dma support")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>

An irq_work is a very heavy weight solution.

Perhaps we need a iio_trigger_poll* that can be called from a tasklet?
Or indeed a generic irq function that can be.

Hmm.  This isn't actually a 'real' trigger (I think) anyway as it's
only ever calling it's own irq thread.  In this case we could just
bypass and call that function directly.

Sometimes the trigger infrastructure of IIO is just not suited to
how a particular device works!

We need to maintain the trigger infrastructure for it's ability to
select the trigger, but not necessarily push the data through it.

So I think it would be safe to just call the block for dma_chan
being set in _adc_trigger_handler directly. 

If you take this approach, make sure there are comments saying why.
I don't want people to cut and paste it into new driver unless they
understand the reasoning!

We have had drivers do this in the past, though I can't find one
right now (am335x used to do this for example, but got reworked
to suport the touchscreen at the same time and this path went
away).

Jonathan

> ---
>  drivers/iio/adc/Kconfig     |  1 +
>  drivers/iio/adc/stm32-adc.c | 32 ++++++++++++++++++++++++++++++--
>  2 files changed, 31 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 76db6e5..059407a 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -775,6 +775,7 @@ config STM32_ADC_CORE
>  	select MFD_STM32_TIMERS
>  	select IIO_STM32_TIMER_TRIGGER
>  	select IIO_TRIGGERED_BUFFER
> +	select IRQ_WORK
>  	help
>  	  Select this option to enable the core driver for STMicroelectronics
>  	  STM32 analog-to-digital converter (ADC).
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index 205e169..1aa3189 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -20,6 +20,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <linux/irq_work.h>
>  #include <linux/module.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> @@ -297,6 +298,7 @@ struct stm32_adc_cfg {
>   * @smpr_val:		sampling time settings (e.g. smpr1 / smpr2)
>   * @cal:		optional calibration data on some devices
>   * @chan_name:		channel name array
> + * @work:		irq work used to call trigger poll routine
>   */
>  struct stm32_adc {
>  	struct stm32_adc_common	*common;
> @@ -320,6 +322,7 @@ struct stm32_adc {
>  	u32			smpr_val[2];
>  	struct stm32_adc_calib	cal;
>  	char			chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
> +	struct irq_work		work;
>  };
>  
>  struct stm32_adc_diff_channel {
> @@ -1473,11 +1476,32 @@ static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc)
>  	return 0;
>  }
>  
> +static void stm32_adc_dma_irq_work(struct irq_work *work)
> +{
> +	struct stm32_adc *adc = container_of(work, struct stm32_adc, work);
> +	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +
> +	/*
> +	 * iio_trigger_poll calls generic_handle_irq(). So, it requires hard
> +	 * irq context, and cannot be called directly from dma callback,
> +	 * dma cb has to schedule this work instead.
> +	 */
> +	iio_trigger_poll(indio_dev->trig);
> +}
> +
>  static void stm32_adc_dma_buffer_done(void *data)
>  {
>  	struct iio_dev *indio_dev = data;
> +	struct stm32_adc *adc = iio_priv(indio_dev);
>  
> -	iio_trigger_poll_chained(indio_dev->trig);
> +	/*
> +	 * Invoques iio_trigger_poll() from hard irq context: We can't
> +	 * call iio_trigger_poll() nor iio_trigger_poll_chained()
> +	 * directly from DMA callback (under tasklet e.g. softirq).
> +	 * They require respectively HW IRQ and threaded IRQ context
> +	 * as it might sleep.
> +	 */
> +	irq_work_queue(&adc->work);
>  }
>  
>  static int stm32_adc_dma_start(struct iio_dev *indio_dev)
> @@ -1585,8 +1609,10 @@ static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
>  	if (!adc->dma_chan)
>  		stm32_adc_conv_irq_disable(adc);
>  
> -	if (adc->dma_chan)
> +	if (adc->dma_chan) {
>  		dmaengine_terminate_all(adc->dma_chan);
> +		irq_work_sync(&adc->work);
> +	}
>  
>  	if (stm32_adc_set_trig(indio_dev, NULL))
>  		dev_err(&indio_dev->dev, "Can't clear trigger\n");
> @@ -1872,6 +1898,8 @@ static int stm32_adc_dma_request(struct iio_dev *indio_dev)
>  	if (ret)
>  		goto err_free;
>  
> +	init_irq_work(&adc->work, stm32_adc_dma_irq_work);
> +
>  	return 0;
>  
>  err_free:


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2019-03-30 16:39 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-26 12:44 [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA Fabrice Gasnier
2019-03-27 12:51 ` Mukesh Ojha
2019-03-27 13:22   ` Mukesh Ojha
2019-03-30 16:38 ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).