TTY/Serial fixes for 6.5-rc7

Here are some small tty and serial core fixes for 6.5-rc7 that resolve a
 lot of reported issues.
 
 Primarily in here is the fixes for the serial bus code from Tony that
 came in -rc1, as it hit wider testing with the huge number of different
 types of systems and serial ports.  All of the reported issues with
 duplicate names and other issues with this code are now resolved.
 
 Other than that included in here is:
  - n_gsm fix for a previous fix
  - 8250 lockdep annotation fix
  - fsl_lpuart serial driver fix
  - TIOCSTI documentation update for previous CAP_SYS_ADMIN change
 
 All of these have been in linux-next for a while with no reported
 problems.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCZOEjmg8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ykpSgCfajOM7BUzL1kOrfKNvHQuPmOYlIUAnAot+4M+
 HkvS58Xs2+PM14y/KG1j
 =6DRj
 -----END PGP SIGNATURE-----

Merge tag 'tty-6.5-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty

Pull tty/serial fixes from Greg KH:
 "Here are some small tty and serial core fixes for 6.5-rc7 that resolve
  a lot of reported issues.

  Primarily in here are the fixes for the serial bus code from Tony that
  came in -rc1, as it hit wider testing with the huge number of
  different types of systems and serial ports. All of the reported
  issues with duplicate names and other issues with this code are now
  resolved.

  Other than that included in here is:

   - n_gsm fix for a previous fix

   - 8250 lockdep annotation fix

   - fsl_lpuart serial driver fix

   - TIOCSTI documentation update for previous CAP_SYS_ADMIN change

  All of these have been in linux-next for a while with no reported
  problems"

* tag 'tty-6.5-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty:
  serial: core: Fix serial core port id, including multiport devices
  serial: 8250: drop lockdep annotation from serial8250_clear_IER()
  tty: n_gsm: fix the UAF caused by race condition in gsm_cleanup_mux
  serial: core: Revert port_id use
  TIOCSTI: Document CAP_SYS_ADMIN behaviour in Kconfig
  serial: 8250: Fix oops for port->pm on uart_change_pm()
  serial: 8250: Reinit port_id when adding back serial8250_isa_devs
  serial: core: Fix kmemleak issue for serial core device remove
  MAINTAINERS: Merge TTY layer and serial drivers
  serial: core: Fix serial_base_match() after fixing controller port name
  serial: core: Fix serial core controller port name to show controller id
  serial: core: Fix serial core port id to not use port->line
  serial: core: Controller id cannot be negative
  tty: serial: fsl_lpuart: Clear the error flags by writing 1 for lpuart32 platforms
This commit is contained in:
Linus Torvalds 2023-08-20 08:26:51 +02:00
commit b320441c04
9 changed files with 72 additions and 34 deletions

View File

@ -19224,13 +19224,6 @@ F: Documentation/devicetree/bindings/serial/serial.yaml
F: drivers/tty/serdev/ F: drivers/tty/serdev/
F: include/linux/serdev.h F: include/linux/serdev.h
SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
L: linux-serial@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/serial/
F: drivers/tty/serial/
SERIAL IR RECEIVER SERIAL IR RECEIVER
M: Sean Young <sean@mess.org> M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
@ -21635,20 +21628,16 @@ W: https://github.com/srcres258/linux-doc
T: git git://github.com/srcres258/linux-doc.git doc-zh-tw T: git git://github.com/srcres258/linux-doc.git doc-zh-tw
F: Documentation/translations/zh_TW/ F: Documentation/translations/zh_TW/
TTY LAYER TTY LAYER AND SERIAL DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org> M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Jiri Slaby <jirislaby@kernel.org> M: Jiri Slaby <jirislaby@kernel.org>
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
L: linux-serial@vger.kernel.org L: linux-serial@vger.kernel.org
S: Supported S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git
F: Documentation/devicetree/bindings/serial/
F: Documentation/driver-api/serial/ F: Documentation/driver-api/serial/
F: drivers/tty/ F: drivers/tty/
F: drivers/tty/serial/serial_base.h
F: drivers/tty/serial/serial_base_bus.c
F: drivers/tty/serial/serial_core.c
F: drivers/tty/serial/serial_ctrl.c
F: drivers/tty/serial/serial_port.c
F: include/linux/selection.h F: include/linux/selection.h
F: include/linux/serial.h F: include/linux/serial.h
F: include/linux/serial_core.h F: include/linux/serial_core.h

View File

@ -164,6 +164,9 @@ config LEGACY_TIOCSTI
userspace depends on this functionality to continue operating userspace depends on this functionality to continue operating
normally. normally.
Processes which run with CAP_SYS_ADMIN, such as BRLTTY, can
use TIOCSTI even when this is set to N.
This functionality can be changed at runtime with the This functionality can be changed at runtime with the
dev.tty.legacy_tiocsti sysctl. This configuration option sets dev.tty.legacy_tiocsti sysctl. This configuration option sets
the default value of the sysctl. the default value of the sysctl.

View File

