2022-06-06 10:26:34

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 00/36] RS485 serial_rs485 sanitization

This series adds sanitization to serial_rs485 struct before passing it
to driver's rs485_config. This takes the work Lino Sanfilippo started
(0ed12afa5655^..60efd0513916) a bit further. By moving sanitization of
the rs485 struct into the serial core, per driver rs485_config() is
more into the point, that is, setting up the hw to realize RS485.

The other benefit is that with the sanitization, the other drivers no
longer need to care when new things are added to serial_rs485 as serial
core handles them on the other drivers' behalf. The addressing mode
changes I'll submit separately will take advantage of this. The
addressing mode changes were the main motivator for doing the changes,
however, I believe these changes stand on their feet even w/o
considering the addressing mode changes.

The series is long because per driver changes are split into two
different stages. The key objectives here for the split have been to
keep things bisect safe and to do changes per driver rather than in one
large block. This required 4 stages:

1) Add datastructure entries & other preps (01-03)
2) Per driver rs485_supported (04-21)
3) Sanitization, core taking advantage of rs485_supported (22-24)
4) Cleanup per driver custom sanitization code (25-36)

As you can see, the downside of this split is that the per driver code
is split to 2+4 patches which makes some things moving less obvious.
Merging them is only possible if the stages 2-4 are done in one large
change (little bits here and there could be left out from it but not
much).

In stage 3 patches, there are a few userspace interface impacting
changes with userspace api regression potential:

a) Some drivers have not cleared flags/fields in per driver code while
other drivers have. The old behavior is inconsistent. Now the bits
will get cleaned up by serial core. I don't believe it's going to
cause issues.

b) Init path now sanitizes configuration if rs485_config is being
called from the init path (mainly coming from dt). It attempts to
repair some incorrect configurations which seems ok.

However, if RS485 mode is not enabled at boot, serial_rs485 struct
gets cleared in order for it to match what the port is configured
with (RS232). Such clearing implies losing values that were
configured through dt and that could perhaps be seen as unwanted
side-effect from having consistent serial_rs485?

There is also impact for the ioctl path from this clearing of
serial_rs485 when RS485 is disabled but impact seems minor at most.

c) Returning -EINVAL for non-legacy flags. This also affects setting
bits that were previously padding (that is, all flags bits
currently not defined in include/uapi/linux/serial.h). It was
possible to put garbage into them earlier but no more. I guess
this is not very likely a big issue. No non-legacy flags are
added in this series (the addressing mode changes submitted
separately will add new flags).

Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]

Ilpo Järvinen (36):
serial: Add uart_rs485_config()
serial: Move serial_rs485 sanitization into separate function
serial: Add rs485_supported to uart_port
serial: 8250: Create serial8250_em485_supported for em485 users
serial: 8250_bcm2835aux: Use serial8250_em485_supported
serial: 8250_dwlib: Fill in rs485_supported
serial: 8250_exar: Fill in rs485_supported
serial: 8250_fintek: Fill in rs485_supported
serial: 8250_lpc18cc: Fill in rs485_supported
serial: 8250_of: Use serial8250_em485_supported
serial: 8250_pci: Fill in rs485_supported for pci_fintek
serial: pl011: Fill in rs485_supported
serial: ar933x: Fill in rs485_supported
serial: atmel: Fill in rs485_supported
serial: fsl_lpuart: Fill in rs485_supported
serial: imx: Fill in rs485_supported
serial: max310x: Fill in rs485_supported
serial: mcf: Fill in rs485_supported
serial: omap: Fill in rs485_supported
serial: sc16is7xx: Fill in rs485_supported
serial: stm32: Fill in rs485_supported
serial: Sanitize rs485_struct
serial: Clear rs485 struct when non-RS485 mode is set
serial: return -EINVAL for non-legacy RS485 flags
serial: 8250_dwlib: Remove serial_rs485 sanitization
serial: 8250_fintek: Remove serial_rs485 sanitization
serial: 8250: lpc18xx: Remove serial_rs485 sanitization
serial: 8250_pci: Remove serial_rs485 sanitization
serial: pl011: Remove serial_rs485 sanitization
serial: fsl_lpuart: Call core's sanitization and remove custom one
serial: imx: Remove serial_rs485 sanitization
serial: max310x: Remove serial_rs485 sanitization
serial: 8250_exar: Remove serial_rs485 assignment
serial: mcf: Remove serial_rs485 assignment
serial: sc16is7xx: Remove serial_rs485 assignment
serial: 8250: Remove serial_rs485 sanitization from em485

.../driver-api/serial/serial-rs485.rst | 12 +-
drivers/tty/serial/8250/8250.h | 1 +
drivers/tty/serial/8250/8250_bcm2835aux.c | 1 +
drivers/tty/serial/8250/8250_core.c | 1 +
drivers/tty/serial/8250/8250_dwlib.c | 17 +--
drivers/tty/serial/8250/8250_exar.c | 14 +-
drivers/tty/serial/8250/8250_fintek.c | 29 +++--
drivers/tty/serial/8250/8250_lpc18xx.c | 20 +--
drivers/tty/serial/8250/8250_of.c | 1 +
drivers/tty/serial/8250/8250_pci.c | 24 +---
drivers/tty/serial/8250/8250_port.c | 28 ++--
drivers/tty/serial/amba-pl011.c | 13 +-
drivers/tty/serial/ar933x_uart.c | 7 +
drivers/tty/serial/atmel_serial.c | 7 +
drivers/tty/serial/fsl_lpuart.c | 25 +---
drivers/tty/serial/imx.c | 19 ++-
drivers/tty/serial/max310x.c | 9 +-
drivers/tty/serial/mcf.c | 7 +-
drivers/tty/serial/omap-serial.c | 8 ++
drivers/tty/serial/sc16is7xx.c | 8 +-
drivers/tty/serial/serial_core.c | 120 ++++++++++++++----
drivers/tty/serial/stm32-usart.c | 8 ++
include/linux/serial_core.h | 2 +
23 files changed, 247 insertions(+), 134 deletions(-)

