2022-06-22 15:55:29

by Lino Sanfilippo

[permalink] [raw]
Subject: [PATCH 0/8] Fixes and cleanup for RS485

From: Lino Sanfilippo <[email protected]>

The following series includes cleanup and fixes around RS485 in the serial
core and uart drivers:

Patch 1: Only request the rs485 termination gpio if it is supported.
Patch 2: Set the rs485 termination GPIO in the serial core. This is needed
since if the gpio is only accessible in sleepable context. It also
is a further step to make the RS485 handling more generic.
Patch 3: Move sanitizing of RS485 delays into an own function. This is in
preparation of patch 4.
Patch 4: Sanitize RS485 delays read from device tree.
Patch 5: Correct RS485 delays in binding documentation.
Patch 6: Remove redundant code in 8250_dwlib.
Patch 7: Remove redundant code in ar933x.
Patch 8: Remove redundant code in 8250-lpc18xx.

This patchset is based tty-testing.

Lino Sanfilippo (8):
serial: core: only get RS485 termination gpio if supported
serial: core, 8250: set RS485 termination gpio in serial core
serial: core: move sanitizing of RS485 delays into own function
serial: core: sanitize RS485 delays read from device tree
dt_bindings: rs485: Correct delay values
serial: 8250_dwlib: remove redundant sanity check for RS485 flags
serial: ar933x: Remove redundant assignment in rs485_config
serial: 8250: lpc18xx: Remove redundant sanity check for RS485 flags

.../devicetree/bindings/serial/rs485.yaml | 4 +-
drivers/tty/serial/8250/8250_dwlib.c | 10 +--
drivers/tty/serial/8250/8250_lpc18xx.c | 6 +-
drivers/tty/serial/8250/8250_port.c | 3 -
drivers/tty/serial/ar933x_uart.c | 1 -
drivers/tty/serial/serial_core.c | 85 ++++++++++++-------
6 files changed, 59 insertions(+), 50 deletions(-)


base-commit: df36f3e3fbb76d30d623a1623e31e3ce9c2fa750
--
2.36.1


2022-06-22 15:57:04

by Lino Sanfilippo

[permalink] [raw]
Subject: [PATCH 8/8] serial: 8250: lpc18xx: Remove redundant sanity check for RS485 flags

From: Lino Sanfilippo <[email protected]>

Before the drivers rs485_config() function is called the serial core
already ensures that only one of both options RTS on send or RTS after send
is set. So remove the concerning sanity check in the driver function to
avoid redundancy.

Signed-off-by: Lino Sanfilippo <[email protected]>
---
drivers/tty/serial/8250/8250_lpc18xx.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 3a1cb51cbc91..21896adeb172 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -44,12 +44,8 @@ static int lpc18xx_rs485_config(struct uart_port *port,
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
LPC18XX_UART_RS485CTRL_DCTRL;

- if (rs485->flags & SER_RS485_RTS_ON_SEND) {
+ if (rs485->flags & SER_RS485_RTS_ON_SEND)
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV;
- rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
- } else {
- rs485->flags |= SER_RS485_RTS_AFTER_SEND;
- }
}

if (rs485->delay_rts_after_send) {
--
2.36.1

2022-06-22 16:12:03

by Lino Sanfilippo

[permalink] [raw]
Subject: [PATCH 7/8] serial: ar933x: Remove redundant assignment in rs485_config

From: Lino Sanfilippo <[email protected]>

In uart_set_rs485_config() the serial core already assigns the passed
serial_rs485 struct to the uart port.

So remove the assignment in the drivers rs485_config() function to avoid
redundancy.

Signed-off-by: Lino Sanfilippo <[email protected]>
---
drivers/tty/serial/ar933x_uart.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index ab2c5b2a1ce8..857e010d01dc 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -591,7 +591,6 @@ static int ar933x_config_rs485(struct uart_port *port,
dev_err(port->dev, "RS485 needs rts-gpio\n");
return 1;
}
- port->rs485 = *rs485conf;
return 0;
}

--
2.36.1

2022-06-22 16:12:54

by Lino Sanfilippo

[permalink] [raw]
Subject: [PATCH 4/8] serial: core: sanitize RS485 delays read from device tree

From: Lino Sanfilippo <[email protected]>

When setting the RS485 configuration from userspace via TIOCSRS485 the
delays are clamped to 100ms. Make this consistent with the values passed
in by means of device tree parameters.

