* [PATCH 0/2] fsl_lpuart: Add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp
@ 2023-07-10 1:38 Sherry Sun
2023-07-10 1:38 ` [PATCH 1/2] tty: serial: fsl_lpuart: move the lpuart32_int() below Sherry Sun
2023-07-10 1:38 ` [PATCH 2/2] tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
0 siblings, 2 replies; 3+ messages in thread
From: Sherry Sun @ 2023-07-10 1:38 UTC (permalink / raw)
To: gregkh, jirislaby; +Cc: linux-serial, linux-kernel, linux-imx
Now in the lpuart driver, we use receive dma timer to simulate the hardware EOP
event, but the timer latency is big which cause the Bluetooth Firmware download
timeout on Android platform(it has a limited FW download time window).
So here we use IDLE interrupt support for receive dma on
imx7ulp/imx8ulp/imx8qxp platforms to replace the receive dma timer, which can
reduce the BT FW download time obviously and the performance close to hardware
EOP.
Patch#1 move the lpuart32_int() below lpuart_copy_rx_to_tty() to avoid the
function declaration in Patch#2.
Sherry Sun (2):
tty: serial: fsl_lpuart: move the lpuart32_int() below
tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on
imx7ulp/imx8ulp/imx8qxp
drivers/tty/serial/fsl_lpuart.c | 83 ++++++++++++++++++++++++---------
1 file changed, 61 insertions(+), 22 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] tty: serial: fsl_lpuart: move the lpuart32_int() below
2023-07-10 1:38 [PATCH 0/2] fsl_lpuart: Add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
@ 2023-07-10 1:38 ` Sherry Sun
2023-07-10 1:38 ` [PATCH 2/2] tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
1 sibling, 0 replies; 3+ messages in thread
From: Sherry Sun @ 2023-07-10 1:38 UTC (permalink / raw)
To: gregkh, jirislaby; +Cc: linux-serial, linux-kernel, linux-imx
Move the lpuart32_int() below lpuart_copy_rx_to_tty(), this is a
preparation patch for the next patch to avoid the function declaration,
no actual functional changes.
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
drivers/tty/serial/fsl_lpuart.c | 39 ++++++++++++++++-----------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 6c652d77f566..653cf8eb5a72 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1066,26 +1066,6 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t lpuart32_int(int irq, void *dev_id)
-{
- struct lpuart_port *sport = dev_id;
- unsigned long sts, rxcount;
-
- sts = lpuart32_read(&sport->port, UARTSTAT);
- rxcount = lpuart32_read(&sport->port, UARTWATER);
- rxcount = rxcount >> UARTWATER_RXCNT_OFF;
-
- if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use)
- lpuart32_rxint(sport);
-
- if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
- lpuart32_txint(sport);
-
- lpuart32_write(&sport->port, sts, UARTSTAT);
- return IRQ_HANDLED;
-}
-
-
static inline void lpuart_handle_sysrq_chars(struct uart_port *port,
unsigned char *p, int count)
{
@@ -1278,6 +1258,25 @@ static void lpuart_dma_rx_complete(void *arg)
lpuart_copy_rx_to_tty(sport);
}
+static irqreturn_t lpuart32_int(int irq, void *dev_id)
+{
+ struct lpuart_port *sport = dev_id;
+ unsigned long sts, rxcount;
+
+ sts = lpuart32_read(&sport->port, UARTSTAT);
+ rxcount = lpuart32_read(&sport->port, UARTWATER);
+ rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+
+ if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use)
+ lpuart32_rxint(sport);
+
+ if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
+ lpuart32_txint(sport);
+
+ lpuart32_write(&sport->port, sts, UARTSTAT);
+ return IRQ_HANDLED;
+}
+
/*
* Timer function to simulate the hardware EOP (End Of Package) event.
* The timer callback is to check for new RX data and copy to TTY buffer.
--
2.17.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH 2/2] tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp
2023-07-10 1:38 [PATCH 0/2] fsl_lpuart: Add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
2023-07-10 1:38 ` [PATCH 1/2] tty: serial: fsl_lpuart: move the lpuart32_int() below Sherry Sun
@ 2023-07-10 1:38 ` Sherry Sun
1 sibling, 0 replies; 3+ messages in thread
From: Sherry Sun @ 2023-07-10 1:38 UTC (permalink / raw)
To: gregkh, jirislaby; +Cc: linux-serial, linux-kernel, linux-imx
Add IDLE interrupt support for receive dma on imx7ulp/imx8ulp/imx8qxp
platforms to replace the receive dma timer function, because the receive
dma timer has bigger latency than idle interrupt triggering, which may
cause the Bluetooth Firmware download timeout on Android platform(it
has a limited FW download time window).
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
drivers/tty/serial/fsl_lpuart.c | 44 +++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 653cf8eb5a72..c1980ea52666 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -290,6 +290,7 @@ struct lpuart_port {
wait_queue_head_t dma_wait;
bool is_cs7; /* Set to true when character size is 7 */
/* and the parity is enabled */
+ bool dma_idle_int;
};
struct lpuart_soc_data {
@@ -1248,7 +1249,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
spin_unlock_irqrestore(&sport->port.lock, flags);
tty_flip_buffer_push(port);
- mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
+ if (!sport->dma_idle_int)
+ mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
}
static void lpuart_dma_rx_complete(void *arg)
@@ -1258,6 +1260,28 @@ static void lpuart_dma_rx_complete(void *arg)
lpuart_copy_rx_to_tty(sport);
}
+static void lpuart32_dma_idleint(struct lpuart_port *sport)
+{
+ enum dma_status dmastat;
+ struct dma_chan *chan = sport->dma_rx_chan;
+ struct circ_buf *ring = &sport->rx_ring;
+ struct dma_tx_state state;
+ int count = 0;
+
+ dmastat = dmaengine_tx_status(chan, sport->dma_rx_cookie, &state);
+ if (dmastat == DMA_ERROR) {
+ dev_err(sport->port.dev, "Rx DMA transfer failed!\n");
+ return;
+ }
+
+ ring->head = sport->rx_sgl.length - state.residue;
+ count = CIRC_CNT(ring->head, ring->tail, sport->rx_sgl.length);
+
+ /* Check if new data received before copying */
+ if (count)
+ lpuart_copy_rx_to_tty(sport);
+}
+
static irqreturn_t lpuart32_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
@@ -1273,6 +1297,9 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id)
if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use)
lpuart32_txint(sport);
+ if ((sts & UARTSTAT_IDLE) && sport->lpuart_dma_rx_use && sport->dma_idle_int)
+ lpuart32_dma_idleint(sport);
+
lpuart32_write(&sport->port, sts, UARTSTAT);
return IRQ_HANDLED;
}
@@ -1394,6 +1421,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
unsigned long temp = lpuart32_read(&sport->port, UARTBAUD);
lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD);
+
+ if (sport->dma_idle_int) {
+ unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL);
+
+ lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL);
+ }
} else {
writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS,
sport->port.membase + UARTCR5);
@@ -1409,7 +1442,9 @@ static void lpuart_dma_rx_free(struct uart_port *port)
struct dma_chan *chan = sport->dma_rx_chan;
dmaengine_terminate_sync(chan);
- del_timer_sync(&sport->lpuart_timer);
+ if (!sport->dma_idle_int)
+ del_timer_sync(&sport->lpuart_timer);
+
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
sport->rx_ring.tail = 0;
@@ -1671,6 +1706,9 @@ static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
static void rx_dma_timer_init(struct lpuart_port *sport)
{
+ if (sport->dma_idle_int)
+ return;
+
timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0);
sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
add_timer(&sport->lpuart_timer);
@@ -2833,6 +2871,8 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.type = PORT_LPUART;
sport->devtype = sdata->devtype;
sport->rx_watermark = sdata->rx_watermark;
+ sport->dma_idle_int = is_imx7ulp_lpuart(sport) || is_imx8ulp_lpuart(sport) ||
+ is_imx8qxp_lpuart(sport);
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
--
2.17.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2023-07-10 1:40 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-10 1:38 [PATCH 0/2] fsl_lpuart: Add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
2023-07-10 1:38 ` [PATCH 1/2] tty: serial: fsl_lpuart: move the lpuart32_int() below Sherry Sun
2023-07-10 1:38 ` [PATCH 2/2] tty: serial: fsl_lpuart: add IDLE interrupt support for rx_dma on imx7ulp/imx8ulp/imx8qxp Sherry Sun
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).