msm-geni-serial: Use dma_alloc_coherent to avoid dma map/unmap

Use dma_alloc_coherent and dma_free_coherent to avoid dma_map/
dma_unmap calls for every UART rx transfer.

Change-Id: Ia2d71d19dc26d96f3c2abe12e22d326d21a2e071
Signed-off-by: Mukesh Kumar Savaliya <msavaliy@codeaurora.org>
This commit is contained in:
Mukesh Kumar Savaliya 2020-01-29 06:30:33 +05:30 • committed by Gerrit - the friendly Code Review server
commit c7ba4adfa9
3 changed files with 84 additions and 46 deletions

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
*/
#include <linux/clk.h>
@ -1244,6 +1244,35 @@ int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base,
}
EXPORT_SYMBOL(geni_se_tx_dma_prep);
/**
* geni_se_rx_dma_start() - Prepare the Serial Engine registers for RX DMA
transfers.
* @base: Base address of the SE register block.
* @rx_len: Length of the RX buffer.
* @rx_dma: Pointer to store the mapped DMA address.
*
* This function is used to prepare the Serial Engine registers for DMA RX.
*
* Return: None.
*/
void geni_se_rx_dma_start(void __iomem *base, int rx_len, dma_addr_t *rx_dma)
{
if (!*rx_dma || !base || !rx_len)
return;
geni_write_reg(7, base, SE_DMA_RX_IRQ_EN_SET);
geni_write_reg(GENI_SE_DMA_PTR_L(*rx_dma), base, SE_DMA_RX_PTR_L);
geni_write_reg(GENI_SE_DMA_PTR_H(*rx_dma), base, SE_DMA_RX_PTR_H);
/* RX does not have EOT bit */
geni_write_reg(0, base, SE_DMA_RX_ATTR);
/* Ensure that above register writes went through */
mb();
geni_write_reg(rx_len, base, SE_DMA_RX_LEN);
}
EXPORT_SYMBOL(geni_se_rx_dma_start);
/**
* geni_se_rx_dma_prep() - Prepare the Serial Engine for RX DMA transfer
* @wrapper_dev: QUPv3 Wrapper Device to which the RX buffer is mapped.
@ -1269,12 +1298,8 @@ int geni_se_rx_dma_prep(struct device *wrapper_dev, void __iomem *base,
if (ret)
return ret;
geni_write_reg(7, base, SE_DMA_RX_IRQ_EN_SET);
geni_write_reg(GENI_SE_DMA_PTR_L(*rx_dma), base, SE_DMA_RX_PTR_L);
geni_write_reg(GENI_SE_DMA_PTR_H(*rx_dma), base, SE_DMA_RX_PTR_H);
/* RX does not have EOT bit */
geni_write_reg(0, base, SE_DMA_RX_ATTR);
geni_write_reg(rx_len, base, SE_DMA_RX_LEN);
geni_se_rx_dma_start(base, rx_len, rx_dma);
return 0;
}
EXPORT_SYMBOL(geni_se_rx_dma_prep);

View file