Signed-off-by: Lino Sanfilippo <[email protected]>
---
drivers/tty/serial/serial_core.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index fa6acadd7d0c..2e9f90e73e62 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3382,6 +3382,8 @@ int uart_get_rs485_mode(struct uart_port *port)
rs485conf->delay_rts_after_send = 0;
}

+ uart_sanitize_serial_rs485_delays(port, rs485conf);
+
/*
* Clear full-duplex and enabled flags, set RTS polarity to active high
* to get to a defined state with the following properties:
--
2.36.1

2022-06-22 16:13:02

by Lino Sanfilippo

[permalink] [raw]
Subject: [PATCH 3/8] serial: core: move sanitizing of RS485 delays into own function

From: Lino Sanfilippo <[email protected]>

Move the sanitizing of RS485 delays out of uart_sanitize_serial_rs485()
into the new function uart_sanitize_serial_rs485_delays().

Signed-off-by: Lino Sanfilippo <[email protected]>
---
drivers/tty/serial/serial_core.c | 46 ++++++++++++++++++--------------
1 file changed, 26 insertions(+), 20 deletions(-)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index b387376e6fa2..fa6acadd7d0c 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1297,27 +1297,9 @@ static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *r
return 0;
}

-static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+static void uart_sanitize_serial_rs485_delays(struct uart_port *port,
+ struct serial_rs485 *rs485)
{
- u32 supported_flags = port->rs485_supported->flags;
-
- if (!(rs485->flags & SER_RS485_ENABLED)) {
- memset(rs485, 0, sizeof(*rs485));
- return;
- }
-
- /* pick sane settings if the user hasn't */
- if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) &&
- !(rs485->flags & SER_RS485_RTS_ON_SEND) ==
- !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
- dev_warn_ratelimited(port->dev,
- "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
- port->name, port->line);
- rs485->flags |= SER_RS485_RTS_ON_SEND;
- rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
- supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND;
- }
-
if (!port->rs485_supported->delay_rts_before_send) {
if (rs485->delay_rts_before_send) {
dev_warn_ratelimited(port->dev,
@@ -1345,9 +1327,33 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
"%s (%d): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_after_send);
}
+}
+
+static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+{
+ u32 supported_flags = port->rs485_supported->flags;
+
+ if (!(rs485->flags & SER_RS485_ENABLED)) {
+ memset(rs485, 0, sizeof(*rs485));
+ return;
+ }
+
+ /* pick sane settings if the user hasn't */
+ if ((supported_flags & (SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND)) &&
+ !(rs485->flags & SER_RS485_RTS_ON_SEND) ==
+ !(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
+ dev_warn_ratelimited(port->dev,
+ "%s (%d): invalid RTS setting, using RTS_ON_SEND instead\n",
+ port->name, port->line);
+ rs485->flags |= SER_RS485_RTS_ON_SEND;
+ rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
+ supported_flags |= SER_RS485_RTS_ON_SEND|SER_RS485_RTS_AFTER_SEND;
+ }

rs485->flags &= supported_flags;

+ uart_sanitize_serial_rs485_delays(port, rs485);
+
/* Return clean padding area to userspace */
memset(rs485->padding, 0, sizeof(rs485->padding));
}
--
2.36.1

2022-06-22 16:14:08

by Lino Sanfilippo

[permalink] [raw]
Subject: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

From: Lino Sanfilippo <[email protected]>

In serial8250_em485_config() the termination GPIO is set with the uart_port
spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
since the concerning GPIO expander is connected via SPI or I2C).

Fix this by setting the termination line outside of the uart_port spinlock
in the serial core.

This also makes setting the termination GPIO generic for all uart drivers.

Signed-off-by: Lino Sanfilippo <[email protected]>
---
drivers/tty/serial/8250/8250_port.c | 3 ---
drivers/tty/serial/serial_core.c | 12 ++++++++++++
2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 3e3d784aa628..5245c179cc51 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -675,9 +675,6 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
}

