Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f94cd134 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

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

parents bbe515b6 a9b82f51
Loading
Loading
Loading
Loading
+32 −7
Original line number Diff line number Diff line
/*
 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -1364,6 +1364,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.
@@ -1389,12 +1418,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);
+31 −39
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <soc/qcom/boot_stats.h>
#include <linux/dma-mapping.h>

/* UART specific GENI registers */
#define SE_UART_LOOPBACK_CFG		(0x22C)
@@ -1204,7 +1205,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)
@@ -1221,18 +1221,11 @@ static void start_rx_sequencer(struct uart_port *uport)
		    __func__, 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,
			geni_se_rx_dma_start(uport->membase, DMA_RX_BUF_SIZE,
								&port->rx_dma);
			if (ret) {
				IPC_LOG_MSG(port->ipc_log_misc,
					    "%s: RX DMA map Fail %d\n",
					    __func__, ret);
				goto exit_start_rx_sequencer;
			}
		}
		msm_geni_serial_stop_rx(uport);
	}
@@ -1254,21 +1247,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) {
			IPC_LOG_MSG(port->ipc_log_misc,
				    "%s: RX DMA map Fail %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));
@@ -1416,12 +1402,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: End 0x%x\n",
		    __func__, geni_status);
@@ -1637,16 +1620,13 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
		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);
@@ -1668,11 +1648,8 @@ 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);
	if (msm_port->uart_ssr.is_ssr_down) {
		IPC_LOG_MSG(msm_port->ipc_log_misc, "%s: SSR Down event set\n",
				__func__);
@@ -1989,6 +1966,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);
@@ -2014,14 +1992,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
@@ -2043,12 +2022,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;
	/*
@@ -2056,6 +2035,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;
}
@@ -3101,6 +3088,11 @@ static int msm_geni_serial_remove(struct platform_device *pdev)
		pm_runtime_allow(&pdev->dev);
	wakeup_source_trash(&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;
}

+19 −0
Original line number Diff line number Diff line
@@ -727,6 +727,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.
@@ -855,6 +868,7 @@ int geni_se_iommu_free_buf(struct device *wrapper_dev, dma_addr_t *iova,
 */
void geni_se_dump_dbg_regs(struct se_geni_rsc *rsc, void __iomem *base,
				void *ipc);

#else
static inline unsigned int geni_read_reg_nolog(void __iomem *base, int offset)
{
@@ -1041,5 +1055,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