diff options
author | Hans de Goede <hdegoede@redhat.com> | 2024-05-09 16:15:49 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2024-05-10 11:49:23 +0100 |
commit | e21de1455a721a0cb4217b18589ede846f5b0686 (patch) | |
tree | 6e218046159c556fabb0dd144c79b485dffad221 /drivers/tty | |
parent | a3d8728ab079951741efa11360df43dbfacba7ab (diff) | |
download | lwn-e21de1455a721a0cb4217b18589ede846f5b0686.tar.gz lwn-e21de1455a721a0cb4217b18589ede846f5b0686.zip |
serial: Clear UPF_DEAD before calling tty_port_register_device_attr_serdev()
If a serdev_device_driver is already loaded for a serdev_tty_port when it
gets registered by tty_port_register_device_attr_serdev() then that
driver's probe() method will be called immediately.
The serdev_device_driver's probe() method should then be able to call
serdev_device_open() successfully, but because UPF_DEAD is still dead
serdev_device_open() will fail with -ENXIO in this scenario:
serdev_device_open()
ctrl->ops->open() /* this callback being ttyport_open() */
tty->ops->open() /* this callback being uart_open() */
tty_port_open()
port->ops->activate() /* this callback being uart_port_activate() */
Find bit UPF_DEAD is set in uport->flags and fail with errno -ENXIO.
Fix this be clearing UPF_DEAD before tty_port_register_device_attr_serdev()
note this only moves up the UPD_DEAD clearing a small bit, before:
tty_port_register_device_attr_serdev();
mutex_unlock(&tty_port.mutex);
uart_port.flags &= ~UPF_DEAD;
mutex_unlock(&port_mutex);
after:
uart_port.flags &= ~UPF_DEAD;
tty_port_register_device_attr_serdev();
mutex_unlock(&tty_port.mutex);
mutex_unlock(&port_mutex);
Reported-by: Weifeng Liu <weifeng.liu.z@gmail.com>
Closes: https://lore.kernel.org/platform-driver-x86/20240505130800.2546640-1-weifeng.liu.z@gmail.com/
Tested-by: Weifeng Liu <weifeng.liu.z@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20240509141549.63704-1-hdegoede@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/serial/serial_core.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 84ae70d52b05..2c1a0254d3f4 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3207,6 +3207,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u if (uport->attr_group) uport->tty_groups[1] = uport->attr_group; + /* Ensure serdev drivers can call serdev_device_open() right away */ + uport->flags &= ~UPF_DEAD; + /* * Register the port whether it's detected or not. This allows * setserial to be used to alter this port's parameters. @@ -3217,6 +3220,7 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u if (!IS_ERR(tty_dev)) { device_set_wakeup_capable(tty_dev, 1); } else { + uport->flags |= UPF_DEAD; dev_err(uport->dev, "Cannot register tty device on line %d\n", uport->line); } @@ -3426,8 +3430,6 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) if (ret) goto err_unregister_port_dev; - port->flags &= ~UPF_DEAD; - mutex_unlock(&port_mutex); return 0; |