[PATCH 1/2] serial: qcom_geni: Add shutdown callback to quiesce hardware on reboot
Praveen Talari <[email protected]>
| Newsgroups | org.kernel.vger.linux-serial,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260715-add_shutdown_and_panic_notifier_serial-v1-1-23e3787c7109@oss.qualcomm.com> |
During system reboot, an active UART DMA transfer can leave the GENI Serial Engine in an indeterminate state. On VM-based platforms, if a DMA transfer is in progress when the VM is shut down, the SMMU can raise context faults as the DMA engine continues to access IOVAs that have already been invalidated during VM teardown. Add a shutdown callback to stop TX and RX and bring the hardware to idle before the system resets, preventing both hardware state corruption on reboot and SMMU faults during VM shutdown. The port lock is not taken here since shutdown runs from process context with the device already quiesced from the UART core's perspective; instead, the runtime PM status is checked so that TX/RX are only stopped while clocks and resources are still active, avoiding any register access once the device is runtime suspended. Signed-off-by: Praveen Talari <[email protected]> --- drivers/tty/serial/qcom_geni_serial.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 7ead87b4eb65..21ac2e3bad81 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -2049,6 +2049,18 @@ static const struct dev_pm_ops qcom_geni_serial_pm_ops = { SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume) }; +static void qcom_geni_serial_sys_shutdown(struct platform_device *pdev) +{ + struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct uart_port *uport = &port->uport; + + if (pm_runtime_status_suspended(uport->dev)) + return; + + qcom_geni_serial_stop_tx(uport); + qcom_geni_serial_stop_rx(uport); +} + static const struct of_device_id qcom_geni_serial_match_table[] = { #if IS_ENABLED(CONFIG_SERIAL_QCOM_GENI_CONSOLE) { @@ -2075,6 +2087,7 @@ MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); static struct platform_driver qcom_geni_serial_platform_driver = { .remove = qcom_geni_serial_remove, .probe = qcom_geni_serial_probe, + .shutdown = qcom_geni_serial_sys_shutdown, .driver = { .name = "qcom_geni_serial", .of_match_table = qcom_geni_serial_match_table, -- 2.34.1