--
2.30.2


2022-06-06 10:26:36

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 05/36] serial: 8250_bcm2835aux: Use serial8250_em485_supported

bcm2835aux uses em485, fill in rs485_supported accordingly.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_bcm2835aux.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index 2a1226a78a0c..d9f1e618cfbd 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -108,6 +108,7 @@ static int bcm2835aux_serial_probe(struct platform_device *pdev)
up.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE |
UPF_SKIP_TEST | UPF_IOREMAP;
up.port.rs485_config = serial8250_em485_config;
+ up.port.rs485_supported = &serial8250_em485_supported;
up.rs485_start_tx = bcm2835aux_rs485_start_tx;
up.rs485_stop_tx = bcm2835aux_rs485_stop_tx;

--
2.30.2

2022-06-06 10:26:39

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 04/36] serial: 8250: Create serial8250_em485_supported for em485 users

Create serial8250_em485_supported for the serial_rs485 features
supported by the em485 framework.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250.h | 1 +
drivers/tty/serial/8250/8250_port.c | 8 ++++++++
2 files changed, 9 insertions(+)

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index d70adaa3b117..e5d44867a876 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -187,6 +187,7 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
void serial8250_em485_start_tx(struct uart_8250_port *p);
void serial8250_em485_stop_tx(struct uart_8250_port *p);
void serial8250_em485_destroy(struct uart_8250_port *p);
+extern struct serial_rs485 serial8250_em485_supported;

/* MCR <-> TIOCM conversion */
static inline int serial8250_TIOCM_to_MCR(int tiocm)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index d7384ab364d2..a825fbc215a7 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -647,6 +647,14 @@ void serial8250_em485_destroy(struct uart_8250_port *p)
}
EXPORT_SYMBOL_GPL(serial8250_em485_destroy);

+struct serial_rs485 serial8250_em485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
+ SER_RS485_TERMINATE_BUS | SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+EXPORT_SYMBOL_GPL(serial8250_em485_supported);
+
/**
* serial8250_em485_config() - generic ->rs485_config() callback
* @port: uart port
--
2.30.2

2022-06-06 10:26:42

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 07/36] serial: 8250_exar: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_exar.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 7292917ac878..11916f603a3d 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -113,6 +113,7 @@ struct exar8250;

struct exar8250_platform {
int (*rs485_config)(struct uart_port *, struct serial_rs485 *);
+ const struct serial_rs485 *rs485_supported;
int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
void (*unregister_gpio)(struct uart_8250_port *);
};
@@ -431,10 +432,15 @@ static int generic_rs485_config(struct uart_port *port,
return 0;
}

+static const struct serial_rs485 generic_rs485_supported = {
+ .flags = SER_RS485_ENABLED,
+};
+
static const struct exar8250_platform exar8250_default_platform = {
.register_gpio = xr17v35x_register_gpio,
.unregister_gpio = xr17v35x_unregister_gpio,
.rs485_config = generic_rs485_config,
+ .rs485_supported = &generic_rs485_supported,
};

static int iot2040_rs485_config(struct uart_port *port,
@@ -470,6 +476,10 @@ static int iot2040_rs485_config(struct uart_port *port,
return generic_rs485_config(port, rs485);
}

+static const struct serial_rs485 iot2040_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_TERMINATE_BUS,
+};
+
static const struct property_entry iot2040_gpio_properties[] = {
PROPERTY_ENTRY_U32("exar,first-pin", 10),
PROPERTY_ENTRY_U32("ngpios", 1),
@@ -498,6 +508,7 @@ static int iot2040_register_gpio(struct pci_dev *pcidev,

static const struct exar8250_platform iot2040_platform = {
.rs485_config = iot2040_rs485_config,
+ .rs485_supported = &iot2040_rs485_supported,
.register_gpio = iot2040_register_gpio,
.unregister_gpio = xr17v35x_unregister_gpio,
};
@@ -540,6 +551,7 @@ pci_xr17v35x_setup(struct exar8250 *priv, struct pci_dev *pcidev,

port->port.uartclk = baud * 16;
port->port.rs485_config = platform->rs485_config;
+ port->port.rs485_supported = platform->rs485_supported;

/*
* Setup the UART clock for the devices on expansion slot to
--
2.30.2

2022-06-06 10:26:46

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 06/36] serial: 8250_dwlib: Fill in rs485_supported

Add information on supported serial_rs485 features. When the driver is
using em485, take advantage of serial8250_em485_supported.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_dwlib.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index fbabfdd8c7b8..120b29519d74 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -149,6 +149,11 @@ static bool dw8250_detect_rs485_hw(struct uart_port *p)
return reg;
}

+static const struct serial_rs485 dw8250_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RX_DURING_TX | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+};
+
void dw8250_setup_port(struct uart_port *p)
{
struct dw8250_port_data *pd = p->private_data;
@@ -159,8 +164,10 @@ void dw8250_setup_port(struct uart_port *p)
pd->hw_rs485_support = dw8250_detect_rs485_hw(p);
if (pd->hw_rs485_support) {
p->rs485_config = dw8250_rs485_config;
+ p->rs485_supported = &dw8250_rs485_supported;
} else {
p->rs485_config = serial8250_em485_config;
+ p->rs485_supported = &serial8250_em485_supported;
up->rs485_start_tx = serial8250_em485_start_tx;
up->rs485_stop_tx = serial8250_em485_stop_tx;
}
--
2.30.2

2022-06-06 10:29:16

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 08/36] serial: 8250_fintek: Fill in rs485_supported

Add information on supported serial_rs485 features.

Differentiate based on which port is in question.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_fintek.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index dba5950b8d0e..6e98c376e082 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -424,6 +424,17 @@ static int probe_setup_port(struct fintek_8250 *pdata,
return -ENODEV;
}

+/* Only the first port supports delays */
+static const struct serial_rs485 fintek_8250_rs485_supported_port0 = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
+static const struct serial_rs485 fintek_8250_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
+};
+
static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
{
struct fintek_8250 *pdata = uart->port.private_data;
@@ -435,6 +446,10 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
case CHIP_ID_F81866:
case CHIP_ID_F81865:
uart->port.rs485_config = fintek_8250_rs485_config;
+ if (!pdata->index)
+ uart->port.rs485_supported = &fintek_8250_rs485_supported_port0;
+ else
+ uart->port.rs485_supported = &fintek_8250_rs485_supported;
break;

default: /* No RS485 Auto direction functional */
--
2.30.2

2022-06-06 10:31:31

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 14/36] serial: atmel: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/atmel_serial.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index dd1c7e4bd1c9..74dd1d3ac46f 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2473,6 +2473,12 @@ static const struct uart_ops atmel_pops = {
#endif
};

