[PATCH v6 4/6] serial: take termios_rwsem for .rs485_config() & pass termios as param

From: Ilpo Järvinen
Date: Mon Jun 13 2022 - 03:53:14 EST


To be able to alter ADDRB within .rs485_config(), take termios_rwsem
before calling .rs485_config() and pass termios.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx>
---
drivers/tty/serial/8250/8250.h | 3 ++-
drivers/tty/serial/8250/8250_dwlib.c | 3 ++-
drivers/tty/serial/8250/8250_exar.c | 9 +++++----
drivers/tty/serial/8250/8250_fintek.c | 2 +-
drivers/tty/serial/8250/8250_lpc18xx.c | 2 +-
drivers/tty/serial/8250/8250_pci.c | 2 +-
drivers/tty/serial/8250/8250_port.c | 3 ++-
drivers/tty/serial/amba-pl011.c | 2 +-
drivers/tty/serial/ar933x_uart.c | 2 +-
drivers/tty/serial/atmel_serial.c | 2 +-
drivers/tty/serial/fsl_lpuart.c | 4 ++--
drivers/tty/serial/imx.c | 2 +-
drivers/tty/serial/max310x.c | 2 +-
drivers/tty/serial/mcf.c | 3 ++-
drivers/tty/serial/omap-serial.c | 3 ++-
drivers/tty/serial/sc16is7xx.c | 2 +-
drivers/tty/serial/serial_core.c | 15 +++++++++++----
drivers/tty/serial/stm32-usart.c | 2 +-
include/linux/serial_core.h | 3 ++-
19 files changed, 40 insertions(+), 26 deletions(-)

diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 36aebf3ec02c..3183bfe1334d 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -203,7 +203,8 @@ void serial8250_rpm_put(struct uart_8250_port *p);
void serial8250_rpm_get_tx(struct uart_8250_port *p);
void serial8250_rpm_put_tx(struct uart_8250_port *p);

-int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485);
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios);
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);
diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index c83e7eaf3877..c9d9bd7f7bd9 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -85,7 +85,8 @@ void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, struct
}
EXPORT_SYMBOL_GPL(dw8250_do_set_termios);

-static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485)
+static int dw8250_rs485_config(struct uart_port *p, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
u32 tcr;

diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 0eae2d8a9494..4988629135f6 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -112,7 +112,8 @@
struct exar8250;

struct exar8250_platform {
- int (*rs485_config)(struct uart_port *, struct serial_rs485 *);
+ int (*rs485_config)(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios);
const struct serial_rs485 *rs485_supported;
int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
void (*unregister_gpio)(struct uart_8250_port *);
@@ -410,7 +411,7 @@ static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
}

static int generic_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
u8 __iomem *p = port->membase;
@@ -442,7 +443,7 @@ static const struct exar8250_platform exar8250_default_platform = {
};

static int iot2040_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
u8 __iomem *p = port->membase;
@@ -471,7 +472,7 @@ static int iot2040_rs485_config(struct uart_port *port,
value |= mode;
writeb(value, p + UART_EXAR_MPIOLVL_7_0);

- return generic_rs485_config(port, rs485);
+ return generic_rs485_config(port, rs485, termios);
}

static const struct serial_rs485 iot2040_rs485_supported = {
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index 1fb86c73786c..e48d52534bef 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -192,7 +192,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
}

static int fintek_8250_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
uint8_t config = 0;
struct fintek_8250 *pdata = port->private_data;
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 3a1cb51cbc91..1865f7bc5020 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -33,7 +33,7 @@ struct lpc18xx_uart_data {
};

static int lpc18xx_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(port);
u32 rs485_ctrl_reg = 0;
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index b6d71268aa7d..35c799641e32 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -1554,7 +1554,7 @@ pci_brcm_trumanage_setup(struct serial_private *priv,

/* We should do proper H/W transceiver setting before change to RS485 mode */
static int pci_fintek_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct pci_dev *pci_dev = to_pci_dev(port->dev);
u8 setting;
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 8ff9f4815c7b..8ab0584bdba2 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -664,7 +664,8 @@ EXPORT_SYMBOL_GPL(serial8250_em485_supported);
* if the uart is incapable of driving RTS as a Transmit Enable signal in
* hardware, relying on software emulation instead.
*/
-int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485)
+int serial8250_em485_config(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(port);

diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index eccd66625d25..aefb0600a82c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2198,7 +2198,7 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
}

static int pl011_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index ab2c5b2a1ce8..930d9aed90f5 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -581,7 +581,7 @@ static const struct uart_ops ar933x_uart_ops = {
};

static int ar933x_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct ar933x_uart_port *up =
container_of(port, struct ar933x_uart_port, port);
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 74dd1d3ac46f..b032e7c30ce0 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -286,7 +286,7 @@ static void atmel_tasklet_schedule(struct atmel_uart_port *atmel_port,

/* Enable or disable the rs485 support */
static int atmel_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
unsigned int mode;
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index d35414cb3e4e..3e8da24a3f76 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1356,7 +1356,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
}

static int lpuart_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
@@ -1386,7 +1386,7 @@ static int lpuart_config_rs485(struct uart_port *port,
}

static int lpuart32_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index f4edde54175f..8a63ab6e0d8e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1908,7 +1908,7 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)

