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

Commit 1902b96d authored by Chandana Kishori Chiluveru's avatar Chandana Kishori Chiluveru
Browse files

serial: msm_geni_serial: Add ioctl for sending uart error codes to BT host



Add changes in serial driver to update uart errors. When BT host
driver observes a fault in BT transfers this ioctl needs to be
called. On this ioctl call uart driver will return uart error
to BT host if there are any.

Change-Id: I741b017038b63f1a03aca2169c2190b94b95a15a
Signed-off-by: default avatarChandana Kishori Chiluveru <cchiluve@codeaurora.org>
parent bebc15ab
Loading
Loading
Loading
Loading
+86 −5
Original line number Diff line number Diff line
@@ -148,6 +148,30 @@
#define DMA_RX_BUF_SIZE		(2048)
#define UART_CONSOLE_RX_WM	(2)

enum uart_error_code {
	UART_ERROR_DEFAULT,
	UART_ERROR_INVALID_FW_LOADED,
	UART_ERROR_CLK_GET_FAIL,
	UART_ERROR_SE_CLK_RATE_FIND_FAIL,
	UART_ERROR_SE_RESOURCES_INIT_FAIL,
	UART_ERROR_SE_RESOURCES_ON_FAIL,
	UART_ERROR_SE_RESOURCES_OFF_FAIL,
	UART_ERROR_TX_DMA_MAP_FAIL,
	UART_ERROR_TX_CANCEL_FAIL,
	UART_ERROR_TX_ABORT_FAIL,
	UART_ERROR_TX_FSM_RESET_FAIL,
	UART_ERROR_RX_CANCEL_FAIL,
	UART_ERROR_RX_ABORT_FAIL,
	UART_ERROR_RX_FSM_RESET_FAIL,
	UART_ERROR_RX_TTY_INSET_FAIL,
	UART_ERROR_ILLEGAL_INTERRUPT,
	UART_ERROR_BUFFER_OVERRUN,
	UART_ERROR_RX_PARITY_ERROR,
	UART_ERROR_RX_BREAK_ERROR,
	UART_ERROR_RX_SBE_ERROR,
	SOC_ERROR_START_TX_IOS_SOC_RFR_HIGH
};

struct msm_geni_serial_ver_info {
	int hw_major_ver;
	int hw_minor_ver;
@@ -208,6 +232,7 @@ struct msm_geni_serial_port {
	spinlock_t rx_lock;
	bool pm_auto_suspend_disable;
	bool is_clock_off;
	enum uart_error_code uart_error;
};

static const struct uart_ops msm_geni_serial_pops;
@@ -264,6 +289,18 @@ static bool msm_geni_serial_spinlocked(struct uart_port *uport)
	return !locked;
}

/*
 * The below API is required to pass UART error code to BT HOST.
 */
