Message ID | efd9397662ff743f95298ca6aad4efdfa0ba1962.1716811405.git.geert+renesas@glider.be (mailing list archive) |
---|---|
State | RFC |
Delegated to: | Geert Uytterhoeven |
Headers | show |
Series | pmdomain: renesas: rmobile-sysc: Remove serial console handling | expand |
On Mon, May 27, 2024 at 2:41 PM Geert Uytterhoeven <geert+renesas@glider.be> wrote: > Earlycon relies on the serial port to be initialized by the firmware > and/or bootloader. Linux is not aware of any hardware dependencies that > must be met to keep the port working, and thus cannot guarantee they > stay met, until the full serial driver takes over. > > E.g. all unused clocks and unused PM Domains are disabled in a late > initcall. As this happens after the full serial driver has taken over, > the serial port's clock and/or PM Domain are no longer deemed unused, > and this is typically not a problem. > > However, if the serial port's clock or PM Domain is shared with another > device, and that other device is runtime-suspended before the full > serial driver has probed, the serial port's clock and/or PM Domain will > be disabled inadvertently. Any subsequent serial console output will > cause a crash or system lock-up. > > Provide a mechanism to let the clock and/or PM Domain subsystem or > drivers handle this, by exporting the clock and PM Domain dependencies > for the serial port, as available in the system's device tree. > Note that as this is done during early boot-up, the device_node > structure pointing to the earlycon console is not yet created, so this > has to resort to raw property data. > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > --- a/include/linux/serial_core.h > +++ b/include/linux/serial_core.h > @@ -954,6 +954,16 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED; > static inline int setup_earlycon(char *buf) { return 0; } > #endif > > +#ifdef CONFIG_OF_EARLY_FLATTREE This should include a check for CONFIG_SERIAL_EARLYCON. > +extern const __be32 *earlycon_clocks, *earlycon_power_domains; > +extern int earlycon_clocks_ncells, earlycon_power_domains_ncells; > +#else > +#define earlycon_clocks NULL > +#define earlycon_clocks_ncells 0 > +#define earlycon_power_domains NULL > +#define earlycon_power_domains_ncells 0 > +#endif > + > /* Variant of uart_console_registered() when the console_list_lock is held. */ > static inline bool uart_console_registered_locked(struct uart_port *port) > { Gr{oetje,eeting}s, Geert
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index a5fbb6ed38aed681..abe4831d9685e2b8 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -250,11 +250,14 @@ early_param("earlycon", param_setup_earlycon); #ifdef CONFIG_OF_EARLY_FLATTREE +const __be32 *earlycon_clocks, *earlycon_power_domains; +int earlycon_clocks_ncells, earlycon_power_domains_ncells; + int __init of_setup_earlycon(const struct earlycon_id *match, unsigned long node, const char *options) { - int err; + int err, size; struct uart_port *port = &early_console_dev.port; const __be32 *val; bool big_endian; @@ -309,6 +312,15 @@ int __init of_setup_earlycon(const struct earlycon_id *match, if (val) port->uartclk = be32_to_cpu(*val); + earlycon_clocks = of_get_flat_dt_prop(node, "clocks", &size); + if (earlycon_clocks) + earlycon_clocks_ncells = size / sizeof(u32); + + earlycon_power_domains = of_get_flat_dt_prop(node, "power-domains", + &size); + if (earlycon_power_domains) + earlycon_power_domains_ncells = size / sizeof(u32); + if (options) { early_console_dev.baud = simple_strtoul(options, NULL, 0); strscpy(early_console_dev.options, options, diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 8cb65f50e830c8d4..70689a3363951dac 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -954,6 +954,16 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED; static inline int setup_earlycon(char *buf) { return 0; } #endif +#ifdef CONFIG_OF_EARLY_FLATTREE +extern const __be32 *earlycon_clocks, *earlycon_power_domains; +extern int earlycon_clocks_ncells, earlycon_power_domains_ncells; +#else +#define earlycon_clocks NULL +#define earlycon_clocks_ncells 0 +#define earlycon_power_domains NULL +#define earlycon_power_domains_ncells 0 +#endif + /* Variant of uart_console_registered() when the console_list_lock is held. */ static inline bool uart_console_registered_locked(struct uart_port *port) {
Earlycon relies on the serial port to be initialized by the firmware and/or bootloader. Linux is not aware of any hardware dependencies that must be met to keep the port working, and thus cannot guarantee they stay met, until the full serial driver takes over. E.g. all unused clocks and unused PM Domains are disabled in a late initcall. As this happens after the full serial driver has taken over, the serial port's clock and/or PM Domain are no longer deemed unused, and this is typically not a problem. However, if the serial port's clock or PM Domain is shared with another device, and that other device is runtime-suspended before the full serial driver has probed, the serial port's clock and/or PM Domain will be disabled inadvertently. Any subsequent serial console output will cause a crash or system lock-up. Provide a mechanism to let the clock and/or PM Domain subsystem or drivers handle this, by exporting the clock and PM Domain dependencies for the serial port, as available in the system's device tree. Note that as this is done during early boot-up, the device_node structure pointing to the earlycon console is not yet created, so this has to resort to raw property data. Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> --- drivers/tty/serial/earlycon.c | 14 +++++++++++++- include/linux/serial_core.h | 10 ++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-)