Hi, Geert, On 19.12.2024 16:26, Geert Uytterhoeven wrote: > Hi Claudiu, > > On Wed, Dec 4, 2024 at 4:58 PM Claudiu <claudiu.beznea@xxxxxxxxx> wrote: >> From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> >> >> The early_console_setup() function initializes sci_ports[0].port with an >> object of type struct uart_port obtained from the struct earlycon_device >> passed as an argument to early_console_setup(). >> >> Later, during serial port probing, the serial port used as earlycon >> (e.g., port A) might be remapped to a different position in the sci_ports[] >> array, and a different serial port (e.g., port B) might be assigned to slot >> 0. For example: >> >> sci_ports[0] = port B >> sci_ports[X] = port A >> >> In this scenario, the new port mapped at index zero (port B) retains the >> data associated with the earlycon configuration. Consequently, after the >> Linux boot process, any access to the serial port now mapped to >> sci_ports[0] (port B) will block the original earlycon port (port A). >> >> To address this, introduce an early_console_exit() function to clean up >> sci_ports[0] when earlycon is exited. >> >> To prevent the cleanup of sci_ports[0] while the serial device is still >> being used by earlycon, introduce the struct sci_port::probing flag and >> account for it in early_console_exit(). >> >> Fixes: 0b0cced19ab1 ("serial: sh-sci: Add CONFIG_SERIAL_EARLYCON support") >> Cc: stable@xxxxxxxxxxxxxxx >> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> >> --- >> >> Changes since the integrated patch: >> - adjust the commit message to address Geert comments at [1] >> - Introduce the struct sci_port::probing flag to prevent the cleanup >> of sci_ports[0] while the serial device is still being used by earlycon > > Thanks for the update! > >> --- a/drivers/tty/serial/sh-sci.c >> +++ b/drivers/tty/serial/sh-sci.c >> @@ -159,6 +159,7 @@ struct sci_port { >> bool autorts; >> bool tx_occurred; >> bool earlycon; >> + bool probing; > > This is only used in sci_ports[0], so it can be a single global flag, > instead of a flag embedded in each sci_port structure. > >> }; >> >> #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS >> @@ -3386,7 +3387,8 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, >> static int sci_probe_single(struct platform_device *dev, >> unsigned int index, >> struct plat_sci_port *p, >> - struct sci_port *sciport) >> + struct sci_port *sciport, >> + struct resource *sci_res) >> { >> int ret; >> >> @@ -3433,12 +3435,15 @@ static int sci_probe_single(struct platform_device *dev, >> sciport->port.flags |= UPF_HARD_FLOW; >> } >> >> - ret = uart_add_one_port(&sci_uart_driver, &sciport->port); >> - if (ret) { >> - return ret; >> + if (sci_ports[0].earlycon && sci_ports[0].port.mapbase == sci_res->start) { >> + /* >> + * Skip cleanup up the sci_port[0] in early_console_exit(), this > > Double up > >> + * port is the same as the earlycon one. >> + */ >> + sci_ports[0].probing = true; >> } >> >> - return 0; >> + return uart_add_one_port(&sci_uart_driver, &sciport->port); >> } >> >> static int sci_probe(struct platform_device *dev) >> @@ -3496,7 +3501,7 @@ static int sci_probe(struct platform_device *dev) >> >> platform_set_drvdata(dev, sp); >> >> - ret = sci_probe_single(dev, dev_id, p, sp); >> + ret = sci_probe_single(dev, dev_id, p, sp, res); >> if (ret) >> return ret; >> >> @@ -3579,6 +3584,20 @@ sh_early_platform_init_buffer("earlyprintk", &sci_driver, >> #ifdef CONFIG_SERIAL_SH_SCI_EARLYCON >> static struct plat_sci_port port_cfg; >> >> +static int early_console_exit(struct console *co) >> +{ >> + struct sci_port *sci_port = &sci_ports[0]; >> + >> + /* >> + * Clean the slot used by earlycon. A new SCI device might >> + * map to this slot. >> + */ >> + if (sci_port->earlycon && !sci_port->probing) >> + memset(sci_port, 0, sizeof(*sci_port)); > > Aha, so this clears sci_port.earlycon, too (cfr. my comment on > PATCH 4/6). Still, I don't think this is sufficient: shouldn't > sci_port.earlycon be cleared unconditionally? I remember I had failures with unconditional clear. I'll double check it though and adjust accordingly, if needed. Thank you, Claudiu > >> + >> + return 0; >> +} >> + >> static int __init early_console_setup(struct earlycon_device *device, >> int type) >> { >> @@ -3596,6 +3615,8 @@ static int __init early_console_setup(struct earlycon_device *device, >> SCSCR_RE | SCSCR_TE | port_cfg.scscr); >> >> device->con->write = serial_console_write; >> + device->con->exit = early_console_exit; >> + >> return 0; >> } >> static int __init sci_early_console_setup(struct earlycon_device *device, > > Gr{oetje,eeting}s, > > Geert > > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like that. > -- Linus Torvalds