From patchwork Fri Sep 6 13:13:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Johan Hovold X-Patchwork-Id: 826560 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 597091CEABA; Fri, 6 Sep 2024 13:14:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725628499; cv=none; b=fMaxQOh5gGrub3GjR8oWzwd6r682+WQ5lMxugI3EbNogCXXsZTBDLW/as5drHwEYsQp9usdDXZjVSYled5ESzj8Dx6TSxf5WuAL/CqBRMpQ8BWubsyA66spuIupGpn5TpiQIs1q1kVtyU6PS0NXDIMQcWzuA9pbP1ISMDzcEpsw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725628499; c=relaxed/simple; bh=jnKVyYN+SV7nlAeyPE7L9pSbDmJ6KJbzfXanDeOFtkY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hUVLHTiFh3vcMK9ojU4NK+r4zEpekThtPRLXVb6nfPAD4YLwqdvzkuM0fh8QHQqUu7PXj0LCeM39XX49I9zlxlxr0PdkAR8sRd6HjGkMtKUPbchxKbLhN72GwsJssDf8HPnqdVcMltA7glv1hyH/xsH8DBhRL2s88B39YtPnJ5E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uLplXKpk; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uLplXKpk" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AF385C4CECC; Fri, 6 Sep 2024 13:14:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725628498; bh=jnKVyYN+SV7nlAeyPE7L9pSbDmJ6KJbzfXanDeOFtkY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uLplXKpkQmAFbYwGrhB7HAkJI/iwJ4vFa20ncc8/6gB2Vtz+O8ueLk+01LgB81DOx 1usFrZSQ9vYzGutmG69/+cbrA64je0sNJMRBtxgHXzN965st8INczOeyU1RsQhI3w/ odvFCKgnaGGYGS1Thw2QSm7/Z+zS4w/rZvoBPv28JdMCiOdYB1aM4iHjSKiv8L1BKj SJZOjgiqkoFQ8EHGpR4BT8ux2hL5ZMs+d4GIad2q0l4jFzuGtYpSLBcFnOw+Q6ihWp qxlibYoz33ZB47G9e6KP7VCGJikDA5LURO2Hzpx7buhxoG9deTRa2hIjGvtNvXtuHP fl36JN6ElMt5A== Received: from johan by xi.lan with local (Exim 4.97.1) (envelope-from ) id 1smYo3-000000006Au-3Bw1; Fri, 06 Sep 2024 15:15:19 +0200 From: Johan Hovold To: Greg Kroah-Hartman Cc: Jiri Slaby , Bjorn Andersson , Konrad Dybcio , Douglas Anderson , =?utf-8?q?N=C3=ADcolas_F_=2E_R_?= =?utf-8?q?=2E_A_=2E_Prado?= , linux-arm-msm@vger.kernel.org, linux-serial@vger.kernel.org, linux-kernel@vger.kernel.org, Johan Hovold , stable@vger.kernel.org Subject: [PATCH v2 8/8] serial: qcom-geni: fix polled console corruption Date: Fri, 6 Sep 2024 15:13:36 +0200 Message-ID: <20240906131336.23625-9-johan+linaro@kernel.org> X-Mailer: git-send-email 2.44.2 In-Reply-To: <20240906131336.23625-1-johan+linaro@kernel.org> References: <20240906131336.23625-1-johan+linaro@kernel.org> Precedence: bulk X-Mailing-List: linux-serial@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The polled UART operations are used by the kernel debugger (KDB, KGDB), which can interrupt the kernel at any point in time. The current Qualcomm GENI implementation does not really work when there is on-going serial output as it inadvertently "hijacks" the current tx command, which can result in both the initial debugger output being corrupted as well as the corruption of any on-going serial output (up to 4k characters) when execution resumes: 0190: abcdefghijklmnopqrstuvwxyz0123456789 0190: abcdefghijklmnopqrstuvwxyz0123456789 0191: abcdefghijklmnop[ 50.825552] sysrq: DEBUG qrstuvwxyz0123456789 0191: abcdefghijklmnopqrstuvwxyz0123456789 Entering kdb (current=0xffff53510b4cd280, pid 640) on processor 2 due to Keyboard Entry [2]kdb> go omlji3h3h2g2g1f1f0e0ezdzdycycxbxbwawav :t72r2rp o9n976k5j5j4i4i3h3h2g2g1f1f0e0ezdzdycycxbxbwawavu:t7t8s8s8r2r2q0q0p o9n9n8ml6k6k5j5j4i4i3h3h2g2g1f1f0e0ezdzdycycxbxbwawav v u:u:t9t0s4s4rq0p o9n9n8m8m7l7l6k6k5j5j40q0p p o o9n9n8m8m7l7l6k6k5j5j4i4i3h3h2g2g1f1f0e0ezdzdycycxbxbwawav :t8t9s4s4r4r4q0q0p Fix this by making sure that the polled output implementation waits for the tx fifo to drain before cancelling any on-going longer transfers. As the polled code cannot take any locks, leave the state variables as they are and instead make sure that the interrupt handler always starts a new tx command when there is data in the write buffer. Since the debugger can interrupt the interrupt handler when it is writing data to the tx fifo, it is currently not possible to fully prevent losing up to 64 bytes of tty output on resume. Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") Cc: stable@vger.kernel.org # 4.17 Reviewed-by: Douglas Anderson Tested-by: NĂ­colas F. R. A. Prado Signed-off-by: Johan Hovold --- drivers/tty/serial/qcom_geni_serial.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index f23fd0ac3cfd..6f0db310cf69 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -145,6 +145,7 @@ static const struct uart_ops qcom_geni_uart_pops; static struct uart_driver qcom_geni_console_driver; static struct uart_driver qcom_geni_uart_driver; +static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport); static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport); static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport) @@ -384,13 +385,14 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) static void qcom_geni_serial_poll_put_char(struct uart_port *uport, unsigned char c) { - writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + if (qcom_geni_serial_main_active(uport)) { + qcom_geni_serial_poll_tx_done(uport); + __qcom_geni_serial_cancel_tx_cmd(uport); + } + writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_setup_tx(uport, 1); - WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, - M_TX_FIFO_WATERMARK_EN, true)); writel(c, uport->membase + SE_GENI_TX_FIFOn); - writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_poll_tx_done(uport); } #endif @@ -677,13 +679,10 @@ static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport) writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } -static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport) +static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport); - if (!qcom_geni_serial_main_active(uport)) - return; - geni_se_cancel_m_cmd(&port->se); if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { @@ -693,6 +692,16 @@ static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport) writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); +} + +static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport); + + if (!qcom_geni_serial_main_active(uport)) + return; + + __qcom_geni_serial_cancel_tx_cmd(uport); port->tx_remaining = 0; port->tx_queued = 0; @@ -919,7 +928,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport, if (!chunk) goto out_write_wakeup; - if (!port->tx_remaining) { + if (!active) { qcom_geni_serial_setup_tx(uport, pending); port->tx_remaining = pending; port->tx_queued = 0;