/* called with port.lock taken and irqs off or from .probe without locking */
static int imx_uart_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct imx_port *sport = (struct imx_port *)port;
u32 ucr2;
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index d7d1791fcb57..0e1dfad03825 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -1027,7 +1027,7 @@ static void max310x_rs_proc(struct work_struct *ws)
}

static int max310x_rs485_config(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct max310x_one *one = to_max310x_port(port);

diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 036f178e3d66..fbdf8c53ddd0 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -431,7 +431,8 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
/****************************************************************************/

/* Enable or disable the RS485 support */
-static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
unsigned char mr1, mr2;

diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 98622c35d896..07446bcbfa8c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1325,7 +1325,8 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up)

/* Enable or disable the rs485 support */
static int
-serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
+serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485,
+ struct ktermios *termios)
{
struct uart_omap_port *up = to_uart_omap_port(port);
unsigned int mode;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 2ceecaa4a478..f84c693ef5e7 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1128,7 +1128,7 @@ static void sc16is7xx_set_termios(struct uart_port *port,
}

static int sc16is7xx_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485)
+ struct serial_rs485 *rs485, struct ktermios *termios)
{
struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 621fc15e2e54..76bb1b77b06e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1359,7 +1359,8 @@ int uart_rs485_config(struct uart_port *port)

uart_sanitize_serial_rs485(port, rs485);

- ret = port->rs485_config(port, rs485);
+ ret = port->rs485_config(port, rs485, NULL);
+
if (ret)
memset(rs485, 0, sizeof(*rs485));

@@ -1383,7 +1384,7 @@ static int uart_get_rs485_config(struct uart_port *port,
return 0;
}

-static int uart_set_rs485_config(struct uart_port *port,
+static int uart_set_rs485_config(struct tty_struct *tty, struct uart_port *port,
struct serial_rs485 __user *rs485_user)
{
struct serial_rs485 rs485;
@@ -1402,7 +1403,7 @@ static int uart_set_rs485_config(struct uart_port *port,
uart_sanitize_serial_rs485(port, &rs485);

spin_lock_irqsave(&port->lock, flags);
- ret = port->rs485_config(port, &rs485);
+ ret = port->rs485_config(port, &rs485, &tty->termios);
if (!ret)
port->rs485 = rs485;
spin_unlock_irqrestore(&port->lock, flags);
@@ -1511,6 +1512,10 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
if (ret != -ENOIOCTLCMD)
goto out;

+ /* rs485_config requires more locking than others */
+ if (cmd == TIOCGRS485)
+ down_write(&tty->termios_rwsem);
+
mutex_lock(&port->mutex);
uport = uart_port_check(state);

@@ -1534,7 +1539,7 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
break;

case TIOCSRS485:
- ret = uart_set_rs485_config(uport, uarg);
+ ret = uart_set_rs485_config(tty, uport, uarg);
break;

case TIOCSISO7816:
@@ -1551,6 +1556,8 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
}
out_up:
mutex_unlock(&port->mutex);
+ if (cmd == TIOCGRS485)
+ up_write(&tty->termios_rwsem);
out:
return ret;
}
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index db3dd9731ee1..de8e3cbda4f3 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -98,7 +98,7 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
}

static int stm32_usart_config_rs485(struct uart_port *port,
- struct serial_rs485 *rs485conf)
+ struct serial_rs485 *rs485conf, struct ktermios *termios)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 5518b70177b3..9577cffb5593 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -132,7 +132,8 @@ struct uart_port {
unsigned int old);
void (*handle_break)(struct uart_port *);
int (*rs485_config)(struct uart_port *,
- struct serial_rs485 *rs485);
+ struct serial_rs485 *rs485,
+ struct ktermios *termios);
int (*iso7816_config)(struct uart_port *,
struct serial_iso7816 *iso7816);
unsigned int irq; /* irq number */
--
2.30.2