@ -3042,12 +3042,13 @@ static void gsm_error(struct gsm_mux *gsm)
static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
{ {
int i; int i;
struct gsm_dlci *dlci = gsm->dlci[0]; struct gsm_dlci *dlci;
struct gsm_msg *txq, *ntxq; struct gsm_msg *txq, *ntxq;
gsm->dead = true; gsm->dead = true;
mutex_lock(&gsm->mutex); mutex_lock(&gsm->mutex);
dlci = gsm->dlci[0];
if (dlci) { if (dlci) {
if (disc && dlci->state != DLCI_CLOSED) { if (disc && dlci->state != DLCI_CLOSED) {
gsm_dlci_begin_close(dlci); gsm_dlci_begin_close(dlci);

View File

@ -497,6 +497,7 @@ static struct uart_8250_port *serial8250_setup_port(int index)
up = &serial8250_ports[index]; up = &serial8250_ports[index];
up->port.line = index; up->port.line = index;
up->port.port_id = index;
serial8250_init_port(up); serial8250_init_port(up);
if (!base_ops) if (!base_ops)
@ -1040,6 +1041,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart_remove_one_port(&serial8250_reg, &uart->port); uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.ctrl_id = up->port.ctrl_id; uart->port.ctrl_id = up->port.ctrl_id;
uart->port.port_id = up->port.port_id;
uart->port.iobase = up->port.iobase; uart->port.iobase = up->port.iobase;
uart->port.membase = up->port.membase; uart->port.membase = up->port.membase;
uart->port.irq = up->port.irq; uart->port.irq = up->port.irq;
@ -1202,6 +1204,7 @@ void serial8250_unregister_port(int line)
uart->port.flags &= ~UPF_BOOT_AUTOCONF; uart->port.flags &= ~UPF_BOOT_AUTOCONF;
uart->port.type = PORT_UNKNOWN; uart->port.type = PORT_UNKNOWN;
uart->port.dev = &serial8250_isa_devs->dev; uart->port.dev = &serial8250_isa_devs->dev;
uart->port.port_id = line;
uart->capabilities = 0; uart->capabilities = 0;
serial8250_init_port(uart); serial8250_init_port(uart);
serial8250_apply_quirks(uart); serial8250_apply_quirks(uart);

View File

@ -703,9 +703,6 @@ static void serial8250_set_sleep(struct uart_8250_port *p, int sleep)
static void serial8250_clear_IER(struct uart_8250_port *up) static void serial8250_clear_IER(struct uart_8250_port *up)
{ {
/* Port locked to synchronize UART_IER access against the console. */
lockdep_assert_held_once(&up->port.lock);
if (up->capabilities & UART_CAP_UUE) if (up->capabilities & UART_CAP_UUE)
serial_out(up, UART_IER, UART_IER_UUE); serial_out(up, UART_IER, UART_IER_UUE);
else else
@ -3278,6 +3275,7 @@ void serial8250_init_port(struct uart_8250_port *up)
spin_lock_init(&port->lock); spin_lock_init(&port->lock);
port->ctrl_id = 0; port->ctrl_id = 0;
port->pm = NULL;
port->ops = &serial8250_pops; port->ops = &serial8250_pops;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE); port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);

View File

@ -1139,8 +1139,8 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
if (sr & (UARTSTAT_PE | UARTSTAT_FE)) { if (sr & (UARTSTAT_PE | UARTSTAT_FE)) {
/* Read DR to clear the error flags */ /* Clear the error flags */
lpuart32_read(&sport->port, UARTDATA); lpuart32_write(&sport->port, sr, UARTSTAT);
if (sr & UARTSTAT_PE) if (sr & UARTSTAT_PE)
sport->port.icount.parity++; sport->port.icount.parity++;

View File

@ -16,6 +16,7 @@ struct device;
struct serial_ctrl_device { struct serial_ctrl_device {
struct device dev; struct device dev;
struct ida port_ida;
}; };
struct serial_port_device { struct serial_port_device {

View File

@ -10,6 +10,7 @@
#include <linux/container_of.h> #include <linux/container_of.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/idr.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/serial_core.h> #include <linux/serial_core.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -19,11 +20,25 @@
static bool serial_base_initialized; static bool serial_base_initialized;
static const struct device_type serial_ctrl_type = {
.name = "ctrl",
};
static const struct device_type serial_port_type = {
.name = "port",
};
static int serial_base_match(struct device *dev, struct device_driver *drv) static int serial_base_match(struct device *dev, struct device_driver *drv)
{ {
int len = strlen(drv->name); if (dev->type == &serial_ctrl_type &&
str_has_prefix(drv->name, serial_ctrl_type.name))
return 1;
return !strncmp(dev_name(dev), drv->name, len); if (dev->type == &serial_port_type &&
str_has_prefix(drv->name, serial_port_type.name))
return 1;
return 0;
} }
static struct bus_type serial_base_bus_type = { static struct bus_type serial_base_bus_type = {
@ -48,7 +63,8 @@ static int serial_base_device_init(struct uart_port *port,
struct device *parent_dev, struct device *parent_dev,
const struct device_type *type, const struct device_type *type,
void (*release)(struct device *dev), void (*release)(struct device *dev),
int id) unsigned int ctrl_id,
unsigned int port_id)
{ {
device_initialize(dev); device_initialize(dev);
dev->type = type; dev->type = type;
@ -61,12 +77,15 @@ static int serial_base_device_init(struct uart_port *port,
return -EPROBE_DEFER; return -EPROBE_DEFER;
} }
return dev_set_name(dev, "%s.%s.%d", type->name, dev_name(port->dev), id); if (type == &serial_ctrl_type)
} return dev_set_name(dev, "%s:%d", dev_name(port->dev), ctrl_id);
static const struct device_type serial_ctrl_type = { if (type == &serial_port_type)
.name = "ctrl", return dev_set_name(dev, "%s:%d.%d", dev_name(port->dev),
}; ctrl_id, port_id);
return -EINVAL;
}
static void serial_base_ctrl_release(struct device *dev) static void serial_base_ctrl_release(struct device *dev)
{ {
@ -81,6 +100,7 @@ void serial_base_ctrl_device_remove(struct serial_ctrl_device *ctrl_dev)
return; return;
device_del(&ctrl_dev->dev); device_del(&ctrl_dev->dev);
put_device(&ctrl_dev->dev);
} }
struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port, struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port,
@ -93,10 +113,12 @@ struct serial_ctrl_device *serial_base_ctrl_add(struct uart_port *port,
if (!ctrl_dev) if (!ctrl_dev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ida_init(&ctrl_dev->port_ida);
err = serial_base_device_init(port, &ctrl_dev->dev, err = serial_base_device_init(port, &ctrl_dev->dev,
parent, &serial_ctrl_type, parent, &serial_ctrl_type,
serial_base_ctrl_release, serial_base_ctrl_release,
port->ctrl_id); port->ctrl_id, 0);
if (err) if (err)
goto err_put_device; goto err_put_device;
@ -112,10 +134,6 @@ err_put_device:
return ERR_PTR(err); return ERR_PTR(err);
} }
static const struct device_type serial_port_type = {
.name = "port",
};
static void serial_base_port_release(struct device *dev) static void serial_base_port_release(struct device *dev)
{ {
struct serial_port_device *port_dev = to_serial_base_port_device(dev); struct serial_port_device *port_dev = to_serial_base_port_device(dev);
@ -127,16 +145,31 @@ struct serial_port_device *serial_base_port_add(struct uart_port *port,
struct serial_ctrl_device *ctrl_dev) struct serial_ctrl_device *ctrl_dev)
{ {
struct serial_port_device *port_dev; struct serial_port_device *port_dev;
int min = 0, max = -1; /* Use -1 for max to apply IDA defaults */
int err; int err;
port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
if (!port_dev) if (!port_dev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* Device driver specified port_id vs automatic assignment? */
if (port->port_id) {
min = port->port_id;
max = port->port_id;
}
err = ida_alloc_range(&ctrl_dev->port_ida, min, max, GFP_KERNEL);
if (err < 0) {
kfree(port_dev);
return ERR_PTR(err);
}
port->port_id = err;
err = serial_base_device_init(port, &port_dev->dev, err = serial_base_device_init(port, &port_dev->dev,
&ctrl_dev->dev, &serial_port_type, &ctrl_dev->dev, &serial_port_type,
serial_base_port_release, serial_base_port_release,
port->line); port->ctrl_id, port->port_id);
if (err) if (err)
goto err_put_device; goto err_put_device;
@ -150,16 +183,25 @@ struct serial_port_device *serial_base_port_add(struct uart_port *port,
err_put_device: err_put_device:
put_device(&port_dev->dev); put_device(&port_dev->dev);
ida_free(&ctrl_dev->port_ida, port->port_id);
return ERR_PTR(err); return ERR_PTR(err);
} }
void serial_base_port_device_remove(struct serial_port_device *port_dev) void serial_base_port_device_remove(struct serial_port_device *port_dev)
{ {
struct serial_ctrl_device *ctrl_dev;
struct device *parent;
if (!port_dev) if (!port_dev)
return; return;
parent = port_dev->dev.parent;
ctrl_dev = to_serial_base_ctrl_device(parent);
device_del(&port_dev->dev); device_del(&port_dev->dev);
ida_free(&ctrl_dev->port_ida, port_dev->port->port_id);
put_device(&port_dev->dev);
} }
static int serial_base_init(void) static int serial_base_init(void)

View File

@ -459,7 +459,8 @@ struct uart_port {
struct serial_rs485 *rs485); struct serial_rs485 *rs485);
int (*iso7816_config)(struct uart_port *, int (*iso7816_config)(struct uart_port *,
struct serial_iso7816 *iso7816); struct serial_iso7816 *iso7816);
int ctrl_id; /* optional serial core controller id */ unsigned int ctrl_id; /* optional serial core controller id */
unsigned int port_id; /* optional serial core port id */
unsigned int irq; /* irq number */ unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */ unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */ unsigned int uartclk; /* base uart clock */