+static const struct serial_rs485 atmel_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
/*
* Configure the port from the platform device resource info.
*/
@@ -2494,6 +2500,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
port->mapbase = mpdev->resource[0].start;
port->irq = platform_get_irq(mpdev, 0);
port->rs485_config = atmel_config_rs485;
+ port->rs485_supported = &atmel_rs485_supported;
port->iso7816_config = atmel_config_iso7816;
port->membase = NULL;

--
2.30.2

2022-06-06 10:31:31

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 16/36] serial: imx: Fill in rs485_supported

Add information on supported serial_rs485 features.

In the case where RTS is lacking, RS485 cannot be enabled so provide
zero rs485_supported for that case. Perhaps it would make sense to not
provide rs485_config() at all in that case but such a change would have
userspace visible impact/change in behavior so this patch does not
attempt it.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/imx.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 9ce09b81ac9b..ba853bc9b4db 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2200,6 +2200,14 @@ static enum hrtimer_restart imx_trigger_stop_tx(struct hrtimer *t)
return HRTIMER_NORESTART;
}

+static const struct serial_rs485 imx_no_rs485 = {}; /* No RS485 if no RTS */
+static const struct serial_rs485 imx_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
+ SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
/* Default RX DMA buffer configuration */
#define RX_DMA_PERIODS 16
#define RX_DMA_PERIOD_LEN (PAGE_SIZE / 4)
@@ -2279,6 +2287,11 @@ static int imx_uart_probe(struct platform_device *pdev)
sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE);
sport->port.ops = &imx_uart_pops;
sport->port.rs485_config = imx_uart_rs485_config;
+ /* RTS is required to control the RS485 transmitter */
+ if (sport->have_rtscts || sport->have_rtsgpio)
+ sport->port.rs485_supported = &imx_rs485_supported;
+ else
+ sport->port.rs485_supported = &imx_no_rs485;
sport->port.flags = UPF_BOOT_AUTOCONF;
timer_setup(&sport->timer, imx_uart_timeout, 0);

--
2.30.2

2022-06-06 10:31:35

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 09/36] serial: 8250_lpc18cc: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_lpc18xx.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 570e25d6f37e..66ce5d05fe9c 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -98,6 +98,12 @@ static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value)
writel(value, p->membase + offset);
}

+static const struct serial_rs485 lpc18xx_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_after_send = 1,
+ /* Delay RTS before send is not supported */
+};
+
static int lpc18xx_serial_probe(struct platform_device *pdev)
{
struct lpc18xx_uart_data *data;
@@ -168,6 +174,7 @@ static int lpc18xx_serial_probe(struct platform_device *pdev)
uart.port.uartclk = clk_get_rate(data->clk_uart);
uart.port.private_data = data;
uart.port.rs485_config = lpc18xx_rs485_config;
+ uart.port.rs485_supported = &lpc18xx_rs485_supported;
uart.port.serial_out = lpc18xx_uart_serial_out;

uart.dma = &data->dma;
--
2.30.2

2022-06-06 10:31:38

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 13/36] serial: ar933x: Fill in rs485_supported

Add information on supported serial_rs485 features.

In the case where RTS is lacking, RS485 cannot be enabled so provide
zero rs485_supported for that case. Perhaps it would make sense to not
provide rs485_config() at all in that case but such a change would have
userspace visible impact/change in behavior so this patch does not
attempt it.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/ar933x_uart.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 6269dbf93546..ab2c5b2a1ce8 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -702,6 +702,11 @@ static struct uart_driver ar933x_uart_driver = {
.cons = NULL, /* filled in runtime */
};

+static const struct serial_rs485 ar933x_no_rs485 = {};
+static const struct serial_rs485 ar933x_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
+};
+
static int ar933x_uart_probe(struct platform_device *pdev)
{
struct ar933x_uart_port *up;
@@ -773,6 +778,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
port->fifosize = AR933X_UART_FIFO_SIZE;
port->ops = &ar933x_uart_ops;
port->rs485_config = ar933x_config_rs485;
+ port->rs485_supported = &ar933x_rs485_supported;

baud = ar933x_uart_get_baud(port->uartclk, AR933X_UART_MAX_SCALE, 1);
up->min_baud = max_t(unsigned int, baud, AR933X_UART_MIN_BAUD);
@@ -796,6 +802,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
!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;
}

#ifdef CONFIG_SERIAL_AR933X_CONSOLE
--
2.30.2

2022-06-06 10:31:39

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 10/36] serial: 8250_of: Use serial8250_em485_supported

8250_of uses em485, fill in rs485_supported accordingly.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_of.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 5a699a1aa79c..65cccd559db2 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -165,6 +165,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev,

port->dev = &ofdev->dev;
port->rs485_config = serial8250_em485_config;
+ port->rs485_supported = &serial8250_em485_supported;
up->rs485_start_tx = serial8250_em485_start_tx;
up->rs485_stop_tx = serial8250_em485_stop_tx;

--
2.30.2

2022-06-06 10:31:41

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 18/36] serial: mcf: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/mcf.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 2aec62b5d6c4..655255e0c76a 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -453,6 +453,10 @@ static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
return 0;
}

+static const struct serial_rs485 mcf_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
+};
+
/****************************************************************************/

