mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: Denis Mukhin <dmukhin@ford.com> Signed-off-by: Ingo Molnar <mingo@kernel.org> Link: https://lore.kernel.org/r/20250324-earlyprintk-v3-1-aee7421dc469@ford.com
This commit is contained in:
parent
2c118f50d7
commit
3181424aea
2 changed files with 52 additions and 2 deletions
|
@ -1407,14 +1407,21 @@
|
||||||
earlyprintk=serial[,0x...[,baudrate]]
|
earlyprintk=serial[,0x...[,baudrate]]
|
||||||
earlyprintk=ttySn[,baudrate]
|
earlyprintk=ttySn[,baudrate]
|
||||||
earlyprintk=dbgp[debugController#]
|
earlyprintk=dbgp[debugController#]
|
||||||
earlyprintk=pciserial[,force],bus:device.function[,baudrate]
|
earlyprintk=pciserial[,force],bus:device.function[,{nocfg|baudrate}]
|
||||||
earlyprintk=xdbc[xhciController#]
|
earlyprintk=xdbc[xhciController#]
|
||||||
earlyprintk=bios
|
earlyprintk=bios
|
||||||
|
earlyprintk=mmio,membase[,{nocfg|baudrate}]
|
||||||
|
|
||||||
earlyprintk is useful when the kernel crashes before
|
earlyprintk is useful when the kernel crashes before
|
||||||
the normal console is initialized. It is not enabled by
|
the normal console is initialized. It is not enabled by
|
||||||
default because it has some cosmetic problems.
|
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
|
Append ",keep" to not disable it when the real console
|
||||||
takes over.
|
takes over.
|
||||||
|
|
||||||
|
|
|
@ -190,7 +190,6 @@ static __init void early_serial_init(char *s)
|
||||||
early_serial_hw_init(divisor);
|
early_serial_hw_init(divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PCI
|
|
||||||
static __noendbr void mem32_serial_out(unsigned long addr, int offset, int value)
|
static __noendbr void mem32_serial_out(unsigned long addr, int offset, int value)
|
||||||
{
|
{
|
||||||
u32 __iomem *vaddr = (u32 __iomem *)addr;
|
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);
|
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()
|
* early_pci_serial_init()
|
||||||
*
|
*
|
||||||
|
@ -351,6 +389,11 @@ static int __init setup_early_printk(char *buf)
|
||||||
keep = (strstr(buf, "keep") != NULL);
|
keep = (strstr(buf, "keep") != NULL);
|
||||||
|
|
||||||
while (*buf != '\0') {
|
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)) {
|
if (!strncmp(buf, "serial", 6)) {
|
||||||
buf += 6;
|
buf += 6;
|
||||||
early_serial_init(buf);
|
early_serial_init(buf);
|
||||||
|
|
Loading…
Add table
Reference in a new issue