Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

serial: earlycon: prefer EARLYCON_DECLARE() variant

If a driver exposes early consoles with EARLYCON_DECLARE() and
OF_EARLYCON_DECLARE(), pefer the non-OF variant if the user specifies it
by
earlycon=<driver>,<options>

The rationale behind this is that some drivers register multiple setup
functions under the same driver name. Eg.

OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup);
OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup);
OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup);
EARLYCON_DECLARE(lpuart, lpuart_early_console_setup);
EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup);

It depends on the order of the entries which console_setup() actually
gets called. To make things worse, I guess it also depends on the
compiler how these are ordered. Thus always prefer the EARLYCON_DECLARE()
ones.

Signed-off-by: Michael Walle <michael@walle.cc>
Link: https://lore.kernel.org/r/20200220174607.24285-1-michael@walle.cc
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Michael Walle and committed by
Greg Kroah-Hartman
f8c3686c 4f5f5887

+11
+11
drivers/tty/serial/earlycon.c
··· 170 170 int __init setup_earlycon(char *buf) 171 171 { 172 172 const struct earlycon_id **p_match; 173 + bool empty_compatible = true; 173 174 174 175 if (!buf || !buf[0]) 175 176 return -EINVAL; ··· 178 177 if (early_con.flags & CON_ENABLED) 179 178 return -EALREADY; 180 179 180 + again: 181 181 for (p_match = __earlycon_table; p_match < __earlycon_table_end; 182 182 p_match++) { 183 183 const struct earlycon_id *match = *p_match; 184 184 size_t len = strlen(match->name); 185 185 186 186 if (strncmp(buf, match->name, len)) 187 + continue; 188 + 189 + /* prefer entries with empty compatible */ 190 + if (empty_compatible && *match->compatible) 187 191 continue; 188 192 189 193 if (buf[len]) { ··· 199 193 buf = NULL; 200 194 201 195 return register_earlycon(buf, match); 196 + } 197 + 198 + if (empty_compatible) { 199 + empty_compatible = false; 200 + goto again; 202 201 } 203 202 204 203 return -ENOENT;