- gpiod_set_value(port->rs485_term_gpio,
- rs485->flags & SER_RS485_TERMINATE_BUS);
-
/*
* Both serial8250_em485_init() and serial8250_em485_destroy()
* are idempotent.
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 015f4e1da647..b387376e6fa2 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1352,12 +1352,23 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
memset(rs485->padding, 0, sizeof(rs485->padding));
}

+static void uart_set_rs485_termination(struct uart_port *port,
+ const struct serial_rs485 *rs485)
+{
+ if (!port->rs485_term_gpio || !(rs485->flags & SER_RS485_ENABLED))
+ return;
+
+ gpiod_set_value_cansleep(port->rs485_term_gpio,
+ !!(rs485->flags & SER_RS485_TERMINATE_BUS));
+}
+
int uart_rs485_config(struct uart_port *port)
{
struct serial_rs485 *rs485 = &port->rs485;
int ret;

uart_sanitize_serial_rs485(port, rs485);
+ uart_set_rs485_termination(port, rs485);

ret = port->rs485_config(port, rs485);
if (ret)
@@ -1400,6 +1411,7 @@ static int uart_set_rs485_config(struct uart_port *port,
if (ret)
return ret;
uart_sanitize_serial_rs485(port, &rs485);
+ uart_set_rs485_termination(port, &rs485);

spin_lock_irqsave(&port->lock, flags);
ret = port->rs485_config(port, &rs485);
--
2.36.1

2022-06-22 17:10:58

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

On Wed, Jun 22, 2022 at 05:46:53PM +0200, Lino Sanfilippo wrote:
> From: Lino Sanfilippo <[email protected]>
>
> In serial8250_em485_config() the termination GPIO is set with the uart_port
> spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
> since the concerning GPIO expander is connected via SPI or I2C).
>
> Fix this by setting the termination line outside of the uart_port spinlock
> in the serial core.

This doesn't describe that this patch is actually changing GPIO to support
sleep mode. So, it doesn't fix anything. Please rephrase the commit message
accordingly.

> This also makes setting the termination GPIO generic for all uart drivers.

UART

--
With Best Regards,
Andy Shevchenko


2022-06-23 02:10:51

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

On 22.06.22 at 19:06, Andy Shevchenko wrote:
> On Wed, Jun 22, 2022 at 05:46:53PM +0200, Lino Sanfilippo wrote:
>> From: Lino Sanfilippo <[email protected]>
>>
>> In serial8250_em485_config() the termination GPIO is set with the uart_port
>> spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
>> since the concerning GPIO expander is connected via SPI or I2C).
>>
>> Fix this by setting the termination line outside of the uart_port spinlock
>> in the serial core.
>
> This doesn't describe that this patch is actually changing GPIO to support
> sleep mode. So, it doesn't fix anything. Please rephrase the commit message
> accordingly.

Good point, I will adjust the commit message in the next version.

>> This also makes setting the termination GPIO generic for all uart drivers.
>
> UART
>

Right, upper letters should be used.

Thanks a lot for the review!

Regards,
Lino


2022-06-23 16:55:11

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH 3/8] serial: core: move sanitizing of RS485 delays into own function

On Wed, Jun 22, 2022 at 05:46:54PM +0200, Lino Sanfilippo wrote:
> From: Lino Sanfilippo <[email protected]>
>
> Move the sanitizing of RS485 delays out of uart_sanitize_serial_rs485()
> into the new function uart_sanitize_serial_rs485_delays().

...

> + /* pick sane settings if the user hasn't */

Be consistent with the style (capitalization) of one-line comments. It might
require another patch to make it all consistent.

(Below is left for a context)

> /* Return clean padding area to userspace */

--
With Best Regards,
Andy Shevchenko


2022-06-23 20:29:51

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 3/8] serial: core: move sanitizing of RS485 delays into own function


On 23.06.22 at 18:25, Andy Shevchenko wrote:
> On Wed, Jun 22, 2022 at 05:46:54PM +0200, Lino Sanfilippo wrote:
>> From: Lino Sanfilippo <[email protected]>
>>
>> Move the sanitizing of RS485 delays out of uart_sanitize_serial_rs485()
>> into the new function uart_sanitize_serial_rs485_delays().
>
> ...
>
>> + /* pick sane settings if the user hasn't */
>
> Be consistent with the style (capitalization) of one-line comments.

Ok, I will adjust this.

> (Below is left for a context)
>
>> /* Return clean padding area to userspace */
>
Regards,
Lino

2022-06-25 09:58:13

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 3/8] serial: core: move sanitizing of RS485 delays into own function

On Wed, 22 Jun 2022, Lino Sanfilippo wrote:

> From: Lino Sanfilippo <[email protected]>
>
> Move the sanitizing of RS485 delays out of uart_sanitize_serial_rs485()
> into the new function uart_sanitize_serial_rs485_delays().
>
> Signed-off-by: Lino Sanfilippo <[email protected]>

Reviewed-by: Ilpo J?rvinen <[email protected]>