/*
@@ -502,6 +506,7 @@ int __init early_mcf_setup(struct mcf_platform_uart *platp)
port->uartclk = MCF_BUSCLK;
port->flags = UPF_BOOT_AUTOCONF;
port->rs485_config = mcf_config_rs485;
+ port->rs485_supported = &mcf_rs485_supported;
port->ops = &mcf_uart_ops;
}

@@ -629,6 +634,7 @@ static int mcf_probe(struct platform_device *pdev)
port->ops = &mcf_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
port->rs485_config = mcf_config_rs485;
+ port->rs485_supported = &mcf_rs485_supported;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MCF_CONSOLE);

uart_add_one_port(&mcf_driver, port);
--
2.30.2

2022-06-06 10:31:48

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 20/36] serial: sc16is7xx: Fill in rs485_supported

Add information on supported serial_rs485 features.

This driver does not support delay_rts_after_send but the pre-existing
behavior is to return -EINVAL if delay_rts_after_send is non-zero. In
contrast, other drivers that do not support delay_rts_after_send either
zero delay_rts_after_send or do not care (leave the inaccurate value).
As changing this would cause userspace visible impact, the change is
not attempted here. But perhaps it should be still tried (maybe nobody
finds that kind of API oddity significant)?

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/sc16is7xx.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 8472bf70477c..b3162dfe97b1 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1354,6 +1354,12 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip,
}
#endif

+static const struct serial_rs485 sc16is7xx_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */
+};
+
static int sc16is7xx_probe(struct device *dev,
const struct sc16is7xx_devtype *devtype,
struct regmap *regmap, int irq)
@@ -1456,6 +1462,7 @@ static int sc16is7xx_probe(struct device *dev,
s->p[i].port.iotype = UPIO_PORT;
s->p[i].port.uartclk = freq;
s->p[i].port.rs485_config = sc16is7xx_config_rs485;
+ s->p[i].port.rs485_supported = &sc16is7xx_rs485_supported;
s->p[i].port.ops = &sc16is7xx_ops;
s->p[i].old_mctrl = 0;
s->p[i].port.line = sc16is7xx_alloc_line();
--
2.30.2

2022-06-06 10:31:55

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 23/36] serial: Clear rs485 struct when non-RS485 mode is set

When SER_RS485_ENABLED is not set, having any other flag/field set in
serial_rs485 struct does not have an effect different from not having
them set. Thus, make the serial_rs485 struct also match the behavior
for all flags, not just SER_RS485_ENABLED.

Some drivers do similar clearing of rs485 struct in their
rs485_config() already, but not all. This change makes the behavior
consistent across drivers.

Don't try to validate rs485 struct further when no RS485 is requested,
this silences some bogus warnings.

This change has (minor) userspace visible impact.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/serial_core.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index f0d7b3d20731..6be538720564 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1280,6 +1280,11 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
{
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) ==
@@ -1329,10 +1334,15 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
int uart_rs485_config(struct uart_port *port)
{
struct serial_rs485 *rs485 = &port->rs485;
+ int ret;

uart_sanitize_serial_rs485(port, rs485);

- return port->rs485_config(port, rs485);
+ ret = port->rs485_config(port, rs485);
+ if (ret)
+ memset(rs485, 0, sizeof(*rs485));
+
+ return ret;
}
EXPORT_SYMBOL_GPL(uart_rs485_config);

--
2.30.2

2022-06-06 10:31:56

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 22/36] serial: Sanitize rs485_struct

Sanitize serial_rs485 struct before calling into rs485_setup. The
drivers provide supported_rs485 to help sanitization of the fields.

If neither of SER_RS485_RTS_ON_SEND or SER_RS485_RTS_AFTER_SEND
supported, don't pretend they can be set to sane settings but clear
them both instead. If only one of them is supported it may look
tempting to use the one driver supports to set the other, however, the
userspace does not have that information readily available so it
wouldn't be helpful.

While adjusting the documentation, remove also the claim that
TIOCGRS485 would call driver specific code. In reality, it does nothing
else than copies the stored serial_rs485 structure from uart_port to
userspace.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
.../driver-api/serial/serial-rs485.rst | 12 ++++---
drivers/tty/serial/serial_core.c | 33 ++++++++++++++++---
2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/Documentation/driver-api/serial/serial-rs485.rst b/Documentation/driver-api/serial/serial-rs485.rst
index 6bc824f948f9..00b5d333acba 100644
--- a/Documentation/driver-api/serial/serial-rs485.rst
+++ b/Documentation/driver-api/serial/serial-rs485.rst
@@ -38,10 +38,14 @@ RS485 Serial Communications
the values given by the device tree.

Any driver for devices capable of working both as RS232 and RS485 should
- implement the rs485_config callback in the uart_port structure. The
- serial_core calls rs485_config to do the device specific part in response
- to TIOCSRS485 and TIOCGRS485 ioctls (see below). The rs485_config callback
- receives a pointer to struct serial_rs485.
+ implement the rs485_config callback and provide rs485_supported in the
+ uart_port structure. The serial core calls rs485_config to do the device
+ specific part in response to TIOCSRS485 ioctl (see below). The rs485_config
+ callback receives a pointer to a sanitizated serial_rs485 structure. The
+ serial_rs485 userspace provides is sanitized before calling rs485_config
+ using rs485_supported that indicates what RS485 features the driver supports
+ for the uart_port. TIOCGRS485 ioctl can be used to read back the
+ serial_rs485 structure matching to the current configuration.

