linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/7] add virt-dma support for imx-sdma
@ 2018-06-14 13:35 Robin Gong
  2018-06-14 13:35 ` [PATCH v4 1/7] tty: serial: imx: correct dma cookie status Robin Gong
                   ` (6 more replies)
  0 siblings, 7 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

The legacy sdma driver has below limitations or drawbacks:
  1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
     one page size for one channel regardless of only few BDs needed
     most time. But in few cases, the max PAGE_SIZE maybe not enough.
  2. One SDMA channel can't stop immediatley once channel disabled which
     means SDMA interrupt may come in after this channel terminated.There
     are some patches for this corner case such as commit "2746e2c389f9",
     but not cover non-cyclic.

The common virt-dma overcomes the above limitations. It can alloc bd
dynamically and free bd once this tx transfer done. No memory wasted or
maximum limititation here, only depends on how many memory can be requested
from kernel. For No.2, such issue can be workaround by checking if there
is available descript("sdmac->desc") now once the unwanted interrupt
coming. At last the common virt-dma is easier for sdma driver maintain.

Change from v3:
  1. add two uart patches which impacted by this patchset.
  2. unlock 'vc.lock' before cyclic dma callback and lock again after
     it because some driver such as uart will call dmaengine_tx_status
     which will acquire 'vc.lock' again and dead lock comes out.
  3. remove 'Revert commit' stuff since that patch is not wrong and
     combine two patch into one patch as Sascha's comment.

Change from v2:
  1. include Sascha's patch to make the main patch easier to review.
     Thanks Sacha.
  2. remove useless 'desc'/'chan' in struct sdma_channe.

Change from v1:
  1. split v1 patch into 5 patches.
  2. remove some unnecessary condition check.
  3. remove unnecessary 'pending' list.

Robin Gong (6):
  tty: serial: imx: correct dma cookie status
  dmaengine: imx-sdma: add virt-dma support
  dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct
    sdma_channel'
  dmaengine: imx-sdma: remove the maximum limitation for bd numbers
  dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap
  tty: serial: imx: split all dma setup operations out of 'port.lock'
    protector

Sascha Hauer (1):
  dmaengine: imx-sdma: factor out a struct sdma_desc from struct
    sdma_channel

 drivers/dma/Kconfig      |   1 +
 drivers/dma/imx-sdma.c   | 394 +++++++++++++++++++++++++++--------------------
 drivers/tty/serial/imx.c |  99 ++++++------
 3 files changed, 282 insertions(+), 212 deletions(-)

-- 
2.7.4


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

* [PATCH v4 1/7] tty: serial: imx: correct dma cookie status
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  2018-06-14 13:35 ` [PATCH v4 2/7] dmaengine: imx-sdma: factor out a struct sdma_desc from struct sdma_channel Robin Gong
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

Correct to check the right rx dma cookie status in spit of it
works because only one cookie is running in the current sdma.
But it will not once sdma driver support multi cookies
running based on virt-dma.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/tty/serial/imx.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index c2fc6be..b83bc2c 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1051,7 +1051,7 @@ static void imx_uart_dma_rx_callback(void *data)
 	unsigned int r_bytes;
 	unsigned int bd_size;
 
-	status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state);
+	status = dmaengine_tx_status(chan, sport->rx_cookie, &state);
 
 	if (status == DMA_ERROR) {
 		imx_uart_clear_rx_errors(sport);
-- 
2.7.4


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

* [PATCH v4 2/7] dmaengine: imx-sdma: factor out a struct sdma_desc from struct sdma_channel
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
  2018-06-14 13:35 ` [PATCH v4 1/7] tty: serial: imx: correct dma cookie status Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  2018-06-14 13:35 ` [PATCH v4 3/7] dmaengine: imx-sdma: add virt-dma support Robin Gong
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

From: Sascha Hauer <s.hauer@pengutronix.de>

This is a preparation step to make the adding of virt-dma easier.
We create a struct sdma_desc, move some fields from struct sdma_channel
there and add a pointer from the former to the latter. For now we
allocate the data statically in struct sdma_channel, but with
virt-dma support it will be dynamically allocated.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/dma/imx-sdma.c | 137 ++++++++++++++++++++++++++++++-------------------
 1 file changed, 83 insertions(+), 54 deletions(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index ccd03c3..556d087 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -296,6 +296,30 @@ struct sdma_context_data {
 struct sdma_engine;
 
 /**
+ * struct sdma_desc - descriptor structor for one transfer
+ * @vd			descriptor for virt dma
+ * @num_bd		max NUM_BD. number of descriptors currently handling
+ * @buf_tail		ID of the buffer that was processed
+ * @buf_ptail		ID of the previous buffer that was processed
+ * @period_len		period length, used in cyclic.
+ * @chn_real_count	the real count updated from bd->mode.count
+ * @chn_count		the transfer count setuped
+ * @sdmac		sdma_channel pointer
+ * @bd			pointer of alloced bd
+ */
+struct sdma_desc {
+	unsigned int		num_bd;
+	dma_addr_t		bd_phys;
+	unsigned int		buf_tail;
+	unsigned int		buf_ptail;
+	unsigned int		period_len;
+	unsigned int		chn_real_count;
+	unsigned int		chn_count;
+	struct sdma_channel	*sdmac;
+	struct sdma_buffer_descriptor *bd;
+};
+
+/**
  * struct sdma_channel - housekeeping for a SDMA channel
  *
  * @sdma		pointer to the SDMA engine for this channel
@@ -305,11 +329,10 @@ struct sdma_engine;
  * @event_id0		aka dma request line
  * @event_id1		for channels that use 2 events
  * @word_size		peripheral access size
- * @buf_tail		ID of the buffer that was processed
- * @buf_ptail		ID of the previous buffer that was processed
- * @num_bd		max NUM_BD. number of descriptors currently handling
  */
 struct sdma_channel {
+	struct sdma_desc		*desc;
+	struct sdma_desc		_desc;
 	struct sdma_engine		*sdma;
 	unsigned int			channel;
 	enum dma_transfer_direction		direction;
@@ -317,12 +340,6 @@ struct sdma_channel {
 	unsigned int			event_id0;
 	unsigned int			event_id1;
 	enum dma_slave_buswidth		word_size;
-	unsigned int			buf_tail;
-	unsigned int			buf_ptail;
-	unsigned int			num_bd;
-	unsigned int			period_len;
-	struct sdma_buffer_descriptor	*bd;
-	dma_addr_t			bd_phys;
 	unsigned int			pc_from_device, pc_to_device;
 	unsigned int			device_to_device;
 	unsigned long			flags;
@@ -332,10 +349,8 @@ struct sdma_channel {
 	u32				shp_addr, per_addr;
 	struct dma_chan			chan;
 	spinlock_t			lock;
-	struct dma_async_tx_descriptor	desc;
+	struct dma_async_tx_descriptor	txdesc;
 	enum dma_status			status;
-	unsigned int			chn_count;
-	unsigned int			chn_real_count;
 	struct tasklet_struct		tasklet;
 	struct imx_dma_data		data;
 	bool				enabled;
@@ -398,6 +413,8 @@ struct sdma_engine {
 	u32				spba_start_addr;
 	u32				spba_end_addr;
 	unsigned int			irq;
+	dma_addr_t			bd0_phys;
+	struct sdma_buffer_descriptor	*bd0;
 };
 
 static struct sdma_driver_data sdma_imx31 = {
@@ -632,7 +649,7 @@ static int sdma_run_channel0(struct sdma_engine *sdma)
 static int sdma_load_script(struct sdma_engine *sdma, void *buf, int size,
 		u32 address)
 {
-	struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
 	void *buf_virt;
 	dma_addr_t buf_phys;
 	int ret;
@@ -707,7 +724,9 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 	 * call callback function.
 	 */
 	while (1) {
-		bd = &sdmac->bd[sdmac->buf_tail];
+		struct sdma_desc *desc = sdmac->desc;
+
+		bd = &desc->bd[desc->buf_tail];
 
 		if (bd->mode.status & BD_DONE)
 			break;
@@ -723,11 +742,11 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 		* the number of bytes present in the current buffer descriptor.
 		*/
 
-		sdmac->chn_real_count = bd->mode.count;
+		desc->chn_real_count = bd->mode.count;
 		bd->mode.status |= BD_DONE;
-		bd->mode.count = sdmac->period_len;
-		sdmac->buf_ptail = sdmac->buf_tail;
-		sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd;
+		bd->mode.count = desc->period_len;
+		desc->buf_ptail = desc->buf_tail;
+		desc->buf_tail = (desc->buf_tail + 1) % desc->num_bd;
 
 		/*
 		 * The callback is called from the interrupt context in order
@@ -736,7 +755,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 		 * executed.
 		 */
 
-		dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
+		dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
 
 		if (error)
 			sdmac->status = old_status;
@@ -749,17 +768,17 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
 	struct sdma_buffer_descriptor *bd;
 	int i, error = 0;
 
-	sdmac->chn_real_count = 0;
+	sdmac->desc->chn_real_count = 0;
 	/*
 	 * non loop mode. Iterate over all descriptors, collect
 	 * errors and call callback function
 	 */
-	for (i = 0; i < sdmac->num_bd; i++) {
-		bd = &sdmac->bd[i];
+	for (i = 0; i < sdmac->desc->num_bd; i++) {
+		bd = &sdmac->desc->bd[i];
 
 		 if (bd->mode.status & (BD_DONE | BD_RROR))
 			error = -EIO;
-		 sdmac->chn_real_count += bd->mode.count;
+		 sdmac->desc->chn_real_count += bd->mode.count;
 	}
 
 	if (error)
@@ -767,9 +786,9 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
 	else
 		sdmac->status = DMA_COMPLETE;
 
-	dma_cookie_complete(&sdmac->desc);
+	dma_cookie_complete(&sdmac->txdesc);
 
-	dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL);
+	dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
 }
 
 static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -897,7 +916,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
 	int channel = sdmac->channel;
 	int load_address;
 	struct sdma_context_data *context = sdma->context;
-	struct sdma_buffer_descriptor *bd0 = sdma->channel[0].bd;
+	struct sdma_buffer_descriptor *bd0 = sdma->bd0;
 	int ret;
 	unsigned long flags;
 
@@ -1100,18 +1119,22 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
 static int sdma_request_channel(struct sdma_channel *sdmac)
 {
 	struct sdma_engine *sdma = sdmac->sdma;
+	struct sdma_desc *desc;
 	int channel = sdmac->channel;
 	int ret = -EBUSY;
 
-	sdmac->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdmac->bd_phys,
+	sdmac->desc = &sdmac->_desc;
+	desc = sdmac->desc;
+
+	desc->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &desc->bd_phys,
 					GFP_KERNEL);
-	if (!sdmac->bd) {
+	if (!desc->bd) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	sdma->channel_control[channel].base_bd_ptr = sdmac->bd_phys;
-	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+	sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
+	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
 
 	sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
 	return 0;
@@ -1176,10 +1199,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
 	if (ret)
 		goto disable_clk_ahb;
 
-	dma_async_tx_descriptor_init(&sdmac->desc, chan);
-	sdmac->desc.tx_submit = sdma_tx_submit;
+	dma_async_tx_descriptor_init(&sdmac->txdesc, chan);
+	sdmac->txdesc.tx_submit = sdma_tx_submit;
 	/* txd.flags will be overwritten in prep funcs */
-	sdmac->desc.flags = DMA_CTRL_ACK;
+	sdmac->txdesc.flags = DMA_CTRL_ACK;
 
 	return 0;
 
@@ -1194,6 +1217,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
+	struct sdma_desc *desc = sdmac->desc;
 
 	sdma_disable_channel(chan);
 
@@ -1207,7 +1231,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
 	sdma_set_channel_priority(sdmac, 0);
 
-	dma_free_coherent(NULL, PAGE_SIZE, sdmac->bd, sdmac->bd_phys);
+	dma_free_coherent(NULL, PAGE_SIZE, desc->bd, desc->bd_phys);
 
 	clk_disable(sdma->clk_ipg);
 	clk_disable(sdma->clk_ahb);
@@ -1223,6 +1247,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 	int ret, i, count;
 	int channel = sdmac->channel;
 	struct scatterlist *sg;
+	struct sdma_desc *desc = sdmac->desc;
 
 	if (sdmac->status == DMA_IN_PROGRESS)
 		return NULL;
@@ -1230,9 +1255,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
 	sdmac->flags = 0;
 
-	sdmac->buf_tail = 0;
-	sdmac->buf_ptail = 0;
-	sdmac->chn_real_count = 0;
+	desc->buf_tail = 0;
+	desc->buf_ptail = 0;
+	desc->chn_real_count = 0;
 
 	dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
 			sg_len, channel);
@@ -1249,9 +1274,9 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 		goto err_out;
 	}
 
-	sdmac->chn_count = 0;
+	desc->chn_count = 0;
 	for_each_sg(sgl, sg, sg_len, i) {
-		struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+		struct sdma_buffer_descriptor *bd = &desc->bd[i];
 		int param;
 
 		bd->buffer_addr = sg->dma_address;
@@ -1266,7 +1291,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 		}
 
 		bd->mode.count = count;
-		sdmac->chn_count += count;
+		desc->chn_count += count;
 
 		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
 			ret =  -EINVAL;
@@ -1307,10 +1332,10 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 		bd->mode.status = param;
 	}
 
-	sdmac->num_bd = sg_len;
-	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+	desc->num_bd = sg_len;
+	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
 
-	return &sdmac->desc;
+	return &sdmac->txdesc;
 err_out:
 	sdmac->status = DMA_ERROR;
 	return NULL;
@@ -1326,6 +1351,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 	int num_periods = buf_len / period_len;
 	int channel = sdmac->channel;
 	int ret, i = 0, buf = 0;
+	struct sdma_desc *desc = sdmac->desc;
 
 	dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
 
@@ -1334,10 +1360,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 
 	sdmac->status = DMA_IN_PROGRESS;
 
-	sdmac->buf_tail = 0;
-	sdmac->buf_ptail = 0;
-	sdmac->chn_real_count = 0;
-	sdmac->period_len = period_len;
+	desc->buf_tail = 0;
+	desc->buf_ptail = 0;
+	desc->chn_real_count = 0;
+	desc->period_len = period_len;
 
 	sdmac->flags |= IMX_DMA_SG_LOOP;
 	sdmac->direction = direction;
@@ -1358,7 +1384,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 	}
 
 	while (buf < buf_len) {
-		struct sdma_buffer_descriptor *bd = &sdmac->bd[i];
+		struct sdma_buffer_descriptor *bd = &desc->bd[i];
 		int param;
 
 		bd->buffer_addr = dma_addr;
@@ -1389,10 +1415,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 		i++;
 	}
 
-	sdmac->num_bd = num_periods;
-	sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
+	desc->num_bd = num_periods;
+	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
 
-	return &sdmac->desc;
+	return &sdmac->txdesc;
 err_out:
 	sdmac->status = DMA_ERROR;
 	return NULL;
@@ -1431,13 +1457,14 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 				      struct dma_tx_state *txstate)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	struct sdma_desc *desc = sdmac->desc;
 	u32 residue;
 
 	if (sdmac->flags & IMX_DMA_SG_LOOP)
-		residue = (sdmac->num_bd - sdmac->buf_ptail) *
-			   sdmac->period_len - sdmac->chn_real_count;
+		residue = (desc->num_bd - desc->buf_ptail) *
+			   desc->period_len - desc->chn_real_count;
 	else
-		residue = sdmac->chn_count - sdmac->chn_real_count;
+		residue = desc->chn_count - desc->chn_real_count;
 
 	dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
 			 residue);
@@ -1661,6 +1688,8 @@ static int sdma_init(struct sdma_engine *sdma)
 	if (ret)
 		goto err_dma_alloc;
 
+	sdma->bd0 = sdma->channel[0].desc->bd;
+
 	sdma_config_ownership(&sdma->channel[0], false, true, false);
 
 	/* Set Command Channel (Channel Zero) */
-- 
2.7.4


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

* [PATCH v4 3/7] dmaengine: imx-sdma: add virt-dma support
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
  2018-06-14 13:35 ` [PATCH v4 1/7] tty: serial: imx: correct dma cookie status Robin Gong
  2018-06-14 13:35 ` [PATCH v4 2/7] dmaengine: imx-sdma: factor out a struct sdma_desc from struct sdma_channel Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  2018-06-14 13:35 ` [PATCH v4 4/7] dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct sdma_channel' Robin Gong
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

The legacy sdma driver has below limitations or drawbacks:
  1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
     one page size for one channel regardless of only few BDs needed
     most time. But in few cases, the max PAGE_SIZE maybe not enough.
  2. One SDMA channel can't stop immediatley once channel disabled which
     means SDMA interrupt may come in after this channel terminated.There
     are some patches for this corner case such as commit "2746e2c389f9",
     but not cover non-cyclic.

The common virt-dma overcomes the above limitations. It can alloc bd
dynamically and free bd once this tx transfer done. No memory wasted or
maximum limititation here, only depends on how many memory can be requested
from kernel. For No.2, such issue can be workaround by checking if there
is available descript("sdmac->desc") now once the unwanted interrupt
coming. At last the common virt-dma is easier for sdma driver maintain.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/dma/Kconfig    |   1 +
 drivers/dma/imx-sdma.c | 261 ++++++++++++++++++++++++++++++++-----------------
 2 files changed, 170 insertions(+), 92 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 6d61cd0..78715a2 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -257,6 +257,7 @@ config IMX_SDMA
 	tristate "i.MX SDMA support"
 	depends on ARCH_MXC
 	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
 	help
 	  Support the i.MX SDMA engine. This engine is integrated into
 	  Freescale i.MX25/31/35/51/53/6 chips.
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 556d087..719bf9f 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -48,6 +48,7 @@
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
 
 #include "dmaengine.h"
+#include "virt-dma.h"
 
 /* SDMA registers */
 #define SDMA_H_C0PTR		0x000