--
i.

2022-06-25 10:11:00

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 4/8] serial: core: sanitize RS485 delays read from device tree

On Wed, 22 Jun 2022, Lino Sanfilippo wrote:

> From: Lino Sanfilippo <[email protected]>
>
> When setting the RS485 configuration from userspace via TIOCSRS485 the
> delays are clamped to 100ms. Make this consistent with the values passed
> in by means of device tree parameters.
>
> Signed-off-by: Lino Sanfilippo <[email protected]>
> ---
> drivers/tty/serial/serial_core.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index fa6acadd7d0c..2e9f90e73e62 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -3382,6 +3382,8 @@ int uart_get_rs485_mode(struct uart_port *port)
> rs485conf->delay_rts_after_send = 0;
> }
>
> + uart_sanitize_serial_rs485_delays(port, rs485conf);
> +
> /*
> * Clear full-duplex and enabled flags, set RTS polarity to active high
> * to get to a defined state with the following properties:
> --
> 2.36.1

While above works, if we go to this change user-visible behavior route,
uart_get_rs485_mode() could just call full uart_sanitize_serial_rs485()?

The sanitization is currently being done during probe in
uart_rs485_config() which has another challenge to tackle. The RS485
supporting UART drivers are not consistently calling it during their
probe(), only a few of them do but it would make more sense if all of them
would enter into RS485 mode w/ linux,rs485-enabled-at-boot-time being
set. However, making such change might run afoul with the expectations of
users.


--
i.

2022-06-25 10:15:54

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 7/8] serial: ar933x: Remove redundant assignment in rs485_config

On Wed, 22 Jun 2022, Lino Sanfilippo wrote:

> From: Lino Sanfilippo <[email protected]>
>
> In uart_set_rs485_config() the serial core already assigns the passed
> serial_rs485 struct to the uart port.
>
> So remove the assignment in the drivers rs485_config() function to avoid
> redundancy.
>
> Signed-off-by: Lino Sanfilippo <[email protected]>
> ---
> drivers/tty/serial/ar933x_uart.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
> index ab2c5b2a1ce8..857e010d01dc 100644
> --- a/drivers/tty/serial/ar933x_uart.c
> +++ b/drivers/tty/serial/ar933x_uart.c
> @@ -591,7 +591,6 @@ static int ar933x_config_rs485(struct uart_port *port,
> dev_err(port->dev, "RS485 needs rts-gpio\n");
> return 1;
> }
> - port->rs485 = *rs485conf;
> return 0;
> }

Hmm, I realize that for some reason I missed cleaning up this particular
driver after introducing the serial_rs485 sanitization. It shouldn't need
that preceeding if block either because ar933x_no_rs485 gets applied if
there's no rts_gpiod so the core clears SER_RS485_ENABLED.


--
i.

2022-06-25 10:25:41

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 8/8] serial: 8250: lpc18xx: Remove redundant sanity check for RS485 flags

On Wed, 22 Jun 2022, Lino Sanfilippo wrote:

> From: Lino Sanfilippo <[email protected]>
>
> Before the drivers rs485_config() function is called the serial core
> already ensures that only one of both options RTS on send or RTS after send
> is set. So remove the concerning sanity check in the driver function to
> avoid redundancy.
>
> Signed-off-by: Lino Sanfilippo <[email protected]>

Reviewed-by: Ilpo J?rvinen <[email protected]>

--
i.

2022-06-25 10:55:28

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

On Wed, 22 Jun 2022, Lino Sanfilippo wrote:

> From: Lino Sanfilippo <[email protected]>
>
> In serial8250_em485_config() the termination GPIO is set with the uart_port
> spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
> since the concerning GPIO expander is connected via SPI or I2C).
>
> Fix this by setting the termination line outside of the uart_port spinlock
> in the serial core.
>
> This also makes setting the termination GPIO generic for all uart drivers.
>
> Signed-off-by: Lino Sanfilippo <[email protected]>
> ---
> drivers/tty/serial/8250/8250_port.c | 3 ---
> drivers/tty/serial/serial_core.c | 12 ++++++++++++
> 2 files changed, 12 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
> index 3e3d784aa628..5245c179cc51 100644
> --- a/drivers/tty/serial/8250/8250_port.c
> +++ b/drivers/tty/serial/8250/8250_port.c
> @@ -675,9 +675,6 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
> rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
> }
>
> - gpiod_set_value(port->rs485_term_gpio,
> - rs485->flags & SER_RS485_TERMINATE_BUS);
> -
> /*
> * Both serial8250_em485_init() and serial8250_em485_destroy()
> * are idempotent.
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 015f4e1da647..b387376e6fa2 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -1352,12 +1352,23 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
> memset(rs485->padding, 0, sizeof(rs485->padding));
> }
>
> +static void uart_set_rs485_termination(struct uart_port *port,
> + const struct serial_rs485 *rs485)
> +{
> + if (!port->rs485_term_gpio || !(rs485->flags & SER_RS485_ENABLED))
> + return;
> +
> + gpiod_set_value_cansleep(port->rs485_term_gpio,
> + !!(rs485->flags & SER_RS485_TERMINATE_BUS));
> +}
> +
> int uart_rs485_config(struct uart_port *port)
> {
> struct serial_rs485 *rs485 = &port->rs485;
> int ret;
>
> uart_sanitize_serial_rs485(port, rs485);
> + uart_set_rs485_termination(port, rs485);
>
> ret = port->rs485_config(port, rs485);
> if (ret)
> @@ -1400,6 +1411,7 @@ static int uart_set_rs485_config(struct uart_port *port,
> if (ret)
> return ret;
> uart_sanitize_serial_rs485(port, &rs485);
> + uart_set_rs485_termination(port, &rs485);
>
> spin_lock_irqsave(&port->lock, flags);
> ret = port->rs485_config(port, &rs485);

When port->rs485_config(port, &rs485) returns non-zero, the input got
partially applied?


--
i.

2022-06-25 20:06:35

by Lukas Wunner

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

On Wed, Jun 22, 2022 at 05:46:53PM +0200, Lino Sanfilippo wrote:
> From: Lino Sanfilippo <[email protected]>
>
> In serial8250_em485_config() the termination GPIO is set with the uart_port
> spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
> since the concerning GPIO expander is connected via SPI or I2C).
>
> Fix this by setting the termination line outside of the uart_port spinlock
> in the serial core.
[...]
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -1400,6 +1411,7 @@ static int uart_set_rs485_config(struct uart_port *port,
> if (ret)
> return ret;
> uart_sanitize_serial_rs485(port, &rs485);
> + uart_set_rs485_termination(port, &rs485);
>
> spin_lock_irqsave(&port->lock, flags);
> ret = port->rs485_config(port, &rs485);

That's one way to solve the issue. Another would be to push
acquisition of the port spinlock down into drivers.

I think in most drivers we don't need to take the port spinlock at all
or only for a few specific register accesses. So taking the lock here
in the midlayer is likely unwarranted. However, changing that requires
going through every single driver's ->rs485_config() callback and
checking whether it needs the lock or not. That's painful, but
unavoidable in the long run. This patch just kicks the can down the road...

Thanks,

Lukas

2022-06-26 13:53:38

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

On 25.06.22 at 21:58, Lukas Wunner wrote:
> On Wed, Jun 22, 2022 at 05:46:53PM +0200, Lino Sanfilippo wrote:
>> From: Lino Sanfilippo <[email protected]>
>>
>> In serial8250_em485_config() the termination GPIO is set with the uart_port
>> spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
>> since the concerning GPIO expander is connected via SPI or I2C).
>>
>> Fix this by setting the termination line outside of the uart_port spinlock
>> in the serial core.
> [...]
>> --- a/drivers/tty/serial/serial_core.c
>> +++ b/drivers/tty/serial/serial_core.c
>> @@ -1400,6 +1411,7 @@ static int uart_set_rs485_config(struct uart_port *port,
>> if (ret)
>> return ret;
>> uart_sanitize_serial_rs485(port, &rs485);
>> + uart_set_rs485_termination(port, &rs485);
>>
>> spin_lock_irqsave(&port->lock, flags);
>> ret = port->rs485_config(port, &rs485);
>
> That's one way to solve the issue. Another would be to push
> acquisition of the port spinlock down into drivers.
>
> I think in most drivers we don't need to take the port spinlock at all
> or only for a few specific register accesses. So taking the lock here
> in the midlayer is likely unwarranted. However, changing that requires
> going through every single driver's ->rs485_config() callback and
> checking whether it needs the lock or not.

As a first step its sufficient to take the lock in each drivers rs485_config()
function and remove it from uart_set_rs485_config(). Then after time sort out
the drivers that dont require the lock and remove it from their function.

However the point of this patch was also to generalize the handling of the
termination GPIO, so I would still see this placed in uart_set_rs485_config().

Regards,
Lino



2022-06-26 14:22:48

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 7/8] serial: ar933x: Remove redundant assignment in rs485_config

On 25.06.22 at 12:14, Ilpo Järvinen wrote:
> On Wed, 22 Jun 2022, Lino Sanfilippo wrote:
>
>> From: Lino Sanfilippo <[email protected]>
>>
>> In uart_set_rs485_config() the serial core already assigns the passed
>> serial_rs485 struct to the uart port.
>>
>> So remove the assignment in the drivers rs485_config() function to avoid
>> redundancy.
>>
>> Signed-off-by: Lino Sanfilippo <[email protected]>
>> ---
>> drivers/tty/serial/ar933x_uart.c | 1 -
>> 1 file changed, 1 deletion(-)
>>
>> diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
>> index ab2c5b2a1ce8..857e010d01dc 100644
>> --- a/drivers/tty/serial/ar933x_uart.c
>> +++ b/drivers/tty/serial/ar933x_uart.c
>> @@ -591,7 +591,6 @@ static int ar933x_config_rs485(struct uart_port *port,
>> dev_err(port->dev, "RS485 needs rts-gpio\n");
>> return 1;
>> }
>> - port->rs485 = *rs485conf;
>> return 0;
>> }
>
> Hmm, I realize that for some reason I missed cleaning up this particular
> driver after introducing the serial_rs485 sanitization. It shouldn't need
> that preceeding if block either because ar933x_no_rs485 gets applied if
> there's no rts_gpiod so the core clears SER_RS485_ENABLED.
>

I think we still need that "if" in case that RS485 was not enabled at driver
startup (no rs485-enabled-at-boot-time) and no RTS GPIO was defined but then
RS485 is enabled via TIOCSRS485.

Maybe in ar933x_uart_probe()

if ((port->rs485.flags & SER_RS485_ENABLED) &&
!up->rts_gpiod) {
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
port->rs485.flags &= ~SER_RS485_ENABLED;
port->rs485_supported = &ar933x_no_rs485;
}

should rather be

if (!up->rts_gpiod) {
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
port->rs485.flags &= ~SER_RS485_ENABLED;
port->rs485_supported = &ar933x_no_rs485;
}




Regards,
Lino



2022-06-26 15:02:40

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 4/8] serial: core: sanitize RS485 delays read from device tree

On 25.06.22 at 12:05, Ilpo Järvinen wrote:
> On Wed, 22 Jun 2022, Lino Sanfilippo wrote:
>
>> From: Lino Sanfilippo <[email protected]>
>>
>> When setting the RS485 configuration from userspace via TIOCSRS485 the
>> delays are clamped to 100ms. Make this consistent with the values passed
>> in by means of device tree parameters.
>>
>> Signed-off-by: Lino Sanfilippo <[email protected]>
>> ---
>> drivers/tty/serial/serial_core.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
>> index fa6acadd7d0c..2e9f90e73e62 100644
>> --- a/drivers/tty/serial/serial_core.c
>> +++ b/drivers/tty/serial/serial_core.c
>> @@ -3382,6 +3382,8 @@ int uart_get_rs485_mode(struct uart_port *port)
>> rs485conf->delay_rts_after_send = 0;
>> }
>>
>> + uart_sanitize_serial_rs485_delays(port, rs485conf);
>> +
>> /*
>> * Clear full-duplex and enabled flags, set RTS polarity to active high
>> * to get to a defined state with the following properties:
>> --
>> 2.36.1
>
> While above works, if we go to this change user-visible behavior route,
> uart_get_rs485_mode() could just call full uart_sanitize_serial_rs485()?

As it is now uart_sanitize_serial_rs485() will clear the entire serial_rs485 struct and
return immediately if rs485-enabled-at-boot-time (and thus SER_RS485_ENABLED)
is not set. That was one of the reasons I moved the delay checks into an own fucntion. The other
reason is that the remaining sanity check for RTS on send/after send in uart_sanitize_serial_rs485() is not
required in uart_get_rs485_mode() since here we already ensure a sane setting.

Regards,
Lino

2022-06-26 15:50:53

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core


Hi,

On 25.06.22 at 12:40, Ilpo Järvinen wrote:
>> +
>> int uart_rs485_config(struct uart_port *port)
>> {
>> struct serial_rs485 *rs485 = &port->rs485;
>> int ret;
>>
>> uart_sanitize_serial_rs485(port, rs485);
>> + uart_set_rs485_termination(port, rs485);
>>
>> ret = port->rs485_config(port, rs485);
>> if (ret)
>> @@ -1400,6 +1411,7 @@ static int uart_set_rs485_config(struct uart_port *port,
>> if (ret)
>> return ret;
>> uart_sanitize_serial_rs485(port, &rs485);
>> + uart_set_rs485_termination(port, &rs485);
>>
>> spin_lock_irqsave(&port->lock, flags);
>> ret = port->rs485_config(port, &rs485);
>
> When port->rs485_config(port, &rs485) returns non-zero, the input got
> partially applied?
>
>
The thing is we dont know what the state of the termination GPIO (asserted or deasserted)
was before we set it and port->rs485_config() failed, so we cannot restore it.
We could read the GPIO before we change it but AFAIK this is unsafe since it is an output
pin. Maybe add a boolean variable "rs485_termination_gpio_asserted" to uart_port to track the
current state?


Regards,
Lino



2022-06-27 08:52:22

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 7/8] serial: ar933x: Remove redundant assignment in rs485_config

On Sun, 26 Jun 2022, Lino Sanfilippo wrote:

> On 25.06.22 at 12:14, Ilpo Järvinen wrote:
> > On Wed, 22 Jun 2022, Lino Sanfilippo wrote:
> >
> >> From: Lino Sanfilippo <[email protected]>
> >>
> >> In uart_set_rs485_config() the serial core already assigns the passed
> >> serial_rs485 struct to the uart port.
> >>
> >> So remove the assignment in the drivers rs485_config() function to avoid
> >> redundancy.
> >>
> >> Signed-off-by: Lino Sanfilippo <[email protected]>
> >> ---
> >> drivers/tty/serial/ar933x_uart.c | 1 -
> >> 1 file changed, 1 deletion(-)
> >>
> >> diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
> >> index ab2c5b2a1ce8..857e010d01dc 100644
> >> --- a/drivers/tty/serial/ar933x_uart.c
> >> +++ b/drivers/tty/serial/ar933x_uart.c
> >> @@ -591,7 +591,6 @@ static int ar933x_config_rs485(struct uart_port *port,
> >> dev_err(port->dev, "RS485 needs rts-gpio\n");
> >> return 1;
> >> }
> >> - port->rs485 = *rs485conf;
> >> return 0;
> >> }
> >
> > Hmm, I realize that for some reason I missed cleaning up this particular
> > driver after introducing the serial_rs485 sanitization. It shouldn't need
> > that preceeding if block either because ar933x_no_rs485 gets applied if
> > there's no rts_gpiod so the core clears SER_RS485_ENABLED.
>
> I think we still need that "if" in case that RS485 was not enabled at driver
> startup (no rs485-enabled-at-boot-time) and no RTS GPIO was defined but then
> RS485 is enabled via TIOCSRS485.
>
> Maybe in ar933x_uart_probe()
>
> if ((port->rs485.flags & SER_RS485_ENABLED) &&
> !up->rts_gpiod) {
> dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
> port->rs485.flags &= ~SER_RS485_ENABLED;
> port->rs485_supported = &ar933x_no_rs485;
> }
>
> should rather be

I think it would be better (and what I should have done while moving the
check there in the first place but I missed it). In addition, however, it
would be useful to not print unnecessarily:

> if (!up->rts_gpiod) {

if (port->rs485.flags & SER_RS485_ENABLED) {

> dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
> port->rs485.flags &= ~SER_RS485_ENABLED;

}

> port->rs485_supported = &ar933x_no_rs485;
> }

--
i.

2022-06-28 08:49:37

by Ilpo Järvinen

[permalink] [raw]
Subject: Re: [PATCH 2/8] serial: core, 8250: set RS485 termination gpio in serial core

On Sun, 26 Jun 2022, Lino Sanfilippo wrote:

> On 25.06.22 at 21:58, Lukas Wunner wrote:
> > On Wed, Jun 22, 2022 at 05:46:53PM +0200, Lino Sanfilippo wrote:
> >> From: Lino Sanfilippo <[email protected]>
> >>
> >> In serial8250_em485_config() the termination GPIO is set with the uart_port
> >> spinlock held. This is an issue if setting the GPIO line can sleep (e.g.
> >> since the concerning GPIO expander is connected via SPI or I2C).
> >>
> >> Fix this by setting the termination line outside of the uart_port spinlock
> >> in the serial core.
> > [...]
> >> --- a/drivers/tty/serial/serial_core.c
> >> +++ b/drivers/tty/serial/serial_core.c
> >> @@ -1400,6 +1411,7 @@ static int uart_set_rs485_config(struct uart_port *port,
> >> if (ret)
> >> return ret;
> >> uart_sanitize_serial_rs485(port, &rs485);
> >> + uart_set_rs485_termination(port, &rs485);
> >>
> >> spin_lock_irqsave(&port->lock, flags);
> >> ret = port->rs485_config(port, &rs485);
> >
> > That's one way to solve the issue. Another would be to push
> > acquisition of the port spinlock down into drivers.
> >
> > I think in most drivers we don't need to take the port spinlock at all
> > or only for a few specific register accesses. So taking the lock here
> > in the midlayer is likely unwarranted. However, changing that requires
> > going through every single driver's ->rs485_config() callback and
> > checking whether it needs the lock or not.
>
> As a first step its sufficient to take the lock in each drivers rs485_config()
> function and remove it from uart_set_rs485_config(). Then after time sort out
> the drivers that dont require the lock and remove it from their function.
>
> However the point of this patch was also to generalize the handling of the
> termination GPIO, so I would still see this placed in uart_set_rs485_config().

Additional thing to consider is that core currently handles also the
port->rs485 assignment under spinlock when ->rs485_config() was
successful. TIOCSRS485 ioctl calls are synchronized by other primitives
wrt. each other (port mutex and now also termios_rwsem) but drivers
probably would like to see consistent rs485 which can only be realized by
holding port->lock.


--
i.

2022-06-30 01:33:31

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 7/8] serial: ar933x: Remove redundant assignment in rs485_config



On 27.06.22 10:14, Ilpo Järvinen wrote:
> On Sun, 26 Jun 2022, Lino Sanfilippo wrote:
>
>> On 25.06.22 at 12:14, Ilpo Järvinen wrote:
>>> On Wed, 22 Jun 2022, Lino Sanfilippo wrote:
>>>
>>>> From: Lino Sanfilippo <[email protected]>
>>>>
>>>> In uart_set_rs485_config() the serial core already assigns the passed
>>>> serial_rs485 struct to the uart port.
>>>>
>>>> So remove the assignment in the drivers rs485_config() function to avoid
>>>> redundancy.
>>>>
>>>> Signed-off-by: Lino Sanfilippo <[email protected]>
>>>> ---
>>>> drivers/tty/serial/ar933x_uart.c | 1 -
>>>> 1 file changed, 1 deletion(-)
>>>>
>>>> diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
>>>> index ab2c5b2a1ce8..857e010d01dc 100644
>>>> --- a/drivers/tty/serial/ar933x_uart.c
>>>> +++ b/drivers/tty/serial/ar933x_uart.c
>>>> @@ -591,7 +591,6 @@ static int ar933x_config_rs485(struct uart_port *port,
>>>> dev_err(port->dev, "RS485 needs rts-gpio\n");
>>>> return 1;
>>>> }
>>>> - port->rs485 = *rs485conf;
>>>> return 0;
>>>> }
>>>
>>> Hmm, I realize that for some reason I missed cleaning up this particular
>>> driver after introducing the serial_rs485 sanitization. It shouldn't need
>>> that preceeding if block either because ar933x_no_rs485 gets applied if
>>> there's no rts_gpiod so the core clears SER_RS485_ENABLED.
>>
>> I think we still need that "if" in case that RS485 was not enabled at driver
>> startup (no rs485-enabled-at-boot-time) and no RTS GPIO was defined but then
>> RS485 is enabled via TIOCSRS485.
>>
>> Maybe in ar933x_uart_probe()
>>
>> if ((port->rs485.flags & SER_RS485_ENABLED) &&
>> !up->rts_gpiod) {
>> dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
>> port->rs485.flags &= ~SER_RS485_ENABLED;
>> port->rs485_supported = &ar933x_no_rs485;
>> }
>>
>> should rather be
>
> I think it would be better (and what I should have done while moving the
> check there in the first place but I missed it). In addition, however, it
> would be useful to not print unnecessarily:
>
>> if (!up->rts_gpiod) {
>
> if (port->rs485.flags & SER_RS485_ENABLED) {
>
>> dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
>> port->rs485.flags &= ~SER_RS485_ENABLED;
>
> }


Right. I will send a fix for this with the new version of my series.

Regards,
Lino