static void msm_geni_update_uart_error_code(struct msm_geni_serial_port *port,
		enum uart_error_code uart_error_code)
{
	if (!port->is_console && !port->uart_error) {
		port->uart_error = uart_error_code;
		IPC_LOG_MSG(port->ipc_log_misc,
			"%s: uart_error_code:%d\n", __func__, port->uart_error);
	}
}
/*
 * We are enabling the interrupts once the polling operations
 * is completed.
@@ -535,6 +572,7 @@ static int msm_geni_serial_ioctl(struct uart_port *uport, unsigned int cmd,
{
	struct msm_geni_serial_port *port = GET_DEV_PORT(uport);
	int ret = -ENOIOCTLCMD;
	enum uart_error_code uart_error;

	if (port->pm_auto_suspend_disable)
		return ret;
@@ -555,6 +593,15 @@ static int msm_geni_serial_ioctl(struct uart_port *uport, unsigned int cmd,
		ret = !pm_runtime_status_suspended(uport->dev);
		break;
	}
	case MSM_GENI_SERIAL_TIOCFAULT: {
		uart_error = port->uart_error;
		port->uart_error = UART_ERROR_DEFAULT;
		IPC_LOG_MSG(port->ipc_log_misc,
				"%s:TIOCFAULT - uart_error_set:%d new_uart_error:%d\n",
				__func__, uart_error, port->uart_error);
		ret = uart_error;
		break;
	}
	default:
		break;
	}
@@ -603,6 +650,9 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport)
	geni_ios = geni_read_reg_nolog(uport->membase, SE_GENI_IOS);
	if (!(geni_ios & IO2_DATA_IN))
		mctrl |= TIOCM_CTS;
	else
		msm_geni_update_uart_error_code(port, SOC_ERROR_START_TX_IOS_SOC_RFR_HIGH);

	IPC_LOG_MSG(port->ipc_log_misc, "%s: geni_ios:0x%x, mctrl:0x%x\n",
			__func__, geni_ios, mctrl);
	return mctrl;
@@ -1089,6 +1139,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
		IPC_LOG_MSG(msm_port->ipc_log_misc,
		    "%s: TX DMA map Fail %d\n", __func__, ret);

		msm_geni_update_uart_error_code(msm_port, UART_ERROR_TX_DMA_MAP_FAIL);
		geni_write_reg_nolog(0, uport->membase, SE_UART_TX_TRANS_LEN);
		msm_port->m_cmd_done = false;
		msm_port->m_cmd = true;
@@ -1111,6 +1162,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
			"%s: tx_cancel failed 0x%x\n", __func__,
			geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));

			msm_geni_update_uart_error_code(msm_port, UART_ERROR_TX_CANCEL_FAIL);
			msm_port->m_cmd_done = false;
			reinit_completion(&msm_port->m_cmd_timeout);
			/* Give abort command as cancel command failed */
@@ -1127,6 +1179,7 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)
				"%s: tx abort failed 0x%x\n", __func__,
				geni_read_reg_nolog(uport->membase,
							SE_GENI_STATUS));
				msm_geni_update_uart_error_code(msm_port, UART_ERROR_TX_ABORT_FAIL);
			}
		}

@@ -1141,9 +1194,12 @@ static int msm_geni_serial_prep_dma_tx(struct uart_port *uport)

				timeout = geni_wait_for_cmd_done(uport,
							is_irq_masked);
				if (timeout)
				if (timeout) {
					IPC_LOG_MSG(msm_port->ipc_log_misc,
					"%s: tx fsm reset failed\n", __func__);
					msm_geni_update_uart_error_code(msm_port,
					UART_ERROR_TX_FSM_RESET_FAIL);
				}
			}

			if (msm_port->tx_dma) {
@@ -1257,6 +1313,7 @@ static void stop_tx_sequencer(struct uart_port *uport)
		IPC_LOG_MSG(port->ipc_log_misc, "%s: tx_cancel failed 0x%x\n",
		__func__, geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));

		msm_geni_update_uart_error_code(port, UART_ERROR_TX_CANCEL_FAIL);
		port->m_cmd_done = false;
		reinit_completion(&port->m_cmd_timeout);
		geni_abort_m_cmd(uport->membase);
@@ -1269,6 +1326,7 @@ static void stop_tx_sequencer(struct uart_port *uport)
			IPC_LOG_MSG(port->ipc_log_misc,
				"%s: tx abort failed 0x%x\n", __func__,
			geni_read_reg_nolog(uport->membase, SE_GENI_STATUS));
			msm_geni_update_uart_error_code(port, UART_ERROR_TX_ABORT_FAIL);
		}
	}

