On 03/03/2017 18:46, Russell King - ARM Linux wrote: > On Fri, Mar 03, 2017 at 06:26:28PM +0100, Andreas Färber wrote: > >> Am 03.03.2017 um 17:55 schrieb Russell King - ARM Linux: >> >>> On Fri, Mar 03, 2017 at 05:42:02PM +0100, Marc Gonzalez wrote: >>> >>>> I'm confused about early consoles and earlyprintk, and all that good stuff. >>>> When my kernel panics, I don't get the expected output. >>>> >>>> Using "mem=256M ignore_loglevel earlyprintk" >>>> >>>> [ 0.014325] Console: colour dummy device 80x30 >>>> [ 0.018885] console [tty0] enabled >>>> [ 0.022396] bootconsole [earlycon0] disabled >>>> >>>> And it hangs there. >>> >>> tty0 is the kernel virtual terminal console, which is what appears on >>> VGA or framebuffers. This is the default console if nothing else is >>> specified. >>> >>> What happened here is that the virtual terminal console registered, was >>> detected to be the system console, so early console was shut down, and >>> the boot messages logged to the virtual terminal console instead. >> >> Why does passing console= make a difference though? >> >> I expect stdout-path to have the same effect as the command line, and I >> am pretty sure that that was previous behavior in, e.g., v4.4. >> >> Note that I am using earlycon, as opposed to earlyprintk above. > > The property is: > > stdout-path = "dt-node-name:hw-parameters"; > > and this is parsed by the code in drivers/of/fdt.c, > early_init_dt_scan_chosen_stdout() (briefly): > > offset = fdt_path_offset(fdt, "/chosen"); > p = fdt_getprop(fdt, offset, "stdout-path", &l); > > q = strchrnul(p, ':'); > if (*q != '\0') > options = q + 1; > l = q - p; > > /* Get the node specified by stdout-path */ > offset = fdt_path_offset_namelen(fdt, p, l); > if (offset < 0) { > pr_warn("earlycon: stdout-path %.*s not found\n", l, p); > > So here, offset points at the node named by "dt-node-name" above. > > This function then tries to patch the specified node's compatible with > the drivers in the __earlycon_table: > > for (match = __earlycon_table; match < __earlycon_table_end; match++) { > if (!match->compatible[0]) > continue; > > if (fdt_node_check_compatible(fdt, offset, match->compatible)) > continue; > > and when a match is found, calls: > > of_setup_earlycon(match, offset, options); > > Here, we go into the code in drivers/tty/serial/earlycon.c, which reads > the standard properties (like "reg", etc) filling out a uart_port > before calling the early console's ->setup method. If everything goes > to plan, register_console() is called to register the early console. > > So there's nothing there which changes the default system console. > > The next place is of_alias_scan() in drivers/of/base.c. This records > the device_node and options in of_stdout and of_stdout_options > respectively - it, again, does not change the default system console. > > When a serial console is initialised, of_console_check() gets called by > serial core to check whether the DT node for it is "of_stdout", and if > it matches, it modifies the preferred system console. > > This all looks good, and one might expect that it has the desired > effect, but this code is fatally flawed in design: the point at which > of_console_check() gets called is _way_ after consoles like the virtual > terminal console get initialised. What this means is that, at the point > in time that the virtual terminal is initialised, as far as the console > system is concerned, the preferred console is still the virtual terminal. > It knows nothing about the desire for a different console. > > Given the current console handling, it's not easy to solve without > overhauling the way consoles are chosen - the root problem is that the > Linux console system works via Linux device driver names and indexes, > and there's no easy way to translate a DT stdout-path property to a > Linux device driver name and index without the driver having been > initialised. Time for me to take another stab at this issue. Relevant parts of my DT: aliases { serial = &uart; }; chosen { stdout-path = "serial:115200n8"; }; uart: serial@10700 { compatible = "ralink,rt2880-uart"; reg = <0x10700 0x30>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH>; clock-frequency = <7372800>; reg-shift = <2>; }; Relevant part of my kernel config: CONFIG_FIX_EARLYCON_MEM=y CONFIG_GENERIC_EARLY_IOREMAP=y CONFIG_OF_EARLY_FLATTREE=y # # Character devices # CONFIG_TTY=y CONFIG_VT=y CONFIG_CONSOLE_TRANSLATIONS=y CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y # CONFIG_VT_HW_CONSOLE_BINDING is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_SERIAL_NONSTANDARD is not set # # Serial drivers # CONFIG_SERIAL_EARLYCON=y CONFIG_SERIAL_8250=y # CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set # CONFIG_SERIAL_8250_FINTEK is not set CONFIG_SERIAL_8250_CONSOLE=y CONFIG_SERIAL_8250_DMA=y CONFIG_SERIAL_8250_PCI=y CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_8250_RUNTIME_UARTS=4 # CONFIG_SERIAL_8250_EXTENDED is not set CONFIG_SERIAL_8250_FSL=y # CONFIG_SERIAL_8250_DW is not set # CONFIG_SERIAL_8250_EM is not set CONFIG_SERIAL_8250_RT288X=y # CONFIG_SERIAL_8250_MOXA is not set CONFIG_SERIAL_OF_PLATFORM=y # # Non-8250 serial port support # # CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST is not set # CONFIG_SERIAL_UARTLITE is not set CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_JSM is not set # CONFIG_SERIAL_SCCNXP is not set # CONFIG_SERIAL_SC16IS7XX is not set # CONFIG_SERIAL_BCM63XX is not set # CONFIG_SERIAL_ALTERA_JTAGUART is not set # CONFIG_SERIAL_ALTERA_UART is not set # CONFIG_SERIAL_XILINX_PS_UART is not set # CONFIG_SERIAL_ARC is not set # CONFIG_SERIAL_RP2 is not set # CONFIG_SERIAL_FSL_LPUART is not set # CONFIG_SERIAL_CONEXANT_DIGICOLOR is not set # CONFIG_SERIAL_ST_ASC is not set # CONFIG_SERIAL_STM32 is not set # CONFIG_HVC_DCC is not set # CONFIG_IPMI_HANDLER is not set # CONFIG_HW_RANDOM is not set # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y # CONFIG_XILLYBUS is not set CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" # CONFIG_DEBUG_UART_8250 is not set CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h" Booting with mem=256M console=ttyS0,115200 [ 0.000213] Console: colour dummy device 80x30 [ 0.418383] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled [ 0.419837] console [ttyS0] disabled [ 0.419983] 10700.serial: ttyS0 at MMIO 0x10700 (irq = 20, base_baud = 460800) is a Palmchip BK-3103 [ 1.000504] console [ttyS0] enabled Booting with mem=256M [ 0.000212] Console: colour dummy device 80x30 [ 0.000547] console [tty0] enabled [ 0.427260] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled [ 0.428970] 10700.serial: ttyS0 at MMIO 0x10700 (irq = 20, base_baud = 460800) is a Palmchip BK-3103 [ 1.007672] console [ttyS0] enabled Booting with mem=256M earlycon [ 0.000000] ENTER param_setup_earlycon [ 0.000000] ENTER early_init_dt_scan_chosen_stdout [ 0.000000] early_init_dt_scan_chosen_stdout: scan __earlycon_table [ 0.000000] name=uart compatible=snps,dw-apb-uart setup=early_serial8250_setup [ 0.000000] name=uart compatible=nvidia,tegra20-uart setup=early_serial8250_setup [ 0.000000] name=ns16550a compatible=ns16550a setup=early_serial8250_setup [ 0.000000] name=ns16550 compatible=ns16550 setup=early_serial8250_setup [ 0.000000] early_init_dt_scan_chosen_stdout: NO MATCH, return ENODEV [ 0.000000] Malformed early option 'earlycon' [ 0.000215] Console: colour dummy device 80x30 [ 0.000583] console [tty0] enabled [ 0.420043] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled [ 0.421945] 10700.serial: ttyS0 at MMIO 0x10700 (irq = 20, base_baud = 460800) is a Palmchip BK-3103 [ 1.014251] console [ttyS0] enabled drivers/tty/serial/8250/8250_early.c int __init early_serial8250_setup(struct earlycon_device *device, const char *options) EARLYCON_DECLARE(uart8250, early_serial8250_setup); EARLYCON_DECLARE(uart, early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup); OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup); I'm not matching anything, because my UART compatible string is: uart: serial@10700 { compatible = "ralink,rt2880-uart"; If I append "ns16550a" or "ns16550", the kernel hangs from the start: Starting kernel ... @ But if I add DEBUG_LL support with CONFIG_DEBUG_LL=y CONFIG_DEBUG_LL_UART_8250=y CONFIG_DEBUG_UART_PHYS=0x10700 CONFIG_DEBUG_UART_VIRT=0xf0010700 CONFIG_DEBUG_UART_8250_WORD=y CONFIG_DEBUG_UART_8250_PALMCHIP=y and replace the implementation of vprintk_emit() with a very quick and dirty char buf[400]; extern void printascii(const char *); text_len = vsnprintf(buf, sizeof buf, fmt, args); printascii(buf); return text_len; then the kernel boots correctly, and I see the following relevant logs: ENTER param_setup_earlycon ENTER early_init_dt_scan_chosen_stdout early_init_dt_scan_chosen_stdout: scan __earlycon_table name=uart compatible=snps,dw-apb-uart setup=early_serial8250_setup name=uart compatible=nvidia,tegra20-uart setup=early_serial8250_setup name=ns16550a compatible=ns16550a setup=early_serial8250_setup ENTER of_setup_earlycon earlycon: ns16550a0 at MMIO 0x00010700 (options '115200n8') bootconsole [ns16550a0] enabled Kernel command line: mem=256M earlycon Console: colour dummy device 80x30 console [tty0] enabled bootconsole [ns16550a0] disabled Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled 10700.serial: ttyS0 at MMIO 0x10700 (irq = 20, base_baud = 460800) is a Palmchip BK-3103 console [ttyS0] enabled I think the problem is that my UART (Palmchip BK-3103) requires custom accessors to read/write 16550 registers. And these accessors are probably ignored this early in the boot. drivers/tty/serial/8250/8250_port.c #ifdef CONFIG_SERIAL_8250_RT288X /* Au1x00/RT288x UART hardware has a weird register layout */ static const s8 au_io_in_map[8] = { 0, /* UART_RX */ 2, /* UART_IER */ 3, /* UART_IIR */ 5, /* UART_LCR */ 6, /* UART_MCR */ 7, /* UART_LSR */ 8, /* UART_MSR */ -1, /* UART_SCR (unmapped) */ }; It is likely that I need to register a specific OF_EARLYCON_DECLARE, like OMAP did? Regards. -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html