@@ -308,6 +309,7 @@ struct sdma_engine;
  * @bd			pointer of alloced bd
  */
 struct sdma_desc {
+	struct virt_dma_desc	vd;
 	unsigned int		num_bd;
 	dma_addr_t		bd_phys;
 	unsigned int		buf_tail;
@@ -331,8 +333,8 @@ struct sdma_desc {
  * @word_size		peripheral access size
  */
 struct sdma_channel {
+	struct virt_dma_chan		vc;
 	struct sdma_desc		*desc;
-	struct sdma_desc		_desc;
 	struct sdma_engine		*sdma;
 	unsigned int			channel;
 	enum dma_transfer_direction		direction;
@@ -347,11 +349,8 @@ struct sdma_channel {
 	unsigned long			event_mask[2];
 	unsigned long			watermark_level;
 	u32				shp_addr, per_addr;
-	struct dma_chan			chan;
 	spinlock_t			lock;
-	struct dma_async_tx_descriptor	txdesc;
 	enum dma_status			status;
-	struct tasklet_struct		tasklet;
 	struct imx_dma_data		data;
 	bool				enabled;
 };
@@ -705,6 +704,35 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
 	writel_relaxed(val, sdma->regs + chnenbl);
 }
 
+static struct sdma_desc *to_sdma_desc(struct dma_async_tx_descriptor *t)
+{
+	return container_of(t, struct sdma_desc, vd.tx);
+}
+
+static void sdma_start_desc(struct sdma_channel *sdmac)
+{
+	struct virt_dma_desc *vd = vchan_next_desc(&sdmac->vc);
+	struct sdma_desc *desc;
+	struct sdma_engine *sdma = sdmac->sdma;
+	int channel = sdmac->channel;
+
+	if (!vd) {
+		sdmac->desc = NULL;
+		return;
+	}
+	sdmac->desc = desc = to_sdma_desc(&vd->tx);
+	/*
+	 * Do not delete the node in desc_issued list in cyclic mode, otherwise
+	 * the desc alloced will never be freed in vchan_dma_desc_free_list
+	 */
+	if (!(sdmac->flags & IMX_DMA_SG_LOOP))
+		list_del(&vd->node);
+
+	sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
+	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
+	sdma_enable_channel(sdma, sdmac->channel);
+}
+
 static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 {
 	struct sdma_buffer_descriptor *bd;
@@ -723,7 +751,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 	 * loop mode. Iterate over descriptors, re-setup them and
 	 * call callback function.
 	 */
-	while (1) {
+	while (sdmac->desc) {
 		struct sdma_desc *desc = sdmac->desc;
 
 		bd = &desc->bd[desc->buf_tail];
@@ -754,15 +782,16 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 		 * SDMA transaction status by the time the client tasklet is
 		 * executed.
 		 */
-
-		dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
+		spin_unlock(&sdmac->vc.lock);
+		dmaengine_desc_get_callback_invoke(&desc->vd.tx, NULL);
+		spin_lock(&sdmac->vc.lock);
 
 		if (error)
 			sdmac->status = old_status;
 	}
 }
 
-static void mxc_sdma_handle_channel_normal(unsigned long data)
+static void mxc_sdma_handle_channel_normal(struct sdma_channel *data)
 {
 	struct sdma_channel *sdmac = (struct sdma_channel *) data;
 	struct sdma_buffer_descriptor *bd;
@@ -785,10 +814,6 @@ static void mxc_sdma_handle_channel_normal(unsigned long data)
 		sdmac->status = DMA_ERROR;
 	else
 		sdmac->status = DMA_COMPLETE;
-
-	dma_cookie_complete(&sdmac->txdesc);
-
-	dmaengine_desc_get_callback_invoke(&sdmac->txdesc, NULL);
 }
 
 static irqreturn_t sdma_int_handler(int irq, void *dev_id)
@@ -804,12 +829,21 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
 	while (stat) {
 		int channel = fls(stat) - 1;
 		struct sdma_channel *sdmac = &sdma->channel[channel];
+		struct sdma_desc *desc;
+
+		spin_lock(&sdmac->vc.lock);
+		desc = sdmac->desc;
+		if (desc) {
+			if (sdmac->flags & IMX_DMA_SG_LOOP) {
+				sdma_update_channel_loop(sdmac);
+			} else {
+				mxc_sdma_handle_channel_normal(sdmac);
+				vchan_cookie_complete(&desc->vd);
+				sdma_start_desc(sdmac);
+			}
+		}
 
-		if (sdmac->flags & IMX_DMA_SG_LOOP)
-			sdma_update_channel_loop(sdmac);
-		else
-			tasklet_schedule(&sdmac->tasklet);
-
+		spin_unlock(&sdmac->vc.lock);
 		__clear_bit(channel, &stat);
 	}
 
@@ -965,7 +999,7 @@ static int sdma_load_context(struct sdma_channel *sdmac)
 
 static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
 {
-	return container_of(chan, struct sdma_channel, chan);
+	return container_of(chan, struct sdma_channel, vc.chan);
 }
 
 static int sdma_disable_channel(struct dma_chan *chan)
@@ -987,7 +1021,16 @@ static int sdma_disable_channel(struct dma_chan *chan)
 
 static int sdma_disable_channel_with_delay(struct dma_chan *chan)
 {
+	struct sdma_channel *sdmac = to_sdma_chan(chan);
+	unsigned long flags;
+	LIST_HEAD(head);
+
 	sdma_disable_channel(chan);
+	spin_lock_irqsave(&sdmac->vc.lock, flags);
+	vchan_get_all_descriptors(&sdmac->vc, &head);
+	sdmac->desc = NULL;
+	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
+	vchan_dma_desc_free_list(&sdmac->vc, &head);
 
 	/*
 	 * According to NXP R&D team a delay of one BD SDMA cost time
@@ -1116,46 +1159,56 @@ static int sdma_set_channel_priority(struct sdma_channel *sdmac,
 	return 0;
 }
 
-static int sdma_request_channel(struct sdma_channel *sdmac)
+static int sdma_request_channel0(struct sdma_engine *sdma)
 {
-	struct sdma_engine *sdma = sdmac->sdma;
-	struct sdma_desc *desc;
-	int channel = sdmac->channel;
 	int ret = -EBUSY;
 
-	sdmac->desc = &sdmac->_desc;
-	desc = sdmac->desc;
-
-	desc->bd = dma_zalloc_coherent(NULL, PAGE_SIZE, &desc->bd_phys,
+	sdma->bd0 = dma_zalloc_coherent(NULL, PAGE_SIZE, &sdma->bd0_phys,
 					GFP_KERNEL);
-	if (!desc->bd) {
+	if (!sdma->bd0) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	sdma->channel_control[channel].base_bd_ptr = desc->bd_phys;
-	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
+	sdma->channel_control[0].base_bd_ptr = sdma->bd0_phys;
+	sdma->channel_control[0].current_bd_ptr = sdma->bd0_phys;
 
-	sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
+	sdma_set_channel_priority(&sdma->channel[0], MXC_SDMA_DEFAULT_PRIORITY);
 	return 0;
 out:
 
 	return ret;
 }
 
-static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
+
+static int sdma_alloc_bd(struct sdma_desc *desc)
 {
-	unsigned long flags;
-	struct sdma_channel *sdmac = to_sdma_chan(tx->chan);
-	dma_cookie_t cookie;
+	u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
+	int ret = 0;
 
-	spin_lock_irqsave(&sdmac->lock, flags);
+	desc->bd = dma_zalloc_coherent(NULL, bd_size, &desc->bd_phys,
+					GFP_ATOMIC);
+	if (!desc->bd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+out:
+	return ret;
+}
 
-	cookie = dma_cookie_assign(tx);
+static void sdma_free_bd(struct sdma_desc *desc)
+{
+	u32 bd_size = desc->num_bd * sizeof(struct sdma_buffer_descriptor);
 
-	spin_unlock_irqrestore(&sdmac->lock, flags);
+	dma_free_coherent(NULL, bd_size, desc->bd, desc->bd_phys);
+}
 
-	return cookie;
+static void sdma_desc_free(struct virt_dma_desc *vd)
+{
+	struct sdma_desc *desc = container_of(vd, struct sdma_desc, vd);
+
+	sdma_free_bd(desc);
+	kfree(desc);
 }
 
 static int sdma_alloc_chan_resources(struct dma_chan *chan)
@@ -1191,19 +1244,10 @@ static int sdma_alloc_chan_resources(struct dma_chan *chan)
 	if (ret)
 		goto disable_clk_ipg;
 
-	ret = sdma_request_channel(sdmac);
-	if (ret)
-		goto disable_clk_ahb;
-
 	ret = sdma_set_channel_priority(sdmac, prio);
 	if (ret)
 		goto disable_clk_ahb;
 
-	dma_async_tx_descriptor_init(&sdmac->txdesc, chan);
-	sdmac->txdesc.tx_submit = sdma_tx_submit;
-	/* txd.flags will be overwritten in prep funcs */
-	sdmac->txdesc.flags = DMA_CTRL_ACK;
-
 	return 0;
 
 disable_clk_ahb:
@@ -1217,9 +1261,8 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
-	struct sdma_desc *desc = sdmac->desc;
 
-	sdma_disable_channel(chan);
+	sdma_disable_channel_with_delay(chan);
 
 	if (sdmac->event_id0)
 		sdma_event_disable(sdmac, sdmac->event_id0);
@@ -1231,8 +1274,6 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 
 	sdma_set_channel_priority(sdmac, 0);
 
-	dma_free_coherent(NULL, PAGE_SIZE, desc->bd, desc->bd_phys);
-
 	clk_disable(sdma->clk_ipg);
 	clk_disable(sdma->clk_ahb);
 }
@@ -1247,7 +1288,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 	int ret, i, count;
 	int channel = sdmac->channel;
 	struct scatterlist *sg;
-	struct sdma_desc *desc = sdmac->desc;
+	struct sdma_desc *desc;
 
 	if (sdmac->status == DMA_IN_PROGRESS)
 		return NULL;
@@ -1255,23 +1296,34 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
 	sdmac->flags = 0;
 
+	desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+	if (!desc)
+		goto err_out;
+
 	desc->buf_tail = 0;
 	desc->buf_ptail = 0;
+	desc->sdmac = sdmac;
+	desc->num_bd = sg_len;
 	desc->chn_real_count = 0;
 
+	if (sdma_alloc_bd(desc)) {
+		kfree(desc);
+		goto err_out;
+	}
+
 	dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
 			sg_len, channel);
 
 	sdmac->direction = direction;
 	ret = sdma_load_context(sdmac);
 	if (ret)
-		goto err_out;
+		goto err_bd_out;
 
 	if (sg_len > NUM_BD) {
 		dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
 				channel, sg_len, NUM_BD);
 		ret = -EINVAL;
-		goto err_out;
+		goto err_bd_out;
 	}
 
 	desc->chn_count = 0;
@@ -1287,7 +1339,7 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 			dev_err(sdma->dev, "SDMA channel %d: maximum bytes for sg entry exceeded: %d > %d\n",
 					channel, count, 0xffff);
 			ret = -EINVAL;
-			goto err_out;
+			goto err_bd_out;
 		}
 
 		bd->mode.count = count;
@@ -1295,25 +1347,25 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 
 		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES) {
 			ret =  -EINVAL;
-			goto err_out;
+			goto err_bd_out;
 		}
 
 		switch (sdmac->word_size) {
 		case DMA_SLAVE_BUSWIDTH_4_BYTES:
 			bd->mode.command = 0;
 			if (count & 3 || sg->dma_address & 3)
-				return NULL;
+				goto err_bd_out;
 			break;
 		case DMA_SLAVE_BUSWIDTH_2_BYTES:
 			bd->mode.command = 2;
 			if (count & 1 || sg->dma_address & 1)
-				return NULL;
+				goto err_bd_out;
 			break;
 		case DMA_SLAVE_BUSWIDTH_1_BYTE:
 			bd->mode.command = 1;
 			break;
 		default:
-			return NULL;
+			goto err_bd_out;
 		}
 
 		param = BD_DONE | BD_EXTD | BD_CONT;
@@ -1332,10 +1384,10 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 		bd->mode.status = param;
 	}
 
-	desc->num_bd = sg_len;
-	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
-
-	return &sdmac->txdesc;
+	return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+	sdma_free_bd(desc);
+	kfree(desc);
 err_out:
 	sdmac->status = DMA_ERROR;
 	return NULL;
@@ -1351,7 +1403,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 	int num_periods = buf_len / period_len;
 	int channel = sdmac->channel;
 	int ret, i = 0, buf = 0;
-	struct sdma_desc *desc = sdmac->desc;
+	struct sdma_desc *desc;
 
 	dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
 
@@ -1360,27 +1412,39 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 
 	sdmac->status = DMA_IN_PROGRESS;
 
+	desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+	if (!desc)
+		goto err_out;
+
 	desc->buf_tail = 0;
 	desc->buf_ptail = 0;
+	desc->sdmac = sdmac;
+	desc->num_bd = num_periods;
 	desc->chn_real_count = 0;
 	desc->period_len = period_len;
 
 	sdmac->flags |= IMX_DMA_SG_LOOP;
 	sdmac->direction = direction;
+
+	if (sdma_alloc_bd(desc)) {
+		kfree(desc);
+		goto err_bd_out;
+	}
+
 	ret = sdma_load_context(sdmac);
 	if (ret)
-		goto err_out;
+		goto err_bd_out;
 
 	if (num_periods > NUM_BD) {
 		dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
 				channel, num_periods, NUM_BD);
-		goto err_out;
+		goto err_bd_out;
 	}
 
 	if (period_len > 0xffff) {
 		dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
 				channel, period_len, 0xffff);
-		goto err_out;
+		goto err_bd_out;
 	}
 
 	while (buf < buf_len) {
@@ -1392,7 +1456,7 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 		bd->mode.count = period_len;
 
 		if (sdmac->word_size > DMA_SLAVE_BUSWIDTH_4_BYTES)
-			goto err_out;
+			goto err_bd_out;
 		if (sdmac->word_size == DMA_SLAVE_BUSWIDTH_4_BYTES)
 			bd->mode.command = 0;
 		else
@@ -1415,10 +1479,10 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 		i++;
 	}
 
-	desc->num_bd = num_periods;
-	sdma->channel_control[channel].current_bd_ptr = desc->bd_phys;
-
-	return &sdmac->txdesc;
+	return vchan_tx_prep(&sdmac->vc, &desc->vd, flags);
+err_bd_out:
+	sdma_free_bd(desc);
+	kfree(desc);
 err_out:
 	sdmac->status = DMA_ERROR;
 	return NULL;
@@ -1457,14 +1521,31 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 				      struct dma_tx_state *txstate)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
-	struct sdma_desc *desc = sdmac->desc;
+	struct sdma_desc *desc;
 	u32 residue;
+	struct virt_dma_desc *vd;
+	enum dma_status ret;
+	unsigned long flags;
 
-	if (sdmac->flags & IMX_DMA_SG_LOOP)
-		residue = (desc->num_bd - desc->buf_ptail) *
-			   desc->period_len - desc->chn_real_count;
-	else
-		residue = desc->chn_count - desc->chn_real_count;
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret == DMA_COMPLETE || !txstate)
+		return ret;
+
+	spin_lock_irqsave(&sdmac->vc.lock, flags);
+	vd = vchan_find_desc(&sdmac->vc, cookie);
+	if (vd) {
+		desc = to_sdma_desc(&vd->tx);
+		if (sdmac->flags & IMX_DMA_SG_LOOP)
+			residue = (desc->num_bd - desc->buf_ptail) *
+				desc->period_len - desc->chn_real_count;
+		else
+			residue = desc->chn_count - desc->chn_real_count;
+	} else if (sdmac->desc && sdmac->desc->vd.tx.cookie == cookie) {
+		residue = sdmac->desc->chn_count - sdmac->desc->chn_real_count;
+	} else {
+		residue = 0;
+	}
+	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
 
 	dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
 			 residue);
@@ -1475,10 +1556,12 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan,
 static void sdma_issue_pending(struct dma_chan *chan)
 {
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
-	struct sdma_engine *sdma = sdmac->sdma;
+	unsigned long flags;
 
-	if (sdmac->status == DMA_IN_PROGRESS)
-		sdma_enable_channel(sdma, sdmac->channel);
+	spin_lock_irqsave(&sdmac->vc.lock, flags);
+	if (vchan_issue_pending(&sdmac->vc) && !sdmac->desc)
+		sdma_start_desc(sdmac);
+	spin_unlock_irqrestore(&sdmac->vc.lock, flags);
 }
 
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1	34
@@ -1684,12 +1767,10 @@ static int sdma_init(struct sdma_engine *sdma)
 	for (i = 0; i < MAX_DMA_CHANNELS; i++)
 		writel_relaxed(0, sdma->regs + SDMA_CHNPRI_0 + i * 4);
 
-	ret = sdma_request_channel(&sdma->channel[0]);
+	ret = sdma_request_channel0(sdma);
 	if (ret)
 		goto err_dma_alloc;
 
-	sdma->bd0 = sdma->channel[0].desc->bd;
-
 	sdma_config_ownership(&sdma->channel[0], false, true, false);
 
 	/* Set Command Channel (Channel Zero) */
@@ -1850,20 +1931,15 @@ static int sdma_probe(struct platform_device *pdev)
 		sdmac->sdma = sdma;
 		spin_lock_init(&sdmac->lock);
 
-		sdmac->chan.device = &sdma->dma_device;
-		dma_cookie_init(&sdmac->chan);
 		sdmac->channel = i;
-
-		tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
-			     (unsigned long) sdmac);
+		sdmac->vc.desc_free = sdma_desc_free;
 		/*
 		 * Add the channel to the DMAC list. Do not add channel 0 though
 		 * because we need it internally in the SDMA driver. This also means
 		 * that channel 0 in dmaengine counting matches sdma channel 1.
 		 */
 		if (i)
-			list_add_tail(&sdmac->chan.device_node,
-					&sdma->dma_device.channels);
+			vchan_init(&sdmac->vc, &sdma->dma_device);
 	}
 
 	ret = sdma_init(sdma);
@@ -1968,7 +2044,8 @@ static int sdma_remove(struct platform_device *pdev)
 	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
 		struct sdma_channel *sdmac = &sdma->channel[i];
 
-		tasklet_kill(&sdmac->tasklet);
+		tasklet_kill(&sdmac->vc.task);
+		sdma_free_chan_resources(&sdmac->vc.chan);
 	}
 
 	platform_set_drvdata(pdev, NULL);
-- 
2.7.4


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

