Message ID | 20231209125836.16294-1-l.sanfilippo@kunbus.com |
---|---|
Headers | show |
Series | Fixes and improvements for RS485 | expand |
On Sat, 9 Dec 2023, Lino Sanfilippo wrote: > If the imx driver cannot support RS485 it sets the ports rs485_supported > structure to NULL. No, an embedded struct inside struct uart_port cannot be set to NULL, it's always there. Looking into the code, that setting of rs485_supported from imx_no_rs485 is actually superfluous as it should be already cleared to zeros on alloc. > But it still calls uart_get_rs485_mode() which may set > the RS485_ENABLED flag nevertheless. > > This may lead to an attempt to configure RS485 even if it is not supported > when the flag is evaluated in uart_configure_port() at port startup. > > Avoid this by bailing out of uart_get_rs485_mode() if the RS485_ENABLED > flag is not supported by the caller. > > With this fix a check for RTS availability is now obsolete in the imx > driver, since it can not evaluate to true any more. Remove this check, too. > > Fixes: 00d7a00e2a6f ("serial: imx: Fill in rs485_supported") > Cc: Shawn Guo <shawnguo@kernel.org> > Cc: Sascha Hauer <s.hauer@pengutronix.de> > Cc: stable@vger.kernel.org > Suggested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> > Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
On Sat, 9 Dec 2023 13:58:30 +0100 Lino Sanfilippo <l.sanfilippo@kunbus.com> wrote: > Both the imx and stm32 driver set the rx-during-tx GPIO in rs485_config(). > Since this function is called with the port lock held, this can be an > problem in case that setting the GPIO line can sleep (e.g. if a GPIO > expander is used which is connected via SPI or I2C). > > Avoid this issue by moving the GPIO setting outside of the port lock into > the serial core and thus making it a generic feature. > > Fixes: c54d48543689 ("serial: stm32: Add support for rs485 RX_DURING_TX output GPIO") > Fixes: ca530cfa968c ("serial: imx: Add support for RS485 RX_DURING_TX output GPIO") > Cc: Shawn Guo <shawnguo@kernel.org> > Cc: Sascha Hauer <s.hauer@pengutronix.de> > Cc: stable@vger.kernel.org > Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com> > --- > drivers/tty/serial/imx.c | 4 ---- > drivers/tty/serial/serial_core.c | 12 ++++++++++++ > drivers/tty/serial/stm32-usart.c | 5 +---- > 3 files changed, 13 insertions(+), 8 deletions(-) > > diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c > index 708b9852a575..9cffeb23112b 100644 > --- a/drivers/tty/serial/imx.c > +++ b/drivers/tty/serial/imx.c > @@ -1943,10 +1943,6 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio > rs485conf->flags & SER_RS485_RX_DURING_TX) > imx_uart_start_rx(port); > > - if (port->rs485_rx_during_tx_gpio) > - gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, > - !!(rs485conf->flags & SER_RS485_RX_DURING_TX)); > - > return 0; > } > > diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c > index f1348a509552..a0290a5fe8b3 100644 > --- a/drivers/tty/serial/serial_core.c > +++ b/drivers/tty/serial/serial_core.c > @@ -1402,6 +1402,16 @@ static void uart_set_rs485_termination(struct uart_port *port, > !!(rs485->flags & SER_RS485_TERMINATE_BUS)); > } > > +static void uart_set_rs485_rx_during_tx(struct uart_port *port, > + const struct serial_rs485 *rs485) > +{ > + if (!(rs485->flags & SER_RS485_ENABLED)) > + return; > + > + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, > + !!(rs485->flags & SER_RS485_RX_DURING_TX)); > +} > + > static int uart_rs485_config(struct uart_port *port) > { > struct serial_rs485 *rs485 = &port->rs485; > @@ -1413,6 +1423,7 @@ static int uart_rs485_config(struct uart_port *port) > > uart_sanitize_serial_rs485(port, rs485); > uart_set_rs485_termination(port, rs485); > + uart_set_rs485_rx_during_tx(port, rs485); > > uart_port_lock_irqsave(port, &flags); > ret = port->rs485_config(port, NULL, rs485); > @@ -1457,6 +1468,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, > return ret; > uart_sanitize_serial_rs485(port, &rs485); > uart_set_rs485_termination(port, &rs485); > + uart_set_rs485_rx_during_tx(port, &rs485); > > uart_port_lock_irqsave(port, &flags); > ret = port->rs485_config(port, &tty->termios, &rs485); > diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c > index 3048620315d6..ec9a72a5bea9 100644 > --- a/drivers/tty/serial/stm32-usart.c > +++ b/drivers/tty/serial/stm32-usart.c > @@ -226,10 +226,7 @@ static int stm32_usart_config_rs485(struct uart_port *port, struct ktermios *ter > > stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); > > - if (port->rs485_rx_during_tx_gpio) > - gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, > - !!(rs485conf->flags & SER_RS485_RX_DURING_TX)); > - else > + if (!port->rs485_rx_during_tx_gpio) > rs485conf->flags |= SER_RS485_RX_DURING_TX; > > if (rs485conf->flags & SER_RS485_ENABLED) { > -- > 2.42.0 > Reviewed-by: Hugo Villeneuve <hvilleneuve@dimonoff.com> Hugo
Hi, On 11.12.23 11:35, Ilpo Järvinen wrote: > On Sat, 9 Dec 2023, Lino Sanfilippo wrote: > >> Both the imx and stm32 driver set the rx-during-tx GPIO in rs485_config(). >> Since this function is called with the port lock held, this can be an >> problem in case that setting the GPIO line can sleep (e.g. if a GPIO >> expander is used which is connected via SPI or I2C). >> >> Avoid this issue by moving the GPIO setting outside of the port lock into >> the serial core and thus making it a generic feature. >> >> Fixes: c54d48543689 ("serial: stm32: Add support for rs485 RX_DURING_TX output GPIO") >> Fixes: ca530cfa968c ("serial: imx: Add support for RS485 RX_DURING_TX output GPIO") >> Cc: Shawn Guo <shawnguo@kernel.org> >> Cc: Sascha Hauer <s.hauer@pengutronix.de> >> Cc: stable@vger.kernel.org >> Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com> >> --- >> drivers/tty/serial/imx.c | 4 ---- >> drivers/tty/serial/serial_core.c | 12 ++++++++++++ >> drivers/tty/serial/stm32-usart.c | 5 +---- >> 3 files changed, 13 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c >> index 708b9852a575..9cffeb23112b 100644 >> --- a/drivers/tty/serial/imx.c >> +++ b/drivers/tty/serial/imx.c >> @@ -1943,10 +1943,6 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio >> rs485conf->flags & SER_RS485_RX_DURING_TX) >> imx_uart_start_rx(port); >> >> - if (port->rs485_rx_during_tx_gpio) >> - gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, >> - !!(rs485conf->flags & SER_RS485_RX_DURING_TX)); >> - >> return 0; >> } >> >> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c >> index f1348a509552..a0290a5fe8b3 100644 >> --- a/drivers/tty/serial/serial_core.c >> +++ b/drivers/tty/serial/serial_core.c >> @@ -1402,6 +1402,16 @@ static void uart_set_rs485_termination(struct uart_port *port, >> !!(rs485->flags & SER_RS485_TERMINATE_BUS)); >> } >> >> +static void uart_set_rs485_rx_during_tx(struct uart_port *port, >> + const struct serial_rs485 *rs485) >> +{ >> + if (!(rs485->flags & SER_RS485_ENABLED)) >> + return; >> + >> + gpiod_set_value_cansleep(port->rs485_rx_during_tx_gpio, >> + !!(rs485->flags & SER_RS485_RX_DURING_TX)); >> +} >> + >> static int uart_rs485_config(struct uart_port *port) >> { >> struct serial_rs485 *rs485 = &port->rs485; >> @@ -1413,6 +1423,7 @@ static int uart_rs485_config(struct uart_port *port) >> >> uart_sanitize_serial_rs485(port, rs485); >> uart_set_rs485_termination(port, rs485); >> + uart_set_rs485_rx_during_tx(port, rs485); >> >> uart_port_lock_irqsave(port, &flags); >> ret = port->rs485_config(port, NULL, rs485); >> @@ -1457,6 +1468,7 @@ static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port, >> return ret; >> uart_sanitize_serial_rs485(port, &rs485); >> uart_set_rs485_termination(port, &rs485); >> + uart_set_rs485_rx_during_tx(port, &rs485); >> >> uart_port_lock_irqsave(port, &flags); >> ret = port->rs485_config(port, &tty->termios, &rs485); > > Also a nice simplification of driver-side code. > > Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> > > Just noting since this is now in core that if ->rs485_config() fails, > I suppose it's just normal to not rollback gpiod_set_value_cansleep() > (skimming through existing users in tree, it looks it's practically > never touched on the error rollback paths so I guess it's the normal > practice)? > > Anyway, since neither of the users currently don't fail in their > ->rs485_config() so it doesn't seem a critical issue. > Thats a good point actually. Rolling back is not hard to implement and although it may not matter right now since currently no driver returns an error code, this can change very soon. So I will rework this patch for the next version, thanks! Regards, Lino
On 11.12.23 12:00, Ilpo Järvinen wrote: > On Sat, 9 Dec 2023, Lino Sanfilippo wrote: > >> If the imx driver cannot support RS485 it sets the ports rs485_supported >> structure to NULL. > > No, an embedded struct inside struct uart_port cannot be set to NULL, > it's always there. > Hmm, ok. What I meant was that the structure is nullified. "set to NULL" is maybe a bit misleading. I will correct this. > Looking into the code, that setting of rs485_supported from imx_no_rs485 > is actually superfluous as it should be already cleared to zeros on alloc. > Yes. BTW: Another "no_rs485" configuration setting can be found in the ar933x driver. If we do not want to keep those assignments I can remove the one for the imx driver with the next version of this patch... >> But it still calls uart_get_rs485_mode() which may set >> the RS485_ENABLED flag nevertheless. >> >> This may lead to an attempt to configure RS485 even if it is not supported >> when the flag is evaluated in uart_configure_port() at port startup. >> >> Avoid this by bailing out of uart_get_rs485_mode() if the RS485_ENABLED >> flag is not supported by the caller. >> >> With this fix a check for RTS availability is now obsolete in the imx >> driver, since it can not evaluate to true any more. Remove this check, too. >> >> Fixes: 00d7a00e2a6f ("serial: imx: Fill in rs485_supported") >> Cc: Shawn Guo <shawnguo@kernel.org> >> Cc: Sascha Hauer <s.hauer@pengutronix.de> >> Cc: stable@vger.kernel.org >> Suggested-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> >> Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com> >
On Wed, 13 Dec 2023, Lino Sanfilippo wrote: > On 11.12.23 12:00, Ilpo Järvinen wrote: > > On Sat, 9 Dec 2023, Lino Sanfilippo wrote: > > > Looking into the code, that setting of rs485_supported from imx_no_rs485 > > is actually superfluous as it should be already cleared to zeros on alloc. > > > > Yes. BTW: Another "no_rs485" configuration setting can be found in the ar933x driver. > If we do not want to keep those assignments I can remove the one for the imx > driver with the next version of this patch... I think they can just be dropped as it's normal in Linux code to assume that things are zeroed by default. Those "no"-variants originate from the time when supported_rs485 was not yet embedded but just a pointer to a const struct and I didn't realize I could have removed them when I ended up embedding the struct so it can be altered per port.