@@ -1282,9 +1340,11 @@ static void stop_tx_sequencer(struct uart_port *uport)

			timeout = geni_wait_for_cmd_done(uport,
							 is_irq_masked);
			if (timeout)
			if (timeout) {
				IPC_LOG_MSG(port->ipc_log_misc,
				"%s: tx fsm reset failed\n", __func__);
				msm_geni_update_uart_error_code(port, UART_ERROR_TX_FSM_RESET_FAIL);
			}
		}

		if (port->tx_dma) {
@@ -1512,6 +1572,7 @@ static int stop_rx_sequencer(struct uart_port *uport)
		IPC_LOG_MSG(port->console_log,
			    "%s cancel failed timeout:%d is_rx_active:%d 0x%x\n",
			    __func__, timeout, is_rx_active, geni_status);
		msm_geni_update_uart_error_code(port, UART_ERROR_RX_CANCEL_FAIL);
		geni_se_dump_dbg_regs(&port->serial_rsc,
				uport->membase, port->ipc_log_misc);
		/*
@@ -1543,6 +1604,7 @@ static int stop_rx_sequencer(struct uart_port *uport)
			IPC_LOG_MSG(port->console_log,
				"%s abort fail timeout:%d is_rx_active:%d 0x%x\n",
				 __func__, timeout, is_rx_active, geni_status);
			msm_geni_update_uart_error_code(port, UART_ERROR_RX_ABORT_FAIL);
			geni_se_dump_dbg_regs(&port->serial_rsc,
				uport->membase, port->ipc_log_misc);
		}
@@ -1555,9 +1617,11 @@ static int stop_rx_sequencer(struct uart_port *uport)

			timeout = geni_wait_for_cmd_done(uport,
							 is_irq_masked);
			if (timeout)
			if (timeout) {
				IPC_LOG_MSG(port->ipc_log_misc,
				"%s: rx fsm reset failed\n", __func__);
				msm_geni_update_uart_error_code(port, UART_ERROR_RX_FSM_RESET_FAIL);
			}
		}
	}
	/* Enable the interrupts once the cancel operation is done. */
@@ -1821,6 +1885,7 @@ static int msm_geni_serial_handle_dma_rx(struct uart_port *uport, bool drop_rx)
	if (ret != rx_bytes) {
		dev_err(uport->dev, "%s: ret %d rx_bytes %d\n", __func__,
								ret, rx_bytes);
		msm_geni_update_uart_error_code(msm_port, UART_ERROR_RX_TTY_INSET_FAIL);
		WARN_ON(1);
	}
	uport->icount.rx += ret;
@@ -1985,6 +2050,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport)
				"%s.Rx Errors.  0x%x parity:%d\n",
					__func__, dma_rx_status,
					uport->icount.parity);
			msm_geni_update_uart_error_code(msm_port, UART_ERROR_RX_PARITY_ERROR);
			drop_rx = true;
		} else if (dma_rx_status & UART_DMA_RX_BREAK) {
			uport->icount.brk++;
@@ -1992,6 +2058,8 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport)
				"%s.Rx Errors.  0x%x break:%d\n",
				__func__, dma_rx_status,
				uport->icount.brk);
				msm_geni_update_uart_error_code(msm_port,
				UART_ERROR_RX_BREAK_ERROR);
		}

		if (dma_rx_status & RX_EOT ||
@@ -2013,6 +2081,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport)
			IPC_LOG_MSG(msm_port->ipc_log_misc,
				"%s.Rx Errors.  0x%x\n",
				__func__, dma_rx_status);
			msm_geni_update_uart_error_code(msm_port, UART_ERROR_RX_SBE_ERROR);
			WARN_ON(1);
		}

@@ -2066,8 +2135,10 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport,
			IPC_LOG_MSG(msm_port->console_log,
				"%s.Illegal interrupt. sirq 0x%x mirq:0x%x\n",
				 __func__, s_irq_status, m_irq_status);
		else
		else {
			msm_geni_update_uart_error_code(msm_port, UART_ERROR_ILLEGAL_INTERRUPT);
			WARN_ON(1);
		}
		goto exit_geni_serial_isr;
	}

@@ -2080,6 +2151,7 @@ static void msm_geni_serial_handle_isr(struct uart_port *uport,
		IPC_LOG_MSG(msm_port->ipc_log_misc,
			"%s.sirq 0x%x buf_overrun:%d\n",
			__func__, s_irq_status, uport->icount.buf_overrun);
		msm_geni_update_uart_error_code(msm_port, UART_ERROR_BUFFER_OVERRUN);
	}

	dma = geni_read_reg_nolog(uport->membase, SE_GENI_DMA_MODE_EN);