* [PATCH v4 4/7] dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct sdma_channel'
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
                   ` (2 preceding siblings ...)
  2018-06-14 13:35 ` [PATCH v4 3/7] dmaengine: imx-sdma: add virt-dma support Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  2018-06-14 13:35 ` [PATCH v4 5/7] dmaengine: imx-sdma: remove the maximum limitation for bd numbers Robin Gong
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

Since 'sdmac->vc.lock' and 'sdmac->desc' can be used as 'lock' and
'enabled' in 'struct sdma_channel sdmac', remove them.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/dma/imx-sdma.c | 23 -----------------------
 1 file changed, 23 deletions(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 719bf9f..27b76eb 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -349,10 +349,8 @@ struct sdma_channel {
 	unsigned long			event_mask[2];
 	unsigned long			watermark_level;
 	u32				shp_addr, per_addr;
-	spinlock_t			lock;
 	enum dma_status			status;
 	struct imx_dma_data		data;
-	bool				enabled;
 };
 
 #define IMX_DMA_SG_LOOP		BIT(0)
@@ -613,14 +611,7 @@ static int sdma_config_ownership(struct sdma_channel *sdmac,
 
 static void sdma_enable_channel(struct sdma_engine *sdma, int channel)
 {
-	unsigned long flags;
-	struct sdma_channel *sdmac = &sdma->channel[channel];
-
 	writel(BIT(channel), sdma->regs + SDMA_H_START);
-
-	spin_lock_irqsave(&sdmac->lock, flags);
-	sdmac->enabled = true;
-	spin_unlock_irqrestore(&sdmac->lock, flags);
 }
 
 /*
@@ -738,14 +729,6 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
 	struct sdma_buffer_descriptor *bd;
 	int error = 0;
 	enum dma_status	old_status = sdmac->status;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdmac->lock, flags);
-	if (!sdmac->enabled) {
-		spin_unlock_irqrestore(&sdmac->lock, flags);
-		return;
-	}
-	spin_unlock_irqrestore(&sdmac->lock, flags);
 
 	/*
 	 * loop mode. Iterate over descriptors, re-setup them and
@@ -1007,15 +990,10 @@ static int sdma_disable_channel(struct dma_chan *chan)
 	struct sdma_channel *sdmac = to_sdma_chan(chan);
 	struct sdma_engine *sdma = sdmac->sdma;
 	int channel = sdmac->channel;
-	unsigned long flags;
 
 	writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
 	sdmac->status = DMA_ERROR;
 
-	spin_lock_irqsave(&sdmac->lock, flags);
-	sdmac->enabled = false;
-	spin_unlock_irqrestore(&sdmac->lock, flags);
-
 	return 0;
 }
 
@@ -1929,7 +1907,6 @@ static int sdma_probe(struct platform_device *pdev)
 		struct sdma_channel *sdmac = &sdma->channel[i];
 
 		sdmac->sdma = sdma;
-		spin_lock_init(&sdmac->lock);
 
 		sdmac->channel = i;
 		sdmac->vc.desc_free = sdma_desc_free;
-- 
2.7.4


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

* [PATCH v4 5/7] dmaengine: imx-sdma: remove the maximum limitation for bd numbers
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
                   ` (3 preceding siblings ...)
  2018-06-14 13:35 ` [PATCH v4 4/7] dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct sdma_channel' Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  2018-06-14 13:35 ` [PATCH v4 6/7] dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap Robin Gong
  2018-06-14 13:35 ` [PATCH v4 7/7] tty: serial: imx: split all dma setup operations out of 'port.lock' protector Robin Gong
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

No this limitation now after virtual dma used since bd is allocated
dynamically instead of static.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/dma/imx-sdma.c | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 27b76eb..f56226f 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -292,7 +292,6 @@ struct sdma_context_data {
 	u32  scratch7;
 } __attribute__ ((packed));
 
-#define NUM_BD (int)(PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
 
 struct sdma_engine;
 
@@ -1297,13 +1296,6 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 	if (ret)
 		goto err_bd_out;
 
-	if (sg_len > NUM_BD) {
-		dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
-				channel, sg_len, NUM_BD);
-		ret = -EINVAL;
-		goto err_bd_out;
-	}
-
 	desc->chn_count = 0;
 	for_each_sg(sgl, sg, sg_len, i) {
 		struct sdma_buffer_descriptor *bd = &desc->bd[i];
@@ -1413,12 +1405,6 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 	if (ret)
 		goto err_bd_out;
 
-	if (num_periods > NUM_BD) {
-		dev_err(sdma->dev, "SDMA channel %d: maximum number of sg exceeded: %d > %d\n",
-				channel, num_periods, NUM_BD);
-		goto err_bd_out;
-	}
-
 	if (period_len > 0xffff) {
 		dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
 				channel, period_len, 0xffff);
-- 
2.7.4


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

* [PATCH v4 6/7] dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
                   ` (4 preceding siblings ...)
  2018-06-14 13:35 ` [PATCH v4 5/7] dmaengine: imx-sdma: remove the maximum limitation for bd numbers Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  2018-06-14 13:35 ` [PATCH v4 7/7] tty: serial: imx: split all dma setup operations out of 'port.lock' protector Robin Gong
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

There are lot of codes overlap between prep_sg and prep_cyclic function.
Add sdma_transfer_init() function to elimated the code overlap.

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/dma/imx-sdma.c | 83 ++++++++++++++++++++++----------------------------
 1 file changed, 37 insertions(+), 46 deletions(-)

diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index f56226f..e0783a2 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1255,6 +1255,40 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
 	clk_disable(sdma->clk_ahb);
 }
 
+static struct sdma_desc *sdma_transfer_init(struct sdma_channel *sdmac,
+				enum dma_transfer_direction direction, u32 bds)
+{
+	struct sdma_desc *desc;
+
+	desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+	if (!desc)
+		goto err_out;
+
+	sdmac->status = DMA_IN_PROGRESS;
+	sdmac->direction = direction;
+	sdmac->flags = 0;
+
+	desc->chn_count = 0;
+	desc->chn_real_count = 0;
+	desc->buf_tail = 0;
+	desc->buf_ptail = 0;
+	desc->sdmac = sdmac;
+	desc->num_bd = bds;
+
+	if (sdma_alloc_bd(desc))
+		goto err_desc_out;
+
+	if (sdma_load_context(sdmac))
+		goto err_desc_out;
+
+	return desc;
+
+err_desc_out:
+	kfree(desc);
+err_out:
+	return NULL;
+}
+
 static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 		struct dma_chan *chan, struct scatterlist *sgl,
 		unsigned int sg_len, enum dma_transfer_direction direction,
@@ -1267,36 +1301,13 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg(
 	struct scatterlist *sg;
 	struct sdma_desc *desc;
 
-	if (sdmac->status == DMA_IN_PROGRESS)
-		return NULL;
-	sdmac->status = DMA_IN_PROGRESS;
-
-	sdmac->flags = 0;
-
-	desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+	desc = sdma_transfer_init(sdmac, direction, sg_len);
 	if (!desc)
 		goto err_out;
 
-	desc->buf_tail = 0;
-	desc->buf_ptail = 0;
-	desc->sdmac = sdmac;
-	desc->num_bd = sg_len;
-	desc->chn_real_count = 0;
-
-	if (sdma_alloc_bd(desc)) {
-		kfree(desc);
-		goto err_out;
-	}
-
 	dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n",
 			sg_len, channel);
 
