Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1418309 > unrolled thread
| Started by | Nandor Han <nandor.han@ge.com> |
|---|---|
| First post | 2016-06-09 15:20 +0200 |
| Last post | 2016-06-09 15:40 +0200 |
| Articles | 2 — 1 participant |
Back to article view | Back to linux.kernel
[PATCH RFC 0/4] serial,dma: use DMA cyclic for IMX UART driver Nandor Han <nandor.han@ge.com> - 2016-06-09 15:20 +0200
[PATCH RFC 1/4] dma: imx-sdma - reduce transfer latency for DMA cyclic clients Nandor Han <nandor.han@ge.com> - 2016-06-09 15:40 +0200
| From | Nandor Han <nandor.han@ge.com> |
|---|---|
| Date | 2016-06-09 15:20 +0200 |
| Subject | [PATCH RFC 0/4] serial,dma: use DMA cyclic for IMX UART driver |
| Message-ID | <rI7SF-6NK-7@gated-at.bofh.it> |
Update the IMX UART driver to use cyclic DMA in order
to avoid losing serial data because of DMA start latency.
Support variable data length transfers for cyclic channels in
IMX SDMA(Smart DMA) driver and, as specified in
"Documentation/dmaengine/provider.txt" section "General Design Notes",
run the SDMA channel callback directly from the SDMA interrupt context.
Every commit message will explain the changes.
Impacted devices:
IMX6i,IMX53 CPU:
- clients of the IMX UART that have DMA enabled.
- cyclic SDMA clients
(Note:Not able to find others than IMX UART driver)
Functionality tested by connecting the m53evk to my laptop using a
USB-serial converter and start sending, from my laptop 800 bytes
long packets at 8ms interval.
On the m53evk with interrupt load, generated by
connecting/disconnecting at 3s interval a USB HUB having
some devices connected (~4), I receive serial data in a
loop and check that no overruns are created using command:
`watch -n1 cat /proc/tty/driver/IMX-uart`
Also done tests were I check how the data is received when sending packets
bigger than a buffer descriptor size (1024). In my tests I have sent 4 packets
(1028, 2048, 2048, 2048) and check that 7172 bytes were received using
the command:
`watch -n1 cat /proc/tty/driver/IMX-uart`
Result:
serinfo:1.0 driver revision:
2: uart:IMX mmio:0x5000C000 irq:49 tx:0 rx:7172 RTS|CTS|DTR|DSR|CD
Nandor Han (4):
dma: imx-sdma - reduce transfer latency for DMA cyclic clients
dma: imx-sdma - update the residue calculation for cyclic channels
serial: imx-serial - update UART IMX driver to use cyclic DMA
serial: imx-serial - update RX error counters when DMA is used
drivers/dma/imx-sdma.c | 56 +++++++++------
drivers/tty/serial/imx.c | 173 ++++++++++++++++++++++++++++++-----------------
2 files changed, 144 insertions(+), 85 deletions(-)
--
2.8.3
[toc] | [next] | [standalone]
| From | Nandor Han <nandor.han@ge.com> |
|---|---|
| Date | 2016-06-09 15:40 +0200 |
| Subject | [PATCH RFC 1/4] dma: imx-sdma - reduce transfer latency for DMA cyclic clients |
| Message-ID | <rI8lI-6YM-7@gated-at.bofh.it> |
| In reply to | #1418309 |
Having the SDMA driver use a tasklet for running the clients
callback introduce some issues:
- probability to have desynchronized data because of the
race condition created since the DMA transaction status
is retrieved only when the callback is executed, leaving
plenty of time for transaction status to get altered.
- inter-transfer latency which can leave channels idle.
Move the callback execution, for cyclic channels, to SDMA
interrupt (as advised in `Documentation/dmaengine/provider.txt`)
to (a)reduce the inter-transfer latency and (b) eliminate the
race condition possibility where DMA transaction status might
be changed by the time is read.
The responsibility of the SDMA interrupt latency
is moved to the SDMA clients which case by case should defer
the work to bottom-halves when needed.
Signed-off-by: Nandor Han <nandor.han@ge.com>
---
drivers/dma/imx-sdma.c | 36 ++++++++++++++++--------------------
1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 0f6fd42..e497847 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -654,12 +654,6 @@ static void sdma_event_disable(struct sdma_channel *sdmac, unsigned int event)
writel_relaxed(val, sdma->regs + chnenbl);
}
-static void sdma_handle_channel_loop(struct sdma_channel *sdmac)
-{
- if (sdmac->desc.callback)
- sdmac->desc.callback(sdmac->desc.callback_param);
-}
-
static void sdma_update_channel_loop(struct sdma_channel *sdmac)
{
struct sdma_buffer_descriptor *bd;
@@ -678,13 +672,25 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
sdmac->status = DMA_ERROR;
bd->mode.status |= BD_DONE;
+
+ /*
+ * The callback is called from the interrupt context in order
+ * to reduce latency and to avoid the risk of altering the
+ * SDMA transaction status by the time the client tasklet is
+ * executed.
+ */
+
+ if (sdmac->desc.callback)
+ sdmac->desc.callback(sdmac->desc.callback_param);
+
sdmac->buf_tail++;
sdmac->buf_tail %= sdmac->num_bd;
}
}
-static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
+static void mxc_sdma_handle_channel_normal(unsigned long data)
{
+ struct sdma_channel *sdmac = (struct sdma_channel *) data;
struct sdma_buffer_descriptor *bd;
int i, error = 0;
@@ -711,16 +717,6 @@ static void mxc_sdma_handle_channel_normal(struct sdma_channel *sdmac)
sdmac->desc.callback(sdmac->desc.callback_param);
}
-static void sdma_tasklet(unsigned long data)
-{
- struct sdma_channel *sdmac = (struct sdma_channel *) data;
-
- if (sdmac->flags & IMX_DMA_SG_LOOP)
- sdma_handle_channel_loop(sdmac);
- else
- mxc_sdma_handle_channel_normal(sdmac);
-}
-
static irqreturn_t sdma_int_handler(int irq, void *dev_id)
{
struct sdma_engine *sdma = dev_id;
@@ -737,8 +733,8 @@ static irqreturn_t sdma_int_handler(int irq, void *dev_id)
if (sdmac->flags & IMX_DMA_SG_LOOP)
sdma_update_channel_loop(sdmac);
-
- tasklet_schedule(&sdmac->tasklet);
+ else
+ tasklet_schedule(&sdmac->tasklet);
__clear_bit(channel, &stat);
}
@@ -1739,7 +1735,7 @@ static int sdma_probe(struct platform_device *pdev)
dma_cookie_init(&sdmac->chan);
sdmac->channel = i;
- tasklet_init(&sdmac->tasklet, sdma_tasklet,
+ tasklet_init(&sdmac->tasklet, mxc_sdma_handle_channel_normal,
(unsigned long) sdmac);
/*
* Add the channel to the DMAC list. Do not add channel 0 though
--
2.8.3
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web