4. Usage from user-level
========================
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 44a50158552d..f0d7b3d20731 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1278,36 +1278,61 @@ static int uart_get_icount(struct tty_struct *tty,

static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485)
{
+ u32 supported_flags = port->rs485_supported->flags;
+
/* pick sane settings if the user hasn't */
- if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
+ 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 (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
+ if (!port->rs485_supported->delay_rts_before_send) {
+ if (rs485->delay_rts_before_send) {
+ dev_warn_ratelimited(port->dev,
+ "%s (%d): RTS delay before sending not supported\n",
+ port->name, port->line);
+ }
+ rs485->delay_rts_before_send = 0;
+ } else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
"%s (%d): RTS delay before sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_before_send);
}

- if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
+ if (!port->rs485_supported->delay_rts_after_send) {
+ if (rs485->delay_rts_after_send) {
+ dev_warn_ratelimited(port->dev,
+ "%s (%d): RTS delay after sending not supported\n",
+ port->name, port->line);
+ }
+ rs485->delay_rts_after_send = 0;
+ } else if (rs485->delay_rts_after_send > RS485_MAX_RTS_DELAY) {
rs485->delay_rts_after_send = RS485_MAX_RTS_DELAY;
dev_warn_ratelimited(port->dev,
"%s (%d): RTS delay after sending clamped to %u ms\n",
port->name, port->line, rs485->delay_rts_after_send);
}
+
+ rs485->flags &= supported_flags;
+
/* Return clean padding area to userspace */
memset(rs485->padding, 0, sizeof(rs485->padding));
}

int uart_rs485_config(struct uart_port *port)
{
- return port->rs485_config(port, &port->rs485);
+ struct serial_rs485 *rs485 = &port->rs485;
+
+ uart_sanitize_serial_rs485(port, rs485);
+
+ return port->rs485_config(port, rs485);
}
EXPORT_SYMBOL_GPL(uart_rs485_config);

--
2.30.2

2022-06-06 10:31:58

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 21/36] serial: stm32: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/stm32-usart.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index b7b44f4050d4..db3dd9731ee1 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -1375,6 +1375,13 @@ static void stm32_usart_deinit_port(struct stm32_port *stm32port)
clk_disable_unprepare(stm32port->clk);
}

+static const struct serial_rs485 stm32_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
+ SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
static int stm32_usart_init_port(struct stm32_port *stm32port,
struct platform_device *pdev)
{
@@ -1394,6 +1401,7 @@ static int stm32_usart_init_port(struct stm32_port *stm32port,
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE);
port->irq = irq;
port->rs485_config = stm32_usart_config_rs485;
+ port->rs485_supported = &stm32_rs485_supported;

ret = stm32_usart_init_rs485(port, pdev);
if (ret)
--
2.30.2

2022-06-06 10:32:02

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 17/36] serial: max310x: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/max310x.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index a0b6ea52d133..9837f542a55a 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1249,6 +1249,12 @@ static int max310x_gpio_set_config(struct gpio_chip *chip, unsigned int offset,
}
#endif

+static const struct serial_rs485 max310x_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
static int max310x_probe(struct device *dev, const struct max310x_devtype *devtype,
struct regmap *regmap, int irq)
{
@@ -1357,6 +1363,7 @@ static int max310x_probe(struct device *dev, const struct max310x_devtype *devty
s->p[i].port.membase = (void __iomem *)~0;
s->p[i].port.uartclk = uartclk;
s->p[i].port.rs485_config = max310x_rs485_config;
+ s->p[i].port.rs485_supported = &max310x_rs485_supported;
s->p[i].port.ops = &max310x_ops;
/* Disable all interrupts */
max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0);
--
2.30.2

2022-06-06 10:32:05

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 12/36] serial: pl011: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/amba-pl011.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 97ef41cb2721..cdc466e89aa8 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2751,6 +2751,13 @@ static int pl011_register_port(struct uart_amba_port *uap)
return ret;
}

+static const struct serial_rs485 pl011_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
+ SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct uart_amba_port *uap;
@@ -2777,6 +2784,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
uap->port.irq = dev->irq[0];
uap->port.ops = &amba_pl011_pops;
uap->port.rs485_config = pl011_rs485_config;
+ uap->port.rs485_supported = &pl011_rs485_supported;
snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev));

ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
--
2.30.2

2022-06-06 10:32:11

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 15/36] serial: fsl_lpuart: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/fsl_lpuart.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 509a7912fa9d..88692dc9eefa 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -2621,6 +2621,11 @@ static struct uart_driver lpuart_reg = {
.cons = LPUART_CONSOLE,
};

+static const struct serial_rs485 lpuart_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
+ /* delay_rts_* and RX_DURING_TX are not supported */
+};
+
static int lpuart_probe(struct platform_device *pdev)
{
const struct lpuart_soc_data *sdata = of_device_get_match_data(&pdev->dev);
@@ -2660,6 +2665,7 @@ static int lpuart_probe(struct platform_device *pdev)
sport->port.rs485_config = lpuart32_config_rs485;
else
sport->port.rs485_config = lpuart_config_rs485;
+ sport->port.rs485_supported = &lpuart_rs485_supported;

sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->ipg_clk)) {
--
2.30.2

2022-06-06 10:32:28

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 28/36] serial: 8250_pci: Remove serial_rs485 sanitization

Serial core handles serial_rs485 sanitization and copying rs485 struct.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_pci.c | 14 --------------
1 file changed, 14 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index a76254031bc2..b6d71268aa7d 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1562,14 +1562,6 @@ static int pci_fintek_rs485_config(struct uart_port *port,

pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting);

- if (rs485->flags & SER_RS485_ENABLED)
- memset(rs485->padding, 0, sizeof(rs485->padding));
- else
- memset(rs485, 0, sizeof(*rs485));
-
- /* F81504/508/512 not support RTS delay before or after send */
- rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
-
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable RTS H/W control mode */
setting |= FINTEK_RTS_CONTROL_BY_HW;
@@ -1581,9 +1573,6 @@ static int pci_fintek_rs485_config(struct uart_port *port,
/* RTS driving low on TX */
setting |= FINTEK_RTS_INVERT;
}
-
- rs485->delay_rts_after_send = 0;
- rs485->delay_rts_before_send = 0;
} else {
/* Disable RTS H/W control mode */
setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT);
@@ -1591,9 +1580,6 @@ static int pci_fintek_rs485_config(struct uart_port *port,

pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting);

- if (rs485 != &port->rs485)
- port->rs485 = *rs485;
-
return 0;
}

--
2.30.2

