Commit 3181424a authored by Denis Mukhin's avatar Denis Mukhin Committed by Ingo Molnar
Browse files

x86/early_printk: Add support for MMIO-based UARTs



During the bring-up of an x86 board, the kernel was crashing before
reaching the platform's console driver because of a bug in the firmware,
leaving no trace of the boot progress.

The only available method to debug the kernel boot process was via the
platform's MMIO-based UART, as the board lacked an I/O port-based UART,
PCI UART, or functional video output.

Then it turned out that earlyprintk= does not have a knob to configure
the MMIO-mapped UART.

Extend the early printk facility to support platform MMIO-based UARTs
on x86 systems, enabling debugging during the system bring-up phase.

The command line syntax to enable platform MMIO-based UART is:

  earlyprintk=mmio,membase[,{nocfg|baudrate}][,keep]

Note, the change does not integrate MMIO-based UART support to:

  arch/x86/boot/early_serial_console.c

Also, update kernel parameters documentation with the new syntax and
add the missing 'nocfg' setting to the PCI serial cards description.

Signed-off-by: default avatarDenis Mukhin <dmukhin@ford.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20250324-earlyprintk-v3-1-aee7421dc469@ford.com
parent 2c118f50
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -1407,14 +1407,21 @@
			earlyprintk=serial[,0x...[,baudrate]]
			earlyprintk=ttySn[,baudrate]
			earlyprintk=dbgp[debugController#]
			earlyprintk=pciserial[,force],bus:device.function[,baudrate]
			earlyprintk=pciserial[,force],bus:device.function[,{nocfg|baudrate}]
			earlyprintk=xdbc[xhciController#]
			earlyprintk=bios
			earlyprintk=mmio,membase[,{nocfg|baudrate}]

			earlyprintk is useful when the kernel crashes before
			the normal console is initialized. It is not enabled by
			default because it has some cosmetic problems.

			Only 32-bit memory addresses are supported for "mmio"
			and "pciserial" devices.

			Use "nocfg" to skip UART configuration, assume
			BIOS/firmware has configured UART correctly.

			Append ",keep" to not disable it when the real console
			takes over.

+44 −1
Original line number Diff line number Diff line
@@ -190,7 +190,6 @@ static __init void early_serial_init(char *s)
	early_serial_hw_init(divisor);
}

#ifdef CONFIG_PCI
static __noendbr void mem32_serial_out(unsigned long addr, int offset, int value)
{
	u32 __iomem *vaddr = (u32 __iomem *)addr;
@@ -207,6 +206,45 @@ static __noendbr unsigned int mem32_serial_in(unsigned long addr, int offset)
}
ANNOTATE_NOENDBR_SYM(mem32_serial_in);

/*
 * early_mmio_serial_init() - Initialize MMIO-based early serial console.
 * @s: MMIO-based serial specification.
 */
static __init void early_mmio_serial_init(char *s)
{
	unsigned long baudrate;
	unsigned long membase;
	char *e;

	if (*s == ',')
		s++;

	if (!strncmp(s, "0x", 2)) {
		/* NB: only 32-bit addresses are supported. */
		membase = simple_strtoul(s, &e, 16);
		early_serial_base = (unsigned long)early_ioremap(membase, PAGE_SIZE);

		static_call_update(serial_in, mem32_serial_in);
		static_call_update(serial_out, mem32_serial_out);

		s += strcspn(s, ",");
		if (*s == ',')
			s++;
	}

	if (!strncmp(s, "nocfg", 5)) {
		baudrate = 0;
	} else {
		baudrate = simple_strtoul(s, &e, 0);
		if (baudrate == 0 || s == e)
			baudrate = DEFAULT_BAUD;
	}

	if (baudrate)
		early_serial_hw_init(115200 / baudrate);
}

#ifdef CONFIG_PCI
/*
 * early_pci_serial_init()
 *
@@ -351,6 +389,11 @@ static int __init setup_early_printk(char *buf)
	keep = (strstr(buf, "keep") != NULL);

	while (*buf != '\0') {
		if (!strncmp(buf, "mmio", 4)) {
			early_mmio_serial_init(buf + 4);
			early_console_register(&early_serial_console, keep);
			buf += 4;
		}
		if (!strncmp(buf, "serial", 6)) {
			buf += 6;
			early_serial_init(buf);