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@xxxxxxxxx> Closes: https://lore.kernel.org/platform-driver-x86/20240505130800.2546640-1-weifeng.liu.z@xxxxxxxxx/ Tested-by: Weifeng Liu <weifeng.liu.z@xxxxxxxxx> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx> --- Cc: Tony Lindgren <tony.lindgren@xxxxxxxxxxxxxxx> Cc: Maximilian Luz <luzmaximilian@xxxxxxxxx> Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> --- drivers/tty/serial/serial_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c476d884356d..b47a277978a0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3211,6 +3211,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. @@ -3221,6 +3224,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; -- 2.44.0