@@ -2572,6 +2644,7 @@ static void msm_geni_serial_set_termios(struct uart_port *uport,
	if (ret) {
		dev_err(uport->dev, "%s: Failed(%d) to find src clk for 0x%x\n",
				__func__, ret, baud);
		msm_geni_update_uart_error_code(port, UART_ERROR_SE_CLK_RATE_FIND_FAIL);
		goto exit_set_termios;
	}

@@ -3075,6 +3148,7 @@ static int msm_geni_serial_get_clk(struct platform_device *pdev,
	if (IS_ERR(dev_port->serial_rsc.se_clk)) {
		ret = PTR_ERR(dev_port->serial_rsc.se_clk);
		dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret);
		msm_geni_update_uart_error_code(dev_port, UART_ERROR_CLK_GET_FAIL);
		return ret;
	}

@@ -3082,6 +3156,7 @@ static int msm_geni_serial_get_clk(struct platform_device *pdev,
	if (IS_ERR(dev_port->serial_rsc.m_ahb_clk)) {
		ret = PTR_ERR(dev_port->serial_rsc.m_ahb_clk);
		dev_err(&pdev->dev, "Err getting M AHB clk %d\n", ret);
		msm_geni_update_uart_error_code(dev_port, UART_ERROR_CLK_GET_FAIL);
		return ret;
	}

@@ -3089,6 +3164,7 @@ static int msm_geni_serial_get_clk(struct platform_device *pdev,
	if (IS_ERR(dev_port->serial_rsc.s_ahb_clk)) {
		ret = PTR_ERR(dev_port->serial_rsc.s_ahb_clk);
		dev_err(&pdev->dev, "Err getting S AHB clk %d\n", ret);
		msm_geni_update_uart_error_code(dev_port, UART_ERROR_CLK_GET_FAIL);
		return ret;
	}

@@ -3127,8 +3203,10 @@ static int msm_geni_serial_read_dtsi(struct platform_device *pdev,
			UART_CORE2X_VOTE,
			(DEFAULT_SE_CLK * DEFAULT_BUS_WIDTH));

	if (ret)
	if (ret) {
		msm_geni_update_uart_error_code(dev_port, UART_ERROR_SE_RESOURCES_INIT_FAIL);
		return ret;
	}

	dev_port->serial_rsc.ctrl_dev = &pdev->dev;

@@ -3304,6 +3382,7 @@ static int msm_geni_serial_probe(struct platform_device *pdev)
	msm_geni_serial_debug_init(uport, is_console);
	dev_port->port_setup = false;

	dev_port->uart_error = UART_ERROR_DEFAULT;
	ret = msm_geni_serial_get_ver_info(uport);
	if (ret) {
		dev_err(&pdev->dev, "Failed to Read FW ver: %d\n", ret);
@@ -3422,6 +3501,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev)
	ret = se_geni_resources_off(&port->serial_rsc);
	if (ret) {
		dev_err(dev, "%s: Error ret %d\n", __func__, ret);
		msm_geni_update_uart_error_code(port, UART_ERROR_SE_RESOURCES_OFF_FAIL);
		goto exit_runtime_suspend;
	}

@@ -3458,6 +3538,7 @@ static int msm_geni_serial_runtime_resume(struct device *dev)
	ret = se_geni_resources_on(&port->serial_rsc);
	if (ret) {
		dev_err(dev, "%s: Error ret %d\n", __func__, ret);
		msm_geni_update_uart_error_code(port, UART_ERROR_SE_RESOURCES_ON_FAIL);
		__pm_relax(port->geni_wake);
		goto exit_runtime_resume;
	}
+2 −2
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/*
 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
 */

#ifndef __UAPI_LINUX_MSM_GENI_SERIAL_H
#define __UAPI_LINUX_MSM_GENI_SERIAL_H

/* IOCTLS used by BT clients to control UART power state */

#define MSM_GENI_SERIAL_TIOCFAULT	0x54EC	/* Uart fault */
#define MSM_GENI_SERIAL_TIOCPMGET	0x54ED	/* PM get */
#define MSM_GENI_SERIAL_TIOCPMPUT	0x54EE	/* PM put */
#define MSM_GENI_SERIAL_TIOCPMACT	0x54EF	/* PM is active */