devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO
@ 2023-10-16  1:32 Richard Laing
  2023-10-16  1:32 ` [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port Richard Laing
  2023-10-16  1:32 ` [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
  0 siblings, 2 replies; 6+ messages in thread
From: Richard Laing @ 2023-10-16  1:32 UTC (permalink / raw)
  To: gregkh, jirislaby, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	ilpo.jarvinen, andriy.shevchenko
  Cc: linux-kernel, linux-serial, devicetree, Richard Laing

During development of a new hardware an issue was seen where writes to
UART_LCR can result in characters that are currently held in the TX FIFO
being lost rather than sent, even if the userspace process has attempted to
flush them.

This is most visible when using the "resize" command (tested on Busybox),
where we have observed the escape code for restoring cursor position
becoming mangled.

This is the same issue as addressed in 
commit 914eaf935ec7 ("serial: 8250_dw: Allow TX FIFO to drain before
writing to UART_LCR") 

for the Armada 38x serial port. This patch makes the fix more generic
allowing it to be applied on any similar UART.

Richard Laing (2):
  serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An
    issue has been observed on the Broadcom BCM56160 serial port which
    appears closely related to a similar issue on the Marvell Armada 38x
    serial port.
  dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO

 .../bindings/serial/snps-dw-apb-uart.yaml      |  6 ++++++
 drivers/tty/serial/8250/8250_dw.c              | 18 ++++++++++++++++++
 drivers/tty/serial/8250/8250_dwlib.h           |  1 +
 3 files changed, 25 insertions(+)

-- 
2.42.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port.
  2023-10-16  1:32 [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
@ 2023-10-16  1:32 ` Richard Laing
  2023-10-16 12:13   ` Ilpo Järvinen
  2023-10-16  1:32 ` [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
  1 sibling, 1 reply; 6+ messages in thread
From: Richard Laing @ 2023-10-16  1:32 UTC (permalink / raw)
  To: gregkh, jirislaby, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	ilpo.jarvinen, andriy.shevchenko
  Cc: linux-kernel, linux-serial, devicetree, Richard Laing

Writes to UART_LCR can result in characters that are currently held in the
TX FIFO being lost rather than sent, even if the userspace process has
attempted to flush them.

This is most visible when using the "resize" command (tested on Busybox),
where we have observed the escape code for restoring cursor position
becoming mangled.

Since this appears to be a more common problem add a new driver option
to flush the TX FIFO before writing to the UART_LCR.

Signed-off-by: Richard Laing <richard.laing@alliedtelesis.co.nz>
---
 drivers/tty/serial/8250/8250_dw.c    | 18 ++++++++++++++++++
 drivers/tty/serial/8250/8250_dwlib.h |  1 +
 2 files changed, 19 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index f4cafca1a7da..17ee824294c7 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -161,6 +161,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
 {
 	struct dw8250_data *d = to_dw8250_data(p->private_data);
 
+	/* Allow the TX to drain before we reconfigure */
+	if (offset == UART_LCR && d->drain_before_lcr_change)
+		dw8250_tx_wait_empty(p);
+
 	writeb(value, p->membase + (offset << p->regshift));
 
 	if (offset == UART_LCR && !d->uart_16550_compatible)
@@ -197,6 +201,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
 {
 	struct dw8250_data *d = to_dw8250_data(p->private_data);
 
+	/* Allow the TX to drain before we reconfigure */
+	if (offset == UART_LCR && d->drain_before_lcr_change)
+		dw8250_tx_wait_empty(p);
+
 	value &= 0xff;
 	__raw_writeq(value, p->membase + (offset << p->regshift));
 	/* Read back to ensure register write ordering. */
@@ -211,6 +219,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
 {
 	struct dw8250_data *d = to_dw8250_data(p->private_data);
 
+	/* Allow the TX to drain before we reconfigure */
+	if (offset == UART_LCR && d->drain_before_lcr_change)
+		dw8250_tx_wait_empty(p);
+
 	writel(value, p->membase + (offset << p->regshift));
 
 	if (offset == UART_LCR && !d->uart_16550_compatible)
@@ -228,6 +240,10 @@ static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
 {
 	struct dw8250_data *d = to_dw8250_data(p->private_data);
 
+	/* Allow the TX to drain before we reconfigure */
+	if (offset == UART_LCR && d->drain_before_lcr_change)
+		dw8250_tx_wait_empty(p);
+
 	iowrite32be(value, p->membase + (offset << p->regshift));
 
 	if (offset == UART_LCR && !d->uart_16550_compatible)
@@ -597,6 +613,8 @@ static int dw8250_probe(struct platform_device *pdev)
 	/* Always ask for fixed clock rate from a property. */
 	device_property_read_u32(dev, "clock-frequency", &p->uartclk);
 
+	data->drain_before_lcr_change = device_property_read_bool(dev, "drain-before-lcr-change");
+
 	/* If there is separate baudclk, get the rate from it. */
 	data->clk = devm_clk_get_optional(dev, "baudclk");
 	if (data->clk == NULL)
diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
index f13e91f2cace..f7d88fa8f058 100644
--- a/drivers/tty/serial/8250/8250_dwlib.h
+++ b/drivers/tty/serial/8250/8250_dwlib.h
@@ -45,6 +45,7 @@ struct dw8250_data {
 
 	unsigned int		skip_autocfg:1;
 	unsigned int		uart_16550_compatible:1;
+	unsigned int		drain_before_lcr_change:1;
 };
 
 void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO
  2023-10-16  1:32 [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
  2023-10-16  1:32 ` [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port Richard Laing
@ 2023-10-16  1:32 ` Richard Laing
  2023-10-16  2:19   ` Rob Herring
  1 sibling, 1 reply; 6+ messages in thread
From: Richard Laing @ 2023-10-16  1:32 UTC (permalink / raw)
  To: gregkh, jirislaby, robh+dt, krzysztof.kozlowski+dt, conor+dt,
	ilpo.jarvinen, andriy.shevchenko
  Cc: linux-kernel, linux-serial, devicetree, Richard Laing

An issue has been observed on the Broadcom BCM56160 serial port which
appears closely related to a similar issue on the Marvell Armada 38x
serial port.

Add a new property to force the TX FIFO to be drained before
changing the UART_LCR.

Signed-off-by: Richard Laing <richard.laing@alliedtelesis.co.nz>
---
 .../devicetree/bindings/serial/snps-dw-apb-uart.yaml        | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
index 17c553123f96..4266ef96832c 100644
--- a/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
+++ b/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml
@@ -114,6 +114,12 @@ properties:
       register. Define this if your serial port does not use this pin.
     type: boolean
 
+  drain-before-lcr-change:
+    description: Force TX buffer flush before LCR change. Make sure all
+    characters in the buffer are sent before reconfiguring. Define this if
+    the UART drops its FIFO when reconfiguring.
+    type: boolean
+
 required:
   - compatible
   - reg
-- 
2.42.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO
  2023-10-16  1:32 ` [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
@ 2023-10-16  2:19   ` Rob Herring
  0 siblings, 0 replies; 6+ messages in thread
From: Rob Herring @ 2023-10-16  2:19 UTC (permalink / raw)
  To: Richard Laing
  Cc: robh+dt, jirislaby, andriy.shevchenko, ilpo.jarvinen, gregkh,
	krzysztof.kozlowski+dt, conor+dt, linux-serial, devicetree,
	linux-kernel


On Mon, 16 Oct 2023 14:32:07 +1300, Richard Laing wrote:
> An issue has been observed on the Broadcom BCM56160 serial port which
> appears closely related to a similar issue on the Marvell Armada 38x
> serial port.
> 
> Add a new property to force the TX FIFO to be drained before
> changing the UART_LCR.
> 
> Signed-off-by: Richard Laing <richard.laing@alliedtelesis.co.nz>
> ---
>  .../devicetree/bindings/serial/snps-dw-apb-uart.yaml        | 6 ++++++
>  1 file changed, 6 insertions(+)
> 

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:
./Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml:120:5: [error] syntax error: could not find expected ':' (syntax)

dtschema/dtc warnings/errors:
make[2]: *** Deleting file 'Documentation/devicetree/bindings/serial/snps-dw-apb-uart.example.dts'
Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml:120:5: could not find expected ':'
make[2]: *** [Documentation/devicetree/bindings/Makefile:26: Documentation/devicetree/bindings/serial/snps-dw-apb-uart.example.dts] Error 1
make[2]: *** Waiting for unfinished jobs....
./Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml:120:5: could not find expected ':'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/serial/snps-dw-apb-uart.yaml: ignoring, error parsing file
make[1]: *** [/builds/robherring/dt-review-ci/linux/Makefile:1427: dt_binding_check] Error 2
make: *** [Makefile:234: __sub-make] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20231016013207.2249946-3-richard.laing@alliedtelesis.co.nz

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port.
  2023-10-16  1:32 ` [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port Richard Laing
@ 2023-10-16 12:13   ` Ilpo Järvinen
  2023-10-16 12:20     ` Ilpo Järvinen
  0 siblings, 1 reply; 6+ messages in thread
From: Ilpo Järvinen @ 2023-10-16 12:13 UTC (permalink / raw)
  To: Richard Laing
  Cc: Greg Kroah-Hartman, Jiri Slaby, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, ilpo.jarvinen, Andy Shevchenko, LKML, linux-serial,
	devicetree

On Mon, 16 Oct 2023, Richard Laing wrote:

Your subject line is way too long. If you refer to some other issue, 
please link to it properly with commit id and/or with Link: tags.

> Writes to UART_LCR can result in characters that are currently held in the
> TX FIFO being lost rather than sent, even if the userspace process has
> attempted to flush them.
> 
> This is most visible when using the "resize" command (tested on Busybox),
> where we have observed the escape code for restoring cursor position
> becoming mangled.
> 
> Since this appears to be a more common problem add a new driver option
> to flush the TX FIFO before writing to the UART_LCR.

This looks like a problem we already have solution for, the userspace can 
use TCSADRAIN/FLUSH to indicate what kind of flushing it wants for Tx 
when it makes the tcsetattr() call. Thus, userspace can avoid the Tx side 
corruption as long as its behavior is sane and doesn't e.g. try to race 
writes with tcsetattr() call as mentioned in commit 094fb49a2d0d ("tty: 
Prevent writing chars during tcsetattr TCSADRAIN/FLUSH").

Have you tried to use the userspace solution? Isn't it working for some 
reason?

-- 
 i.

> 
> Signed-off-by: Richard Laing <richard.laing@alliedtelesis.co.nz>
> ---
>  drivers/tty/serial/8250/8250_dw.c    | 18 ++++++++++++++++++
>  drivers/tty/serial/8250/8250_dwlib.h |  1 +
>  2 files changed, 19 insertions(+)
> 
> diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
> index f4cafca1a7da..17ee824294c7 100644
> --- a/drivers/tty/serial/8250/8250_dw.c
> +++ b/drivers/tty/serial/8250/8250_dw.c
> @@ -161,6 +161,10 @@ static void dw8250_serial_out(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	writeb(value, p->membase + (offset << p->regshift));
>  
>  	if (offset == UART_LCR && !d->uart_16550_compatible)
> @@ -197,6 +201,10 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	value &= 0xff;
>  	__raw_writeq(value, p->membase + (offset << p->regshift));
>  	/* Read back to ensure register write ordering. */
> @@ -211,6 +219,10 @@ static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	writel(value, p->membase + (offset << p->regshift));
>  
>  	if (offset == UART_LCR && !d->uart_16550_compatible)
> @@ -228,6 +240,10 @@ static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
>  {
>  	struct dw8250_data *d = to_dw8250_data(p->private_data);
>  
> +	/* Allow the TX to drain before we reconfigure */
> +	if (offset == UART_LCR && d->drain_before_lcr_change)
> +		dw8250_tx_wait_empty(p);
> +
>  	iowrite32be(value, p->membase + (offset << p->regshift));
>  
>  	if (offset == UART_LCR && !d->uart_16550_compatible)
> @@ -597,6 +613,8 @@ static int dw8250_probe(struct platform_device *pdev)
>  	/* Always ask for fixed clock rate from a property. */
>  	device_property_read_u32(dev, "clock-frequency", &p->uartclk);
>  
> +	data->drain_before_lcr_change = device_property_read_bool(dev, "drain-before-lcr-change");
> +
>  	/* If there is separate baudclk, get the rate from it. */
>  	data->clk = devm_clk_get_optional(dev, "baudclk");
>  	if (data->clk == NULL)
> diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
> index f13e91f2cace..f7d88fa8f058 100644
> --- a/drivers/tty/serial/8250/8250_dwlib.h
> +++ b/drivers/tty/serial/8250/8250_dwlib.h
> @@ -45,6 +45,7 @@ struct dw8250_data {
>  
>  	unsigned int		skip_autocfg:1;
>  	unsigned int		uart_16550_compatible:1;
> +	unsigned int		drain_before_lcr_change:1;
>  };
>  
>  void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port.
  2023-10-16 12:13   ` Ilpo Järvinen
@ 2023-10-16 12:20     ` Ilpo Järvinen
  0 siblings, 0 replies; 6+ messages in thread
From: Ilpo Järvinen @ 2023-10-16 12:20 UTC (permalink / raw)
  To: Richard Laing
  Cc: Greg Kroah-Hartman, Jiri Slaby, robh+dt, krzysztof.kozlowski+dt,
	conor+dt, Andy Shevchenko, LKML, linux-serial, devicetree

[-- Attachment #1: Type: text/plain, Size: 1450 bytes --]

On Mon, 16 Oct 2023, Ilpo Järvinen wrote:

> On Mon, 16 Oct 2023, Richard Laing wrote:
> 
> Your subject line is way too long. If you refer to some other issue, 
> please link to it properly with commit id and/or with Link: tags.
> 
> > Writes to UART_LCR can result in characters that are currently held in the
> > TX FIFO being lost rather than sent, even if the userspace process has
> > attempted to flush them.
> > 
> > This is most visible when using the "resize" command (tested on Busybox),
> > where we have observed the escape code for restoring cursor position
> > becoming mangled.
> > 
> > Since this appears to be a more common problem add a new driver option
> > to flush the TX FIFO before writing to the UART_LCR.
> 
> This looks like a problem we already have solution for, the userspace can 
> use TCSADRAIN/FLUSH to indicate what kind of flushing it wants for Tx 
> when it makes the tcsetattr() call. Thus, userspace can avoid the Tx side 
> corruption as long as its behavior is sane and doesn't e.g. try to race 
> writes with tcsetattr() call as mentioned in commit 094fb49a2d0d ("tty: 
> Prevent writing chars during tcsetattr TCSADRAIN/FLUSH").

I'm sorry, it was actually mentioned in commit 146a37e05d62 ("serial: 
8250: Fix serial8250_tx_empty() race with DMA Tx") although that 
094fb49a2d0d is also related to the draining.

> Have you tried to use the userspace solution? Isn't it working for some 
> reason?

-- 
 i.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-10-16 12:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-16  1:32 [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
2023-10-16  1:32 ` [PATCH] serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Broadcom BCM56160 serial port which appears closely related to a similar issue on the Marvell Armada 38x serial port Richard Laing
2023-10-16 12:13   ` Ilpo Järvinen
2023-10-16 12:20     ` Ilpo Järvinen
2023-10-16  1:32 ` [PATCH] dt-bindings: serial: snps-dw-apb-uart: Add property to drain TX FIFO Richard Laing
2023-10-16  2:19   ` Rob Herring

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).