@ -23,6 +23,7 @@
#include <linux/tty_flip.h>
#include <linux/ioctl.h>
#include <linux/pinctrl/consumer.h>
#include <linux/dma-mapping.h>
/* UART specific GENI registers */
#define SE_UART_LOOPBACK_CFG (0x22C)
@ -1076,7 +1077,6 @@ static void start_rx_sequencer(struct uart_port *uport)
unsigned int geni_m_irq_en;
unsigned int geni_status;
struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
int ret;
u32 geni_se_param = UART_PARAM_RFR_OPEN;
if (port->startup_in_progress)
@ -1084,17 +1084,11 @@ static void start_rx_sequencer(struct uart_port *uport)
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
if (geni_status & S_GENI_CMD_ACTIVE) {
if (port->xfer_mode == SE_DMA && !port->rx_dma) {
if (port->xfer_mode == SE_DMA) {
IPC_LOG_MSG(port->ipc_log_misc,
"%s: GENI: 0x%x\n", __func__, geni_status);
ret = geni_se_rx_dma_prep(port->wrapper_dev,
uport->membase, port->rx_buf, DMA_RX_BUF_SIZE,
&port->rx_dma);
if (ret) {
IPC_LOG_MSG(port->ipc_log_misc,
"%s: RX buff Fail %d\n", __func__, ret);
goto exit_start_rx_sequencer;
}
geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE,
&port->rx_dma);
}
msm_geni_serial_stop_rx(uport);
}
@ -1116,21 +1110,14 @@ static void start_rx_sequencer(struct uart_port *uport)
geni_write_reg_nolog(geni_m_irq_en, uport->membase,
SE_GENI_M_IRQ_EN);
} else if (port->xfer_mode == SE_DMA) {
ret = geni_se_rx_dma_prep(port->wrapper_dev, uport->membase,
port->rx_buf, DMA_RX_BUF_SIZE, &port->rx_dma);
if (ret) {
dev_err(uport->dev, "%s: RX Prep dma failed %d\n",
__func__, ret);
msm_geni_serial_stop_rx(uport);
goto exit_start_rx_sequencer;
}
geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE,
&port->rx_dma);
}
/*
* Ensure the writes to the secondary sequencer and interrupt enables
* go through.
*/
mb();
exit_start_rx_sequencer:
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x, dma_dbg:0x%x\n", __func__,
geni_status, geni_read_reg(uport->membase, SE_DMA_DEBUG_REG0));
@ -1257,12 +1244,9 @@ static void stop_rx_sequencer(struct uart_port *uport)
msm_geni_serial_abort_rx(uport);
}
exit_rx_seq:
if (port->xfer_mode == SE_DMA && port->rx_dma) {
if (port->xfer_mode == SE_DMA && port->rx_dma)
msm_geni_serial_rx_fsm_rst(uport);
geni_se_rx_dma_unprep(port->wrapper_dev, port->rx_dma,
DMA_RX_BUF_SIZE);
port->rx_dma = (dma_addr_t)NULL;
}
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
IPC_LOG_MSG(port->ipc_log_misc, "%s: 0x%x\n", __func__, geni_status);
}
@ -1443,7 +1427,7 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
unsigned int rx_bytes = 0;
struct tty_port *tport;
int ret;
int ret = 0;
unsigned int geni_status;
geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS);
@ -1451,16 +1435,13 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
if (!(geni_status & S_GENI_CMD_ACTIVE))
return 0;
geni_se_rx_dma_unprep(msm_port->wrapper_dev, msm_port->rx_dma,
DMA_RX_BUF_SIZE);
msm_port->rx_dma = (dma_addr_t)NULL;
rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);
if (unlikely(!msm_port->rx_buf)) {
IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: NULL Rx_buf\n",
__func__);
return 0;
}
rx_bytes = geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN);
if (unlikely(!rx_bytes)) {
IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: Size %d\n",
__func__, rx_bytes);
@ -1482,10 +1463,9 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
dump_ipc(msm_port->ipc_log_rx, "DMA Rx", (char *)msm_port->rx_buf, 0,
rx_bytes);
exit_handle_dma_rx:
ret = geni_se_rx_dma_prep(msm_port->wrapper_dev, uport->membase,
msm_port->rx_buf, DMA_RX_BUF_SIZE, &msm_port->rx_dma);
if (ret)
IPC_LOG_MSG(msm_port->ipc_log_rx, "%s: %d\n", __func__, ret);
geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE,
&msm_port->rx_dma);
return ret;
}
@ -1771,6 +1751,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
int ret = 0;
struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport);
unsigned long cfg0, cfg1;
dma_addr_t dma_address;
unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT;
set_rfr_wm(msm_port);
@ -1796,14 +1777,15 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
goto exit_portsetup;
}
msm_port->rx_buf = devm_kzalloc(uport->dev, DMA_RX_BUF_SIZE,
GFP_KERNEL);
msm_port->rx_buf = dma_alloc_coherent(msm_port->wrapper_dev,
DMA_RX_BUF_SIZE, &dma_address, GFP_KERNEL);
if (!msm_port->rx_buf) {
devm_kfree(uport->dev, msm_port->rx_fifo);
msm_port->rx_fifo = NULL;
ret = -ENOMEM;
goto exit_portsetup;
}
msm_port->rx_dma = dma_address;
} else {
/*
* Make an unconditional cancel on the main sequencer to reset
@ -1825,12 +1807,12 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
ret = geni_se_init(uport->membase, msm_port->rx_wm, msm_port->rx_rfr);
if (ret) {
dev_err(uport->dev, "%s: Fail\n", __func__);
goto exit_portsetup;
goto free_dma;
}
ret = geni_se_select_mode(uport->membase, msm_port->xfer_mode);
if (ret)
goto exit_portsetup;
goto free_dma;
msm_port->port_setup = true;
/*
@ -1838,6 +1820,14 @@ static int msm_geni_serial_port_setup(struct uart_port *uport)
* framework.
*/
mb();
return 0;
free_dma:
if (msm_port->rx_dma) {
dma_free_coherent(msm_port->wrapper_dev, DMA_RX_BUF_SIZE,
msm_port->rx_buf, msm_port->rx_dma);
msm_port->rx_dma = (dma_addr_t)NULL;
}
exit_portsetup:
return ret;
}
@ -2806,6 +2796,11 @@ static int msm_geni_serial_remove(struct platform_device *pdev)
if (!uart_console(&port->uport))
wakeup_source_unregister(port->geni_wake);
uart_remove_one_port(drv, &port->uport);
if (port->rx_dma) {
dma_free_coherent(port->wrapper_dev, DMA_RX_BUF_SIZE,
port->rx_buf, port->rx_dma);
port->rx_dma = (dma_addr_t)NULL;
}
return 0;
}

View file

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
*/
#ifndef _LINUX_MSM_GENI_SE
@ -665,6 +665,19 @@ int geni_se_clk_freq_match(struct se_geni_rsc *rsc, unsigned long req_freq,
int geni_se_tx_dma_prep(struct device *wrapper_dev, void __iomem *base,
void *tx_buf, int tx_len, dma_addr_t *tx_dma);
/**
* geni_se_rx_dma_start() - Prepare the Serial Engine registers for RX DMA
transfers.
* @base: Base address of the SE register block.
* @rx_len: Length of the RX buffer.
* @rx_dma: Pointer to store the mapped DMA address.
*
* This function is used to prepare the Serial Engine registers for DMA RX.
*
* Return: None.
*/
void geni_se_rx_dma_start(void __iomem *base, int rx_len, dma_addr_t *rx_dma);
/**
* geni_se_rx_dma_prep() - Prepare the Serial Engine for RX DMA transfer
* @wrapper_dev: QUPv3 Wrapper Device to which the TX buffer is mapped.
@ -979,5 +992,10 @@ static void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
{
}
static void geni_se_rx_dma_start(void __iomem *base, int rx_len,
dma_addr_t *rx_dma)
{
}
#endif
#endif