-	sdmac->direction = direction;
-	ret = sdma_load_context(sdmac);
-	if (ret)
-		goto err_bd_out;
-
-	desc->chn_count = 0;
 	for_each_sg(sgl, sg, sg_len, i) {
 		struct sdma_buffer_descriptor *bd = &desc->bd[i];
 		int param;
@@ -1372,38 +1383,18 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic(
 	struct sdma_engine *sdma = sdmac->sdma;
 	int num_periods = buf_len / period_len;
 	int channel = sdmac->channel;
-	int ret, i = 0, buf = 0;
+	int i = 0, buf = 0;
 	struct sdma_desc *desc;
 
 	dev_dbg(sdma->dev, "%s channel: %d\n", __func__, channel);
 
-	if (sdmac->status == DMA_IN_PROGRESS)
-		return NULL;
-
-	sdmac->status = DMA_IN_PROGRESS;
-
-	desc = kzalloc((sizeof(*desc)), GFP_KERNEL);
+	desc = sdma_transfer_init(sdmac, direction, num_periods);
 	if (!desc)
 		goto err_out;
 
-	desc->buf_tail = 0;
-	desc->buf_ptail = 0;
-	desc->sdmac = sdmac;
-	desc->num_bd = num_periods;
-	desc->chn_real_count = 0;
 	desc->period_len = period_len;
 
 	sdmac->flags |= IMX_DMA_SG_LOOP;
-	sdmac->direction = direction;
-
-	if (sdma_alloc_bd(desc)) {
-		kfree(desc);
-		goto err_bd_out;
-	}
-
-	ret = sdma_load_context(sdmac);
-	if (ret)
-		goto err_bd_out;
 
 	if (period_len > 0xffff) {
 		dev_err(sdma->dev, "SDMA channel %d: maximum period size exceeded: %zu > %d\n",
-- 
2.7.4


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

* [PATCH v4 7/7] tty: serial: imx: split all dma setup operations out of 'port.lock' protector
  2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
                   ` (5 preceding siblings ...)
  2018-06-14 13:35 ` [PATCH v4 6/7] dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap Robin Gong
@ 2018-06-14 13:35 ` Robin Gong
  6 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:35 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams
  Cc: dmaengine, linux-kernel, linux-arm-kernel, linux-imx

After sdma driver change to virt-dma, all bds will be allocated
dynamically with 'port.lock' acquired instead of statically allocated
before. That means the lock sequence is 'port.lock' -> 'fs_reclaim_acquire'
.But in case uart rx/tx dma callback coming after other kernel code which
have already acquired 'fs_reclaim_acquire' lock, which means the above lock
sequence reverted as 'fs_reclaim_acquire' -> 'port.lock'(acquired in uart
dma callback), thus, lockdep warning comes as beow. Actually don't need to
spinlock all DMA operations in UART driver with 'port.lock', because dma
driver can wipe off race condition by commone virt-dma lock . Split all dma
operations out of the code areas which protected by 'port.lock'.

[   46.155406] =====================================================
[   46.161503] WARNING: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected
[   46.168122] 4.17.0-rc6-00008-g7caafa3-dirty #48 Not tainted
[   46.173696] -----------------------------------------------------
[   46.179795] mxc_uart_stress/419 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire:
[   46.186934] fa7c1440 (fs_reclaim){+.+.}, at: fs_reclaim_acquire.part.3+0x0/0x48
[   46.194270]
[   46.194270] and this task is already holding:
[   46.200106] 09a17fda (&port_lock_key){-.-.}, at: uart_write+0x84/0x190
[   46.206658] which would create a new lock dependency:
[   46.211710]  (&port_lock_key){-.-.} -> (fs_reclaim){+.+.}
[   46.217132]
[   46.217132] but this new dependency connects a HARDIRQ-irq-safe lock:
[   46.225051]  (&port_lock_key){-.-.}
[   46.225062]
[   46.225062] ... which became HARDIRQ-irq-safe at:
[   46.234740]   lock_acquire+0x70/0x90
[   46.238326]   _raw_spin_lock_irqsave+0x40/0x54
[   46.242777]   imx_uart_console_write+0x1bc/0x1e0
[   46.247402]   console_unlock+0x320/0x5f0
[   46.251329]   vprintk_emit+0x22c/0x3fc
[   46.255082]   vprintk_default+0x28/0x30
[   46.258923]   vprintk_func+0x78/0xcc
[   46.262503]   printk+0x34/0x54
[   46.265566]   crng_fast_load+0xf8/0x138
[   46.269407]   add_interrupt_randomness+0x21c/0x24c
[   46.274204]   handle_irq_event_percpu+0x40/0x84
[   46.278739]   handle_irq_event+0x40/0x64
[   46.282667]   handle_fasteoi_irq+0xbc/0x178
[   46.286854]   generic_handle_irq+0x28/0x3c
[   46.290954]   __handle_domain_irq+0x6c/0xe8
[   46.295148]   gic_handle_irq+0x64/0xc4
[   46.298904]   __irq_svc+0x70/0x98
[   46.302225]   _raw_spin_unlock_irq+0x30/0x34
[   46.306505]   finish_task_switch+0xc0/0x27c
[   46.310693]   __schedule+0x2c0/0x79c
[   46.314272]   schedule_idle+0x40/0x84
[   46.317941]   do_idle+0x178/0x2b4
[   46.321259]   cpu_startup_entry+0x20/0x24
[   46.325278]   rest_init+0x214/0x264
[   46.328775]   start_kernel+0x39c/0x424
[   46.332527]     (null)
[   46.334891]
[   46.334891] to a HARDIRQ-irq-unsafe lock:
[   46.340379]  (fs_reclaim){+.+.}
[   46.340391]
[   46.340391] ... which became HARDIRQ-irq-unsafe at:
[   46.349885] ...
[   46.349895]   lock_acquire+0x70/0x90
[   46.355225]   fs_reclaim_acquire.part.3+0x38/0x48
[   46.359933]   fs_reclaim_acquire+0x1c/0x20
[   46.364036]   kmem_cache_alloc+0x2c/0x174
[   46.368051]   alloc_worker.constprop.10+0x1c/0x58
[   46.372759]   init_rescuer.part.4+0x18/0xa4
[   46.376952]   workqueue_init+0xc0/0x210
[   46.380793]   kernel_init_freeable+0x58/0x1d8
[   46.385156]   kernel_init+0x10/0x11c
[   46.388736]   ret_from_fork+0x14/0x20
[   46.392399]     (null)
[   46.394762]
[   46.394762] other info that might help us debug this:
[   46.394762]
[   46.402769]  Possible interrupt unsafe locking scenario:
[   46.402769]
[   46.409560]        CPU0                    CPU1
[   46.414092]        ----                    ----
[   46.418622]   lock(fs_reclaim);
[   46.421772]                                local_irq_disable();
[   46.427693]                                lock(&port_lock_key);
[   46.433707]                                lock(fs_reclaim);
[   46.439372]   <Interrupt>
[   46.441993]     lock(&port_lock_key);
[   46.445661]
[   46.445661]  *** DEADLOCK ***
[   46.445661]

Signed-off-by: Robin Gong <yibin.gong@nxp.com>
---
 drivers/tty/serial/imx.c | 97 ++++++++++++++++++++++++++----------------------
 1 file changed, 53 insertions(+), 44 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index b83bc2c..f2a2966 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -223,6 +223,7 @@ struct imx_port {
 	dma_cookie_t		rx_cookie;
 	unsigned int		tx_bytes;
 	unsigned int		dma_tx_nents;
+	struct work_struct	tsk_dma_tx;
 	unsigned int            saved_reg[10];
 	bool			context_saved;
 };
@@ -491,8 +492,6 @@ static void imx_uart_enable_ms(struct uart_port *port)
 	mctrl_gpio_enable_ms(sport->gpios);
 }
 
-static void imx_uart_dma_tx(struct imx_port *sport);
-
 /* called with port.lock taken and irqs off */
 static inline void imx_uart_transmit_buffer(struct imx_port *sport)
 {
@@ -524,7 +523,7 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
 			imx_uart_writel(sport, ucr1, UCR1);
 		} else {
 			imx_uart_writel(sport, ucr1, UCR1);
-			imx_uart_dma_tx(sport);
+			schedule_work(&sport->tsk_dma_tx);
 		}
 
 		return;
@@ -574,7 +573,7 @@ static void imx_uart_dma_tx_callback(void *data)
 		uart_write_wakeup(&sport->port);
 
 	if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
-		imx_uart_dma_tx(sport);
+		schedule_work(&sport->tsk_dma_tx);
 	else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
 		u32 ucr4 = imx_uart_readl(sport, UCR4);
 		ucr4 |= UCR4_TCEN;
@@ -584,19 +583,21 @@ static void imx_uart_dma_tx_callback(void *data)
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-/* called with port.lock taken and irqs off */
-static void imx_uart_dma_tx(struct imx_port *sport)
+static void dma_tx_work(struct work_struct *w)
 {
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
 	struct circ_buf *xmit = &sport->port.state->xmit;
 	struct scatterlist *sgl = sport->tx_sgl;
 	struct dma_async_tx_descriptor *desc;
 	struct dma_chan	*chan = sport->dma_chan_tx;
 	struct device *dev = sport->port.dev;
+	unsigned long flags;
 	u32 ucr1, ucr4;
 	int ret;
 
+	spin_lock_irqsave(&sport->port.lock, flags);
 	if (sport->dma_is_txing)
-		return;
+		goto work_out;
 
 	ucr4 = imx_uart_readl(sport, UCR4);
 	ucr4 &= ~UCR4_TCEN;
@@ -604,45 +605,51 @@ static void imx_uart_dma_tx(struct imx_port *sport)
 
 	sport->tx_bytes = uart_circ_chars_pending(xmit);
 
-	if (xmit->tail < xmit->head) {
-		sport->dma_tx_nents = 1;
-		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
-	} else {
-		sport->dma_tx_nents = 2;
-		sg_init_table(sgl, 2);
-		sg_set_buf(sgl, xmit->buf + xmit->tail,
-				UART_XMIT_SIZE - xmit->tail);
-		sg_set_buf(sgl + 1, xmit->buf, xmit->head);
-	}
+	if (sport->tx_bytes > 0) {
+		if (xmit->tail < xmit->head) {
+			sport->dma_tx_nents = 1;
+			sg_init_one(sgl, xmit->buf + xmit->tail,
+					sport->tx_bytes);
+		} else {
+			sport->dma_tx_nents = 2;
+			sg_init_table(sgl, 2);
+			sg_set_buf(sgl, xmit->buf + xmit->tail,
+					UART_XMIT_SIZE - xmit->tail);
+			sg_set_buf(sgl + 1, xmit->buf, xmit->head);
+		}
+		spin_unlock_irqrestore(&sport->port.lock, flags);
 
-	ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
-	if (ret == 0) {
-		dev_err(dev, "DMA mapping error for TX.\n");
-		return;
-	}
-	desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
+		ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+		if (ret == 0) {
+			dev_err(dev, "DMA mapping error for TX.\n");
+			return;
+		}
+		desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
 					DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
-	if (!desc) {
-		dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
-			     DMA_TO_DEVICE);
-		dev_err(dev, "We cannot prepare for the TX slave dma!\n");
-		return;
-	}
-	desc->callback = imx_uart_dma_tx_callback;
-	desc->callback_param = sport;
+		if (!desc) {
+			dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
+				     DMA_TO_DEVICE);
+			dev_err(dev, "We cannot prepare for the TX slave dma!\n");
+			return;
+		}
+		desc->callback = imx_uart_dma_tx_callback;
+		desc->callback_param = sport;
 
-	dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
-			uart_circ_chars_pending(xmit));
+		dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
+				uart_circ_chars_pending(xmit));
 
-	ucr1 = imx_uart_readl(sport, UCR1);
-	ucr1 |= UCR1_TXDMAEN;
-	imx_uart_writel(sport, ucr1, UCR1);
+		ucr1 = imx_uart_readl(sport, UCR1);
+		ucr1 |= UCR1_TXDMAEN;
+		imx_uart_writel(sport, ucr1, UCR1);
 
-	/* fire it */
-	sport->dma_is_txing = 1;
-	dmaengine_submit(desc);
-	dma_async_issue_pending(chan);
-	return;
+		/* fire it */
+		sport->dma_is_txing = 1;
+		dmaengine_submit(desc);
+		dma_async_issue_pending(chan);
+		return;
+	}
+work_out:
+	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 /* called with port.lock taken and irqs off */
@@ -696,7 +703,7 @@ static void imx_uart_start_tx(struct uart_port *port)
 
 		if (!uart_circ_empty(&port->state->xmit) &&
 		    !uart_tx_stopped(port))
-			imx_uart_dma_tx(sport);
+			schedule_work(&sport->tsk_dma_tx);
 		return;
 	}
 }
@@ -1405,7 +1412,9 @@ static int imx_uart_startup(struct uart_port *port)
 	 */
 	imx_uart_enable_ms(&sport->port);
 
+	spin_unlock_irqrestore(&sport->port.lock, flags);
 	if (dma_is_inited) {
+		INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
 		imx_uart_enable_dma(sport);
 		imx_uart_start_rx_dma(sport);
 	} else {
@@ -1418,8 +1427,6 @@ static int imx_uart_startup(struct uart_port *port)
 		imx_uart_writel(sport, ucr2, UCR2);
 	}
 
-	spin_unlock_irqrestore(&sport->port.lock, flags);
-
 	return 0;
 }
 
@@ -1435,6 +1442,8 @@ static void imx_uart_shutdown(struct uart_port *port)
 		dmaengine_terminate_sync(sport->dma_chan_tx);
 		dmaengine_terminate_sync(sport->dma_chan_rx);
 
+		cancel_work_sync(&sport->tsk_dma_tx);
+
 		spin_lock_irqsave(&sport->port.lock, flags);
 		imx_uart_stop_tx(port);
 		imx_uart_stop_rx(port);
-- 
2.7.4


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

* [PATCH v4 0/7] add virt-dma support for imx-sdma
@ 2018-06-14 14:02 Robin Gong
  2018-06-14  8:53 ` Lucas Stach
  0 siblings, 1 reply; 13+ messages in thread
From: Robin Gong @ 2018-06-14 14:02 UTC (permalink / raw)
  To: vkoul, s.hauer, l.stach, dan.j.williams, gregkh, jslaby
  Cc: linux-serial, dmaengine, linux-kernel, linux-arm-kernel, linux-imx

The legacy sdma driver has below limitations or drawbacks:
  1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
     one page size for one channel regardless of only few BDs needed
     most time. But in few cases, the max PAGE_SIZE maybe not enough.
  2. One SDMA channel can't stop immediatley once channel disabled which
     means SDMA interrupt may come in after this channel terminated.There
     are some patches for this corner case such as commit "2746e2c389f9",
     but not cover non-cyclic.

The common virt-dma overcomes the above limitations. It can alloc bd
dynamically and free bd once this tx transfer done. No memory wasted or
maximum limititation here, only depends on how many memory can be requested
from kernel. For No.2, such issue can be workaround by checking if there
is available descript("sdmac->desc") now once the unwanted interrupt
coming. At last the common virt-dma is easier for sdma driver maintain.

Change from v3:
  1. add two uart patches which impacted by this patchset.
  2. unlock 'vc.lock' before cyclic dma callback and lock again after
     it because some driver such as uart will call dmaengine_tx_status
     which will acquire 'vc.lock' again and dead lock comes out.
  3. remove 'Revert commit' stuff since that patch is not wrong and
     combine two patch into one patch as Sascha's comment.

Change from v2:
  1. include Sascha's patch to make the main patch easier to review.
     Thanks Sacha.
  2. remove useless 'desc'/'chan' in struct sdma_channe.

Change from v1:
  1. split v1 patch into 5 patches.
  2. remove some unnecessary condition check.
  3. remove unnecessary 'pending' list.

Robin Gong (6):
  tty: serial: imx: correct dma cookie status
  dmaengine: imx-sdma: add virt-dma support
  dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct
    sdma_channel'
  dmaengine: imx-sdma: remove the maximum limitation for bd numbers
  dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap
  tty: serial: imx: split all dma setup operations out of 'port.lock'
    protector

Sascha Hauer (1):
  dmaengine: imx-sdma: factor out a struct sdma_desc from struct
    sdma_channel

 drivers/dma/Kconfig      |   1 +
 drivers/dma/imx-sdma.c   | 394 +++++++++++++++++++++++++++--------------------
 drivers/tty/serial/imx.c |  99 ++++++------
 3 files changed, 282 insertions(+), 212 deletions(-)

-- 
2.7.4


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

* RE: [PATCH v4 0/7] add virt-dma support for imx-sdma
  2018-06-14 10:22     ` Lucas Stach
@ 2018-06-14 13:12       ` Robin Gong
  0 siblings, 0 replies; 13+ messages in thread
From: Robin Gong @ 2018-06-14 13:12 UTC (permalink / raw)
  To: Lucas Stach, s.hauer, vkoul, dan.j.williams, gregkh, jslaby
  Cc: dmaengine, linux-kernel, linux-arm-kernel, dl-linux-imx, linux-serial

Hi Lucas,
	I didn't met your unstable console issue before, anyway, I'll do more test and look into Audio issue.

-----Original Message-----
From: Lucas Stach [mailto:l.stach@pengutronix.de] 
Sent: 2018年6月14日 18:22
To: Robin Gong <yibin.gong@nxp.com>; s.hauer@pengutronix.de; vkoul@kernel.org; dan.j.williams@intel.com; gregkh@linuxfoundation.org; jslaby@suse.com
Cc: dmaengine@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>; linux-serial@vger.kernel.org
Subject: Re: [PATCH v4 0/7] add virt-dma support for imx-sdma

Am Donnerstag, den 14.06.2018, 10:09 +0000 schrieb Robin Gong:
> Hi Lucas,
> 	Could you double check again? Still can reproduce lockdep warning on 
> UART if change spin_lock_lockirqsave/spinlock_unlock_irqrestore to 
> spin_lock/spin_unlock in sdma_int_handler as you said without 
> patch7/7.

Yes, I can reproduce the lockdep issue with _irqsave variants in the IRQ handler and 7/7 reverted. It fixes the pcm issue though.

> Would you please ask below two more questions?
> 1. Does your uart case pass now with my v4 patchset?

It seems to work, but the change seems to impact the non-DMA serial somehow. On several boots the system was unable to present a login prompt, so patch 7/7 seems to break other stuff and it's a pretty invasive change to the serial driver, which is known to be non-trivial.

I don't have the bandwidth to dig through this patch currently, but I wonder if it couldn't be simplified with the spinlock stuff in the sdma driver fixed.

> 2. Do you make some code change in your local('I just gave this series 
> a spin')to reproduce your below issue? If yes, could you post your 
> change?

The lockdep splat below was without any changes to your series.

Regards,
Lucas

> On 四, 2018-06-14 at 10:53 +0200, Lucas Stach wrote:
> > Hi Robin,
> > 
> > I just gave this series a spin and it seems there is even more 
> > locking fun, see the lockdep output below. After taking a short look 
> > it seems this is caused by using the wrong spinlock variants in 
> > sdma_int_handler(), those should also use the _irqsave ones. When 
> > fixing this you might want to reconsider patch 7/7, as it's probably 
> > not needed at all.
> > 
> > Regards,
> > Lucas
> > 
> > [   20.479401]
> > ========================================================
> > [   20.485769] WARNING: possible irq lock inversion dependency 
> > detected [   20.492140] 4.17.0+ #1538 Not tainted [   20.495814] 
> > ----------------------------------------------------
> > --
> > --
> > [   20.502181] systemd/1 just changed the state of lock:
> > [   20.507247] c0abdafc (&(&substream->self_group.lock)->rlock){-
> > ...}, at: snd_pcm_stream_lock+0x54/0x60 [   20.516523] but this lock 
> > took another, HARDIRQ-unsafe lock in the
> > past:
> > [   20.523234]  (fs_reclaim){+.+.}
> > [   20.523253]
> > [   20.523253]
> > [   20.523253] and interrupts could create inverse lock ordering 
> > between them.
> > [   20.523253]
> > [   20.537804]
> > [   20.537804] other info that might help us debug this:
> > [   20.544344]  Possible interrupt unsafe locking scenario:
> > [   20.544344]
> > [   20.551144]        CPU0                    CPU1 [   20.555686]        
> > ----                    ---- [   20.560224]   lock(fs_reclaim); [   
> > 20.563386]                                local_irq_disable(); [   
> > 20.569315]                                lock(&(&substream-
> > > self_group.lock)->rlock);
> > 
> > [   20.577337]                                lock(fs_reclaim); [   
> > 20.583014]   <Interrupt> [   20.585643]     
> > lock(&(&substream->self_group.lock)->rlock);
> > [   20.591322]
> > [   20.591322]  *** DEADLOCK ***
> > [   20.591322]
> > [   20.597260] 1 lock held by systemd/1:
> > [   20.607806]  #0: ab23d11c (snd_pcm_link_rwlock){.-..}, at:
> > snd_pcm_stream_lock+0x4c/0x60
> > [   20.615951]
> > [   20.615951] the shortest dependencies between 2nd lock and 1st
> > lock:
> > [   20.623799]  -> (fs_reclaim){+.+.} ops: 248474 { [   20.628456]     
> > HARDIRQ-ON-W at:
> > [   20.631716]                       lock_acquire+0x260/0x29c [   
> > 20.637223]                       fs_reclaim_acquire+0x48/0x58 [   
> > 20.643075]                       kmem_cache_alloc_trace+0x3c/0x
> > 36
> > 4
> > [   20.649366]                       alloc_worker.constprop.15+0x28
> > /0
> > x64
> > [   20.655824]                       init_rescuer.part.5+0x20/0xa4 [   
> > 20.661764]                       workqueue_init+0x124/0x1f8 [   
> > 20.667446]                       kernel_init_freeable+0x60/0x55
> > 0
> > [   20.673561]                       kernel_init+0x18/0x120 [   
> > 20.678890]                       ret_from_fork+0x14/0x20 [   
> > 20.684299]                         (null) [   20.688408]     
> > SOFTIRQ-ON-W at:
> > [   20.691659]                       lock_acquire+0x260/0x29c [   
> > 20.697158]                       fs_reclaim_acquire+0x48/0x58 [   
> > 20.703006]                       kmem_cache_alloc_trace+0x3c/0x
> > 36
> > 4
> > [   20.709288]                       alloc_worker.constprop.15+0x28
> > /0
> > x64
> > [   20.709301]                       init_rescuer.part.5+0x20/0xa4 [   
> > 20.720717]                       workqueue_init+0x124/0x1f8 [   
> > 20.720729]                       kernel_init_freeable+0x60/0x55
> > 0
> > [   20.720738]                       kernel_init+0x18/0x120 [   
> > 20.720746]                       ret_from_fork+0x14/0x20 [   
> > 20.720751]                         (null) [   20.720756]     INITIAL 
> > USE at:
> > [   20.720770]                      lock_acquire+0x260/0x29c [   
> > 20.720782]                      fs_reclaim_acquire+0x48/0x58 [   
> > 20.774374]                      kmem_cache_alloc_trace+0x3c/0x3
> > 64
> > [   20.780574]                      alloc_worker.constprop.15+0x28/ 
> > 0x
> > 64
> > [   20.786945]                      init_rescuer.part.5+0x20/0xa4 [   
> > 20.792794]                      workqueue_init+0x124/0x1f8 [   
> > 20.798384]                      kernel_init_freeable+0x60/0x550 [   
> > 20.804406]                      kernel_init+0x18/0x120 [   
> > 20.809648]                      ret_from_fork+0x14/0x20 [   
> > 20.814971]                        (null) [   20.818992]   } [   
> > 20.820768]   ... key      at: [<80e22074>]
> > __fs_reclaim_map+0x0/0x10
> > [   20.827220]   ... acquired at:
> > [   20.830289]    fs_reclaim_acquire+0x48/0x58 [   20.834487]    
> > kmem_cache_alloc_trace+0x3c/0x364 [   20.839123]    
> > sdma_transfer_init+0x44/0x130 [   20.843409]    
> > sdma_prep_dma_cyclic+0x78/0x21c [   20.847869]    
> > snd_dmaengine_pcm_trigger+0xdc/0x184
> > [   20.852764]    soc_pcm_trigger+0x164/0x190 [   20.856876]    
> > snd_pcm_do_start+0x34/0x40 [   20.860902]    
> > snd_pcm_action_single+0x48/0x74 [   20.865360]    
> > snd_pcm_action+0x34/0xfc [   20.869213]    
> > snd_pcm_ioctl+0x910/0x10ec [   20.873241]    vfs_ioctl+0x30/0x44 [   
> > 20.876657]    do_vfs_ioctl+0xac/0x974 [   20.880421]    
> > ksys_ioctl+0x48/0x64 [   20.883923]    sys_ioctl+0x18/0x1c [   
> > 20.887340]    ret_fast_syscall+0x0/0x28 [   20.891277]    0x7289bcbc 
> > [   20.893909] [   20.895410] -> 
> > (&(&substream->self_group.lock)->rlock){-...}
> > ops:
> > 59 {
> > [   20.901977]    IN-HARDIRQ-W at:
> > [   20.905143]                     lock_acquire+0x260/0x29c [   
> > 20.910473]                     _raw_spin_lock+0x48/0x58 [   
> > 20.915801]                     snd_pcm_stream_lock+0x54/0x60 [   
> > 20.921561]                     _snd_pcm_stream_lock_irqsave+0x4 0/
> > 0x48
> > [   20.928107]                     snd_pcm_period_elapsed+0x2c/0xa4 
> > [   20.934127]                     dmaengine_pcm_dma_complete+0x54/ 
> > 0x
> > 58
> > [   20.940498]                     sdma_int_handler+0x1dc/0x2a8 [   
> > 20.946179]                     __handle_irq_event_percpu+0x1fc/ 0x
> > 498
> > [   20.952635]                     handle_irq_event_percpu+0x38/0x8 
> > c [   20.958742]                     handle_irq_event+0x48/0x6c [   
> > 20.964242]                     handle_fasteoi_irq+0xc4/0x138 [   
> > 20.970006]                     generic_handle_irq+0x28/0x38 [   
> > 20.975681]                     __handle_domain_irq+0xb0/0xc4 [   
> > 20.981443]                     gic_handle_irq+0x68/0xa0 [   
> > 20.986769]                     __irq_svc+0x70/0xb0 [   20.991662]                     
> > _raw_spin_unlock_irq+0x38/0x6c [   20.997511]                     
> > task_work_run+0x90/0xb8 [   21.002751]                     
> > do_work_pending+0xc8/0xd0 [   21.008164]                     
> > slow_work_pending+0xc/0x20 [   21.013661]                     
> > 0x76c77e86 [   21.017768]    INITIAL USE at:
> > [   21.020844]                    lock_acquire+0x260/0x29c [   
> > 21.026086]                    _raw_spin_lock+0x48/0x58 [   
> > 21.031328]                    snd_pcm_stream_lock+0x54/0x60 [   
> > 21.037002]                    snd_pcm_stream_lock_irq+0x38/0x3c [   
> > 21.043023]                    snd_pcm_sync_ptr+0x214/0x260 [   
> > 21.048609]                    snd_pcm_ioctl+0xbe0/0x10ec [   
> > 21.054027]                    vfs_ioctl+0x30/0x44 [   21.058832]                    
> > do_vfs_ioctl+0xac/0x974 [   21.063984]                    
> > ksys_ioctl+0x48/0x64 [   21.068875]                    
> > sys_ioctl+0x18/0x1c [   21.073679]                    
> > ret_fast_syscall+0x0/0x28 [   21.079004]                    
> > 0x7e9026dc [   21.083023]  } [   21.084710]  ... key      at: 
> > [<8162a6e4>] __key.31798+0x0/0x8 [   21.090552]  ... acquired at:
> > [   21.093537]    mark_lock+0x3a4/0x69c [   21.097128]    
> > __lock_acquire+0x420/0x16d4 [   21.101239]    
> > lock_acquire+0x260/0x29c [   21.105091]    _raw_spin_lock+0x48/0x58 
> > [   21.108940]    snd_pcm_stream_lock+0x54/0x60 [   21.113226]    
> > _snd_pcm_stream_lock_irqsave+0x40/0x48
> > [   21.118296]    snd_pcm_period_elapsed+0x2c/0xa4 [   21.122841]    
> > dmaengine_pcm_dma_complete+0x54/0x58
> > [   21.127735]    sdma_int_handler+0x1dc/0x2a8 [   21.131937]    
> > __handle_irq_event_percpu+0x1fc/0x498
> > [   21.136915]    handle_irq_event_percpu+0x38/0x8c [   21.141547]    
> > handle_irq_event+0x48/0x6c [   21.145570]    
> > handle_fasteoi_irq+0xc4/0x138 [   21.149854]    
> > generic_handle_irq+0x28/0x38 [   21.154052]    
> > __handle_domain_irq+0xb0/0xc4 [   21.158335]    
> > gic_handle_irq+0x68/0xa0 [   21.162184]    __irq_svc+0x70/0xb0 [   
> > 21.165601]    _raw_spin_unlock_irq+0x38/0x6c [   21.169973]    
> > task_work_run+0x90/0xb8 [   21.173735]    do_work_pending+0xc8/0xd0 
> > [   21.177670]    slow_work_pending+0xc/0x20 [   21.181691]    
> > 0x76c77e86 [   21.184320] [   21.185821] [   21.185821] stack 
> > backtrace:
> > [   21.190198] CPU: 0 PID: 1 Comm: systemd Not tainted 4.17.0+
> > #1538
> > [   21.196303] Hardware name: Freescale i.MX6 Quad/DualLite (Device
> > Tree)
> > [   21.202841] Backtrace:
> > [   21.205314] [<8010e318>] (dump_backtrace) from [<8010e604>]
> > (show_stack+0x20/0x24)
> > [   21.212900]  r7:80e9f3d0 r6:00000000 r5:60070193 r4:80e9f3d0 [   
> > 21.218581] [<8010e5e4>] (show_stack) from [<8099b660>]
> > (dump_stack+0xa4/0xd8)
> > [   21.225825] [<8099b5bc>] (dump_stack) from [<8017b52c>]
> > (print_irq_inversion_bug+0x15c/0x1fc)
> > [   21.234368]  r9:814da818 r8:00000001 r7:ee926c00 r6:00000000
> > r5:ee915bb0 r4:814da818
> > [   21.242133] [<8017b3d0>] (print_irq_inversion_bug) from 
> > [<8017b6dc>] (check_usage_forwards+0x110/0x13c)
> > [   21.251544]  r9:00000002 r8:80bfd3e2 r7:ee926c00 r6:ee927148
> > r5:80e08488 r4:00000001
> > [   21.259306] [<8017b5cc>] (check_usage_forwards) from [<8017c2a4>]
> > (mark_lock+0x3a4/0x69c)
> > [   21.267500]  r9:ee926c00 r8:80a03cd8 r7:00000101 r6:00000002
> > r5:00000000 r4:ee927148
> > [   21.275263] [<8017bf00>] (mark_lock) from [<8017cf68>]
> > (__lock_acquire+0x420/0x16d4)
> > [   21.283023]  r10:ee927148 r9:ed4620e4 r8:ee926c00 r7:00000000
> > r6:00000001 r5:00000001
> > [   21.290863]  r4:00000490
> > [   21.293416] [<8017cb48>] (__lock_acquire) from [<8017ed58>]
> > (lock_acquire+0x260/0x29c)
> > [   21.301350]  r10:00000001 r9:80e084a4 r8:00000000 r7:00000000
> > r6:00000000 r5:ed4620e4
> > [   21.309189]  r4:00000000
> > [   21.311746] [<8017eaf8>] (lock_acquire) from [<809b74f0>]
> > (_raw_spin_lock+0x48/0x58)
> > [   21.319506]  r10:ee0a4714 r9:ed457100 r8:ee0a46c8 r7:ee0a4714
> > r6:ee0a4010 r5:807847b0
> > [   21.327346]  r4:ed4620d4
> > [   21.329902] [<809b74a8>] (_raw_spin_lock) from [<807847b0>]
> > (snd_pcm_stream_lock+0x54/0x60)
> > [   21.338265]  r5:ed462000 r4:ed462000 [   21.341863] [<8078475c>] 
> > (snd_pcm_stream_lock) from [<80784838>]
> > (_snd_pcm_stream_lock_irqsave+0x40/0x48)
> > [   21.351440]  r5:ed462000 r4:60070193 [   21.355042] [<807847f8>] 
> > (_snd_pcm_stream_lock_irqsave) from [<8078b044>] 
> > (snd_pcm_period_elapsed+0x2c/0xa4)
> > [   21.364881]  r5:ee3ef000 r4:ed462000 [   21.368478] [<8078b018>] 
> > (snd_pcm_period_elapsed) from [<8078d7b4>] 
> > (dmaengine_pcm_dma_complete+0x54/0x58)
> > [   21.378148]  r7:ee0a4714 r6:ee0a4010 r5:00000007 r4:ee0a46bc [   
> > 21.383827] [<8078d760>] (dmaengine_pcm_dma_complete) from 
> > [<80504c0c>] (sdma_int_handler+0x1dc/0x2a8) [   21.393157] 
> > [<80504a30>] (sdma_int_handler) from [<8018cd28>]
> > (__handle_irq_event_percpu+0x1fc/0x498)
> > [   21.402393]  r10:00000000 r9:eeafd400 r8:80e084a4 r7:00000038
> > r6:00000038 r5:80ea3c12
> > [   21.410233]  r4:ee2b5d40
> > [   21.412787] [<8018cb2c>] (__handle_irq_event_percpu) from 
> > [<8018cffc>] (handle_irq_event_percpu+0x38/0x8c)
> > [   21.422457]  r10:00000000 r9:ee914000 r8:ee81d400 r7:00000038
> > r6:eeafd400 r5:eeafd464
> > [   21.430296]  r4:80e08488
> > [   21.432852] [<8018cfc4>] (handle_irq_event_percpu) from 
> > [<8018d098>] (handle_irq_event+0x48/0x6c) [   21.441736]  
> > r6:eeafd464 r5:eeafd464 r4:eeafd400 [   21.446374] [<8018d050>] 
> > (handle_irq_event) from [<8019146c>]
> > (handle_fasteoi_irq+0xc4/0x138)
> > [   21.454912]  r7:00000038 r6:eeafd464 r5:80e10a60 r4:eeafd400 [   
> > 21.460589] [<801913a8>] (handle_fasteoi_irq) from [<8018bd9c>]
> > (generic_handle_irq+0x28/0x38)
> > [   21.469214]  r7:00000038 r6:80d92ae4 r5:00000000 r4:00000000 [   
> > 21.474893] [<8018bd74>] (generic_handle_irq) from [<8018c48c>]
> > (__handle_domain_irq+0xb0/0xc4)
> > [   21.483611] [<8018c3dc>] (__handle_domain_irq) from [<80102330>]
> > (gic_handle_irq+0x68/0xa0)
> > [   21.491978]  r9:ee914000 r8:f4001100 r7:80e5c6bc r6:ee915f00 
> > r5:80e08c3c r4:f4000100 [   21.499738] [<801022c8>] (gic_handle_irq) 
> > from [<801019f0>]
> > (__irq_svc+0x70/0xb0)
> > [   21.507233] Exception stack(0xee915f00 to 0xee915f48) [   
> > 21.512303] 5f00: 00000001 00000004 00000000 ee926c00 ee9270a8
> > ee926c00 ecc45e00 ee9270a8
> > [   21.520498] 5f20: 80ec23b0 ee914000 00000000 ee915f64 ee915f20
> > ee915f50 8017c7c0 809b78ac
> > [   21.528687] 5f40: 20070013 ffffffff [   21.532193]  r9:ee914000 
> > r8:80ec23b0 r7:ee915f34 r6:ffffffff
> > r5:20070013 r4:809b78ac
> > [   21.539959] [<809b7874>] (_raw_spin_unlock_irq) from [<8014e98c>]
> > (task_work_run+0x90/0xb8)
> > [   21.548321]  r5:ee926c00 r4:ecc45e00 [   21.551913] [<8014e8fc>] 
> > (task_work_run) from [<8010da3c>]
> > (do_work_pending+0xc8/0xd0)
> > [   21.559848]  r9:ee914000 r8:801011c4 r7:ee915fb0 r6:ffffe000
> > r5:00000004 r4:801011c4
> > [   21.567608] [<8010d974>] (do_work_pending) from [<80101034>]
> > (slow_work_pending+0xc/0x20)
> > [   21.575797] Exception stack(0xee915fb0 to 0xee915ff8) [   
> > 21.580864] 5fa0:                                     00000000
> > 020c34e8 46059f00 00000000
> > [   21.589059] 5fc0: 00000002 76f133a4 020df680 00000006 76e6e168
> > 00000035 7ef81778 00000035
> > [   21.597253] 5fe0: 00000006 7ef816a0 76c75d67 76c77e86 20070030
> > 00000039
> > [   21.603883]  r7:00000006 r6:020df680 r5:76f133a4 r4:00000002
> > 
> > Am Donnerstag, den 14.06.2018, 22:02 +0800 schrieb Robin Gong:
> > > 
> > > The legacy sdma driver has below limitations or drawbacks:
> > >   1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and 
> > > alloc
> > >      one page size for one channel regardless of only few BDs 
> > > needed
> > >      most time. But in few cases, the max PAGE_SIZE maybe not 
> > > enough.
> > >   2. One SDMA channel can't stop immediatley once channel disabled 
> > > which
> > >      means SDMA interrupt may come in after this channel 
> > > terminated.There
> > >      are some patches for this corner case such as commit 
> > > "2746e2c389f9",
> > >      but not cover non-cyclic.
> > > 
> > > The common virt-dma overcomes the above limitations. It can alloc 
> > > bd dynamically and free bd once this tx transfer done. No memory 
> > > wasted or maximum limititation here, only depends on how many 
> > > memory can be requested from kernel. For No.2, such issue can be 
> > > workaround by checking if there is available 
> > > descript("sdmac->desc") now once the unwanted interrupt coming. At 
> > > last the common virt-dma is easier for sdma driver maintain.
> > > 
> > > Change from v3:
> > >   1. add two uart patches which impacted by this patchset.
> > >   2. unlock 'vc.lock' before cyclic dma callback and lock again 
> > > after
> > >      it because some driver such as uart will call 
> > > dmaengine_tx_status
> > >      which will acquire 'vc.lock' again and dead lock comes out.
> > >   3. remove 'Revert commit' stuff since that patch is not wrong 
> > > and
> > >      combine two patch into one patch as Sascha's comment.
> > > 
> > > Change from v2:
> > >   1. include Sascha's patch to make the main patch easier to 
> > > review.
> > >      Thanks Sacha.
> > >   2. remove useless 'desc'/'chan' in struct sdma_channe.
> > > 
> > > Change from v1:
> > >   1. split v1 patch into 5 patches.
> > >   2. remove some unnecessary condition check.
> > >   3. remove unnecessary 'pending' list.
> > > 
> > > Robin Gong (6):
> > >   tty: serial: imx: correct dma cookie status
> > >   dmaengine: imx-sdma: add virt-dma support
> > >   dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 
> > > 'struct
> > >     sdma_channel'
> > >   dmaengine: imx-sdma: remove the maximum limitation for bd 
> > > numbers
> > >   dmaengine: imx-sdma: add sdma_transfer_init to decrease code 
> > > overlap
> > >   tty: serial: imx: split all dma setup operations out of 
> > > 'port.lock'
> > >     protector
> > > 
> > > Sascha Hauer (1):
> > >   dmaengine: imx-sdma: factor out a struct sdma_desc from struct
> > >     sdma_channel
> > > 
> > >  drivers/dma/Kconfig      |   1 +
> > >  drivers/dma/imx-sdma.c   | 394 +++++++++++++++++++++++++++------
> > > --------------
> > >  drivers/tty/serial/imx.c |  99 ++++++------
> > >  3 files changed, 282 insertions(+), 212 deletions(-)

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

* Re: [PATCH v4 0/7] add virt-dma support for imx-sdma
  2018-06-14 10:09   ` Robin Gong
@ 2018-06-14 10:22     ` Lucas Stach
  2018-06-14 13:12       ` Robin Gong
  0 siblings, 1 reply; 13+ messages in thread
From: Lucas Stach @ 2018-06-14 10:22 UTC (permalink / raw)
  To: Robin Gong, s.hauer, vkoul, dan.j.williams, gregkh, jslaby
  Cc: dmaengine, linux-kernel, linux-arm-kernel, dl-linux-imx, linux-serial

Am Donnerstag, den 14.06.2018, 10:09 +0000 schrieb Robin Gong:
> Hi Lucas,
> 	Could you double check again? Still can reproduce lockdep
> warning on UART if change
> spin_lock_lockirqsave/spinlock_unlock_irqrestore to
> spin_lock/spin_unlock in sdma_int_handler as you said without
> patch7/7.

Yes, I can reproduce the lockdep issue with _irqsave variants in the
IRQ handler and 7/7 reverted. It fixes the pcm issue though.

> Would you please ask below two more questions?
> 1. Does your uart case pass now with my v4 patchset?

It seems to work, but the change seems to impact the non-DMA serial
somehow. On several boots the system was unable to present a login
prompt, so patch 7/7 seems to break other stuff and it's a pretty
invasive change to the serial driver, which is known to be non-trivial.

I don't have the bandwidth to dig through this patch currently, but I
wonder if it couldn't be simplified with the spinlock stuff in the sdma
driver fixed.

> 2. Do you make some code change in your local('I just gave this
> series
> a spin')to reproduce your below issue? If yes, could you post your
> change?

The lockdep splat below was without any changes to your series.

Regards,
Lucas

> On 四, 2018-06-14 at 10:53 +0200, Lucas Stach wrote:
> > Hi Robin,
> > 
> > I just gave this series a spin and it seems there is even more
> > locking
> > fun, see the lockdep output below. After taking a short look it
> > seems
> > this is caused by using the wrong spinlock variants in
> > sdma_int_handler(), those should also use the _irqsave ones. When
> > fixing this you might want to reconsider patch 7/7, as it's
> > probably
> > not needed at all.
> > 
> > Regards,
> > Lucas
> > 
> > [   20.479401]
> > ========================================================
> > [   20.485769] WARNING: possible irq lock inversion dependency
> > detected
> > [   20.492140] 4.17.0+ #1538 Not tainted
> > [   20.495814] ----------------------------------------------------
> > --
> > --
> > [   20.502181] systemd/1 just changed the state of lock:
> > [   20.507247] c0abdafc (&(&substream->self_group.lock)->rlock){-
> > ...}, at: snd_pcm_stream_lock+0x54/0x60
> > [   20.516523] but this lock took another, HARDIRQ-unsafe lock in
> > the
> > past:
> > [   20.523234]  (fs_reclaim){+.+.}
> > [   20.523253] 
> > [   20.523253] 
> > [   20.523253] and interrupts could create inverse lock ordering
> > between them.
> > [   20.523253] 
> > [   20.537804] 
> > [   20.537804] other info that might help us debug this:
> > [   20.544344]  Possible interrupt unsafe locking scenario:
> > [   20.544344] 
> > [   20.551144]        CPU0                    CPU1
> > [   20.555686]        ----                    ----
> > [   20.560224]   lock(fs_reclaim);
> > [   20.563386]                                local_irq_disable();
> > [   20.569315]                                lock(&(&substream-
> > > self_group.lock)->rlock);
> > 
> > [   20.577337]                                lock(fs_reclaim);
> > [   20.583014]   <Interrupt>
> > [   20.585643]     lock(&(&substream->self_group.lock)->rlock);
> > [   20.591322] 
> > [   20.591322]  *** DEADLOCK ***
> > [   20.591322] 
> > [   20.597260] 1 lock held by systemd/1:
> > [   20.607806]  #0: ab23d11c (snd_pcm_link_rwlock){.-..}, at:
> > snd_pcm_stream_lock+0x4c/0x60
> > [   20.615951] 
> > [   20.615951] the shortest dependencies between 2nd lock and 1st
> > lock:
> > [   20.623799]  -> (fs_reclaim){+.+.} ops: 248474 {
> > [   20.628456]     HARDIRQ-ON-W at:
> > [   20.631716]                       lock_acquire+0x260/0x29c
> > [   20.637223]                       fs_reclaim_acquire+0x48/0x58
> > [   20.643075]                       kmem_cache_alloc_trace+0x3c/0x
> > 36
> > 4
> > [   20.649366]                       alloc_worker.constprop.15+0x28
> > /0
> > x64
> > [   20.655824]                       init_rescuer.part.5+0x20/0xa4
> > [   20.661764]                       workqueue_init+0x124/0x1f8
> > [   20.667446]                       kernel_init_freeable+0x60/0x55
> > 0
> > [   20.673561]                       kernel_init+0x18/0x120
> > [   20.678890]                       ret_from_fork+0x14/0x20
> > [   20.684299]                         (null)
> > [   20.688408]     SOFTIRQ-ON-W at:
> > [   20.691659]                       lock_acquire+0x260/0x29c
> > [   20.697158]                       fs_reclaim_acquire+0x48/0x58
> > [   20.703006]                       kmem_cache_alloc_trace+0x3c/0x
> > 36
> > 4
> > [   20.709288]                       alloc_worker.constprop.15+0x28
> > /0
> > x64
> > [   20.709301]                       init_rescuer.part.5+0x20/0xa4
> > [   20.720717]                       workqueue_init+0x124/0x1f8
> > [   20.720729]                       kernel_init_freeable+0x60/0x55
> > 0
> > [   20.720738]                       kernel_init+0x18/0x120
> > [   20.720746]                       ret_from_fork+0x14/0x20
> > [   20.720751]                         (null)
> > [   20.720756]     INITIAL USE at:
> > [   20.720770]                      lock_acquire+0x260/0x29c
> > [   20.720782]                      fs_reclaim_acquire+0x48/0x58
> > [   20.774374]                      kmem_cache_alloc_trace+0x3c/0x3
> > 64
> > [   20.780574]                      alloc_worker.constprop.15+0x28/
> > 0x
> > 64
> > [   20.786945]                      init_rescuer.part.5+0x20/0xa4
> > [   20.792794]                      workqueue_init+0x124/0x1f8
> > [   20.798384]                      kernel_init_freeable+0x60/0x550
> > [   20.804406]                      kernel_init+0x18/0x120
> > [   20.809648]                      ret_from_fork+0x14/0x20
> > [   20.814971]                        (null)
> > [   20.818992]   }
> > [   20.820768]   ... key      at: [<80e22074>]
> > __fs_reclaim_map+0x0/0x10
> > [   20.827220]   ... acquired at:
> > [   20.830289]    fs_reclaim_acquire+0x48/0x58
> > [   20.834487]    kmem_cache_alloc_trace+0x3c/0x364
> > [   20.839123]    sdma_transfer_init+0x44/0x130
> > [   20.843409]    sdma_prep_dma_cyclic+0x78/0x21c
> > [   20.847869]    snd_dmaengine_pcm_trigger+0xdc/0x184
> > [   20.852764]    soc_pcm_trigger+0x164/0x190
> > [   20.856876]    snd_pcm_do_start+0x34/0x40
> > [   20.860902]    snd_pcm_action_single+0x48/0x74
> > [   20.865360]    snd_pcm_action+0x34/0xfc
> > [   20.869213]    snd_pcm_ioctl+0x910/0x10ec
> > [   20.873241]    vfs_ioctl+0x30/0x44
> > [   20.876657]    do_vfs_ioctl+0xac/0x974
> > [   20.880421]    ksys_ioctl+0x48/0x64
> > [   20.883923]    sys_ioctl+0x18/0x1c
> > [   20.887340]    ret_fast_syscall+0x0/0x28
> > [   20.891277]    0x7289bcbc
> > [   20.893909] 
> > [   20.895410] -> (&(&substream->self_group.lock)->rlock){-...}
> > ops:
> > 59 {
> > [   20.901977]    IN-HARDIRQ-W at:
> > [   20.905143]                     lock_acquire+0x260/0x29c
> > [   20.910473]                     _raw_spin_lock+0x48/0x58
> > [   20.915801]                     snd_pcm_stream_lock+0x54/0x60
> > [   20.921561]                     _snd_pcm_stream_lock_irqsave+0x4
> > 0/
> > 0x48
> > [   20.928107]                     snd_pcm_period_elapsed+0x2c/0xa4
> > [   20.934127]                     dmaengine_pcm_dma_complete+0x54/
> > 0x
> > 58
> > [   20.940498]                     sdma_int_handler+0x1dc/0x2a8
> > [   20.946179]                     __handle_irq_event_percpu+0x1fc/
> > 0x
> > 498
> > [   20.952635]                     handle_irq_event_percpu+0x38/0x8
> > c
> > [   20.958742]                     handle_irq_event+0x48/0x6c
> > [   20.964242]                     handle_fasteoi_irq+0xc4/0x138
> > [   20.970006]                     generic_handle_irq+0x28/0x38
> > [   20.975681]                     __handle_domain_irq+0xb0/0xc4
> > [   20.981443]                     gic_handle_irq+0x68/0xa0
> > [   20.986769]                     __irq_svc+0x70/0xb0
> > [   20.991662]                     _raw_spin_unlock_irq+0x38/0x6c
> > [   20.997511]                     task_work_run+0x90/0xb8
> > [   21.002751]                     do_work_pending+0xc8/0xd0
> > [   21.008164]                     slow_work_pending+0xc/0x20
> > [   21.013661]                     0x76c77e86
> > [   21.017768]    INITIAL USE at:
> > [   21.020844]                    lock_acquire+0x260/0x29c
> > [   21.026086]                    _raw_spin_lock+0x48/0x58
> > [   21.031328]                    snd_pcm_stream_lock+0x54/0x60
> > [   21.037002]                    snd_pcm_stream_lock_irq+0x38/0x3c
> > [   21.043023]                    snd_pcm_sync_ptr+0x214/0x260
> > [   21.048609]                    snd_pcm_ioctl+0xbe0/0x10ec
> > [   21.054027]                    vfs_ioctl+0x30/0x44
> > [   21.058832]                    do_vfs_ioctl+0xac/0x974
> > [   21.063984]                    ksys_ioctl+0x48/0x64
> > [   21.068875]                    sys_ioctl+0x18/0x1c
> > [   21.073679]                    ret_fast_syscall+0x0/0x28
> > [   21.079004]                    0x7e9026dc
> > [   21.083023]  }
> > [   21.084710]  ... key      at: [<8162a6e4>] __key.31798+0x0/0x8
> > [   21.090552]  ... acquired at:
> > [   21.093537]    mark_lock+0x3a4/0x69c
> > [   21.097128]    __lock_acquire+0x420/0x16d4
> > [   21.101239]    lock_acquire+0x260/0x29c
> > [   21.105091]    _raw_spin_lock+0x48/0x58
> > [   21.108940]    snd_pcm_stream_lock+0x54/0x60
> > [   21.113226]    _snd_pcm_stream_lock_irqsave+0x40/0x48
> > [   21.118296]    snd_pcm_period_elapsed+0x2c/0xa4
> > [   21.122841]    dmaengine_pcm_dma_complete+0x54/0x58
> > [   21.127735]    sdma_int_handler+0x1dc/0x2a8
> > [   21.131937]    __handle_irq_event_percpu+0x1fc/0x498
> > [   21.136915]    handle_irq_event_percpu+0x38/0x8c
> > [   21.141547]    handle_irq_event+0x48/0x6c
> > [   21.145570]    handle_fasteoi_irq+0xc4/0x138
> > [   21.149854]    generic_handle_irq+0x28/0x38
> > [   21.154052]    __handle_domain_irq+0xb0/0xc4
> > [   21.158335]    gic_handle_irq+0x68/0xa0
> > [   21.162184]    __irq_svc+0x70/0xb0
> > [   21.165601]    _raw_spin_unlock_irq+0x38/0x6c
> > [   21.169973]    task_work_run+0x90/0xb8
> > [   21.173735]    do_work_pending+0xc8/0xd0
> > [   21.177670]    slow_work_pending+0xc/0x20
> > [   21.181691]    0x76c77e86
> > [   21.184320] 
> > [   21.185821] 
> > [   21.185821] stack backtrace:
> > [   21.190198] CPU: 0 PID: 1 Comm: systemd Not tainted 4.17.0+
> > #1538
> > [   21.196303] Hardware name: Freescale i.MX6 Quad/DualLite (Device
> > Tree)
> > [   21.202841] Backtrace: 
> > [   21.205314] [<8010e318>] (dump_backtrace) from [<8010e604>]
> > (show_stack+0x20/0x24)
> > [   21.212900]  r7:80e9f3d0 r6:00000000 r5:60070193 r4:80e9f3d0
> > [   21.218581] [<8010e5e4>] (show_stack) from [<8099b660>]
> > (dump_stack+0xa4/0xd8)
> > [   21.225825] [<8099b5bc>] (dump_stack) from [<8017b52c>]
> > (print_irq_inversion_bug+0x15c/0x1fc)
> > [   21.234368]  r9:814da818 r8:00000001 r7:ee926c00 r6:00000000
> > r5:ee915bb0 r4:814da818
> > [   21.242133] [<8017b3d0>] (print_irq_inversion_bug) from
> > [<8017b6dc>] (check_usage_forwards+0x110/0x13c)
> > [   21.251544]  r9:00000002 r8:80bfd3e2 r7:ee926c00 r6:ee927148
> > r5:80e08488 r4:00000001
> > [   21.259306] [<8017b5cc>] (check_usage_forwards) from
> > [<8017c2a4>]
> > (mark_lock+0x3a4/0x69c)
> > [   21.267500]  r9:ee926c00 r8:80a03cd8 r7:00000101 r6:00000002
> > r5:00000000 r4:ee927148
> > [   21.275263] [<8017bf00>] (mark_lock) from [<8017cf68>]
> > (__lock_acquire+0x420/0x16d4)
> > [   21.283023]  r10:ee927148 r9:ed4620e4 r8:ee926c00 r7:00000000
> > r6:00000001 r5:00000001
> > [   21.290863]  r4:00000490
> > [   21.293416] [<8017cb48>] (__lock_acquire) from [<8017ed58>]
> > (lock_acquire+0x260/0x29c)
> > [   21.301350]  r10:00000001 r9:80e084a4 r8:00000000 r7:00000000
> > r6:00000000 r5:ed4620e4
> > [   21.309189]  r4:00000000
> > [   21.311746] [<8017eaf8>] (lock_acquire) from [<809b74f0>]
> > (_raw_spin_lock+0x48/0x58)
> > [   21.319506]  r10:ee0a4714 r9:ed457100 r8:ee0a46c8 r7:ee0a4714
> > r6:ee0a4010 r5:807847b0
> > [   21.327346]  r4:ed4620d4
> > [   21.329902] [<809b74a8>] (_raw_spin_lock) from [<807847b0>]
> > (snd_pcm_stream_lock+0x54/0x60)
> > [   21.338265]  r5:ed462000 r4:ed462000
> > [   21.341863] [<8078475c>] (snd_pcm_stream_lock) from [<80784838>]
> > (_snd_pcm_stream_lock_irqsave+0x40/0x48)
> > [   21.351440]  r5:ed462000 r4:60070193
> > [   21.355042] [<807847f8>] (_snd_pcm_stream_lock_irqsave) from
> > [<8078b044>] (snd_pcm_period_elapsed+0x2c/0xa4)
> > [   21.364881]  r5:ee3ef000 r4:ed462000
> > [   21.368478] [<8078b018>] (snd_pcm_period_elapsed) from
> > [<8078d7b4>] (dmaengine_pcm_dma_complete+0x54/0x58)
> > [   21.378148]  r7:ee0a4714 r6:ee0a4010 r5:00000007 r4:ee0a46bc
> > [   21.383827] [<8078d760>] (dmaengine_pcm_dma_complete) from
> > [<80504c0c>] (sdma_int_handler+0x1dc/0x2a8)
> > [   21.393157] [<80504a30>] (sdma_int_handler) from [<8018cd28>]
> > (__handle_irq_event_percpu+0x1fc/0x498)
> > [   21.402393]  r10:00000000 r9:eeafd400 r8:80e084a4 r7:00000038
> > r6:00000038 r5:80ea3c12
> > [   21.410233]  r4:ee2b5d40
> > [   21.412787] [<8018cb2c>] (__handle_irq_event_percpu) from
> > [<8018cffc>] (handle_irq_event_percpu+0x38/0x8c)
> > [   21.422457]  r10:00000000 r9:ee914000 r8:ee81d400 r7:00000038
> > r6:eeafd400 r5:eeafd464
> > [   21.430296]  r4:80e08488
> > [   21.432852] [<8018cfc4>] (handle_irq_event_percpu) from
> > [<8018d098>] (handle_irq_event+0x48/0x6c)
> > [   21.441736]  r6:eeafd464 r5:eeafd464 r4:eeafd400
> > [   21.446374] [<8018d050>] (handle_irq_event) from [<8019146c>]
> > (handle_fasteoi_irq+0xc4/0x138)
> > [   21.454912]  r7:00000038 r6:eeafd464 r5:80e10a60 r4:eeafd400
> > [   21.460589] [<801913a8>] (handle_fasteoi_irq) from [<8018bd9c>]
> > (generic_handle_irq+0x28/0x38)
> > [   21.469214]  r7:00000038 r6:80d92ae4 r5:00000000 r4:00000000
> > [   21.474893] [<8018bd74>] (generic_handle_irq) from [<8018c48c>]
> > (__handle_domain_irq+0xb0/0xc4)
> > [   21.483611] [<8018c3dc>] (__handle_domain_irq) from [<80102330>]
> > (gic_handle_irq+0x68/0xa0)
> > [   21.491978]  r9:ee914000 r8:f4001100 r7:80e5c6bc r6:ee915f00
> > r5:80e08c3c r4:f4000100
> > [   21.499738] [<801022c8>] (gic_handle_irq) from [<801019f0>]
> > (__irq_svc+0x70/0xb0)
> > [   21.507233] Exception stack(0xee915f00 to 0xee915f48)
> > [   21.512303] 5f00: 00000001 00000004 00000000 ee926c00 ee9270a8
> > ee926c00 ecc45e00 ee9270a8
> > [   21.520498] 5f20: 80ec23b0 ee914000 00000000 ee915f64 ee915f20
> > ee915f50 8017c7c0 809b78ac
> > [   21.528687] 5f40: 20070013 ffffffff
> > [   21.532193]  r9:ee914000 r8:80ec23b0 r7:ee915f34 r6:ffffffff
> > r5:20070013 r4:809b78ac
> > [   21.539959] [<809b7874>] (_raw_spin_unlock_irq) from
> > [<8014e98c>]
> > (task_work_run+0x90/0xb8)
> > [   21.548321]  r5:ee926c00 r4:ecc45e00
> > [   21.551913] [<8014e8fc>] (task_work_run) from [<8010da3c>]
> > (do_work_pending+0xc8/0xd0)
> > [   21.559848]  r9:ee914000 r8:801011c4 r7:ee915fb0 r6:ffffe000
> > r5:00000004 r4:801011c4
> > [   21.567608] [<8010d974>] (do_work_pending) from [<80101034>]
> > (slow_work_pending+0xc/0x20)
> > [   21.575797] Exception stack(0xee915fb0 to 0xee915ff8)
> > [   21.580864] 5fa0:                                     00000000
> > 020c34e8 46059f00 00000000
> > [   21.589059] 5fc0: 00000002 76f133a4 020df680 00000006 76e6e168
> > 00000035 7ef81778 00000035
> > [   21.597253] 5fe0: 00000006 7ef816a0 76c75d67 76c77e86 20070030
> > 00000039
> > [   21.603883]  r7:00000006 r6:020df680 r5:76f133a4 r4:00000002
> > 
> > Am Donnerstag, den 14.06.2018, 22:02 +0800 schrieb Robin Gong:
> > > 
> > > The legacy sdma driver has below limitations or drawbacks:
> > >   1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and
> > > alloc
> > >      one page size for one channel regardless of only few BDs
> > > needed
> > >      most time. But in few cases, the max PAGE_SIZE maybe not
> > > enough.
> > >   2. One SDMA channel can't stop immediatley once channel
> > > disabled
> > > which
> > >      means SDMA interrupt may come in after this channel
> > > terminated.There
> > >      are some patches for this corner case such as commit
> > > "2746e2c389f9",
> > >      but not cover non-cyclic.
> > > 
> > > The common virt-dma overcomes the above limitations. It can alloc
> > > bd
> > > dynamically and free bd once this tx transfer done. No memory
> > > wasted or
> > > maximum limititation here, only depends on how many memory can be
> > > requested
> > > from kernel. For No.2, such issue can be workaround by checking
> > > if
> > > there
> > > is available descript("sdmac->desc") now once the unwanted
> > > interrupt
> > > coming. At last the common virt-dma is easier for sdma driver
> > > maintain.
> > > 
> > > Change from v3:
> > >   1. add two uart patches which impacted by this patchset.
> > >   2. unlock 'vc.lock' before cyclic dma callback and lock again
> > > after
> > >      it because some driver such as uart will call
> > > dmaengine_tx_status
> > >      which will acquire 'vc.lock' again and dead lock comes out.
> > >   3. remove 'Revert commit' stuff since that patch is not wrong
> > > and
> > >      combine two patch into one patch as Sascha's comment.
> > > 
> > > Change from v2:
> > >   1. include Sascha's patch to make the main patch easier to
> > > review.
> > >      Thanks Sacha.
> > >   2. remove useless 'desc'/'chan' in struct sdma_channe.
> > > 
> > > Change from v1:
> > >   1. split v1 patch into 5 patches.
> > >   2. remove some unnecessary condition check.
> > >   3. remove unnecessary 'pending' list.
> > > 
> > > Robin Gong (6):
> > >   tty: serial: imx: correct dma cookie status
> > >   dmaengine: imx-sdma: add virt-dma support
> > >   dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in
> > > 'struct
> > >     sdma_channel'
> > >   dmaengine: imx-sdma: remove the maximum limitation for bd
> > > numbers
> > >   dmaengine: imx-sdma: add sdma_transfer_init to decrease code
> > > overlap
> > >   tty: serial: imx: split all dma setup operations out of
> > > 'port.lock'
> > >     protector
> > > 
> > > Sascha Hauer (1):
> > >   dmaengine: imx-sdma: factor out a struct sdma_desc from struct
> > >     sdma_channel
> > > 
> > >  drivers/dma/Kconfig      |   1 +
> > >  drivers/dma/imx-sdma.c   | 394 +++++++++++++++++++++++++++------
> > > --------------
> > >  drivers/tty/serial/imx.c |  99 ++++++------
> > >  3 files changed, 282 insertions(+), 212 deletions(-)

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

* Re: [PATCH v4 0/7] add virt-dma support for imx-sdma
  2018-06-14  8:53 ` Lucas Stach
@ 2018-06-14 10:09   ` Robin Gong
  2018-06-14 10:22     ` Lucas Stach
  0 siblings, 1 reply; 13+ messages in thread
From: Robin Gong @ 2018-06-14 10:09 UTC (permalink / raw)
  To: l.stach, s.hauer, vkoul, dan.j.williams, gregkh, jslaby
  Cc: dmaengine, linux-kernel, linux-arm-kernel, dl-linux-imx, linux-serial

Hi Lucas,
	Could you double check again? Still can reproduce lockdep
warning on UART if change
spin_lock_lockirqsave/spinlock_unlock_irqrestore to
spin_lock/spin_unlock in sdma_int_handler as you said without patch7/7.
Would you please ask below two more questions?
1. Does your uart case pass now with my v4 patchset?
2. Do you make some code change in your local('I just gave this series
a spin')to reproduce your below issue? If yes, could you post your
change?

On 四, 2018-06-14 at 10:53 +0200, Lucas Stach wrote:
> Hi Robin,
> 
> I just gave this series a spin and it seems there is even more
> locking
> fun, see the lockdep output below. After taking a short look it seems
> this is caused by using the wrong spinlock variants in
> sdma_int_handler(), those should also use the _irqsave ones. When
> fixing this you might want to reconsider patch 7/7, as it's probably
> not needed at all.
> 
> Regards,
> Lucas
> 
> [   20.479401]
> ========================================================
> [   20.485769] WARNING: possible irq lock inversion dependency
> detected
> [   20.492140] 4.17.0+ #1538 Not tainted
> [   20.495814] ------------------------------------------------------
> --
> [   20.502181] systemd/1 just changed the state of lock:
> [   20.507247] c0abdafc (&(&substream->self_group.lock)->rlock){-
> ...}, at: snd_pcm_stream_lock+0x54/0x60
> [   20.516523] but this lock took another, HARDIRQ-unsafe lock in the
> past:
> [   20.523234]  (fs_reclaim){+.+.}
> [   20.523253] 
> [   20.523253] 
> [   20.523253] and interrupts could create inverse lock ordering
> between them.
> [   20.523253] 
> [   20.537804] 
> [   20.537804] other info that might help us debug this:
> [   20.544344]  Possible interrupt unsafe locking scenario:
> [   20.544344] 
> [   20.551144]        CPU0                    CPU1
> [   20.555686]        ----                    ----
> [   20.560224]   lock(fs_reclaim);
> [   20.563386]                                local_irq_disable();
> [   20.569315]                                lock(&(&substream-
> >self_group.lock)->rlock);
> [   20.577337]                                lock(fs_reclaim);
> [   20.583014]   <Interrupt>
> [   20.585643]     lock(&(&substream->self_group.lock)->rlock);
> [   20.591322] 
> [   20.591322]  *** DEADLOCK ***
> [   20.591322] 
> [   20.597260] 1 lock held by systemd/1:
> [   20.607806]  #0: ab23d11c (snd_pcm_link_rwlock){.-..}, at:
> snd_pcm_stream_lock+0x4c/0x60
> [   20.615951] 
> [   20.615951] the shortest dependencies between 2nd lock and 1st
> lock:
> [   20.623799]  -> (fs_reclaim){+.+.} ops: 248474 {
> [   20.628456]     HARDIRQ-ON-W at:
> [   20.631716]                       lock_acquire+0x260/0x29c
> [   20.637223]                       fs_reclaim_acquire+0x48/0x58
> [   20.643075]                       kmem_cache_alloc_trace+0x3c/0x36
> 4
> [   20.649366]                       alloc_worker.constprop.15+0x28/0
> x64
> [   20.655824]                       init_rescuer.part.5+0x20/0xa4
> [   20.661764]                       workqueue_init+0x124/0x1f8
> [   20.667446]                       kernel_init_freeable+0x60/0x550
> [   20.673561]                       kernel_init+0x18/0x120
> [   20.678890]                       ret_from_fork+0x14/0x20
> [   20.684299]                         (null)
> [   20.688408]     SOFTIRQ-ON-W at:
> [   20.691659]                       lock_acquire+0x260/0x29c
> [   20.697158]                       fs_reclaim_acquire+0x48/0x58
> [   20.703006]                       kmem_cache_alloc_trace+0x3c/0x36
> 4
> [   20.709288]                       alloc_worker.constprop.15+0x28/0
> x64
> [   20.709301]                       init_rescuer.part.5+0x20/0xa4
> [   20.720717]                       workqueue_init+0x124/0x1f8
> [   20.720729]                       kernel_init_freeable+0x60/0x550
> [   20.720738]                       kernel_init+0x18/0x120
> [   20.720746]                       ret_from_fork+0x14/0x20
> [   20.720751]                         (null)
> [   20.720756]     INITIAL USE at:
> [   20.720770]                      lock_acquire+0x260/0x29c
> [   20.720782]                      fs_reclaim_acquire+0x48/0x58
> [   20.774374]                      kmem_cache_alloc_trace+0x3c/0x364
> [   20.780574]                      alloc_worker.constprop.15+0x28/0x
> 64
> [   20.786945]                      init_rescuer.part.5+0x20/0xa4
> [   20.792794]                      workqueue_init+0x124/0x1f8
> [   20.798384]                      kernel_init_freeable+0x60/0x550
> [   20.804406]                      kernel_init+0x18/0x120
> [   20.809648]                      ret_from_fork+0x14/0x20
> [   20.814971]                        (null)
> [   20.818992]   }
> [   20.820768]   ... key      at: [<80e22074>]
> __fs_reclaim_map+0x0/0x10
> [   20.827220]   ... acquired at:
> [   20.830289]    fs_reclaim_acquire+0x48/0x58
> [   20.834487]    kmem_cache_alloc_trace+0x3c/0x364
> [   20.839123]    sdma_transfer_init+0x44/0x130
> [   20.843409]    sdma_prep_dma_cyclic+0x78/0x21c
> [   20.847869]    snd_dmaengine_pcm_trigger+0xdc/0x184
> [   20.852764]    soc_pcm_trigger+0x164/0x190
> [   20.856876]    snd_pcm_do_start+0x34/0x40
> [   20.860902]    snd_pcm_action_single+0x48/0x74
> [   20.865360]    snd_pcm_action+0x34/0xfc
> [   20.869213]    snd_pcm_ioctl+0x910/0x10ec
> [   20.873241]    vfs_ioctl+0x30/0x44
> [   20.876657]    do_vfs_ioctl+0xac/0x974
> [   20.880421]    ksys_ioctl+0x48/0x64
> [   20.883923]    sys_ioctl+0x18/0x1c
> [   20.887340]    ret_fast_syscall+0x0/0x28
> [   20.891277]    0x7289bcbc
> [   20.893909] 
> [   20.895410] -> (&(&substream->self_group.lock)->rlock){-...} ops:
> 59 {
> [   20.901977]    IN-HARDIRQ-W at:
> [   20.905143]                     lock_acquire+0x260/0x29c
> [   20.910473]                     _raw_spin_lock+0x48/0x58
> [   20.915801]                     snd_pcm_stream_lock+0x54/0x60
> [   20.921561]                     _snd_pcm_stream_lock_irqsave+0x40/
> 0x48
> [   20.928107]                     snd_pcm_period_elapsed+0x2c/0xa4
> [   20.934127]                     dmaengine_pcm_dma_complete+0x54/0x
> 58
> [   20.940498]                     sdma_int_handler+0x1dc/0x2a8
> [   20.946179]                     __handle_irq_event_percpu+0x1fc/0x
> 498
> [   20.952635]                     handle_irq_event_percpu+0x38/0x8c
> [   20.958742]                     handle_irq_event+0x48/0x6c
> [   20.964242]                     handle_fasteoi_irq+0xc4/0x138
> [   20.970006]                     generic_handle_irq+0x28/0x38
> [   20.975681]                     __handle_domain_irq+0xb0/0xc4
> [   20.981443]                     gic_handle_irq+0x68/0xa0
> [   20.986769]                     __irq_svc+0x70/0xb0
> [   20.991662]                     _raw_spin_unlock_irq+0x38/0x6c
> [   20.997511]                     task_work_run+0x90/0xb8
> [   21.002751]                     do_work_pending+0xc8/0xd0
> [   21.008164]                     slow_work_pending+0xc/0x20
> [   21.013661]                     0x76c77e86
> [   21.017768]    INITIAL USE at:
> [   21.020844]                    lock_acquire+0x260/0x29c
> [   21.026086]                    _raw_spin_lock+0x48/0x58
> [   21.031328]                    snd_pcm_stream_lock+0x54/0x60
> [   21.037002]                    snd_pcm_stream_lock_irq+0x38/0x3c
> [   21.043023]                    snd_pcm_sync_ptr+0x214/0x260
> [   21.048609]                    snd_pcm_ioctl+0xbe0/0x10ec
> [   21.054027]                    vfs_ioctl+0x30/0x44
> [   21.058832]                    do_vfs_ioctl+0xac/0x974
> [   21.063984]                    ksys_ioctl+0x48/0x64
> [   21.068875]                    sys_ioctl+0x18/0x1c
> [   21.073679]                    ret_fast_syscall+0x0/0x28
> [   21.079004]                    0x7e9026dc
> [   21.083023]  }
> [   21.084710]  ... key      at: [<8162a6e4>] __key.31798+0x0/0x8
> [   21.090552]  ... acquired at:
> [   21.093537]    mark_lock+0x3a4/0x69c
> [   21.097128]    __lock_acquire+0x420/0x16d4
> [   21.101239]    lock_acquire+0x260/0x29c
> [   21.105091]    _raw_spin_lock+0x48/0x58
> [   21.108940]    snd_pcm_stream_lock+0x54/0x60
> [   21.113226]    _snd_pcm_stream_lock_irqsave+0x40/0x48
> [   21.118296]    snd_pcm_period_elapsed+0x2c/0xa4
> [   21.122841]    dmaengine_pcm_dma_complete+0x54/0x58
> [   21.127735]    sdma_int_handler+0x1dc/0x2a8
> [   21.131937]    __handle_irq_event_percpu+0x1fc/0x498
> [   21.136915]    handle_irq_event_percpu+0x38/0x8c
> [   21.141547]    handle_irq_event+0x48/0x6c
> [   21.145570]    handle_fasteoi_irq+0xc4/0x138
> [   21.149854]    generic_handle_irq+0x28/0x38
> [   21.154052]    __handle_domain_irq+0xb0/0xc4
> [   21.158335]    gic_handle_irq+0x68/0xa0
> [   21.162184]    __irq_svc+0x70/0xb0
> [   21.165601]    _raw_spin_unlock_irq+0x38/0x6c
> [   21.169973]    task_work_run+0x90/0xb8
> [   21.173735]    do_work_pending+0xc8/0xd0
> [   21.177670]    slow_work_pending+0xc/0x20
> [   21.181691]    0x76c77e86
> [   21.184320] 
> [   21.185821] 
> [   21.185821] stack backtrace:
> [   21.190198] CPU: 0 PID: 1 Comm: systemd Not tainted 4.17.0+ #1538
> [   21.196303] Hardware name: Freescale i.MX6 Quad/DualLite (Device
> Tree)
> [   21.202841] Backtrace: 
> [   21.205314] [<8010e318>] (dump_backtrace) from [<8010e604>]
> (show_stack+0x20/0x24)
> [   21.212900]  r7:80e9f3d0 r6:00000000 r5:60070193 r4:80e9f3d0
> [   21.218581] [<8010e5e4>] (show_stack) from [<8099b660>]
> (dump_stack+0xa4/0xd8)
> [   21.225825] [<8099b5bc>] (dump_stack) from [<8017b52c>]
> (print_irq_inversion_bug+0x15c/0x1fc)
> [   21.234368]  r9:814da818 r8:00000001 r7:ee926c00 r6:00000000
> r5:ee915bb0 r4:814da818
> [   21.242133] [<8017b3d0>] (print_irq_inversion_bug) from
> [<8017b6dc>] (check_usage_forwards+0x110/0x13c)
> [   21.251544]  r9:00000002 r8:80bfd3e2 r7:ee926c00 r6:ee927148
> r5:80e08488 r4:00000001
> [   21.259306] [<8017b5cc>] (check_usage_forwards) from [<8017c2a4>]
> (mark_lock+0x3a4/0x69c)
> [   21.267500]  r9:ee926c00 r8:80a03cd8 r7:00000101 r6:00000002
> r5:00000000 r4:ee927148
> [   21.275263] [<8017bf00>] (mark_lock) from [<8017cf68>]
> (__lock_acquire+0x420/0x16d4)
> [   21.283023]  r10:ee927148 r9:ed4620e4 r8:ee926c00 r7:00000000
> r6:00000001 r5:00000001
> [   21.290863]  r4:00000490
> [   21.293416] [<8017cb48>] (__lock_acquire) from [<8017ed58>]
> (lock_acquire+0x260/0x29c)
> [   21.301350]  r10:00000001 r9:80e084a4 r8:00000000 r7:00000000
> r6:00000000 r5:ed4620e4
> [   21.309189]  r4:00000000
> [   21.311746] [<8017eaf8>] (lock_acquire) from [<809b74f0>]
> (_raw_spin_lock+0x48/0x58)
> [   21.319506]  r10:ee0a4714 r9:ed457100 r8:ee0a46c8 r7:ee0a4714
> r6:ee0a4010 r5:807847b0
> [   21.327346]  r4:ed4620d4
> [   21.329902] [<809b74a8>] (_raw_spin_lock) from [<807847b0>]
> (snd_pcm_stream_lock+0x54/0x60)
> [   21.338265]  r5:ed462000 r4:ed462000
> [   21.341863] [<8078475c>] (snd_pcm_stream_lock) from [<80784838>]
> (_snd_pcm_stream_lock_irqsave+0x40/0x48)
> [   21.351440]  r5:ed462000 r4:60070193
> [   21.355042] [<807847f8>] (_snd_pcm_stream_lock_irqsave) from
> [<8078b044>] (snd_pcm_period_elapsed+0x2c/0xa4)
> [   21.364881]  r5:ee3ef000 r4:ed462000
> [   21.368478] [<8078b018>] (snd_pcm_period_elapsed) from
> [<8078d7b4>] (dmaengine_pcm_dma_complete+0x54/0x58)
> [   21.378148]  r7:ee0a4714 r6:ee0a4010 r5:00000007 r4:ee0a46bc
> [   21.383827] [<8078d760>] (dmaengine_pcm_dma_complete) from
> [<80504c0c>] (sdma_int_handler+0x1dc/0x2a8)
> [   21.393157] [<80504a30>] (sdma_int_handler) from [<8018cd28>]
> (__handle_irq_event_percpu+0x1fc/0x498)
> [   21.402393]  r10:00000000 r9:eeafd400 r8:80e084a4 r7:00000038
> r6:00000038 r5:80ea3c12
> [   21.410233]  r4:ee2b5d40
> [   21.412787] [<8018cb2c>] (__handle_irq_event_percpu) from
> [<8018cffc>] (handle_irq_event_percpu+0x38/0x8c)
> [   21.422457]  r10:00000000 r9:ee914000 r8:ee81d400 r7:00000038
> r6:eeafd400 r5:eeafd464
> [   21.430296]  r4:80e08488
> [   21.432852] [<8018cfc4>] (handle_irq_event_percpu) from
> [<8018d098>] (handle_irq_event+0x48/0x6c)
> [   21.441736]  r6:eeafd464 r5:eeafd464 r4:eeafd400
> [   21.446374] [<8018d050>] (handle_irq_event) from [<8019146c>]
> (handle_fasteoi_irq+0xc4/0x138)
> [   21.454912]  r7:00000038 r6:eeafd464 r5:80e10a60 r4:eeafd400
> [   21.460589] [<801913a8>] (handle_fasteoi_irq) from [<8018bd9c>]
> (generic_handle_irq+0x28/0x38)
> [   21.469214]  r7:00000038 r6:80d92ae4 r5:00000000 r4:00000000
> [   21.474893] [<8018bd74>] (generic_handle_irq) from [<8018c48c>]
> (__handle_domain_irq+0xb0/0xc4)
> [   21.483611] [<8018c3dc>] (__handle_domain_irq) from [<80102330>]
> (gic_handle_irq+0x68/0xa0)
> [   21.491978]  r9:ee914000 r8:f4001100 r7:80e5c6bc r6:ee915f00
> r5:80e08c3c r4:f4000100
> [   21.499738] [<801022c8>] (gic_handle_irq) from [<801019f0>]
> (__irq_svc+0x70/0xb0)
> [   21.507233] Exception stack(0xee915f00 to 0xee915f48)
> [   21.512303] 5f00: 00000001 00000004 00000000 ee926c00 ee9270a8
> ee926c00 ecc45e00 ee9270a8
> [   21.520498] 5f20: 80ec23b0 ee914000 00000000 ee915f64 ee915f20
> ee915f50 8017c7c0 809b78ac
> [   21.528687] 5f40: 20070013 ffffffff
> [   21.532193]  r9:ee914000 r8:80ec23b0 r7:ee915f34 r6:ffffffff
> r5:20070013 r4:809b78ac
> [   21.539959] [<809b7874>] (_raw_spin_unlock_irq) from [<8014e98c>]
> (task_work_run+0x90/0xb8)
> [   21.548321]  r5:ee926c00 r4:ecc45e00
> [   21.551913] [<8014e8fc>] (task_work_run) from [<8010da3c>]
> (do_work_pending+0xc8/0xd0)
> [   21.559848]  r9:ee914000 r8:801011c4 r7:ee915fb0 r6:ffffe000
> r5:00000004 r4:801011c4
> [   21.567608] [<8010d974>] (do_work_pending) from [<80101034>]
> (slow_work_pending+0xc/0x20)
> [   21.575797] Exception stack(0xee915fb0 to 0xee915ff8)
> [   21.580864] 5fa0:                                     00000000
> 020c34e8 46059f00 00000000
> [   21.589059] 5fc0: 00000002 76f133a4 020df680 00000006 76e6e168
> 00000035 7ef81778 00000035
> [   21.597253] 5fe0: 00000006 7ef816a0 76c75d67 76c77e86 20070030
> 00000039
> [   21.603883]  r7:00000006 r6:020df680 r5:76f133a4 r4:00000002
> 
> Am Donnerstag, den 14.06.2018, 22:02 +0800 schrieb Robin Gong:
> > 
> > The legacy sdma driver has below limitations or drawbacks:
> >   1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and
> > alloc
> >      one page size for one channel regardless of only few BDs
> > needed
> >      most time. But in few cases, the max PAGE_SIZE maybe not
> > enough.
> >   2. One SDMA channel can't stop immediatley once channel disabled
> > which
> >      means SDMA interrupt may come in after this channel
> > terminated.There
> >      are some patches for this corner case such as commit
> > "2746e2c389f9",
> >      but not cover non-cyclic.
> > 
> > The common virt-dma overcomes the above limitations. It can alloc
> > bd
> > dynamically and free bd once this tx transfer done. No memory
> > wasted or
> > maximum limititation here, only depends on how many memory can be
> > requested
> > from kernel. For No.2, such issue can be workaround by checking if
> > there
> > is available descript("sdmac->desc") now once the unwanted
> > interrupt
> > coming. At last the common virt-dma is easier for sdma driver
> > maintain.
> > 
> > Change from v3:
> >   1. add two uart patches which impacted by this patchset.
> >   2. unlock 'vc.lock' before cyclic dma callback and lock again
> > after
> >      it because some driver such as uart will call
> > dmaengine_tx_status
> >      which will acquire 'vc.lock' again and dead lock comes out.
> >   3. remove 'Revert commit' stuff since that patch is not wrong and
> >      combine two patch into one patch as Sascha's comment.
> > 
> > Change from v2:
> >   1. include Sascha's patch to make the main patch easier to
> > review.
> >      Thanks Sacha.
> >   2. remove useless 'desc'/'chan' in struct sdma_channe.
> > 
> > Change from v1:
> >   1. split v1 patch into 5 patches.
> >   2. remove some unnecessary condition check.
> >   3. remove unnecessary 'pending' list.
> > 
> > Robin Gong (6):
> >   tty: serial: imx: correct dma cookie status
> >   dmaengine: imx-sdma: add virt-dma support
> >   dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in
> > 'struct
> >     sdma_channel'
> >   dmaengine: imx-sdma: remove the maximum limitation for bd numbers
> >   dmaengine: imx-sdma: add sdma_transfer_init to decrease code
> > overlap
> >   tty: serial: imx: split all dma setup operations out of
> > 'port.lock'
> >     protector
> > 
> > Sascha Hauer (1):
> >   dmaengine: imx-sdma: factor out a struct sdma_desc from struct
> >     sdma_channel
> > 
> >  drivers/dma/Kconfig      |   1 +
> >  drivers/dma/imx-sdma.c   | 394 +++++++++++++++++++++++++++------
> > --------------
> >  drivers/tty/serial/imx.c |  99 ++++++------
> >  3 files changed, 282 insertions(+), 212 deletions(-)
> > 

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

* Re: [PATCH v4 0/7] add virt-dma support for imx-sdma
  2018-06-14 14:02 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
@ 2018-06-14  8:53 ` Lucas Stach
  2018-06-14 10:09   ` Robin Gong
  0 siblings, 1 reply; 13+ messages in thread
From: Lucas Stach @ 2018-06-14  8:53 UTC (permalink / raw)
  To: Robin Gong, vkoul, s.hauer, dan.j.williams, gregkh, jslaby
  Cc: dmaengine, linux-imx, linux-kernel, linux-serial, linux-arm-kernel

Hi Robin,

I just gave this series a spin and it seems there is even more locking
fun, see the lockdep output below. After taking a short look it seems
this is caused by using the wrong spinlock variants in
sdma_int_handler(), those should also use the _irqsave ones. When
fixing this you might want to reconsider patch 7/7, as it's probably
not needed at all.

Regards,
Lucas

[   20.479401] ========================================================
[   20.485769] WARNING: possible irq lock inversion dependency detected
[   20.492140] 4.17.0+ #1538 Not tainted
[   20.495814] --------------------------------------------------------
[   20.502181] systemd/1 just changed the state of lock:
[   20.507247] c0abdafc (&(&substream->self_group.lock)->rlock){-...}, at: snd_pcm_stream_lock+0x54/0x60
[   20.516523] but this lock took another, HARDIRQ-unsafe lock in the past:
[   20.523234]  (fs_reclaim){+.+.}
[   20.523253] 
[   20.523253] 
[   20.523253] and interrupts could create inverse lock ordering between them.
[   20.523253] 
[   20.537804] 
[   20.537804] other info that might help us debug this:
[   20.544344]  Possible interrupt unsafe locking scenario:
[   20.544344] 
[   20.551144]        CPU0                    CPU1
[   20.555686]        ----                    ----
[   20.560224]   lock(fs_reclaim);
[   20.563386]                                local_irq_disable();
[   20.569315]                                lock(&(&substream->self_group.lock)->rlock);
[   20.577337]                                lock(fs_reclaim);
[   20.583014]   <Interrupt>
[   20.585643]     lock(&(&substream->self_group.lock)->rlock);
[   20.591322] 
[   20.591322]  *** DEADLOCK ***
[   20.591322] 
[   20.597260] 1 lock held by systemd/1:
[   20.607806]  #0: ab23d11c (snd_pcm_link_rwlock){.-..}, at: snd_pcm_stream_lock+0x4c/0x60
[   20.615951] 
[   20.615951] the shortest dependencies between 2nd lock and 1st lock:
[   20.623799]  -> (fs_reclaim){+.+.} ops: 248474 {
[   20.628456]     HARDIRQ-ON-W at:
[   20.631716]                       lock_acquire+0x260/0x29c
[   20.637223]                       fs_reclaim_acquire+0x48/0x58
[   20.643075]                       kmem_cache_alloc_trace+0x3c/0x364
[   20.649366]                       alloc_worker.constprop.15+0x28/0x64
[   20.655824]                       init_rescuer.part.5+0x20/0xa4
[   20.661764]                       workqueue_init+0x124/0x1f8
[   20.667446]                       kernel_init_freeable+0x60/0x550
[   20.673561]                       kernel_init+0x18/0x120
[   20.678890]                       ret_from_fork+0x14/0x20
[   20.684299]                         (null)
[   20.688408]     SOFTIRQ-ON-W at:
[   20.691659]                       lock_acquire+0x260/0x29c
[   20.697158]                       fs_reclaim_acquire+0x48/0x58
[   20.703006]                       kmem_cache_alloc_trace+0x3c/0x364
[   20.709288]                       alloc_worker.constprop.15+0x28/0x64
[   20.709301]                       init_rescuer.part.5+0x20/0xa4
[   20.720717]                       workqueue_init+0x124/0x1f8
[   20.720729]                       kernel_init_freeable+0x60/0x550
[   20.720738]                       kernel_init+0x18/0x120
[   20.720746]                       ret_from_fork+0x14/0x20
[   20.720751]                         (null)
[   20.720756]     INITIAL USE at:
[   20.720770]                      lock_acquire+0x260/0x29c
[   20.720782]                      fs_reclaim_acquire+0x48/0x58
[   20.774374]                      kmem_cache_alloc_trace+0x3c/0x364
[   20.780574]                      alloc_worker.constprop.15+0x28/0x64
[   20.786945]                      init_rescuer.part.5+0x20/0xa4
[   20.792794]                      workqueue_init+0x124/0x1f8
[   20.798384]                      kernel_init_freeable+0x60/0x550
[   20.804406]                      kernel_init+0x18/0x120
[   20.809648]                      ret_from_fork+0x14/0x20
[   20.814971]                        (null)
[   20.818992]   }
[   20.820768]   ... key      at: [<80e22074>] __fs_reclaim_map+0x0/0x10
[   20.827220]   ... acquired at:
[   20.830289]    fs_reclaim_acquire+0x48/0x58
[   20.834487]    kmem_cache_alloc_trace+0x3c/0x364
[   20.839123]    sdma_transfer_init+0x44/0x130
[   20.843409]    sdma_prep_dma_cyclic+0x78/0x21c
[   20.847869]    snd_dmaengine_pcm_trigger+0xdc/0x184
[   20.852764]    soc_pcm_trigger+0x164/0x190
[   20.856876]    snd_pcm_do_start+0x34/0x40
[   20.860902]    snd_pcm_action_single+0x48/0x74
[   20.865360]    snd_pcm_action+0x34/0xfc
[   20.869213]    snd_pcm_ioctl+0x910/0x10ec
[   20.873241]    vfs_ioctl+0x30/0x44
[   20.876657]    do_vfs_ioctl+0xac/0x974
[   20.880421]    ksys_ioctl+0x48/0x64
[   20.883923]    sys_ioctl+0x18/0x1c
[   20.887340]    ret_fast_syscall+0x0/0x28
[   20.891277]    0x7289bcbc
[   20.893909] 
[   20.895410] -> (&(&substream->self_group.lock)->rlock){-...} ops: 59 {
[   20.901977]    IN-HARDIRQ-W at:
[   20.905143]                     lock_acquire+0x260/0x29c
[   20.910473]                     _raw_spin_lock+0x48/0x58
[   20.915801]                     snd_pcm_stream_lock+0x54/0x60
[   20.921561]                     _snd_pcm_stream_lock_irqsave+0x40/0x48
[   20.928107]                     snd_pcm_period_elapsed+0x2c/0xa4
[   20.934127]                     dmaengine_pcm_dma_complete+0x54/0x58
[   20.940498]                     sdma_int_handler+0x1dc/0x2a8
[   20.946179]                     __handle_irq_event_percpu+0x1fc/0x498
[   20.952635]                     handle_irq_event_percpu+0x38/0x8c
[   20.958742]                     handle_irq_event+0x48/0x6c
[   20.964242]                     handle_fasteoi_irq+0xc4/0x138
[   20.970006]                     generic_handle_irq+0x28/0x38
[   20.975681]                     __handle_domain_irq+0xb0/0xc4
[   20.981443]                     gic_handle_irq+0x68/0xa0
[   20.986769]                     __irq_svc+0x70/0xb0
[   20.991662]                     _raw_spin_unlock_irq+0x38/0x6c
[   20.997511]                     task_work_run+0x90/0xb8
[   21.002751]                     do_work_pending+0xc8/0xd0
[   21.008164]                     slow_work_pending+0xc/0x20
[   21.013661]                     0x76c77e86
[   21.017768]    INITIAL USE at:
[   21.020844]                    lock_acquire+0x260/0x29c
[   21.026086]                    _raw_spin_lock+0x48/0x58
[   21.031328]                    snd_pcm_stream_lock+0x54/0x60
[   21.037002]                    snd_pcm_stream_lock_irq+0x38/0x3c
[   21.043023]                    snd_pcm_sync_ptr+0x214/0x260
[   21.048609]                    snd_pcm_ioctl+0xbe0/0x10ec
[   21.054027]                    vfs_ioctl+0x30/0x44
[   21.058832]                    do_vfs_ioctl+0xac/0x974
[   21.063984]                    ksys_ioctl+0x48/0x64
[   21.068875]                    sys_ioctl+0x18/0x1c
[   21.073679]                    ret_fast_syscall+0x0/0x28
[   21.079004]                    0x7e9026dc
[   21.083023]  }
[   21.084710]  ... key      at: [<8162a6e4>] __key.31798+0x0/0x8
[   21.090552]  ... acquired at:
[   21.093537]    mark_lock+0x3a4/0x69c
[   21.097128]    __lock_acquire+0x420/0x16d4
[   21.101239]    lock_acquire+0x260/0x29c
[   21.105091]    _raw_spin_lock+0x48/0x58
[   21.108940]    snd_pcm_stream_lock+0x54/0x60
[   21.113226]    _snd_pcm_stream_lock_irqsave+0x40/0x48
[   21.118296]    snd_pcm_period_elapsed+0x2c/0xa4
[   21.122841]    dmaengine_pcm_dma_complete+0x54/0x58
[   21.127735]    sdma_int_handler+0x1dc/0x2a8
[   21.131937]    __handle_irq_event_percpu+0x1fc/0x498
[   21.136915]    handle_irq_event_percpu+0x38/0x8c
[   21.141547]    handle_irq_event+0x48/0x6c
[   21.145570]    handle_fasteoi_irq+0xc4/0x138
[   21.149854]    generic_handle_irq+0x28/0x38
[   21.154052]    __handle_domain_irq+0xb0/0xc4
[   21.158335]    gic_handle_irq+0x68/0xa0
[   21.162184]    __irq_svc+0x70/0xb0
[   21.165601]    _raw_spin_unlock_irq+0x38/0x6c
[   21.169973]    task_work_run+0x90/0xb8
[   21.173735]    do_work_pending+0xc8/0xd0
[   21.177670]    slow_work_pending+0xc/0x20
[   21.181691]    0x76c77e86
[   21.184320] 
[   21.185821] 
[   21.185821] stack backtrace:
[   21.190198] CPU: 0 PID: 1 Comm: systemd Not tainted 4.17.0+ #1538
[   21.196303] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
[   21.202841] Backtrace: 
[   21.205314] [<8010e318>] (dump_backtrace) from [<8010e604>] (show_stack+0x20/0x24)
[   21.212900]  r7:80e9f3d0 r6:00000000 r5:60070193 r4:80e9f3d0
[   21.218581] [<8010e5e4>] (show_stack) from [<8099b660>] (dump_stack+0xa4/0xd8)
[   21.225825] [<8099b5bc>] (dump_stack) from [<8017b52c>] (print_irq_inversion_bug+0x15c/0x1fc)
[   21.234368]  r9:814da818 r8:00000001 r7:ee926c00 r6:00000000 r5:ee915bb0 r4:814da818
[   21.242133] [<8017b3d0>] (print_irq_inversion_bug) from [<8017b6dc>] (check_usage_forwards+0x110/0x13c)
[   21.251544]  r9:00000002 r8:80bfd3e2 r7:ee926c00 r6:ee927148 r5:80e08488 r4:00000001
[   21.259306] [<8017b5cc>] (check_usage_forwards) from [<8017c2a4>] (mark_lock+0x3a4/0x69c)
[   21.267500]  r9:ee926c00 r8:80a03cd8 r7:00000101 r6:00000002 r5:00000000 r4:ee927148
[   21.275263] [<8017bf00>] (mark_lock) from [<8017cf68>] (__lock_acquire+0x420/0x16d4)
[   21.283023]  r10:ee927148 r9:ed4620e4 r8:ee926c00 r7:00000000 r6:00000001 r5:00000001
[   21.290863]  r4:00000490
[   21.293416] [<8017cb48>] (__lock_acquire) from [<8017ed58>] (lock_acquire+0x260/0x29c)
[   21.301350]  r10:00000001 r9:80e084a4 r8:00000000 r7:00000000 r6:00000000 r5:ed4620e4
[   21.309189]  r4:00000000
[   21.311746] [<8017eaf8>] (lock_acquire) from [<809b74f0>] (_raw_spin_lock+0x48/0x58)
[   21.319506]  r10:ee0a4714 r9:ed457100 r8:ee0a46c8 r7:ee0a4714 r6:ee0a4010 r5:807847b0
[   21.327346]  r4:ed4620d4
[   21.329902] [<809b74a8>] (_raw_spin_lock) from [<807847b0>] (snd_pcm_stream_lock+0x54/0x60)
[   21.338265]  r5:ed462000 r4:ed462000
[   21.341863] [<8078475c>] (snd_pcm_stream_lock) from [<80784838>] (_snd_pcm_stream_lock_irqsave+0x40/0x48)
[   21.351440]  r5:ed462000 r4:60070193
[   21.355042] [<807847f8>] (_snd_pcm_stream_lock_irqsave) from [<8078b044>] (snd_pcm_period_elapsed+0x2c/0xa4)
[   21.364881]  r5:ee3ef000 r4:ed462000
[   21.368478] [<8078b018>] (snd_pcm_period_elapsed) from [<8078d7b4>] (dmaengine_pcm_dma_complete+0x54/0x58)
[   21.378148]  r7:ee0a4714 r6:ee0a4010 r5:00000007 r4:ee0a46bc
[   21.383827] [<8078d760>] (dmaengine_pcm_dma_complete) from [<80504c0c>] (sdma_int_handler+0x1dc/0x2a8)
[   21.393157] [<80504a30>] (sdma_int_handler) from [<8018cd28>] (__handle_irq_event_percpu+0x1fc/0x498)
[   21.402393]  r10:00000000 r9:eeafd400 r8:80e084a4 r7:00000038 r6:00000038 r5:80ea3c12
[   21.410233]  r4:ee2b5d40
[   21.412787] [<8018cb2c>] (__handle_irq_event_percpu) from [<8018cffc>] (handle_irq_event_percpu+0x38/0x8c)
[   21.422457]  r10:00000000 r9:ee914000 r8:ee81d400 r7:00000038 r6:eeafd400 r5:eeafd464
[   21.430296]  r4:80e08488
[   21.432852] [<8018cfc4>] (handle_irq_event_percpu) from [<8018d098>] (handle_irq_event+0x48/0x6c)
[   21.441736]  r6:eeafd464 r5:eeafd464 r4:eeafd400
[   21.446374] [<8018d050>] (handle_irq_event) from [<8019146c>] (handle_fasteoi_irq+0xc4/0x138)
[   21.454912]  r7:00000038 r6:eeafd464 r5:80e10a60 r4:eeafd400
[   21.460589] [<801913a8>] (handle_fasteoi_irq) from [<8018bd9c>] (generic_handle_irq+0x28/0x38)
[   21.469214]  r7:00000038 r6:80d92ae4 r5:00000000 r4:00000000
[   21.474893] [<8018bd74>] (generic_handle_irq) from [<8018c48c>] (__handle_domain_irq+0xb0/0xc4)
[   21.483611] [<8018c3dc>] (__handle_domain_irq) from [<80102330>] (gic_handle_irq+0x68/0xa0)
[   21.491978]  r9:ee914000 r8:f4001100 r7:80e5c6bc r6:ee915f00 r5:80e08c3c r4:f4000100
[   21.499738] [<801022c8>] (gic_handle_irq) from [<801019f0>] (__irq_svc+0x70/0xb0)
[   21.507233] Exception stack(0xee915f00 to 0xee915f48)
[   21.512303] 5f00: 00000001 00000004 00000000 ee926c00 ee9270a8 ee926c00 ecc45e00 ee9270a8
[   21.520498] 5f20: 80ec23b0 ee914000 00000000 ee915f64 ee915f20 ee915f50 8017c7c0 809b78ac
[   21.528687] 5f40: 20070013 ffffffff
[   21.532193]  r9:ee914000 r8:80ec23b0 r7:ee915f34 r6:ffffffff r5:20070013 r4:809b78ac
[   21.539959] [<809b7874>] (_raw_spin_unlock_irq) from [<8014e98c>] (task_work_run+0x90/0xb8)
[   21.548321]  r5:ee926c00 r4:ecc45e00
[   21.551913] [<8014e8fc>] (task_work_run) from [<8010da3c>] (do_work_pending+0xc8/0xd0)
[   21.559848]  r9:ee914000 r8:801011c4 r7:ee915fb0 r6:ffffe000 r5:00000004 r4:801011c4
[   21.567608] [<8010d974>] (do_work_pending) from [<80101034>] (slow_work_pending+0xc/0x20)
[   21.575797] Exception stack(0xee915fb0 to 0xee915ff8)
[   21.580864] 5fa0:                                     00000000 020c34e8 46059f00 00000000
[   21.589059] 5fc0: 00000002 76f133a4 020df680 00000006 76e6e168 00000035 7ef81778 00000035
[   21.597253] 5fe0: 00000006 7ef816a0 76c75d67 76c77e86 20070030 00000039
[   21.603883]  r7:00000006 r6:020df680 r5:76f133a4 r4:00000002

Am Donnerstag, den 14.06.2018, 22:02 +0800 schrieb Robin Gong:
> The legacy sdma driver has below limitations or drawbacks:
>   1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and alloc
>      one page size for one channel regardless of only few BDs needed
>      most time. But in few cases, the max PAGE_SIZE maybe not enough.
>   2. One SDMA channel can't stop immediatley once channel disabled which
>      means SDMA interrupt may come in after this channel terminated.There
>      are some patches for this corner case such as commit "2746e2c389f9",
>      but not cover non-cyclic.
> 
> The common virt-dma overcomes the above limitations. It can alloc bd
> dynamically and free bd once this tx transfer done. No memory wasted or
> maximum limititation here, only depends on how many memory can be requested
> from kernel. For No.2, such issue can be workaround by checking if there
> is available descript("sdmac->desc") now once the unwanted interrupt
> coming. At last the common virt-dma is easier for sdma driver maintain.
> 
> Change from v3:
>   1. add two uart patches which impacted by this patchset.
>   2. unlock 'vc.lock' before cyclic dma callback and lock again after
>      it because some driver such as uart will call dmaengine_tx_status
>      which will acquire 'vc.lock' again and dead lock comes out.
>   3. remove 'Revert commit' stuff since that patch is not wrong and
>      combine two patch into one patch as Sascha's comment.
> 
> Change from v2:
>   1. include Sascha's patch to make the main patch easier to review.
>      Thanks Sacha.
>   2. remove useless 'desc'/'chan' in struct sdma_channe.
> 
> Change from v1:
>   1. split v1 patch into 5 patches.
>   2. remove some unnecessary condition check.
>   3. remove unnecessary 'pending' list.
> 
> Robin Gong (6):
>   tty: serial: imx: correct dma cookie status
>   dmaengine: imx-sdma: add virt-dma support
>   dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct
>     sdma_channel'
>   dmaengine: imx-sdma: remove the maximum limitation for bd numbers
>   dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap
>   tty: serial: imx: split all dma setup operations out of 'port.lock'
>     protector
> 
> Sascha Hauer (1):
>   dmaengine: imx-sdma: factor out a struct sdma_desc from struct
>     sdma_channel
> 
>  drivers/dma/Kconfig      |   1 +
>  drivers/dma/imx-sdma.c   | 394 +++++++++++++++++++++++++++--------------------
>  drivers/tty/serial/imx.c |  99 ++++++------
>  3 files changed, 282 insertions(+), 212 deletions(-)
> 

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

end of thread, other threads:[~2018-06-14 13:12 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-14 13:35 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
2018-06-14 13:35 ` [PATCH v4 1/7] tty: serial: imx: correct dma cookie status Robin Gong
2018-06-14 13:35 ` [PATCH v4 2/7] dmaengine: imx-sdma: factor out a struct sdma_desc from struct sdma_channel Robin Gong
2018-06-14 13:35 ` [PATCH v4 3/7] dmaengine: imx-sdma: add virt-dma support Robin Gong
2018-06-14 13:35 ` [PATCH v4 4/7] dmaengine: imx-sdma: remove useless 'lock' and 'enabled' in 'struct sdma_channel' Robin Gong
2018-06-14 13:35 ` [PATCH v4 5/7] dmaengine: imx-sdma: remove the maximum limitation for bd numbers Robin Gong
2018-06-14 13:35 ` [PATCH v4 6/7] dmaengine: imx-sdma: add sdma_transfer_init to decrease code overlap Robin Gong
2018-06-14 13:35 ` [PATCH v4 7/7] tty: serial: imx: split all dma setup operations out of 'port.lock' protector Robin Gong
2018-06-14 14:02 [PATCH v4 0/7] add virt-dma support for imx-sdma Robin Gong
2018-06-14  8:53 ` Lucas Stach
2018-06-14 10:09   ` Robin Gong
2018-06-14 10:22     ` Lucas Stach
2018-06-14 13:12       ` Robin Gong

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).