From a659f1264c8550773728cf8a30dc81bf27ddebe7 Mon Sep 17 00:00:00 2001 From: Panicker Harish Date: Mon, 8 Jul 2024 17:40:40 +0530 Subject: [PATCH] serial: msm_geni_serial: Prevent geni register access while suspend is in progress While runtime suspend is in progress and before it completes, if mctrl is invoked, there is a possibility that it may access the geni register without the voting clock. To address this issue, add mutual exclusion to prevent mctrl from accessing the geni register while suspension is in progress. Change-Id: I3b2d5f6314680ce6cc91c8f0b50f11c37d896868 Signed-off-by: Mehul Raninga Signed-off-by: Panicker Harish --- drivers/tty/serial/msm_geni_serial.c | 55 ++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 28cc64726835..ed464fe97bc6 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -6,19 +6,22 @@ #include #include +#include #include #include -#include -#include #include +#include #include +#include #include #include #include #include #include +#include #include #include +#include #include #include #include @@ -28,9 +31,6 @@ #include #include #include -#include -#include -#include #include static bool con_enabled = IS_ENABLED(CONFIG_SERIAL_MSM_GENI_CONSOLE_DEFAULT_ENABLED); @@ -459,6 +459,12 @@ struct msm_geni_serial_port { int hs_uart_operation; struct msm_geni_serial_ssr uart_ssr; struct geni_se_rsc rsc; + /** + * mutex to prevent race condition between runtime + * suspend and get_mctrl which tries to access IOS registers + * when runtime suspend was in progress + */ + struct mutex suspend_resume_lock; }; static const struct uart_ops msm_geni_serial_pops; @@ -1407,17 +1413,26 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) return 0; } - if (!uart_console(uport) && device_pending_suspend(uport)) { - UART_LOG_DBG(port->ipc_log_misc, uport->dev, - "%s.Device is suspended, %s\n", - __func__, current->comm); - return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; + if (!uart_console(uport)) { + if (!mutex_trylock(&port->suspend_resume_lock)) { + UART_LOG_DBG(port->ipc_log_misc, uport->dev, + "%s.Device is being suspended, %s\n", + __func__, current->comm); + return mctrl; + } + if (device_pending_suspend(uport)) { + UART_LOG_DBG(port->ipc_log_misc, uport->dev, + "%s.Device is suspended, %s\n", + __func__, current->comm); + mutex_unlock(&port->suspend_resume_lock); + return mctrl | TIOCM_CTS; + } } geni_ios = geni_read_reg(uport->membase, SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) mctrl |= TIOCM_CTS; - else + else if (!uart_console(uport)) msm_geni_update_uart_error_code(port, SOC_ERROR_START_TX_IOS_SOC_RFR_HIGH); if (!port->manual_flow) @@ -1425,6 +1440,10 @@ static unsigned int msm_geni_serial_get_mctrl(struct uart_port *uport) UART_LOG_DBG(port->ipc_log_misc, uport->dev, "%s: geni_ios:0x%x, mctrl:0x%x\n", __func__, geni_ios, mctrl); + + if (!uart_console(uport)) + mutex_unlock(&port->suspend_resume_lock); + return mctrl; } @@ -5519,6 +5538,8 @@ static int msm_geni_serial_probe(struct platform_device *pdev) if (!dev_port->is_console) spin_lock_init(&dev_port->rx_lock); + mutex_init(&dev_port->suspend_resume_lock); + ret = uart_add_one_port(drv, uport); if (ret) dev_err(&pdev->dev, "Failed to register uart_port: %d\n", ret); @@ -5615,7 +5636,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) unsigned long long start_time; u32 geni_status = geni_read_reg(port->uport.membase, SE_GENI_STATUS); - + mutex_lock(&port->suspend_resume_lock); UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: Start geni_status : 0x%x\n", __func__, geni_status); @@ -5641,7 +5662,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) */ if (port->wakeup_byte && port->wakeup_irq) msm_geni_serial_allow_rx(port); - return -EBUSY; + ret = -EBUSY; + goto exit_runtime_suspend; } } /* @@ -5658,7 +5680,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) */ if (port->wakeup_byte && port->wakeup_irq) msm_geni_serial_allow_rx(port); - return -EBUSY; + ret = -EBUSY; + goto exit_runtime_suspend; } geni_status = geni_read_reg(port->uport.membase, SE_GENI_STATUS); @@ -5689,7 +5712,8 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: return, stop_rx_seq busy\n", __func__); enable_irq(port->uport.irq); - return -EBUSY; + ret = -EBUSY; + goto exit_runtime_suspend; } } if (count) @@ -5725,6 +5749,7 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) UART_LOG_DBG(port->ipc_log_pwr, dev, "%s: End %d\n", __func__, ret); __pm_relax(port->geni_wake); exit_runtime_suspend: + mutex_unlock(&port->suspend_resume_lock); return ret; }