2022-06-06 10:32:28

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 30/36] serial: fsl_lpuart: Call core's sanitization and remove custom one

Serial core handles serial_rs485 sanitization. Remove custom
sanitization from lpuart_config_rs485.

This change loses dev_err when SER_RS485_RX_DURING_TX is set due to
incorrect configuration. Other drivers do not do similar prinout for
full-duplex case and it should be done in serial core if it is
desirable to notify on this condition. Personally, I doesn't see it
important because the kernel gracefully downgrades to half-duplex.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/fsl_lpuart.c | 17 -----------------
1 file changed, 17 deletions(-)

diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 88692dc9eefa..d35414cb3e4e 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1365,11 +1365,6 @@ static int lpuart_config_rs485(struct uart_port *port,
~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
writeb(modem, sport->port.membase + UARTMODEM);

- /* clear unsupported configurations */
- rs485->delay_rts_before_send = 0;
- rs485->delay_rts_after_send = 0;
- rs485->flags &= ~SER_RS485_RX_DURING_TX;
-
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */
modem |= UARTMODEM_TXRTSE;
@@ -1400,11 +1395,6 @@ static int lpuart32_config_rs485(struct uart_port *port,
& ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
lpuart32_write(&sport->port, modem, UARTMODIR);

- /* clear unsupported configurations */
- rs485->delay_rts_before_send = 0;
- rs485->delay_rts_after_send = 0;
- rs485->flags &= ~SER_RS485_RX_DURING_TX;
-
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */
modem |= UARTMODEM_TXRTSE;
@@ -2723,13 +2713,6 @@ static int lpuart_probe(struct platform_device *pdev)
if (ret)
goto failed_get_rs485;

- if (sport->port.rs485.flags & SER_RS485_RX_DURING_TX)
- dev_err(&pdev->dev, "driver doesn't support RX during TX\n");
-
- if (sport->port.rs485.delay_rts_before_send ||
- sport->port.rs485.delay_rts_after_send)
- dev_err(&pdev->dev, "driver doesn't support RTS delays\n");
-
uart_rs485_config(&sport->port);

ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0,
--
2.30.2

2022-06-06 10:32:29

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 27/36] serial: 8250: lpc18xx: Remove serial_rs485 sanitization

Serial core handles serial_rs485 sanitization and copying rs485 struct.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_lpc18xx.c | 13 -------------
1 file changed, 13 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 66ce5d05fe9c..3a1cb51cbc91 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -40,14 +40,6 @@ static int lpc18xx_rs485_config(struct uart_port *port,
u32 rs485_dly_reg = 0;
unsigned baud_clk;

- if (rs485->flags & SER_RS485_ENABLED)
- memset(rs485->padding, 0, sizeof(rs485->padding));
- else
- memset(rs485, 0, sizeof(*rs485));
-
- rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
- SER_RS485_RTS_AFTER_SEND;
-
if (rs485->flags & SER_RS485_ENABLED) {
rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN |
LPC18XX_UART_RS485CTRL_DCTRL;
@@ -73,14 +65,9 @@ static int lpc18xx_rs485_config(struct uart_port *port,
/ baud_clk;
}

- /* Delay RTS before send not supported */
- rs485->delay_rts_before_send = 0;
-
serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg);
serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg);

- port->rs485 = *rs485;
-
return 0;
}

--
2.30.2

2022-06-06 10:32:30

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 33/36] serial: 8250_exar: Remove serial_rs485 assignment

Serial core handles serial_rs485 assignment.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_exar.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 11916f603a3d..528779b40049 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -427,8 +427,6 @@ static int generic_rs485_config(struct uart_port *port,
if (is_rs485)
writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);

- port->rs485 = *rs485;
-
return 0;
}

--
2.30.2

2022-06-06 10:33:27

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 32/36] serial: max310x: Remove serial_rs485 sanitization

Serial core handles serial_rs485 sanitization.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/max310x.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 9837f542a55a..d7d1791fcb57 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1035,8 +1035,6 @@ static int max310x_rs485_config(struct uart_port *port,
(rs485->delay_rts_after_send > 0x0f))
return -ERANGE;

- rs485->flags &= SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX |
- SER_RS485_ENABLED;
port->rs485 = *rs485;

schedule_work(&one->rs_work);
--
2.30.2

2022-06-06 10:33:27

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 34/36] serial: mcf: Remove serial_rs485 assignment

Serial core handles serial_rs485 assignment.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/mcf.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 655255e0c76a..036f178e3d66 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -448,7 +448,6 @@ static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
}
writeb(mr1, port->membase + MCFUART_UMR);
writeb(mr2, port->membase + MCFUART_UMR);
- port->rs485 = *rs485;

return 0;
}
--
2.30.2

2022-06-06 10:33:27

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 26/36] serial: 8250_fintek: Remove serial_rs485 sanitization

Serial core handles serial_rs485 sanitization and copying rs485 struct.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_fintek.c | 14 --------------
1 file changed, 14 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index 6e98c376e082..1fb86c73786c 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -206,19 +206,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
!(rs485->flags & SER_RS485_RTS_AFTER_SEND))
return -EINVAL;
- memset(rs485->padding, 0, sizeof(rs485->padding));
config |= RS485_URA;
- } else {
- memset(rs485, 0, sizeof(*rs485));
- }
-
- rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
- SER_RS485_RTS_AFTER_SEND;
-
- /* Only the first port supports delays */
- if (pdata->index) {
- rs485->delay_rts_before_send = 0;
- rs485->delay_rts_after_send = 0;
}

if (rs485->delay_rts_before_send) {
@@ -241,8 +229,6 @@ static int fintek_8250_rs485_config(struct uart_port *port,
sio_write_reg(pdata, RS485, config);
fintek_8250_exit_key(pdata->base_port);

- port->rs485 = *rs485;
-
return 0;
}

--
2.30.2

2022-06-06 10:33:49

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 35/36] serial: sc16is7xx: Remove serial_rs485 assignment

