From aac28acd98b460a5b4ea61cee8df4faa29338d85 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 6 Apr 2021 12:46:35 +0530 Subject: [PATCH 1/3] serial: msm_geni_serial: Reduce wait for transfer delay This is to reduce wait for transfer delay which is introducing total 20msec delay during port_close()/BT off usecase. Also added other debug logs required in this change. Change-Id: Ia1135b097e6b9137ee3fb9504b2d8c29c05dbab3 Signed-off-by: Chandana Kishori Chiluveru --- drivers/platform/msm/msm-geni-se.c | 16 +++++++++-- drivers/tty/serial/msm_geni_serial.c | 41 +++++++++++----------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/drivers/platform/msm/msm-geni-se.c b/drivers/platform/msm/msm-geni-se.c index 103a3bfb02e7..66a34dd7816d 100644 --- a/drivers/platform/msm/msm-geni-se.c +++ b/drivers/platform/msm/msm-geni-se.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ #include @@ -1541,6 +1541,10 @@ void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, u32 se_dma_rx_len_in = 0; u32 se_dma_tx_len = 0; u32 se_dma_tx_len_in = 0; + u32 geni_m_irq_en = 0; + u32 geni_s_irq_en = 0; + u32 geni_dma_tx_irq_en = 0; + u32 geni_dma_rx_irq_en = 0; struct geni_se_device *geni_se_dev; if (!ipc) @@ -1569,6 +1573,10 @@ void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, se_dma_rx_len_in = geni_read_reg(base, SE_DMA_RX_LEN_IN); se_dma_tx_len = geni_read_reg(base, SE_DMA_TX_LEN); se_dma_tx_len_in = geni_read_reg(base, SE_DMA_TX_LEN_IN); + geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN); + geni_s_irq_en = geni_read_reg(base, SE_GENI_S_IRQ_EN); + geni_dma_tx_irq_en = geni_read_reg(base, SE_DMA_TX_IRQ_EN); + geni_dma_rx_irq_en = geni_read_reg(base, SE_DMA_RX_IRQ_EN); GENI_SE_DBG(ipc, false, NULL, "%s: m_cmd0:0x%x, m_irq_status:0x%x, geni_status:0x%x, geni_ios:0x%x\n", @@ -1580,7 +1588,11 @@ void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base, "se_dma_dbg:0x%x, m_cmd_ctrl:0x%x, dma_rxlen:0x%x, dma_rxlen_in:0x%x\n", se_dma_dbg, m_cmd_ctrl, se_dma_rx_len, se_dma_rx_len_in); GENI_SE_DBG(ipc, false, NULL, - "dma_txlen:0x%x, dma_txlen_in:0x%x\n", se_dma_tx_len, se_dma_tx_len_in); + "dma_txlen:0x%x, dma_txlen_in:0x%x s_irq_status:0x%x\n", + se_dma_tx_len, se_dma_tx_len_in, s_irq_status); + GENI_SE_DBG(ipc, false, NULL, + "dma_txirq_en:0x%x, dma_rxirq_en:0x%x geni_m_irq_en:0x%x geni_s_irq_en:0x%x\n", + geni_dma_tx_irq_en, geni_dma_rx_irq_en, geni_m_irq_en, geni_s_irq_en); } EXPORT_SYMBOL(geni_se_dump_dbg_regs); diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 4198043061db..3d84327d14de 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -114,8 +114,8 @@ #define WAKEBYTE_TIMEOUT_MSEC (2000) #define WAIT_XFER_MAX_ITER (2) -#define WAIT_XFER_MAX_TIMEOUT_US (10000) -#define WAIT_XFER_MIN_TIMEOUT_US (9000) +#define WAIT_XFER_MAX_TIMEOUT_US (150) +#define WAIT_XFER_MIN_TIMEOUT_US (100) #define IPC_LOG_PWR_PAGES (10) #define IPC_LOG_MISC_PAGES (30) #define IPC_LOG_TX_RX_PAGES (30) @@ -460,7 +460,6 @@ static void wait_for_transfers_inflight(struct uart_port *uport) int iter = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned int geni_status; - bool CTS, RX; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop rx is called before this. */ @@ -477,19 +476,8 @@ static void wait_for_transfers_inflight(struct uart_port *uport) } } if (check_transfers_inflight(uport)) { - u32 geni_status = geni_read_reg_nolog(uport->membase, - SE_GENI_STATUS); - u32 geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS); - u32 rx_fifo_status = geni_read_reg_nolog(uport->membase, - SE_GENI_RX_FIFO_STATUS); - u32 rx_dma = - geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN); - CTS = geni_ios & 0x2; // b[1] = UART CTS <- Peer RFR - RX = geni_ios & 0x1; // b[0] = UART RX <- Peer TX - - IPC_LOG_MSG(port->ipc_log_misc, - "%s: geni=0x%x rx_fifo=0x%x rx_dma=0x%x, CTS_IO=%d, RX_IO=%d\n", - __func__, geni_status, rx_fifo_status, rx_dma, CTS, RX); + geni_se_dump_dbg_regs(&port->serial_rsc, + uport->membase, port->ipc_log_misc); } } @@ -1346,16 +1334,20 @@ static void start_rx_sequencer(struct uart_port *uport) if (geni_status & S_GENI_CMD_ACTIVE) { if (port->xfer_mode == SE_DMA) { IPC_LOG_MSG(port->ipc_log_misc, - "%s: GENI: 0x%x\n", __func__, geni_status); + "%s: mapping rx dma GENI: 0x%x\n", + __func__, geni_status); geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &port->rx_dma); } msm_geni_serial_stop_rx(uport); } - if (port->xfer_mode == SE_DMA) + if (port->xfer_mode == SE_DMA) { + IPC_LOG_MSG(port->ipc_log_misc, + "%s. mapping rx dma\n", __func__); geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &port->rx_dma); + } /* Start RX with the RFR_OPEN to keep RFR in always ready state */ geni_setup_s_cmd(uport->membase, UART_START_READ, geni_se_param); @@ -1992,6 +1984,8 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) msm_geni_serial_handle_dma_rx(uport, drop_rx); if (!(dma_rx_status & RX_GENI_CANCEL_IRQ)) { + IPC_LOG_MSG(msm_port->ipc_log_misc, + "%s. mapping rx dma\n", __func__); geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE, &msm_port->rx_dma); } else { @@ -2062,12 +2056,8 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport, goto exit_geni_serial_isr; } - if (m_irq_status & (M_IO_DATA_ASSERT_EN | M_IO_DATA_DEASSERT_EN)) { + if (m_irq_status & (M_IO_DATA_ASSERT_EN | M_IO_DATA_DEASSERT_EN)) uport->icount.cts++; - IPC_LOG_MSG(msm_port->ipc_log_misc, - "%s. cts counter:%d\n", __func__, - uport->icount.cts); - } if (s_irq_status & S_RX_FIFO_WR_ERR_EN) { uport->icount.overrun++; @@ -3313,6 +3303,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) u32 geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS); + IPC_LOG_MSG(port->ipc_log_pwr, "%s: Start\n", __func__); wait_for_transfers_inflight(&port->uport); /* * Manual RFR On. @@ -3326,8 +3317,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) __func__, ret); return -EBUSY; } - geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS); + geni_status = geni_read_reg_nolog(port->uport.membase, SE_GENI_STATUS); if ((geni_status & M_GENI_CMD_ACTIVE)) stop_tx_sequencer(&port->uport); @@ -3349,7 +3340,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) port->edge_count = 0; enable_irq(port->wakeup_irq); } - IPC_LOG_MSG(port->ipc_log_pwr, "%s:\n", __func__); + IPC_LOG_MSG(port->ipc_log_pwr, "%s: End\n", __func__); __pm_relax(port->geni_wake); exit_runtime_suspend: return ret; From 235585bd23b2272fc5c8c560b13cee13607918b4 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 6 Apr 2021 12:55:52 +0530 Subject: [PATCH 2/3] serial: msm_geni_serial: Do not change Flow control from termios This change ensures UART driver doesn't control the flow lines when baud change is requested. UART client must ensure that peer device is flowed off before requesting the baud change. If UART driver control the Flow lines it may happen that after baud rate change, immediately driver decides to Flow it ON which may have side effect to client if it doesn't really intend to receive anything from ther peer side. This way we are ensuring the window of baud change is controlled by client and not disturbed by the driver. Change-Id: Id88ae03dc8a81830393597e72109ee7015cb6226 Signed-off-by: Mukesh Kumar Savaliya Signed-off-by: Chandana Kishori Chiluveru --- drivers/tty/serial/msm_geni_serial.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 3d84327d14de..bb9397279d4b 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1430,7 +1430,6 @@ static int stop_rx_sequencer(struct uart_port *uport) } if (!uart_console(uport)) { - msm_geni_serial_set_manual_flow(false, port); /* * Wait for the stale timeout to happen if there * is any data pending in the rx fifo. @@ -1547,9 +1546,6 @@ static int stop_rx_sequencer(struct uart_port *uport) port->s_cmd = false; exit_rx_seq: - if (!uart_console(uport)) - msm_geni_serial_set_manual_flow(true, port); - geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: End 0x%x dma_dbg:0x%x\n", __func__, geni_status, @@ -3304,9 +3300,10 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Start\n", __func__); + /* Flow off from UART */ + msm_geni_serial_set_manual_flow(false, port); wait_for_transfers_inflight(&port->uport); /* - * Manual RFR On. * Stop Rx. * Disable Interrupt * Resources off @@ -3315,6 +3312,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) if (ret) { IPC_LOG_MSG(port->ipc_log_pwr, "%s: stop rx failed %d\n", __func__, ret); + /* Flow on from UART */ + msm_geni_serial_allow_rx(port); return -EBUSY; } @@ -3325,7 +3324,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) disable_irq(port->uport.irq); /* - * Above stop_rx disabled the flow so we need to enable it here + * Flow on from UART + * Above before stop_rx disabled the flow so we need to enable it here * Make sure wake up interrupt is enabled before RFR is made low */ msm_geni_serial_allow_rx(port); From f46551cd83d64aa6bd1823e73ee84901f1ffb3bf Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 6 Apr 2021 12:59:43 +0530 Subject: [PATCH 3/3] serial: msm_geni_serial: Bailout from suspend if RX data is pending This change is to resolve potential race btw stop rx and cancel rx due to interrupt latency in the system. Change-Id: I7b510949f75bac5ec9f8f42f3d139131b259600f Signed-off-by: Chandana Kishori Chiluveru --- drivers/tty/serial/msm_geni_serial.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index bb9397279d4b..b475acc88bda 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1417,6 +1417,7 @@ static int stop_rx_sequencer(struct uart_port *uport) bool is_rx_active; unsigned int stale_delay; u32 dma_rx_status, s_irq_status; + int usage_count; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); @@ -1458,6 +1459,14 @@ static int stop_rx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->ipc_log_misc, "%s: Interrupt delay\n", __func__); handle_rx_dma_xfer(s_irq_status, uport); + if (!port->ioctl_count) { + usage_count = atomic_read(&uport->dev->power.usage_count); + IPC_LOG_MSG(port->ipc_log_misc, + "%s: Abort Stop Rx, extend the PM timer, usage_count:%d\n", + __func__, usage_count); + pm_runtime_mark_last_busy(uport->dev); + return -EBUSY; + } } }