linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Fabrice Gasnier <fabrice.gasnier@st.com>
To: <jic23@kernel.org>
Cc: <linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>, <mcoquelin.stm32@gmail.com>,
	<alexandre.torgue@st.com>, <fabrice.gasnier@st.com>,
	<linux-iio@vger.kernel.org>, <lars@metafoo.de>, <knaack.h@gmx.de>,
	<pmeerw@pmeerw.net>, <linux-stm32@st-md-mailman.stormreply.com>
Subject: [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA
Date: Tue, 26 Mar 2019 13:44:04 +0100	[thread overview]
Message-ID: <1553604244-10922-1-git-send-email-fabrice.gasnier@st.com> (raw)

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


             reply	other threads:[~2019-03-26 12:44 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-03-26 12:44 Fabrice Gasnier [this message]
2019-03-27 12:51 ` [PATCH] iio: adc: stm32: fix sleep inside atomic section when using DMA Mukesh Ojha
2019-03-27 13:22   ` Mukesh Ojha
2019-03-30 16:38 ` Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1553604244-10922-1-git-send-email-fabrice.gasnier@st.com \
    --to=fabrice.gasnier@st.com \
    --cc=alexandre.torgue@st.com \
    --cc=jic23@kernel.org \
    --cc=knaack.h@gmx.de \
    --cc=lars@metafoo.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-stm32@st-md-mailman.stormreply.com \
    --cc=mcoquelin.stm32@gmail.com \
    --cc=pmeerw@pmeerw.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).