Serial core handles serial_rs485 assignment. It is safe to remove this
assignment because sc16is7xx_reg_proc() takes port.lock at start (and
sc16is7xx_reconf_rs485() would too).

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/sc16is7xx.c | 1 -
1 file changed, 1 deletion(-)

diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index b3162dfe97b1..2ceecaa4a478 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1143,7 +1143,6 @@ static int sc16is7xx_config_rs485(struct uart_port *port,
return -EINVAL;
}

- port->rs485 = *rs485;
one->config.flags |= SC16IS7XX_RECONF_RS485;
kthread_queue_work(&s->kworker, &one->reg_work);

--
2.30.2

2022-06-06 10:34:35

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 36/36] serial: 8250: Remove serial_rs485 sanitization from em485

Serial core handles serial_rs485 sanitization.

When em485 init fails, there are two possible paths of entry:

1) uart_rs485_config (init path) that fully clears port->rs485 on
error.

2) ioctl path with a pre-existing, valid port->rs485 unto which the
kernel falls back on error and port->rs485 should therefore be
kept untouched. The temporary rs485 struct is not returned to
userspace in case of error so its flag don't matter.

...Thus SER_RS485_ENABLED clearing on error can/should be dropped.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_port.c | 18 ++----------------
1 file changed, 2 insertions(+), 16 deletions(-)

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

- /* clamp the delays to [0, 100ms] */
- rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
- rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
-
- memset(rs485->padding, 0, sizeof(rs485->padding));
- port->rs485 = *rs485;
-
gpiod_set_value(port->rs485_term_gpio,
rs485->flags & SER_RS485_TERMINATE_BUS);

@@ -689,15 +682,8 @@ int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
* Both serial8250_em485_init() and serial8250_em485_destroy()
* are idempotent.
*/
- if (rs485->flags & SER_RS485_ENABLED) {
- int ret = serial8250_em485_init(up);
-
- if (ret) {
- rs485->flags &= ~SER_RS485_ENABLED;
- port->rs485.flags &= ~SER_RS485_ENABLED;
- }
- return ret;
- }
+ if (rs485->flags & SER_RS485_ENABLED)
+ return serial8250_em485_init(up);

serial8250_em485_destroy(up);
return 0;
--
2.30.2

2022-06-06 10:34:44

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 31/36] serial: imx: Remove serial_rs485 sanitization

The driver provides different rs485_supported for the case where RTS is
not available making it unnecessary to handle it in
imx_uart_rs485_config.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/imx.c | 4 ----
1 file changed, 4 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index ba853bc9b4db..1e96ddd2e262 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1913,10 +1913,6 @@ static int imx_uart_rs485_config(struct uart_port *port,
struct imx_port *sport = (struct imx_port *)port;
u32 ucr2;

- /* RTS is required to control the transmitter */
- if (!sport->have_rtscts && !sport->have_rtsgpio)
- rs485conf->flags &= ~SER_RS485_ENABLED;
-
if (rs485conf->flags & SER_RS485_ENABLED) {
/* Enable receiver if low-active RTS signal is requested */
if (sport->have_rtscts && !sport->have_rtsgpio &&
--
2.30.2

2022-06-06 10:34:55

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 19/36] serial: omap: Fill in rs485_supported

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/omap-serial.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 46f4d4cacb6e..98622c35d896 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1559,6 +1559,13 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up,
return 0;
}

+static const struct serial_rs485 serial_omap_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND |
+ SER_RS485_RX_DURING_TX,
+ .delay_rts_before_send = 1,
+ .delay_rts_after_send = 1,
+};
+
static int serial_omap_probe(struct platform_device *pdev)
{
struct omap_uart_port_info *omap_up_info = dev_get_platdata(&pdev->dev);
@@ -1636,6 +1643,7 @@ static int serial_omap_probe(struct platform_device *pdev)
up->port.flags = omap_up_info->flags;
up->port.uartclk = omap_up_info->uartclk;
up->port.rs485_config = serial_omap_config_rs485;
+ up->port.rs485_supported = &serial_omap_rs485_supported;
if (!up->port.uartclk) {
up->port.uartclk = DEFAULT_CLK_SPEED;
dev_warn(&pdev->dev,
--
2.30.2

2022-06-06 10:34:57

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 24/36] serial: return -EINVAL for non-legacy RS485 flags

In order to be add new flags more cleanly and safely, return -EINVAL
from TIOCSRS485 ioctl for the flags bits which are not among the
current legacy ones.

This might cause a regression for userspace as those non-flag bits do
not currently trigger -EINVAL. However, it would only occur if the
userspace is sending garbage bits so perhaps we'll get away with this
change.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/serial_core.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 6be538720564..621fc15e2e54 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1276,6 +1276,27 @@ static int uart_get_icount(struct tty_struct *tty,
return 0;
}

+#define SER_RS485_LEGACY_FLAGS (SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | \
+ SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX | \
+ SER_RS485_TERMINATE_BUS)
+
+static int uart_check_rs485_flags(struct uart_port *port, struct serial_rs485 *rs485)
+{
+ u32 flags = rs485->flags;
+
+ /* Don't return -EINVAL for unsupported legacy flags */
+ flags &= ~SER_RS485_LEGACY_FLAGS;
+
+ /*
+ * For any bit outside of the legacy ones that is not supported by
+ * the driver, return -EINVAL.
+ */
+ if (flags & ~port->rs485_supported->flags)
+ return -EINVAL;
+
+ return 0;
+}
+
static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs485 *rs485)
{
u32 supported_flags = port->rs485_supported->flags;
@@ -1375,6 +1396,9 @@ static int uart_set_rs485_config(struct uart_port *port,
if (copy_from_user(&rs485, rs485_user, sizeof(*rs485_user)))
return -EFAULT;

+ ret = uart_check_rs485_flags(port, &rs485);
+ if (ret)
+ return ret;
uart_sanitize_serial_rs485(port, &rs485);

spin_lock_irqsave(&port->lock, flags);
--
2.30.2

2022-06-06 10:34:58

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 11/36] serial: 8250_pci: Fill in rs485_supported for pci_fintek

Add information on supported serial_rs485 features.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_pci.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index fb0a49e39072..a76254031bc2 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1597,6 +1597,11 @@ static int pci_fintek_rs485_config(struct uart_port *port,
return 0;
}

+static const struct serial_rs485 pci_fintek_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
+ /* F81504/508/512 does not support RTS delay before or after send */
+};
+
static int pci_fintek_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
@@ -1616,6 +1621,7 @@ static int pci_fintek_setup(struct serial_private *priv,
port->port.iotype = UPIO_PORT;
port->port.iobase = iobase;
port->port.rs485_config = pci_fintek_rs485_config;
+ port->port.rs485_supported = &pci_fintek_rs485_supported;

data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL);
if (!data)
--
2.30.2

