* [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open
@ 2026-10-15 14:46 Otavio Salvador
2026-10-15 14:59 ` sashiko-bot
2026-10-15 15:24 ` Frank Li
0 siblings, 2 replies; 3+ messages in thread
From: Otavio Salvador @ 2026-10-15 14:46 UTC (permalink / raw)
To: gregkh, jirislaby
Cc: Frank.Li, s.hauer, kernel, festevam, linux-serial, imx,
linux-arm-kernel, linux-kernel, Otavio Salvador,
Rodrigo M. Duarte
In RS485 mode the driver releases the transmitter (RTS/DE) from the TX
complete interrupt. On i.MX6UL/ULL the imx6sx cpuidle driver offers an
"ARM power off" state with a declared exit latency of 300us, measured at
up to 2ms. When the CPU enters it while the last character is shifted
out, DE is released that much later. Modbus RTU slaves may answer after
3.5 character times (1.75ms at >=19200 baud), so the head of their reply
collides with our still-driven transmitter and is lost.
Add a CPU latency QoS request of 100us while an RS485 port is open. It
excludes the power-off state but keeps WFI and WAIT (50us) available, so
cpuidle can stay enabled and the constraint only applies while the port
is in use.
The request is added on startup and removed on shutdown, and its value
follows the RS485 state in imx_uart_rs485_config(), so RS485 enabled
through TIOCSRS485 after the port is opened, as libmodbus does, is
covered as well.
Tested-by: Rodrigo M. Duarte <rodrigo.duarte@ossystems.com.br>
Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
---
drivers/tty/serial/imx.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 986fefb45c632..be05ed94bf0c4 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -24,6 +24,7 @@
#include <linux/ktime.h>
#include <linux/mutex.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pm_qos.h>
#include <linux/rational.h>
#include <linux/slab.h>
#include <linux/of.h>
@@ -237,6 +238,7 @@ struct imx_port {
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
unsigned int rxtl;
+ struct pm_qos_request rs485_pm_qos;
};
struct imx_port_ucrs {
@@ -339,6 +341,22 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL);
}
+/*
+ * In RS485 mode the transmitter is only released from the TX complete
+ * interrupt. If the CPU sits in a deep idle state at that point, the wakeup
+ * delays the release long enough to collide with fast responders on the
+ * bus. The i.MX6UL/SX "ARM power off" state has a 300us exit latency and was
+ * measured at up to 2ms, so keep the CPU out of states slower than this while
+ * an RS485 port is open.
+ */
+#define IMX_UART_RS485_CPU_LATENCY_US 100
+
+static s32 imx_uart_rs485_cpu_latency(u32 rs485_flags)
+{
+ return rs485_flags & SER_RS485_ENABLED ?
+ IMX_UART_RS485_CPU_LATENCY_US : PM_QOS_DEFAULT_VALUE;
+}
+
/* called with port.lock taken and irqs off */
static void imx_uart_soft_reset(struct imx_port *sport)
{
@@ -1585,6 +1603,9 @@ static int imx_uart_startup(struct uart_port *port)
uart_port_unlock_irqrestore(&sport->port, flags);
+ cpu_latency_qos_add_request(&sport->rs485_pm_qos,
+ imx_uart_rs485_cpu_latency(port->rs485.flags));
+
return 0;
}
@@ -1710,6 +1731,8 @@ static void imx_uart_shutdown(struct uart_port *port)
clk_disable_unprepare(sport->clk_per);
clk_disable_unprepare(sport->clk_ipg);
+
+ cpu_latency_qos_remove_request(&sport->rs485_pm_qos);
}
/* called with port.lock taken and irqs off */
@@ -2053,6 +2076,11 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
imx_uart_start_rx(port);
}
+ /* The request only exists while the port is open */
+ if (cpu_latency_qos_request_active(&sport->rs485_pm_qos))
+ cpu_latency_qos_update_request(&sport->rs485_pm_qos,
+ imx_uart_rs485_cpu_latency(rs485conf->flags));
+
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open
2026-10-15 14:46 [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open Otavio Salvador
@ 2026-10-15 14:59 ` sashiko-bot
2026-10-15 15:24 ` Frank Li
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-10-15 14:59 UTC (permalink / raw)
To: Otavio Salvador; +Cc: linux-serial
> In RS485 mode the driver releases the transmitter (RTS/DE) from the TX
> complete interrupt. On i.MX6UL/ULL the imx6sx cpuidle driver offers an
> "ARM power off" state with a declared exit latency of 300us, measured at
> up to 2ms. When the CPU enters it while the last character is shifted
> out, DE is released that much later. Modbus RTU slaves may answer after
> 3.5 character times (1.75ms at >=19200 baud), so the head of their reply
> collides with our still-driven transmitter and is lost.
>
> Add a CPU latency QoS request of 100us while an RS485 port is open. It
> excludes the power-off state but keeps WFI and WAIT (50us) available, so
> cpuidle can stay enabled and the constraint only applies while the port
> is in use.
>
> The request is added on startup and removed on shutdown, and its value
> follows the RS485 state in imx_uart_rs485_config(), so RS485 enabled
> through TIOCSRS485 after the port is opened, as libmodbus does, is
> covered as well.
>
> Tested-by: Rodrigo M. Duarte <rodrigo.duarte@ossystems.com.br>
> Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
Sashiko has reviewed this patch and found no issues. It looks great!
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261015144627.2461915-1-otavio@ossystems.com.br?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open
2026-10-15 14:46 [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open Otavio Salvador
2026-10-15 14:59 ` sashiko-bot
@ 2026-10-15 15:24 ` Frank Li
1 sibling, 0 replies; 3+ messages in thread
From: Frank Li @ 2026-10-15 15:24 UTC (permalink / raw)
To: Otavio Salvador
Cc: gregkh, jirislaby, Frank.Li, s.hauer, kernel, festevam,
linux-serial, imx, linux-arm-kernel, linux-kernel,
Rodrigo M. Duarte
On Thu, Oct 15, 2026 at 11:46:27AM -0300, Otavio Salvador wrote:
> [You don't often get email from otavio@ossystems.com.br. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> In RS485 mode the driver releases the transmitter (RTS/DE) from the TX
> complete interrupt. On i.MX6UL/ULL the imx6sx cpuidle driver offers an
> "ARM power off" state with a declared exit latency of 300us, measured at
> up to 2ms. When the CPU enters it while the last character is shifted
> out, DE is released that much later. Modbus RTU slaves may answer after
> 3.5 character times (1.75ms at >=19200 baud), so the head of their reply
> collides with our still-driven transmitter and is lost.
>
> Add a CPU latency QoS request of 100us while an RS485 port is open. It
> excludes the power-off state but keeps WFI and WAIT (50us) available, so
> cpuidle can stay enabled and the constraint only applies while the port
> is in use.
>
> The request is added on startup and removed on shutdown, and its value
> follows the RS485 state in imx_uart_rs485_config(), so RS485 enabled
> through TIOCSRS485 after the port is opened, as libmodbus does, is
> covered as well.
>
> Tested-by: Rodrigo M. Duarte <rodrigo.duarte@ossystems.com.br>
> Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
> ---
Reviewed-by: Frank Li <Frank.Li@nxp.com>
> drivers/tty/serial/imx.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
> index 986fefb45c632..be05ed94bf0c4 100644
> --- a/drivers/tty/serial/imx.c
> +++ b/drivers/tty/serial/imx.c
> @@ -24,6 +24,7 @@
> #include <linux/ktime.h>
> #include <linux/mutex.h>
> #include <linux/pinctrl/consumer.h>
> +#include <linux/pm_qos.h>
> #include <linux/rational.h>
> #include <linux/slab.h>
> #include <linux/of.h>
> @@ -237,6 +238,7 @@ struct imx_port {
> struct hrtimer trigger_start_tx;
> struct hrtimer trigger_stop_tx;
> unsigned int rxtl;
> + struct pm_qos_request rs485_pm_qos;
> };
>
> struct imx_port_ucrs {
> @@ -339,6 +341,22 @@ static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec)
> hrtimer_start(hrt, ms_to_ktime(msec), HRTIMER_MODE_REL);
> }
>
> +/*
> + * In RS485 mode the transmitter is only released from the TX complete
> + * interrupt. If the CPU sits in a deep idle state at that point, the wakeup
> + * delays the release long enough to collide with fast responders on the
> + * bus. The i.MX6UL/SX "ARM power off" state has a 300us exit latency and was
> + * measured at up to 2ms, so keep the CPU out of states slower than this while
> + * an RS485 port is open.
> + */
> +#define IMX_UART_RS485_CPU_LATENCY_US 100
> +
> +static s32 imx_uart_rs485_cpu_latency(u32 rs485_flags)
> +{
> + return rs485_flags & SER_RS485_ENABLED ?
> + IMX_UART_RS485_CPU_LATENCY_US : PM_QOS_DEFAULT_VALUE;
> +}
> +
> /* called with port.lock taken and irqs off */
> static void imx_uart_soft_reset(struct imx_port *sport)
> {
> @@ -1585,6 +1603,9 @@ static int imx_uart_startup(struct uart_port *port)
>
> uart_port_unlock_irqrestore(&sport->port, flags);
>
> + cpu_latency_qos_add_request(&sport->rs485_pm_qos,
> + imx_uart_rs485_cpu_latency(port->rs485.flags));
> +
> return 0;
> }
>
> @@ -1710,6 +1731,8 @@ static void imx_uart_shutdown(struct uart_port *port)
>
> clk_disable_unprepare(sport->clk_per);
> clk_disable_unprepare(sport->clk_ipg);
> +
> + cpu_latency_qos_remove_request(&sport->rs485_pm_qos);
> }
>
> /* called with port.lock taken and irqs off */
> @@ -2053,6 +2076,11 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
> imx_uart_start_rx(port);
> }
>
> + /* The request only exists while the port is open */
> + if (cpu_latency_qos_request_active(&sport->rs485_pm_qos))
> + cpu_latency_qos_update_request(&sport->rs485_pm_qos,
> + imx_uart_rs485_cpu_latency(rs485conf->flags));
> +
> return 0;
> }
>
> --
> 2.55.0
>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-15 15:25 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 14:46 [PATCH] serial: imx: keep the CPU out of deep idle while an RS485 port is open Otavio Salvador
2026-10-15 14:59 ` sashiko-bot
2026-10-15 15:24 ` Frank Li
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.