From: Jason Wessel <jason.wessel@xxxxxxxxxxxxx> This patch some small hooks into the normal serial core so that a uart can be unregistered to be exclusively used for KGDB. These changes allow for registering and unregistering a port with a struct uart_port. From that point on KGDB does raw accesses to the serial IO ports it has taken over. CC: linux-serial@xxxxxxxxxxxxxxx Signed-off-by: Jason Wessel <jason.wessel@xxxxxxxxxxxxx> Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxx> Signed-off-by: Ingo Molnar <mingo@xxxxxxx> Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> --- Documentation/DocBook/kgdb.tmpl | 44 ++++ drivers/serial/8250.c | 30 +++ drivers/serial/8250_kgdb.c | 489 +++++++++++++++++++++++++++++++++++++++ drivers/serial/Kconfig | 2 +- drivers/serial/Makefile | 1 + drivers/serial/serial_core.c | 18 ++- include/linux/serial_8250.h | 2 + lib/Kconfig.kgdb | 21 ++ 8 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 drivers/serial/8250_kgdb.c diff --git a/Documentation/DocBook/kgdb.tmpl b/Documentation/DocBook/kgdb.tmpl index c423411..111a2a0 100644 --- a/Documentation/DocBook/kgdb.tmpl +++ b/Documentation/DocBook/kgdb.tmpl @@ -92,6 +92,50 @@ <chapter id="BootingTheKernel"> <title>Booting the kernel</title> <para> + The Kernel command line option <constant>kgdbwait</constant> makes kgdb + wait for gdb connection during booting of a kernel. If the + <symbol>CONFIG_KGDB_8250</symbol> driver is used (or if applicable, + another serial driver) this breakpoint will happen very early on, before + console output. + </para> + <para> + The serial port configuration must be passed via the + option <constant>kgdb8250=<io|mmio>,<address>[/<regshift>],<baud + rate>,<irq></constant>. The values <constant>io</constant> or + <constant>mmio</constant> refer to if the address being passed next needs + to be memory mapped (<constant>mmio</constant>) or not. The + <constant>address</constant> must be passed in hex and is the hardware + address and will be remapped if passed as <constant>mmio</constant>. An + optional <constant>regshift</constant> value can be given to express + address spreading of the 8250 registers. <constant>regshift</constant> + just as the succeeding <constant>baud rate</constant> and + <constant>irq</constant> values are base-10. The supported values for + <constant>baud rate</constant> are <constant>9600</constant>, + <constant>19200</constant>, <constant>38400</constant>, + <constant>57600</constant>, and <constant>115200</constant>. + </para> + <para> + To specify the values of the serial port at boot: + </para> + <para> + <constant>kgdb8250=io,3f8,115200,3</constant> + </para> + <para> + On IA64 this could also be: + </para> + <para> + <constant>kgdb8250=mmio,0xff5e0000,115200,74</constant> + </para> + <para> + If the debugger is not needed early, the alternative configuration format + <constant>kgdb8250=ttyS<n>,<baud rate></constant> can be used. + The required parameters are then obtained from the standard 8250 driver. + Example: + </para> + <para> + <constant>kgdb8250=ttyS0,115200</constant> + </para> + <para> All drivers can be reconfigured at run time, if <symbol>CONFIG_SYSFS</symbol> and <symbol>CONFIG_MODULES</symbol> are enabled, by echo'ing a new config string to diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 77f7a7f..2b37370 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2580,6 +2580,7 @@ int serial8250_find_port(struct uart_port *p) } return -ENODEV; } +EXPORT_SYMBOL_GPL(serial8250_find_port); #define SERIAL8250_CONSOLE &serial8250_console #else @@ -2863,6 +2864,35 @@ void serial8250_unregister_port(int line) } EXPORT_SYMBOL(serial8250_unregister_port); +/** + * serial8250_get_port_def - Get port definition for a specific line + * @port: generic uart_port output for a specific serial line + * @line: specific serial line index + * + * Return 0 if the port existed + * Return -errno on failure + */ +int serial8250_get_port_def(struct uart_port *port, int line) +{ + struct uart_port *port8250 = &serial8250_ports[line].port; + + if (!port8250->iobase && !port8250->membase) + return -ENODEV; + + port->iobase = port8250->iobase; + port->membase = port8250->membase; + port->irq = port8250->irq; + port->uartclk = port8250->uartclk; + port->fifosize = port8250->fifosize; + port->regshift = port8250->regshift; + port->iotype = port8250->iotype; + port->flags = port8250->flags; + port->mapbase = port8250->mapbase; + port->dev = port8250->dev; + return 0; +} +EXPORT_SYMBOL_GPL(serial8250_get_port_def); + static int __init serial8250_init(void) { int ret, i; diff --git a/drivers/serial/8250_kgdb.c b/drivers/serial/8250_kgdb.c new file mode 100644 index 0000000..ef0ebcf --- /dev/null +++ b/drivers/serial/8250_kgdb.c @@ -0,0 +1,489 @@ +/* + * 8250 serial I/O driver for KGDB. + * + * This is a merging of many different drivers, and all of the people have + * had an impact in some form or another: + * + * 2004-2005 (c) MontaVista Software, Inc. + * 2005-2006 (c) Wind River Systems, Inc. + * + * Amit Kale <amitkale@xxxxxxxxxxxxx>, David Grothe <dave@xxxxxxxx>, + * Scott Foehner <sfoehner@xxxxxxxxxxxx>, George Anzinger <george@xxxxxxxxxx>, + * Robert Walsh <rjwalsh@xxxxxxxxxxxx>, wangdi <wangdi@xxxxxxxxxxxxx>, + * San Mehat, Tom Rini <trini@xxxxxxxxxx>, + * Jason Wessel <jason.wessel@xxxxxxxxxxxxx> + * + * Refactoring and cleanup for initial merge: + * 2008 (c) Jan Kiszka <jan.kiszka@xxxxxx> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/kgdb.h> +#include <linux/interrupt.h> +#include <linux/serial_reg.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/ctype.h> +#include <asm/serial.h> /* for BASE_BAUD */ + +MODULE_DESCRIPTION("KGDB driver for the 8250"); +MODULE_LICENSE("GPL"); + +#define KGD8250_MAX_CONFIG_STR 64 +static char config[KGD8250_MAX_CONFIG_STR]; +static struct kparam_string kps = { + .string = config, + .maxlen = KGD8250_MAX_CONFIG_STR, +}; + +static int kgdb8250_baud; +static void *kgdb8250_addr; +static int kgdb8250_irq = -1; +static struct uart_port kgdb8250_port; + +/* UART port we might have stolen from the 8250 driver */ +static int hijacked_line; + +static int late_init_passed; +static int fully_initialized; +static int buffered_char = -1; + +static struct kgdb_io kgdb8250_io_ops; /* initialized later */ + +static int kgdb8250_uart_init(void); + +static inline unsigned int kgdb8250_ioread(u8 mask) +{ + return ioread8(kgdb8250_addr + (mask << kgdb8250_port.regshift)); +} + +static inline void kgdb8250_iowrite(u8 val, u8 mask) +{ + iowrite8(val, kgdb8250_addr + (mask << kgdb8250_port.regshift)); +} + +/* + * Wait until the interface can accept a char, then write it. + */ +static void kgdb8250_put_debug_char(u8 chr) +{ + while (!(kgdb8250_ioread(UART_LSR) & UART_LSR_THRE)) + cpu_relax(); + + kgdb8250_iowrite(chr, UART_TX); +} + +/* + * Get a byte from the hardware data buffer and return it. + */ +static int kgdb8250_get_debug_char(void) +{ + unsigned int lsr; + + while (1) { + /* Did the interrupt handler catch something before us? */ + if (buffered_char >= 0) + return xchg(&buffered_char, -1); + + lsr = kgdb8250_ioread(UART_LSR); + if (lsr & UART_LSR_DR) + return kgdb8250_ioread(UART_RX); + + /* + * If we have a framing error assume somebody messed with + * our uart. Reprogram it and send '-' both ways... + */ + if (lsr & (UART_LSR_PE | UART_LSR_FE)) { + kgdb8250_uart_init(); + kgdb8250_put_debug_char('-'); + return '-'; + } + + cpu_relax(); + } +} + +/* + * This is the receiver interrupt routine for the GDB stub. + * All that we need to do is verify that the interrupt happened on the + * line we're in charge of. If this is true, schedule a breakpoint and + * return. + */ +static irqreturn_t kgdb8250_interrupt(int irq, void *dev_id) +{ + unsigned int iir = kgdb8250_ioread(UART_IIR); + char c; + + if (iir & UART_IIR_NO_INT) + return IRQ_NONE; + + if ((iir & UART_IIR_ID) == UART_IIR_RDI) { + c = kgdb8250_ioread(UART_RX); + if (c != 0x03) + buffered_char = c; + if (c == 0x03 || !kgdb_connected) + breakpoint(); + } + return IRQ_HANDLED; +} + +/* + * Initializes the UART. + * Returns: + * 0 on success, -errno on failure. + */ +static int kgdb8250_uart_init(void) +{ + unsigned int ier; + unsigned int base_baud = kgdb8250_port.uartclk ? + kgdb8250_port.uartclk / 16 : BASE_BAUD; + + /* Test UART existance. */ + if (kgdb8250_ioread(UART_LSR) == 0xff) + return -EIO; + + /* Disable interrupts. */ + kgdb8250_iowrite(0, UART_IER); + +#ifdef CONFIG_ARCH_OMAP1510 + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (cpu_is_omap1510() && is_omap_port((void *)kgdb8250_addr)) { + if (kgdb8250_baud == 115200) { + base_baud = 1; + kgdb8250_baud = 1; + kgdb8250_iowrite(1, UART_OMAP_OSC_12M_SEL); + } else + kgdb8250_iowrite(0, UART_OMAP_OSC_12M_SEL); + } +#endif + + /* Line settings 8n1, no FIFO, DTR+RTS on. */ + kgdb8250_iowrite(UART_LCR_WLEN8, UART_LCR); + kgdb8250_iowrite(0, UART_FCR); + kgdb8250_iowrite(UART_MCR_OUT2 | UART_MCR_DTR | + UART_MCR_RTS, UART_MCR); + + /* Set baud rate. */ + kgdb8250_iowrite(UART_LCR_WLEN8 | UART_LCR_DLAB, UART_LCR); + kgdb8250_iowrite((base_baud / kgdb8250_baud) & 0xff, UART_DLL); + kgdb8250_iowrite((base_baud / kgdb8250_baud) >> 8, UART_DLM); + kgdb8250_iowrite(UART_LCR_WLEN8, UART_LCR); + + /* Clear pending interrupts. */ + (void) kgdb8250_ioread(UART_IIR); + (void) kgdb8250_ioread(UART_RX); + (void) kgdb8250_ioread(UART_LSR); + (void) kgdb8250_ioread(UART_MSR); + + /* + * Borrowed from the main 8250 driver. + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's + * internal UARTs. + * We're going to explicitly set the UUE bit to 0 before + * trying to write and read a 1 just to make sure it's not + * already a 1 and maybe locked there before we even start start. + */ + ier = kgdb8250_ioread(UART_IER); + kgdb8250_iowrite(ier & ~UART_IER_UUE, UART_IER); + if (!(kgdb8250_ioread(UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ + kgdb8250_iowrite(ier | UART_IER_UUE, UART_IER); + if (kgdb8250_ioread(UART_IER) & UART_IER_UUE) + /* It's an Xscale. */ + ier |= UART_IER_UUE | UART_IER_RTOIE; + } + kgdb8250_iowrite(ier, UART_IER); + + return 0; +} + +/* + * Syntax for this cmdline option is: + * <io|mmio>,<address>[/<regshift>],<baud rate>,<irq> or + * ttyS<n>,<baud rate> + */ +static int kgdb8250_parse_config(char *str) +{ + int line, err; + + /* Save the option string in case we fail and can retry later. */ + strncpy(config, str, KGD8250_MAX_CONFIG_STR-1); + + /* Empty config or leading white space (like LF) means "disabled" */ + if (!strlen(config) || isspace(config[0])) + return 0; + + if (!strncmp(str, "io", 2)) { + kgdb8250_port.iotype = UPIO_PORT; + str += 2; + } else if (!strncmp(str, "mmio", 4)) { + kgdb8250_port.iotype = UPIO_MEM; + kgdb8250_port.flags = UPF_IOREMAP; + str += 4; + } else if (!strncmp(str, "ttyS", 4)) { + str += 4; + if (*str < '0' || *str > '9') + return -EINVAL; + line = simple_strtoul(str, &str, 10); + if (line >= CONFIG_SERIAL_8250_NR_UARTS) + return -EINVAL; + + err = serial8250_get_port_def(&kgdb8250_port, line); + if (err) { + if (late_init_passed) + return err; + printk(KERN_WARNING "kgdb8250: ttyS%d init delayed, " + "use io/mmio syntax for early init.\n", + line); + return 0; + } + + if (*str != ',') + return -EINVAL; + str++; + + kgdb8250_baud = simple_strtoul(str, &str, 10); + if (!kgdb8250_baud) + return -EINVAL; + + if (*str == ',') + return -EINVAL; + + goto finish; + } else + return -EINVAL; + + if (*str != ',') + return -EINVAL; + str++; + + if (kgdb8250_port.iotype == UPIO_PORT) + kgdb8250_port.iobase = simple_strtoul(str, &str, 16); + else + kgdb8250_port.mapbase = + (unsigned long)simple_strtoul(str, &str, 16); + + if (*str == '/') { + str++; + kgdb8250_port.regshift = simple_strtoul(str, &str, 10); + } + + if (*str != ',') + return -EINVAL; + str++; + + kgdb8250_baud = simple_strtoul(str, &str, 10); + if (!kgdb8250_baud) + return -EINVAL; + + if (*str != ',') + return -EINVAL; + str++; + + kgdb8250_port.irq = simple_strtoul(str, &str, 10); + +finish: + err = kgdb_register_io_module(&kgdb8250_io_ops); + if (err) + kgdb8250_addr = 0; + + return err; +} + +static int kgdb8250_early_init(void) +{ + /* Internal driver setup. */ + switch (kgdb8250_port.iotype) { + case UPIO_MEM: + if (kgdb8250_port.flags & UPF_IOREMAP) + kgdb8250_port.membase = ioremap(kgdb8250_port.mapbase, + 8 << kgdb8250_port.regshift); + kgdb8250_addr = kgdb8250_port.membase; + break; + case UPIO_PORT: + default: + kgdb8250_addr = ioport_map(kgdb8250_port.iobase, + 8 << kgdb8250_port.regshift); + } + if (!kgdb8250_addr) + return -EIO; + + if (kgdb8250_uart_init() < 0) { + printk(KERN_ERR "kgdb8250: UART initialization failed\n"); + return -EIO; + } + + return 0; +} + +static int kgdb8250_late_init(void) +{ + int err; + + if (fully_initialized) + return 0; + + late_init_passed = 1; + + /* + * If we didn't initialize yet or if an earlier attempt failed, + * evaluate the configuration and register with KGDB. + */ + if (!kgdb8250_addr) { + err = kgdb8250_parse_config(config); + if (err || !kgdb8250_addr) + return err; + } + + /* Take the port away from the main driver. */ + hijacked_line = serial8250_find_port(&kgdb8250_port); + if (hijacked_line >= 0) + serial8250_unregister_port(hijacked_line); + + /* Now reinit the port as the above has disabled things. */ + kgdb8250_uart_init(); + + /* Request memory/io regions that we use. */ + if (kgdb8250_port.iotype == UPIO_MEM) { + if (!request_mem_region(kgdb8250_port.mapbase, + 8 << kgdb8250_port.regshift, "kgdb")) + goto rollback; + } else { + if (!request_region(kgdb8250_port.iobase, + 8 << kgdb8250_port.regshift, "kgdb")) + goto rollback; + } + + if (request_irq(kgdb8250_port.irq, kgdb8250_interrupt, IRQF_SHARED, + "kgdb", &kgdb8250_port) == 0) { + /* Turn on RX interrupt only. */ + kgdb8250_iowrite(UART_IER_RDI, UART_IER); + + kgdb8250_irq = kgdb8250_port.irq; + } else { + /* + * The IRQ line is not mandatory for KGDB to provide at least + * basic services. So report the error and continue. + */ + printk(KERN_ERR "kgdb8250: failed to request the IRQ (%d)\n", + kgdb8250_irq); + kgdb8250_irq = -1; + } + + fully_initialized = 1; + return 0; + +rollback: + if (hijacked_line >= 0) + serial8250_register_port(&kgdb8250_port); + + printk(KERN_CRIT "kgdb: Unable to reserve mandatory hardware " + "resources.\n"); + return -EBUSY; +} + +static void kgdb8250_cleanup(void) +{ + void *ioaddr = kgdb8250_addr; + + if (!kgdb8250_addr) + return; + + /* Disable and unregister interrupt. */ + kgdb8250_iowrite(0, UART_IER); + (void) kgdb8250_ioread(UART_RX); + + if (kgdb8250_irq >= 0) + free_irq(kgdb8250_irq, &kgdb8250_port); + + /* Deregister from KGDB core. */ + kgdb_unregister_io_module(&kgdb8250_io_ops); + kgdb8250_addr = 0; + + if (!fully_initialized) + return; + + fully_initialized = 0; + + if (kgdb8250_port.iotype == UPIO_MEM) { + if (kgdb8250_port.flags & UPF_IOREMAP) + iounmap(kgdb8250_port.membase); + release_mem_region(kgdb8250_port.mapbase, + 8 << kgdb8250_port.regshift); + } else { + ioport_unmap(ioaddr); + release_region(kgdb8250_port.iobase, + 8 << kgdb8250_port.regshift); + } + + /* Give the port back to the 8250 driver. */ + if (hijacked_line >= 0) + serial8250_register_port(&kgdb8250_port); +} + +static int kgdb8250_set_config(const char *kmessage, struct kernel_param *kp) +{ + int err; + + if (strlen(kmessage) >= KGD8250_MAX_CONFIG_STR) { + printk(KERN_ERR "%s: config string too long.\n", kp->name); + return -ENOSPC; + } + + if (kgdb_connected) { + printk(KERN_ERR "kgd8250: Cannot reconfigure while KGDB is " + "connected.\n"); + return -EBUSY; + } + + if (kgdb8250_addr) + kgdb8250_cleanup(); + + err = kgdb8250_parse_config((char *)kmessage); + + if (err || !late_init_passed) + return err; + + /* Call the botton-half initialization as we are re-configuring. */ + return kgdb8250_late_init(); +} + +static void kgdb8250_pre_exception_handler(void) +{ + if (!kgdb_connected) + try_module_get(THIS_MODULE); +} + +static void kgdb8250_post_exception_handler(void) +{ + if (!kgdb_connected) + module_put(THIS_MODULE); +} + +static struct kgdb_io kgdb8250_io_ops = { + .name = "kgdb8250", + .read_char = kgdb8250_get_debug_char, + .write_char = kgdb8250_put_debug_char, + .init = kgdb8250_early_init, + .pre_exception = kgdb8250_pre_exception_handler, + .post_exception = kgdb8250_post_exception_handler, +}; + +module_init(kgdb8250_late_init); +module_exit(kgdb8250_cleanup); + +module_param_call(kgdb8250, kgdb8250_set_config, param_get_string, &kps, 0644); +MODULE_PARM_DESC(kgdb8250, "ttyS<n>,<baud rate>"); + +#ifdef CONFIG_KGDB_8250 +early_param("kgdb8250", kgdb8250_parse_config); +#endif diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b82595c..7ef9145 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -121,7 +121,7 @@ config SERIAL_8250_CS config SERIAL_8250_NR_UARTS int "Maximum number of 8250/16550 serial ports" - depends on SERIAL_8250 + depends on SERIAL_8250 || KGDB_8250 default "4" help Set this to the number of serial ports you want the driver diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 640cfe4..6ee1b36 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -66,4 +66,5 @@ obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o +obj-$(CONFIG_KGDB_8250) += 8250_kgdb.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 0f5a179..d333fc4 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -33,6 +33,7 @@ #include <linux/serial.h> /* for serial_state and serial_icounter_struct */ #include <linux/delay.h> #include <linux/mutex.h> +#include <linux/kgdb.h> #include <asm/irq.h> #include <asm/uaccess.h> @@ -58,6 +59,12 @@ static struct lock_class_key port_lock_key; #define uart_console(port) (0) #endif +#ifdef CONFIG_KGDB_CONSOLE +#define uart_kgdb(port) (port->cons && !strcmp(port->cons->name, "kgdb")) +#else +#define uart_kgdb(port) (0) +#endif + static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); @@ -1678,6 +1685,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) mmio ? (unsigned long long)port->mapbase : (unsigned long long) port->iobase, port->irq); + if (port->iotype == UPIO_MEM) + ret += sprintf(buf+ret, " membase 0x%08lX", + (unsigned long) port->membase); if (port->type == PORT_UNKNOWN) { strcat(buf, "\n"); @@ -2111,7 +2121,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) case UPIO_TSI: case UPIO_DWAPB: snprintf(address, sizeof(address), - "MMIO 0x%llx", (unsigned long long)port->mapbase); + "MMIO 0x%llx mem 0x%p", + (unsigned long long)port->mapbase, + port->membase); break; default: strlcpy(address, "*unknown*", sizeof(address)); @@ -2175,9 +2187,9 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state, /* * Power down all ports by default, except the - * console if we have one. + * console (real or kgdb) if we have one. */ - if (!uart_console(port)) + if (!uart_console(port) && !uart_kgdb(port)) uart_change_pm(state, 3); } } diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 00b65c0..fc4bac7 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -58,8 +58,10 @@ struct uart_port; int serial8250_register_port(struct uart_port *); void serial8250_unregister_port(int line); +void serial8250_unregister_by_port(struct uart_port *port); void serial8250_suspend_port(int line); void serial8250_resume_port(int line); +int serial8250_get_port_def(struct uart_port *port, int line); extern int early_serial_setup(struct uart_port *port); diff --git a/lib/Kconfig.kgdb b/lib/Kconfig.kgdb index e6fb7e3..3d5c2f8 100644 --- a/lib/Kconfig.kgdb +++ b/lib/Kconfig.kgdb @@ -30,3 +30,24 @@ config KGDB_CONSOLE comment "KGDB I/O drivers" depends on KGDB + +config KGDB_8250 + tristate "8250/16550 and compatible serial support" + depends on KGDB + select SERIAL_8250 + default y + help + Uses a 8250/16550 compatible serial ports to communicate with the + host GDB. This is independent of the normal driver (SERIAL_8250) + for this chipset. The port is configured via kgdb8250=<config>, + passed as kernel or module parameter, respectively. The + configuration comes in two flavors: + + <io|mmio>,<address>[/<regshift>],<baud rate>,<irq> + or + ttyS<n>,<baud rate> + + When built into the kernel, this driver allows debugging of + the early boot process. Note that, as long as the debugger is + attached via this driver, the configured serial port cannot be + used by the standard 8250 driver or serial earlyprintk/earlycon. -- 1.5.4 - 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