2022-06-06 10:34:59

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 25/36] serial: 8250_dwlib: Remove serial_rs485 sanitization

Serial core handles serial_rs485 sanitization and rs485 struct
assignment. As serial_rs485 is already clear for the non-RS485 case by
serial core, there no need to clear flags in the driver.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/8250/8250_dwlib.c | 10 ----------
1 file changed, 10 deletions(-)

diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index 120b29519d74..c83e7eaf3877 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -93,9 +93,6 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
tcr &= ~DW_UART_TCR_XFER_MODE;

if (rs485->flags & SER_RS485_ENABLED) {
- /* Clear unsupported flags. */
- rs485->flags &= SER_RS485_ENABLED | SER_RS485_RX_DURING_TX |
- SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND;
tcr |= DW_UART_TCR_RS485_EN;

if (rs485->flags & SER_RS485_RX_DURING_TX) {
@@ -111,8 +108,6 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
dw8250_writel_ext(p, DW_UART_DE_EN, 1);
dw8250_writel_ext(p, DW_UART_RE_EN, 1);
} else {
- rs485->flags = 0;
-
tcr &= ~DW_UART_TCR_RS485_EN;
}

@@ -127,11 +122,6 @@ static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)

dw8250_writel_ext(p, DW_UART_TCR, tcr);

- rs485->delay_rts_before_send = 0;
- rs485->delay_rts_after_send = 0;
-
- p->rs485 = *rs485;
-
return 0;
}

--
2.30.2

2022-06-06 10:35:06

by Ilpo Järvinen

[permalink] [raw]
Subject: [PATCH 29/36] serial: pl011: Remove serial_rs485 sanitization

Serial core handles serial_rs485 sanitization.

Signed-off-by: Ilpo Järvinen <[email protected]>
---
drivers/tty/serial/amba-pl011.c | 5 -----
1 file changed, 5 deletions(-)

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index cdc466e89aa8..eccd66625d25 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2681,17 +2681,12 @@ static int pl011_find_free_port(void)
static int pl011_get_rs485_mode(struct uart_amba_port *uap)
{
struct uart_port *port = &uap->port;
- struct serial_rs485 *rs485 = &port->rs485;
int ret;

ret = uart_get_rs485_mode(port);
if (ret)
return ret;

- /* clamp the delays to [0, 100ms] */
- rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U);
- rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U);
-
return 0;
}

--
2.30.2

2022-06-25 20:27:17

by Lukas Wunner

[permalink] [raw]
Subject: Re: [PATCH 22/36] serial: Sanitize rs485_struct

On Mon, Jun 06, 2022 at 01:04:19PM +0300, Ilpo J?rvinen wrote:
> - if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
> + if (!port->rs485_supported->delay_rts_before_send) {
> + if (rs485->delay_rts_before_send) {
> + dev_warn_ratelimited(port->dev,
> + "%s (%d): RTS delay before sending not supported\n",
> + port->name, port->line);
> + }
> + rs485->delay_rts_before_send = 0;
> + } else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
> rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
> dev_warn_ratelimited(port->dev,
> "%s (%d): RTS delay before sending clamped to %u ms\n",
> port->name, port->line, rs485->delay_rts_before_send);
> }

This series seems to set rs485_supported->delay_rts_before_send to 1
in all drivers to indicate that a delay is supported.

It would probably be smarter to define it as a maximum, i.e. drivers
declare the supported maximum delay in their rs485_supported struct
and the core can use that to clamp the value. Initially, all drivers
may use RS485_MAX_RTS_DELAY. Some chips only support specific delays
(multiples of the UART clock or baud clock). We can amend their
drivers later according to their capabilities.

Thanks,

Lukas

2022-06-26 12:47:08

by Lino Sanfilippo

[permalink] [raw]
Subject: Re: [PATCH 22/36] serial: Sanitize rs485_struct

On 25.06.22 at 22:12, Lukas Wunner wrote:
> On Mon, Jun 06, 2022 at 01:04:19PM +0300, Ilpo Järvinen wrote:
>> - if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
>> + if (!port->rs485_supported->delay_rts_before_send) {
>> + if (rs485->delay_rts_before_send) {
>> + dev_warn_ratelimited(port->dev,
>> + "%s (%d): RTS delay before sending not supported\n",
>> + port->name, port->line);
>> + }
>> + rs485->delay_rts_before_send = 0;
>> + } else if (rs485->delay_rts_before_send > RS485_MAX_RTS_DELAY) {
>> rs485->delay_rts_before_send = RS485_MAX_RTS_DELAY;
>> dev_warn_ratelimited(port->dev,
>> "%s (%d): RTS delay before sending clamped to %u ms\n",
>> port->name, port->line, rs485->delay_rts_before_send);
>> }
>
> This series seems to set rs485_supported->delay_rts_before_send to 1
> in all drivers to indicate that a delay is supported.
>
> It would probably be smarter to define it as a maximum, i.e. drivers
> declare the supported maximum delay in their rs485_supported struct
> and the core can use that to clamp the value. Initially, all drivers
> may use RS485_MAX_RTS_DELAY. Some chips only support specific delays
> (multiples of the UART clock or baud clock). We can amend their
> drivers later according to their capabilities.

Agreed.

Regards,
Lino