LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [PATCH 1/3] KGDB: Major refactoring
@ 2008-02-05 23:34 Jan Kiszka
  2008-02-05 23:44 ` Maxim Levitsky
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Jan Kiszka @ 2008-02-05 23:34 UTC (permalink / raw)
  To: Jason Wessel, Ingo Molnar
  Cc: Linux Kernel Mailing List, kgdb-bugreport, Thomas Gleixner,
	H. Peter Anvin

As most changes are tightly coupled, this refactoring patch for
KGDB_8250 as well as the core and the new KGDBOC driver comes as a
single chunk. The changes are:
 - Reorganized configuration: I/O drivers can be independently
   configured as module or built-in
 - Dynamic reconfiguration for KGDB_8250 (just like for KGDBOC)
 - Reworked KGDB_8250 configuration string format
 - attachwait removed, arming the debugger via assigning an I/O driver
   implies "attachwait"
 - Cleaned up I/O driver managment of the core
 - Matured the various boot-up, configure, unconfigure code paths for
   both I/O drivers
 - IRQ vs. KGDB_CONSOLE-output SMP race fixed for KGDB_8250
 - Reduced and cleaned up hooks into serial_core/8250
 - Kconfig cleanups

What we no longer have:
 - Simple serial configuration for _early_ debugging, use the io/mem
   format instead or wait until the debugger is able to resolve "ttySx"
   during late-init

To-do:
 - KGDBOC does not yet cleanly interacts with the TTY subsystem to
   attach to some console

Signed-off-by: Jan Kiszka <jan.kiszka@web.de>

---
 drivers/serial/8250.c        |   56 +--
 drivers/serial/8250_kgdb.c   |  731 +++++++++++++++++++------------------------
 drivers/serial/Kconfig       |    3 
 drivers/serial/kgdboc.c      |  118 ++----
 drivers/serial/serial_core.c |    6 
 include/linux/kgdb.h         |   20 -
 kernel/kgdb.c                |  373 +++++----------------
 lib/Kconfig.kgdb             |  153 +--------
 8 files changed, 520 insertions(+), 940 deletions(-)

Index: b/drivers/serial/8250_kgdb.c
===================================================================
--- a/drivers/serial/8250_kgdb.c
+++ b/drivers/serial/8250_kgdb.c
@@ -1,5 +1,5 @@
 /*
- * 8250 interface for kgdb.
+ * 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:
@@ -12,143 +12,100 @@
  * Robert Walsh <rjwalsh@durables.org>, wangdi <wangdi@clusterfs.com>,
  * San Mehat, Tom Rini <trini@mvista.com>,
  * Jason Wessel <jason.wessel@windriver.com>
+ *
+ * Refactoring and cleanup for initial merge:
+ * 2008 (c) Jan Kiszka <jan.kiszka@web.de>
+ *
+ * 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/tty.h>
-#include <linux/serial.h>
 #include <linux/serial_reg.h>
-#include <linux/serialP.h>
 #include <linux/ioport.h>
 #include <linux/io.h>
-#include <asm/serial.h>		/* For BASE_BAUD and SERIAL_PORT_DFNS */
-
-#include "8250.h"
-
-#define GDB_BUF_SIZE	512	/* power of 2, please */
+#include <linux/ctype.h>
+#include <asm/serial.h>		/* for BASE_BAUD */
 
 MODULE_DESCRIPTION("KGDB driver for the 8250");
 MODULE_LICENSE("GPL");
-/* These will conflict with early_param otherwise. */
-#ifdef CONFIG_KGDB_8250_MODULE
-static char config[256];
-module_param_string(kgdb8250, config, 256, 0);
-MODULE_PARM_DESC(kgdb8250,
-		 " kgdb8250=<io or mmio>,<address>,<baud rate>,<irq>\n");
-static struct kgdb_io local_kgdb_io_ops;
-#endif				/* CONFIG_KGDB_8250_MODULE */
-
-#ifdef CONFIG_KGDB_BAUDRATE
-static int kgdb8250_baud = CONFIG_KGDB_BAUDRATE;
-#else
-static int kgdb8250_baud;
-#endif
-#ifdef CONFIG_KGDB_PORT_NUM
-static int kgdb8250_line = CONFIG_KGDB_PORT_NUM;
-#else
-static int kgdb8250_line = -1;
-#endif
-
-/* Flag for if we need to call request_mem_region */
-static int kgdb8250_needs_request_mem_region;
 
-static char kgdb8250_buf[GDB_BUF_SIZE];
-static atomic_t kgdb8250_buf_in_cnt;
-static int kgdb8250_buf_out_inx;
-
-/* Old-style serial definitions, if existant, and a counter. */
-#ifdef CONFIG_KGDB_SIMPLE_SERIAL
-static int __initdata should_copy_rs_table = 1;
-static struct serial_state old_rs_table[] __initdata = {
-#ifdef SERIAL_PORT_DFNS
-	SERIAL_PORT_DFNS
-#endif
+#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,
 };
-#endif
 
-/* Our internal table of UARTS. */
-#define UART_NR	CONFIG_SERIAL_8250_NR_UARTS
-static struct uart_port kgdb8250_ports[UART_NR];
+static int kgdb8250_baud;
+static void *kgdb8250_addr;
+static int kgdb8250_irq = -1;
+static struct uart_port kgdb8250_port;
 
-static struct uart_port *current_port;
+/* UART port we might have stolen from the 8250 driver */
+static int hijacked_line;
 
-/* Base of the UART. */
-static void *kgdb8250_addr;
+static int late_init_passed;
+static int fully_initialized;
+static int buffered_char = -1;
+
+static struct kgdb_io kgdb8250_io_ops;	/* initialized later */
 
-/* Forward declarations. */
 static int kgdb8250_uart_init(void);
-static int __init kgdb_init_io(void);
-static int __init kgdb8250_opt(char *str);
 
-/* These are much shorter calls to ioread8/iowrite8 that take into
- * account our shifts, etc. */
-static inline unsigned int kgdb_ioread(u8 mask)
+static inline unsigned int kgdb8250_ioread(u8 mask)
 {
-	return ioread8(kgdb8250_addr + (mask << current_port->regshift));
+	return ioread8(kgdb8250_addr + (mask << kgdb8250_port.regshift));
 }
 
-static inline void kgdb_iowrite(u8 val, u8 mask)
+static inline void kgdb8250_iowrite(u8 val, u8 mask)
 {
-	iowrite8(val, kgdb8250_addr + (mask << current_port->regshift));
+	iowrite8(val, kgdb8250_addr + (mask << kgdb8250_port.regshift));
 }
 
 /*
  * Wait until the interface can accept a char, then write it.
  */
-static void kgdb_put_debug_char(u8 chr)
+static void kgdb8250_put_debug_char(u8 chr)
 {
-	while (!(kgdb_ioread(UART_LSR) & UART_LSR_THRE)) ;
+	while (!(kgdb8250_ioread(UART_LSR) & UART_LSR_THRE))
+		cpu_relax();
 
-	kgdb_iowrite(chr, UART_TX);
+	kgdb8250_iowrite(chr, UART_TX);
 }
 
 /*
- * Get a byte from the hardware data buffer and return it
+ * Get a byte from the hardware data buffer and return it.
  */
-static int read_data_bfr(void)
+static int kgdb8250_get_debug_char(void)
 {
-	char it = kgdb_ioread(UART_LSR);
+	unsigned int lsr;
 
-	if (it & UART_LSR_DR)
-		return kgdb_ioread(UART_RX);
+	while (1) {
+		/* Did the interrupt handler catch something before us? */
+		if (buffered_char >= 0)
+			return xchg(&buffered_char, -1);
 
-	/*
-	 * If we have a framing error assume somebody messed with
-	 * our uart.  Reprogram it and send '-' both ways...
-	 */
-	if (it & 0xc) {
-		kgdb8250_uart_init();
-		kgdb_put_debug_char('-');
-		return '-';
-	}
+		lsr = kgdb8250_ioread(UART_LSR);
+		if (lsr & UART_LSR_DR)
+			return kgdb8250_ioread(UART_RX);
 
-	return -1;
-}
-
-/*
- * Get a char if available, return -1 if nothing available.
- * Empty the receive buffer first, then look at the interface hardware.
- */
-static int kgdb_get_debug_char(void)
-{
-	int retchr;
+		/*
+		 * 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 '-';
+		}
 
-	/* intr routine has q'd chars */
-	if (atomic_read(&kgdb8250_buf_in_cnt) != 0) {
-		retchr = kgdb8250_buf[kgdb8250_buf_out_inx++];
-		kgdb8250_buf_out_inx &= (GDB_BUF_SIZE - 1);
-		atomic_dec(&kgdb8250_buf_in_cnt);
-		return retchr;
+		cpu_relax();
 	}
-
-	do {
-		retchr = read_data_bfr();
-	} while (retchr < 0);
-
-	return retchr;
 }
 
 /*
@@ -157,77 +114,71 @@ static int kgdb_get_debug_char(void)
  * 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)
+static irqreturn_t kgdb8250_interrupt(int irq, void *dev_id)
 {
-	if (!(kgdb_ioread(UART_IIR) & UART_IIR_RDI))
-		return IRQ_NONE;
+	unsigned int iir = kgdb8250_ioread(UART_IIR);
+	char c;
 
-	/* Throw away the data if another I/O routine is active. */
-	if (kgdb_io_ops.read_char != kgdb_get_debug_char &&
-	    (kgdb_ioread(UART_LSR) & UART_LSR_DR))
-		kgdb_ioread(UART_RX);
-	else
-		breakpoint();
+	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)
+			breakpoint();
+		else
+			buffered_char = c;
+	}
 	return IRQ_HANDLED;
 }
 
 /*
  *  Initializes the UART.
  *  Returns:
- *	0 on success, 1 on failure.
+ *	0 on success, -errno on failure.
  */
 static int kgdb8250_uart_init(void)
 {
 	unsigned int ier;
-	unsigned int base_baud = current_port->uartclk ?
-		current_port->uartclk / 16 : BASE_BAUD;
+	unsigned int base_baud = kgdb8250_port.uartclk ?
+		kgdb8250_port.uartclk / 16 : BASE_BAUD;
 
-	/* test uart existance */
-	if (kgdb_ioread(UART_LSR) == 0xff)
-		return -1;
+	/* Test UART existance. */
+	if (kgdb8250_ioread(UART_LSR) == 0xff)
+		return -EIO;
 
-	/* disable interrupts */
-	kgdb_iowrite(0, UART_IER);
+	/* Disable interrupts. */
+	kgdb8250_iowrite(0, UART_IER);
 
-#if defined(CONFIG_ARCH_OMAP1510)
+#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;
-			kgdb_iowrite(1, UART_OMAP_OSC_12M_SEL);
+			kgdb8250_iowrite(1, UART_OMAP_OSC_12M_SEL);
 		} else
-			kgdb_iowrite(0, UART_OMAP_OSC_12M_SEL);
+			kgdb8250_iowrite(0, UART_OMAP_OSC_12M_SEL);
 	}
 #endif
-	/* set DLAB */
-	kgdb_iowrite(UART_LCR_DLAB, UART_LCR);
 
-	/* set baud */
-	kgdb_iowrite((base_baud / kgdb8250_baud) & 0xff, UART_DLL);
-	kgdb_iowrite((base_baud / kgdb8250_baud) >> 8, UART_DLM);
-
-	/* reset DLAB, set LCR */
-	kgdb_iowrite(UART_LCR_WLEN8, UART_LCR);
-
-	/* set DTR and RTS */
-	kgdb_iowrite(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, UART_MCR);
-
-	/* setup fifo */
-	kgdb_iowrite(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR
-		| UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_8,
-		UART_FCR);
-
-	/* clear pending interrupts */
-	kgdb_ioread(UART_IIR);
-	kgdb_ioread(UART_RX);
-	kgdb_ioread(UART_LSR);
-	kgdb_ioread(UART_MSR);
-
-	/* turn on RX interrupt only */
-	kgdb_iowrite(UART_IER_RDI, UART_IER);
+	/* 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.
@@ -238,344 +189,308 @@ static int kgdb8250_uart_init(void)
 	 * 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 = kgdb_ioread(UART_IER);
-	kgdb_iowrite(ier & ~UART_IER_UUE, UART_IER);
-	if (!(kgdb_ioread(UART_IER) & UART_IER_UUE)) {
+	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.
 		 */
-		kgdb_iowrite(ier | UART_IER_UUE, UART_IER);
-		if (kgdb_ioread(UART_IER) & UART_IER_UUE)
-			/*
-			 * It's an Xscale.
-			 */
+		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;
 	}
-	kgdb_iowrite(ier, UART_IER);
+	kgdb8250_iowrite(ier, UART_IER);
+
 	return 0;
 }
 
 /*
- * Copy the old serial_state table to our uart_port table if we haven't
- * had values specifically configured in.  We need to make sure this only
- * happens once.
+ * Syntax for this cmdline option is:
+ *   <io|mmio|mmap>,<address>[/<regshift>],<baud rate>,<irq> or
+ *   ttyS<n>,<baud rate>
  */
-static void __init kgdb8250_copy_rs_table(void)
+static int kgdb8250_parse_config(char *str)
 {
-#ifdef CONFIG_KGDB_SIMPLE_SERIAL
-	int i;
+	int line, err;
 
-	if (!should_copy_rs_table)
-		return;
+	/* Save the option string in case we fail and can retry later. */
+	strncpy(config, str, KGD8250_MAX_CONFIG_STR-1);
 
-	for (i = 0; i < ARRAY_SIZE(old_rs_table) && i < UART_NR; i++) {
-		if (kgdb8250_ports[i].iobase || kgdb8250_ports[i].irq ||
-			kgdb8250_ports[i].membase)
-			continue;
-		kgdb8250_ports[i].iobase = old_rs_table[i].port;
-		kgdb8250_ports[i].irq = irq_canonicalize(old_rs_table[i].irq);
-		kgdb8250_ports[i].uartclk = old_rs_table[i].baud_base * 16;
-		kgdb8250_ports[i].membase = old_rs_table[i].iomem_base;
-		kgdb8250_ports[i].iotype = old_rs_table[i].io_type;
-		kgdb8250_ports[i].regshift = old_rs_table[i].iomem_reg_shift;
-		kgdb8250_ports[i].line = i;
-	}
+	/* Empty config or leading white space (like LF) means "disabled" */
+	if (!strlen(config) || isspace(config[0]))
+		return 0;
 
-	should_copy_rs_table = 0;
-#endif
-}
+	if (!strncmp(str, "io", 2)) {
+		kgdb8250_port.iotype = UPIO_PORT;
+		str += 2;
+	} else if (!strncmp(str, "mmap", 4)) {
+		kgdb8250_port.iotype = UPIO_MEM;
+		kgdb8250_port.flags |= UPF_IOREMAP;
+		str += 4;
+	} 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;
 
-/*
- * Hookup our IRQ line now that it is safe to do so, after we grab any
- * memory regions we might need to.  If we haven't been initialized yet,
- * go ahead and copy the old_rs_table in.
- */
-static void __init kgdb8250_late_init(void)
-{
-	/* Setup the KGDB uart table if not already initialized */
-	kgdb8250_copy_rs_table();
+		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|mmap syntax for early init.\n",
+			       line);
+			return 0;
+		}
 
-#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
-	/* Take the port away from the main driver. */
-	serial8250_unregister_by_port(current_port);
+		if (*str != ',')
+			return -EINVAL;
+		str++;
 
-	/* Now reinit the port as the above has disabled things. */
-	kgdb8250_uart_init();
-#endif
-	/* We may need to call request_mem_region() first. */
-	if (kgdb8250_needs_request_mem_region)
-		request_mem_region(current_port->mapbase,
-				   8 << current_port->regshift, "kgdb");
-	if (request_irq(current_port->irq, kgdb8250_interrupt, IRQF_SHARED,
-			"GDB-stub", current_port) < 0)
-		printk(KERN_ERR "KGDB failed to request the serial IRQ (%d)\n",
-		       current_port->irq);
-}
-
-static __init int kgdb_init_io(void)
-{
-	/* Setup the KGDB uart table if not already initialized */
-	kgdb8250_copy_rs_table();
-
-	/* We're either a module and parse a config string, or we have a
-	 * semi-static config. */
-#ifdef CONFIG_KGDB_8250_MODULE
-	if (strlen(config)) {
-		if (kgdb8250_opt(config))
+		kgdb8250_baud = simple_strtoul(str, &str, 10);
+		if (!kgdb8250_baud)
 			return -EINVAL;
-	} else {
-		printk(KERN_ERR "kgdb8250: argument error, usage: "
-		       "kgdb8250=<io or mmio>,<address>,<baud rate>,<irq>\n");
-		printk(KERN_ERR "kgdb8250: alt usage: "
-		       "kgdb8250=<line #>,<baud rate>\n");
+
+		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 {
+		if (kgdb8250_port.flags & UPF_IOREMAP)
+			kgdb8250_port.mapbase =
+				(unsigned long) simple_strtoul(str, &str, 16);
+		else
+			kgdb8250_port.membase =
+				(void *) simple_strtoul(str, &str, 16);
+	}
+
+	if (*str == '/') {
+		str++;
+		kgdb8250_port.regshift = simple_strtoul(str, &str, 10);
 	}
-#elif defined(CONFIG_KGDB_SIMPLE_SERIAL)
-	if (kgdb8250_line < 0)
+
+	if (*str != ',')
 		return -EINVAL;
-	/* Setup our pointer to the serial port now. */
-	current_port = &kgdb8250_ports[kgdb8250_line];
-	if (!current_port->membase && !current_port->iobase &&
-		!current_port->irq)
-		serial8250_get_port_def(current_port, kgdb8250_line);
-#elif defined(CONFIG_KGDB_8250_CONF_STRING)
-	if (kgdb8250_opt(CONFIG_KGDB_8250_CONF_STRING))
+	str++;
+
+	kgdb8250_baud = simple_strtoul(str, &str, 10);
+	if (!kgdb8250_baud)
 		return -EINVAL;
-#else
+
+	if (*str != ',')
 		return -EINVAL;
-#endif
+	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 (current_port->iotype) {
+	switch (kgdb8250_port.iotype) {
 	case UPIO_MEM:
-		if (current_port->mapbase)
-			kgdb8250_needs_request_mem_region = 1;
-		if (current_port->flags & UPF_IOREMAP) {
-			current_port->membase = ioremap(current_port->mapbase,
-						8 << current_port->regshift);
-			if (!current_port->membase)
-				return -EIO;	/* Failed. */
-		}
-		kgdb8250_addr = current_port->membase;
+		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(current_port->iobase,
-					   8 << current_port->regshift);
-		if (!kgdb8250_addr)
-			return -EIO;	/* Failed. */
+		kgdb8250_addr = ioport_map(kgdb8250_port.iobase,
+					   8 << kgdb8250_port.regshift);
 	}
+	if (!kgdb8250_addr)
+		return -EIO;
 
-	if (kgdb8250_uart_init() == -1) {
-		printk(KERN_ERR "kgdb8250: init failed\n");
+	if (kgdb8250_uart_init() < 0) {
+		printk(KERN_ERR "kgdb8250: UART initialization failed\n");
 		return -EIO;
 	}
-#ifdef CONFIG_KGDB_8250_MODULE
-	/* Attach the kgdb irq. When this is built into the kernel, it
-	 * is called as a part of late_init sequence.
-	 */
-	kgdb8250_late_init();
-	if (kgdb_register_io_module(&local_kgdb_io_ops))
-		return -EINVAL;
-
-	printk(KERN_INFO "kgdb8250: debugging enabled\n");
-#endif				/* CONFIG_KGD_8250_MODULE */
 
 	return 0;
 }
 
-#ifdef CONFIG_KGDB_8250_MODULE
-/* If it is a module the kgdb_io_ops should be a static which
- * is passed to the KGDB I/O initialization
- */
-static void kgdb8250_pre_exception_handler(void);
-static void kgdb8250_post_exception_handler(void);
+static int kgdb8250_late_init(void)
+{
+	int err;
 
-static struct kgdb_io local_kgdb_io_ops = {
-#else				/* ! CONFIG_KGDB_8250_MODULE */
-struct kgdb_io kgdb_io_ops = {
-#endif				/* ! CONFIG_KGD_8250_MODULE */
-	.read_char = kgdb_get_debug_char,
-	.write_char = kgdb_put_debug_char,
-	.init = kgdb_init_io,
-	.late_init = kgdb8250_late_init,
-#ifdef CONFIG_KGDB_8250_MODULE
-	.pre_exception = kgdb8250_pre_exception_handler,
-	.post_exception = kgdb8250_post_exception_handler,
-#endif
-};
+	if (fully_initialized)
+		return 0;
 
-/**
- * 	kgdb8250_add_port - Define a serial port for use with KGDB
- * 	@i: The index of the port being added
- * 	@serial_req: The &struct uart_port describing the port
- *
- * 	On platforms where we must register the serial device
- * 	dynamically, this is the best option if a platform also normally
- * 	calls early_serial_setup().
- */
-void kgdb8250_add_port(int i, struct uart_port *serial_req)
-{
-	if (i >= UART_NR) {
-		printk(KERN_ERR "KGDB dynamic uart registration failed"
-		   "NR_UARTS is too small");
-		return;
+	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;
 	}
 
-	/* Copy the whole thing over. */
-	if (current_port != &kgdb8250_ports[i])
-		memcpy(&kgdb8250_ports[i], serial_req,
-		sizeof(struct uart_port));
-}
+	/* Take the port away from the main driver. */
+	hijacked_line = serial8250_find_port(&kgdb8250_port);
+	if (hijacked_line >= 0)
+		serial8250_unregister_port(hijacked_line);
 
-/**
- * 	kgdb8250_add_platform_port - Define a serial port for use with KGDB
- * 	@i: The index of the port being added
- * 	@p: The &struct plat_serial8250_port describing the port
- *
- * 	On platforms where we must register the serial device
- * 	dynamically, this is the best option if a platform normally
- * 	handles uart setup with an array of &struct plat_serial8250_port.
- */
-void __init kgdb8250_add_platform_port(int i, struct plat_serial8250_port *p)
-{
-	/* Make sure we've got the built-in data before we override. */
-	kgdb8250_copy_rs_table();
+	/* Now reinit the port as the above has disabled things. */
+	kgdb8250_uart_init();
 
-	if (i >= UART_NR) {
-		printk(KERN_ERR "KGDB dynamic uart registration failed"
-		   "NR_UARTS is too small");
-		return;
+	/* Request memory/io regions that we use. */
+	if (kgdb8250_port.flags & UPF_IOREMAP) {
+		if (!request_mem_region(kgdb8250_port.mapbase,
+					8 << kgdb8250_port.regshift, "kgdb"))
+			goto rollback;
+	} else if (kgdb8250_port.iotype == UPIO_PORT) {
+		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;
 	}
 
-	kgdb8250_ports[i].iobase = p->iobase;
-	kgdb8250_ports[i].membase = p->membase;
-	kgdb8250_ports[i].irq = p->irq;
-	kgdb8250_ports[i].uartclk = p->uartclk;
-	kgdb8250_ports[i].regshift = p->regshift;
-	kgdb8250_ports[i].iotype = p->iotype;
-	kgdb8250_ports[i].flags = p->flags;
-	kgdb8250_ports[i].mapbase = p->mapbase;
+	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;
 }
 
-/*
- * Syntax for this cmdline option is:
- * kgdb8250=<io or mmio>,<address>,<baud rate>,<irq>"
- */
-static int __init kgdb8250_opt(char *str)
+static void kgdb8250_cleanup(void)
 {
-	/* We'll fill out and use the first slot. */
-	current_port = &kgdb8250_ports[0];
+	void *ioaddr = kgdb8250_addr;
 
-	if (!strncmp(str, "io", 2)) {
-		current_port->iotype = UPIO_PORT;
-		str += 2;
-	} else if (!strncmp(str, "mmap", 4)) {
-		current_port->iotype = UPIO_MEM;
-		current_port->flags |= UPF_IOREMAP;
-		str += 4;
-	} else if (!strncmp(str, "mmio", 4)) {
-		current_port->iotype = UPIO_MEM;
-		current_port->flags &= ~UPF_IOREMAP;
-		str += 4;
-	} else if (*str >= '0' || *str <= '9') {
-		kgdb8250_line = *str - '0';
-		/* UARTS in the list from 0 -> 9 */
-		if (kgdb8250_line >= UART_NR)
-			goto errout;
-		current_port = &kgdb8250_ports[kgdb8250_line];
-		if (serial8250_get_port_def(current_port, kgdb8250_line))
-			goto errout;
-		str++;
-		if (*str != ',')
-			goto errout;
-		str++;
-		kgdb8250_baud = simple_strtoul(str, &str, 10);
-		if (!kgdb8250_baud)
-			goto errout;
-		if (*str == ',')
-			goto errout;
-		goto finish;
-	} else
-		goto errout;
+	if (!kgdb8250_addr)
+		return;
 
-	if (*str != ',')
-		goto errout;
-	str++;
+	/* 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 (current_port->iotype == UPIO_PORT)
-		current_port->iobase = simple_strtoul(str, &str, 16);
-	else {
-		if (current_port->flags & UPF_IOREMAP)
-			current_port->mapbase =
-				(unsigned long) simple_strtoul(str, &str, 16);
-		else
-			current_port->membase =
-				(void *) simple_strtoul(str, &str, 16);
+	if (!fully_initialized)
+		return;
+
+	fully_initialized = 0;
+
+	if (kgdb8250_port.iotype == UPIO_PORT) {
+		ioport_unmap(ioaddr);
+		release_region(kgdb8250_port.iobase,
+			       8 << kgdb8250_port.regshift);
+	} else if (kgdb8250_port.flags & UPF_IOREMAP) {
+		iounmap(kgdb8250_port.membase);
+		release_mem_region(kgdb8250_port.mapbase,
+				   8 << kgdb8250_port.regshift);
 	}
 
-	if (*str != ',')
-		goto errout;
-	str++;
+	/* Give the port back to the 8250 driver. */
+	if (hijacked_line >= 0)
+		serial8250_register_port(&kgdb8250_port);
+}
 
-	kgdb8250_baud = simple_strtoul(str, &str, 10);
-	if (!kgdb8250_baud)
-		goto errout;
+static int kgdb8250_set_config(const char *kmessage, struct kernel_param *kp)
+{
+	int err;
 
-	if (*str != ',')
-		goto errout;
-	str++;
+	if (strlen(kmessage) >= KGD8250_MAX_CONFIG_STR) {
+		printk(KERN_ERR "%s: config string too long.\n", kp->name);
+		return -ENOSPC;
+	}
 
-	current_port->irq = simple_strtoul(str, &str, 10);
+	if (kgdb_connected) {
+		printk(KERN_ERR "kgd8250: Cannot reconfigure while KGDB is "
+				"connected.\n");
+		return -EBUSY;
+	}
 
-finish:
-#ifdef CONFIG_KGDB_SIMPLE_SERIAL
-	should_copy_rs_table = 0;
-#endif
+	if (kgdb8250_addr)
+		kgdb8250_cleanup();
 
-	return 0;
+	err = kgdb8250_parse_config((char *)kmessage);
+
+	if (err || !late_init_passed)
+		return err;
 
-errout:
-	printk(KERN_ERR "Invalid syntax for option kgdb8250=\n");
-	return 1;
+	/* Call the botton-half initialization as we are re-configuring. */
+	return kgdb8250_late_init();
 }
 
-#ifdef CONFIG_KGDB_8250_MODULE
 static void kgdb8250_pre_exception_handler(void)
 {
-	if (!module_refcount(THIS_MODULE))
+	if (!kgdb_connected)
 		try_module_get(THIS_MODULE);
 }
 
 static void kgdb8250_post_exception_handler(void)
 {
-	if (!kgdb_connected && module_refcount(THIS_MODULE))
+	if (!kgdb_connected)
 		module_put(THIS_MODULE);
 }
 
-static void cleanup_kgdb8250(void)
-{
-	kgdb_unregister_io_module(&local_kgdb_io_ops);
+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,
+};
 
-	/* Clean up the irq and memory */
-	free_irq(current_port->irq, current_port);
+module_init(kgdb8250_late_init);
+module_exit(kgdb8250_cleanup);
 
-	if (kgdb8250_needs_request_mem_region)
-		release_mem_region(current_port->mapbase,
-				   8 << current_port->regshift);
-	/* Hook up the serial port back to what it was previously
-	 * hooked up to.
-	 */
-#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
-	/* Give the port back to the 8250 driver. */
-	serial8250_register_port(current_port);
-#endif
-}
+module_param_call(kgdb8250, kgdb8250_set_config, param_get_string, &kps, 0644);
+MODULE_PARM_DESC(kgdb8250, "ttyS<n>,<baud rate>");
 
-module_init(kgdb_init_io);
-module_exit(cleanup_kgdb8250);
-#else				/* ! CONFIG_KGDB_8250_MODULE */
-early_param("kgdb8250", kgdb8250_opt);
-#endif				/* ! CONFIG_KGDB_8250_MODULE */
+#ifdef CONFIG_KGDB_8250
+early_param("kgdb8250", kgdb8250_parse_config);
+#endif
Index: b/drivers/serial/8250.c
===================================================================
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2639,6 +2639,7 @@ int serial8250_find_port(struct uart_por
 	}
 	return -ENODEV;
 }
+EXPORT_SYMBOL_GPL(serial8250_find_port);
 
 #define SERIAL8250_CONSOLE	&serial8250_console
 #else
@@ -2926,51 +2927,28 @@ EXPORT_SYMBOL(serial8250_unregister_port
  *  @line: specific serial line index
  *
  *  Return 0 if the port existed
- *  Return 1 on failure
+ *  Return -errno on failure
  */
-
 int serial8250_get_port_def(struct uart_port *port, int line)
 {
-	struct uart_8250_port *uart;
+	struct uart_port *port8250 = &serial8250_ports[line].port;
 
-	if (line < 0 || line >= UART_NR)
-		return 1;
-	uart = &serial8250_ports[line];
-	if (uart) {
-		port->iobase = uart->port.iobase;
-		port->membase = uart->port.membase;
-		port->irq = uart->port.irq;
-		port->uartclk = uart->port.uartclk;
-		port->fifosize = uart->port.fifosize;
-		port->regshift = uart->port.regshift;
-		port->iotype = uart->port.iotype;
-		port->flags = uart->port.flags;
-		port->mapbase = uart->port.mapbase;
-		port->dev =	uart->port.dev;
-		return 0;
-	}
-	return 1;
-}
-EXPORT_SYMBOL(serial8250_get_port_def);
-
-/**
- *	serial8250_unregister_by_port - remove a 16x50 serial port
- *	at runtime.
- *	@port: A &struct uart_port that describes the port to remove.
- *
- *	Remove one serial port.  This may not be called from interrupt
- *	context.  We hand the port back to the our control.
- */
-void serial8250_unregister_by_port(struct uart_port *port)
-{
-	struct uart_8250_port *uart;
-
-	uart = serial8250_find_match_or_unused(port);
+	if (!port8250->iobase && !port8250->membase)
+		return -ENODEV;
 
-	if (uart)
-		serial8250_unregister_port(uart->port.line);
+	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(serial8250_unregister_by_port);
+EXPORT_SYMBOL_GPL(serial8250_get_port_def);
 
 static int __init serial8250_init(void)
 {
Index: b/drivers/serial/Kconfig
===================================================================
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -942,6 +942,9 @@ config SERIAL_CORE
 config SERIAL_CORE_CONSOLE
 	bool
 
+config SERIAL_POLL
+	bool
+
 config SERIAL_68328
 	bool "68328 serial support"
 	depends on M68328 || M68EZ328 || M68VZ328
Index: b/drivers/serial/serial_core.c
===================================================================
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2439,12 +2439,6 @@ int uart_add_one_port(struct uart_driver
 	 */
 	port->flags &= ~UPF_DEAD;
 
-#if defined(CONFIG_KGDB_8250)
-	/* Add any 8250-like ports we find later. */
-	if (port->type <= PORT_MAX_8250)
-		kgdb8250_add_port(port->line, port);
-#endif
-
  out:
 	mutex_unlock(&state->mutex);
 	mutex_unlock(&port_mutex);
Index: b/include/linux/kgdb.h
===================================================================
--- a/include/linux/kgdb.h
+++ b/include/linux/kgdb.h
@@ -233,6 +233,7 @@ struct kgdb_arch {
 
 /**
  * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB.
+ * @name: Name of the I/O driver.
  * @read_char: Pointer to a function that will return one char.
  * @write_char: Pointer to a function that will write one char.
  * @flush: Pointer to a function that will flush any pending writes.
@@ -255,25 +256,20 @@ struct kgdb_arch {
  * notified.
  */
 struct kgdb_io {
-	int	(*read_char) (void);
-	void	(*write_char) (u8);
-	void	(*flush) (void);
-	int	(*init) (void);
-	void	(*late_init) (void);
-	void	(*pre_exception) (void);
-	void	(*post_exception) (void);
+	const char	*name;
+	int		(*read_char) (void);
+	void		(*write_char) (u8);
+	void		(*flush) (void);
+	int		(*init) (void);
+	void		(*pre_exception) (void);
+	void		(*post_exception) (void);
 };
 
-extern struct kgdb_io		kgdb_io_ops;
 extern struct kgdb_arch		arch_kgdb_ops;
 
 int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
 void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
 
-void kgdb8250_add_port(int i, struct uart_port *serial_req);
-void __init
-kgdb8250_add_platform_port(int i, struct plat_serial8250_port *serial_req);
-
 int kgdb_hex2long(char **ptr, long *long_val);
 char *kgdb_mem2hex(char *mem, char *buf, int count);
 char *kgdb_hex2mem(char *buf, char *mem, int count);
Index: b/kernel/kgdb.c
===================================================================
--- a/kernel/kgdb.c
+++ b/kernel/kgdb.c
@@ -53,8 +53,7 @@
 #include <asm/atomic.h>
 #include <asm/system.h>
 
-static int __initdata kgdb_internal_init_complete;
-static int __initdata kgdb_break_asap;
+static int kgdb_break_asap;
 
 struct kgdb_state {
 	int			all_cpus_synced;
@@ -89,30 +88,16 @@ int				kgdb_io_module_registered;
 /* Guard for recursive entry */
 static int			exception_level;
 
-#ifdef CONFIG_KGDB_ATTACH_WAIT
-static int			attachwait = 1;
-#else
-static int			attachwait;
-#endif
-
-module_param(attachwait, int, 0644);
-MODULE_PARM_DESC(attachwait, "Wait for remote debugger after an exception");
-
-/* We provide a kgdb_io_ops structure that may be overriden. */
-struct kgdb_io __weak		kgdb_io_ops;
-EXPORT_SYMBOL_GPL(kgdb_io_ops);
-
-static struct kgdb_io		kgdb_io_ops_prev[KGDB_MAX_IO_HANDLERS];
-
-static int			kgdb_io_handler_cnt;
+static struct kgdb_io		*kgdb_io_ops;
+static DEFINE_SPINLOCK(kgdb_registration_lock);
 
 /*
  * Holds information about breakpoints in a kernel. These breakpoints are
  * added and removed by gdb.
  */
-struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS];
-
-struct kgdb_arch		*kgdb_ops = &arch_kgdb_ops;
+struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS] = {
+	[0 ... KGDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED }
+};
 
 /*
  * KGDB locking is really nasty at places - but we really can only
@@ -126,7 +111,9 @@ struct kgdb_arch		*kgdb_ops = &arch_kgdb
 #define ROUNDUP_WAIT		640000	/* Arbitrary, increase if needed. */
 #define BUF_THREAD_ID_SIZE	16
 
-static spinlock_t		slave_cpu_locks[NR_CPUS];
+static spinlock_t		slave_cpu_locks[NR_CPUS] = {
+	[0 ... NR_CPUS-1] = __SPIN_LOCK_UNLOCKED(slave_cpu_locks)
+};
 static atomic_t			cpu_in_debugger[NR_CPUS];
 atomic_t			kgdb_setting_breakpoint;
 
@@ -185,7 +172,7 @@ int __weak kgdb_arch_set_breakpoint(unsi
 	if (kgdb_get_mem((char *)addr, saved_instr, BREAK_INSTR_SIZE) != 0)
 		return -1;
 
-	if (kgdb_set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
+	if (kgdb_set_mem((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
 						BREAK_INSTR_SIZE) != 0)
 		return -1;
 	return 0;
@@ -228,14 +215,12 @@ static void get_packet(char *buffer)
 	int count;
 	char ch;
 
-	if (!kgdb_io_ops.read_char)
-		return;
 	do {
 		/*
 		 * Spin and wait around for the start character, ignore all
 		 * other characters:
 		 */
-		while ((ch = (kgdb_io_ops.read_char())) != '$')
+		while ((ch = (kgdb_io_ops->read_char())) != '$')
 			/* nothing */;
 
 		kgdb_connected = 1;
@@ -248,7 +233,7 @@ static void get_packet(char *buffer)
 		 * now, read until a # or end of buffer is found:
 		 */
 		while (count < (BUFMAX - 1)) {
-			ch = kgdb_io_ops.read_char();
+			ch = kgdb_io_ops->read_char();
 			if (ch == '#')
 				break;
 			checksum = checksum + ch;
@@ -258,17 +243,17 @@ static void get_packet(char *buffer)
 		buffer[count] = 0;
 
 		if (ch == '#') {
-			xmitcsum = hex(kgdb_io_ops.read_char()) << 4;
-			xmitcsum += hex(kgdb_io_ops.read_char());
+			xmitcsum = hex(kgdb_io_ops->read_char()) << 4;
+			xmitcsum += hex(kgdb_io_ops->read_char());
 
 			if (checksum != xmitcsum)
 				/* failed checksum */
-				kgdb_io_ops.write_char('-');
+				kgdb_io_ops->write_char('-');
 			else
 				/* successful transfer */
-				kgdb_io_ops.write_char('+');
-			if (kgdb_io_ops.flush)
-				kgdb_io_ops.flush();
+				kgdb_io_ops->write_char('+');
+			if (kgdb_io_ops->flush)
+				kgdb_io_ops->flush();
 		}
 	} while (checksum != xmitcsum);
 }
@@ -283,34 +268,31 @@ static void put_packet(char *buffer)
 	int count;
 	char ch;
 
-	if (!kgdb_io_ops.write_char)
-		return;
-
 	/*
 	 * $<packet info>#<checksum>.
 	 */
 	while (1) {
-		kgdb_io_ops.write_char('$');
+		kgdb_io_ops->write_char('$');
 		checksum = 0;
 		count = 0;
 
 		while ((ch = buffer[count])) {
-			kgdb_io_ops.write_char(ch);
+			kgdb_io_ops->write_char(ch);
 			checksum += ch;
 			count++;
 		}
 
-		kgdb_io_ops.write_char('#');
-		kgdb_io_ops.write_char(hexchars[checksum >> 4]);
-		kgdb_io_ops.write_char(hexchars[checksum % 16]);
-		if (kgdb_io_ops.flush)
-			kgdb_io_ops.flush();
+		kgdb_io_ops->write_char('#');
+		kgdb_io_ops->write_char(hexchars[checksum >> 4]);
+		kgdb_io_ops->write_char(hexchars[checksum % 16]);
+		if (kgdb_io_ops->flush)
+			kgdb_io_ops->flush();
 
 		/* Now see what we get in reply. */
-		ch = kgdb_io_ops.read_char();
+		ch = kgdb_io_ops->read_char();
 
 		if (ch == 3)
-			ch = kgdb_io_ops.read_char();
+			ch = kgdb_io_ops->read_char();
 
 		/* If we get an ACK, we are done. */
 		if (ch == '+')
@@ -323,9 +305,9 @@ static void put_packet(char *buffer)
 		 * packet.
 		 */
 		if (ch == '$') {
-			kgdb_io_ops.write_char('-');
-			if (kgdb_io_ops.flush)
-				kgdb_io_ops.flush();
+			kgdb_io_ops->write_char('-');
+			if (kgdb_io_ops->flush)
+				kgdb_io_ops->flush();
 			return;
 		}
 	}
@@ -705,10 +687,10 @@ static struct task_struct *getthread(str
 		return current;
 
 	if (num_online_cpus() && (tid >= pid_max + num_online_cpus() +
-							kgdb_ops->shadowth))
+							arch_kgdb_ops.shadowth))
 		return NULL;
 
-	if (kgdb_ops->shadowth && (tid >= pid_max + num_online_cpus())) {
+	if (arch_kgdb_ops.shadowth && (tid >= pid_max + num_online_cpus())) {
 		return kgdb_get_shadow_thread(regs, tid - pid_max -
 					      num_online_cpus());
 	}
@@ -809,8 +791,8 @@ static void kgdb_wait(struct pt_regs *re
 	kgdb_info[cpu].task = NULL;
 
 	/* fix up hardware debug registers on local cpu */
-	if (kgdb_ops->correct_hw_break)
-		kgdb_ops->correct_hw_break();
+	if (arch_kgdb_ops.correct_hw_break)
+		arch_kgdb_ops.correct_hw_break();
 
 	/* Signal the master CPU that we are done: */
 	atomic_set(&cpu_in_debugger[cpu], 0);
@@ -1013,8 +995,8 @@ int remove_all_break(void)
 	}
 
 	/* Clear hardware breakpoints. */
-	if (kgdb_ops->remove_all_hw_break)
-		kgdb_ops->remove_all_hw_break();
+	if (arch_kgdb_ops.remove_all_hw_break)
+		arch_kgdb_ops.remove_all_hw_break();
 
 	return 0;
 }
@@ -1073,14 +1055,12 @@ static void kgdb_msg_write(const char *s
  */
 int kgdb_io_ready(int print_wait)
 {
-	if (!kgdb_io_ops.read_char)
+	if (!kgdb_io_ops)
 		return 0;
 	if (kgdb_connected)
 		return 1;
 	if (atomic_read(&kgdb_setting_breakpoint))
 		return 1;
-	if (!attachwait)
-		return 0;
 	if (print_wait)
 		printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
 	return 1;
@@ -1147,7 +1127,7 @@ static void gdb_cmd_getregs(struct kgdb_
 	 * in __schedule() sleeping, since all other CPUs
 	 * are in kgdb_wait, and thus have debuggerinfo.
 	 */
-	if (kgdb_ops->shadowth &&
+	if (arch_kgdb_ops.shadowth &&
 			ks->kgdb_usethreadid >= pid_max + num_online_cpus()) {
 
 		shadowregs = kgdb_shadow_regs(ks->linux_regs,
@@ -1279,7 +1259,7 @@ static int gdb_cmd_reboot(struct kgdb_st
 /* Handle the 'q' query packets */
 static void gdb_cmd_query(struct kgdb_state *ks)
 {
-	int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
+	int numshadowth = num_online_cpus() + arch_kgdb_ops.shadowth;
 	struct task_struct *thread;
 	unsigned char thref[8];
 	char *ptr;
@@ -1430,7 +1410,7 @@ static void gdb_cmd_break(struct kgdb_st
 	unsigned long length;
 	int error = 0;
 
-	if (kgdb_ops->set_hw_breakpoint && *bpt_type >= '1') {
+	if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') {
 		/* Unsupported */
 		if (*bpt_type > '4')
 			return;
@@ -1444,7 +1424,7 @@ static void gdb_cmd_break(struct kgdb_st
 	 * Test if this is a hardware breakpoint, and
 	 * if we support it:
 	 */
-	if (*bpt_type == '1' && !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
+	if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT))
 		/* Unsupported. */
 		return;
 
@@ -1469,10 +1449,10 @@ static void gdb_cmd_break(struct kgdb_st
 	else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')
 		error = kgdb_remove_sw_break(addr);
 	else if (remcom_in_buffer[0] == 'Z')
-		error = kgdb_ops->set_hw_breakpoint(addr,
+		error = arch_kgdb_ops.set_hw_breakpoint(addr,
 			(int)length, *bpt_type);
 	else if (remcom_in_buffer[0] == 'z')
-		error = kgdb_ops->remove_hw_breakpoint(addr,
+		error = arch_kgdb_ops.remove_hw_breakpoint(addr,
 			(int) length, *bpt_type);
 
 	if (error == 0)
@@ -1486,7 +1466,6 @@ static int gdb_cmd_exception_pass(struct
 {
 	/* C09 == pass exception
 	 * C15 == detach kgdb, pass exception
-	 * C30 == detach kgdb, stop attachwait, pass exception
 	 */
 	if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') {
 
@@ -1501,14 +1480,6 @@ static int gdb_cmd_exception_pass(struct
 		kgdb_connected = 0;
 		return 1;
 
-	} else if (remcom_in_buffer[1] == '3' && remcom_in_buffer[2] == '0') {
-
-		ks->pass_exception = 1;
-		attachwait = 0;
-		remcom_in_buffer[0] = 'D';
-		remove_all_break();
-		kgdb_connected = 0;
-		return 1;
 	} else {
 		error_packet(remcom_out_buffer, -EINVAL);
 		return 0;
@@ -1557,7 +1528,7 @@ static int gdb_serial_stub(struct kgdb_s
 	ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);
 	ks->pass_exception = 0;
 
-	while (kgdb_io_ops.read_char) {
+	while (1) {
 		error = 0;
 
 		/* Clear the out buffer. */
@@ -1713,8 +1684,7 @@ kgdb_handle_exception(int evector, int s
 	struct kgdb_state *ks = &kgdb_var;
 	unsigned long flags;
 	int error = 0;
-	unsigned i;
-	int cpu;
+	int i, cpu;
 
 	ks->cpu			= raw_smp_processor_id();
 	ks->all_cpus_synced	= 0;
@@ -1788,8 +1758,8 @@ acquirelock:
 		goto kgdb_restore;
 
 	/* Call the I/O driver's pre_exception routine */
-	if (kgdb_io_ops.pre_exception)
-		kgdb_io_ops.pre_exception();
+	if (kgdb_io_ops->pre_exception)
+		kgdb_io_ops->pre_exception();
 
 	kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs;
 	kgdb_info[ks->cpu].task = current;
@@ -1847,15 +1817,15 @@ acquirelock:
 	error = gdb_serial_stub(ks);
 
 	/* Call the I/O driver's post_exception routine */
-	if (kgdb_io_ops.post_exception)
-		kgdb_io_ops.post_exception();
+	if (kgdb_io_ops->post_exception)
+		kgdb_io_ops->post_exception();
 
 	kgdb_info[ks->cpu].debuggerinfo = NULL;
 	kgdb_info[ks->cpu].task = NULL;
 	atomic_set(&cpu_in_debugger[ks->cpu], 0);
 
 	if (!debugger_step || !kgdb_contthread) {
-		for (i = 0; i < NR_CPUS; i++)
+		for (i = NR_CPUS-1; i >= 0; i--)
 			spin_unlock(&slave_cpu_locks[i]);
 		/*
 		 * Wait till all the CPUs have quit
@@ -1968,32 +1938,10 @@ static struct console kgdbcons = {
 };
 #endif
 
-/*
- * Initialization that needs to be done in either of our entry points.
- */
-static void __init kgdb_internal_init(void)
-{
-	int i;
-
-	if (kgdb_internal_init_complete)
-		return;
-	/* Initialize our spinlocks. */
-	for (i = 0; i < NR_CPUS; i++)
-		spin_lock_init(&slave_cpu_locks[i]);
-
-	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++)
-		kgdb_break[i].state = BP_UNDEFINED;
-
-	/* Initialize the I/O handles */
-	memset(&kgdb_io_ops_prev, 0, sizeof(kgdb_io_ops_prev));
-
-	kgdb_internal_init_complete = 1;
-}
-
 #ifdef CONFIG_MAGIC_SYSRQ
 static void sysrq_handle_gdb(int key, struct tty_struct *tty)
 {
-	if (!kgdb_io_ops.read_char) {
+	if (!kgdb_io_ops) {
 		printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
 		return;
 	}
@@ -2061,180 +2009,74 @@ static void kgdb_unregister_hooks(void)
 	}
 }
 
-int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops)
+static void kgdb_initial_breakpoint(void)
 {
+	kgdb_break_asap = 0;
 
-	if (!local_kgdb_io_ops->init)
-		return -EINVAL;
-	if (kgdb_connected) {
-		printk(KERN_ERR "kgdb: Cannot load I/O module while KGDB "
-		       "connected.\n");
-		return -EINVAL;
-	}
+	printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
+	breakpoint();
+}
 
-	/* Save the old values so they can be restored */
-	if (kgdb_io_handler_cnt >= KGDB_MAX_IO_HANDLERS) {
-		printk(KERN_ERR "kgdb: No more I/O handles available.\n");
-		return -EINVAL;
-	}
+int kgdb_register_io_module(struct kgdb_io *new_kgdb_io_ops)
+{
+	int err;
 
-	/*
-	 * Check to see if there is an existing driver and if so save its
-	 * values.  Also check to make sure the same driver was not trying
-	 * to re-register.
-	 */
-	if (kgdb_io_ops.read_char != NULL &&
-		kgdb_io_ops.read_char != local_kgdb_io_ops->read_char) {
-		memcpy(&kgdb_io_ops_prev[kgdb_io_handler_cnt],
-		       &kgdb_io_ops, sizeof(struct kgdb_io));
-		kgdb_io_handler_cnt++;
-	}
+	spin_lock(&kgdb_registration_lock);
 
-	/* Initialize the io values for this module */
-	memcpy(&kgdb_io_ops, local_kgdb_io_ops, sizeof(struct kgdb_io));
+	if (kgdb_io_ops) {
+		spin_unlock(&kgdb_registration_lock);
 
-	/* Make the call to register kgdb if is not initialized */
-	kgdb_register_hooks();
+		printk(KERN_ERR "kgdb: Another I/O driver is already "
+				"registered with KGDB.\n");
+		return -EBUSY;
+	}
 
-	return 0;
-}
-EXPORT_SYMBOL_GPL(kgdb_register_io_module);
+	if (new_kgdb_io_ops->init) {
+		err = new_kgdb_io_ops->init();
+		if (err) {
+			spin_unlock(&kgdb_registration_lock);
+			return err;
+		}
+	}
 
-void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops)
-{
-	int i;
+	kgdb_io_ops = new_kgdb_io_ops;
 
-	/*
-	 * Unregister KGDB if there were no other prior io hooks, else
-	 * restore the io hooks.
-	 */
-	if (kgdb_io_handler_cnt > 0 && kgdb_io_ops_prev[0].read_char != NULL) {
-		/*
-		 * First check if the hook that is in use is the one being
-		 * removed:
-		 */
-		if (kgdb_io_ops.read_char == local_kgdb_io_ops->read_char) {
-			/*
-			 * Set 'i' to the value of where the list should be
-			 * shifed:
-			 */
-			i = kgdb_io_handler_cnt - 1;
-			memcpy(&kgdb_io_ops, &kgdb_io_ops_prev[i],
-			       sizeof(struct kgdb_io));
-		} else {
-			/*
-			 * Simple case to remove an entry for an I/O handler
-			 * that is not in use:
-			 */
-			for (i = 0; i < kgdb_io_handler_cnt; i++) {
-				if (kgdb_io_ops_prev[i].read_char ==
-				    local_kgdb_io_ops->read_char)
-					break;
-			}
-		}
+	spin_unlock(&kgdb_registration_lock);
 
-		/*
-		 * Shift all the entries in the handler array so it is
-		 * ordered from oldest to newest.
-		 */
-		kgdb_io_handler_cnt--;
-		for (; i < kgdb_io_handler_cnt; i++) {
-			memcpy(&kgdb_io_ops_prev[i], &kgdb_io_ops_prev[i + 1],
-			       sizeof(struct kgdb_io));
-		}
+	printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",
+	       new_kgdb_io_ops->name);
 
-		/*
-		 * Handle the case if we are on the last element and set it
-		 * to NULL;
-		 */
-		memset(&kgdb_io_ops_prev[kgdb_io_handler_cnt], 0,
-				sizeof(struct kgdb_io));
+	/* Arm KGDB now. */
+	kgdb_register_hooks();
 
-		if (kgdb_connected) {
-			printk(KERN_ERR "kgdb: WARNING: I/O method changed "
-			       "while kgdb was connected state.\n");
-		}
-	} else {
-		/*
-		 * KGDB is no longer able to communicate out, so
-		 * unregister our hooks and reset state:
-		 */
-		kgdb_unregister_hooks();
-		if (kgdb_connected) {
-			printk(KERN_CRIT "kgdb: I/O module was unloaded while "
-					"a debugging session was running.  "
-					"KGDB will be reset.\n");
-			if (remove_all_break() < 0)
-				printk(KERN_CRIT "kgdb: Reset failed.\n");
-			kgdb_connected = 0;
-		}
-		memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io));
-	}
-}
-EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
+	if (kgdb_break_asap)
+		kgdb_initial_breakpoint();
 
-static void __init kgdb_initial_breakpoint(void)
-{
-	printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
-	breakpoint();
+	return 0;
 }
+EXPORT_SYMBOL_GPL(kgdb_register_io_module);
 
-/*
- * This function can be called very early, either via early_param() or
- * an explicit breakpoint() early on.
- */
-static void __init kgdb_early_entry(void)
+void kgdb_unregister_io_module(struct kgdb_io *old_kgdb_io_ops)
 {
-	/*
-	 * Initialize the KGDB I/O module
-	 * For early entry kgdb_io_ops.init must be defined
-	 */
-	if (!kgdb_io_ops.init || kgdb_io_ops.init()) {
-		printk(KERN_INFO "kgdb: Defering I/O setup to late init.\n");
-		return;
-	}
-	kgdb_internal_init();
-	kgdb_register_io_module(&kgdb_io_ops);
-}
+	BUG_ON(kgdb_connected);
 
-/*
- * This function will always be invoked to make sure that KGDB will grab
- * what it needs to so that if something happens while the system is
- * running, KGDB will get involved.  If kgdb_early_entry() has already
- * been invoked, there is little we need to do.
- */
-static int __init kgdb_late_entry(void)
-{
 	/*
-	 * Late entry may be the first entry, so all initialization
-	 * routines must be called here as well as the early entry
+	 * KGDB is no longer able to communicate out, so
+	 * unregister our hooks and reset state.
 	 */
-	kgdb_internal_init();
+	kgdb_unregister_hooks();
 
-	if (!kgdb_io_module_registered &&
-		(!kgdb_io_ops.init || kgdb_io_ops.init())) {
-		/*
-		 * When KGDB allows I/O via modules and the core I/O init
-		 * fails KGDB must default to defering the I/O setup, and
-		 * appropriately print an error about it.
-		 */
-		printk(KERN_INFO "kgdb: Defering I/O setup to module.\n");
-		memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io));
-		kgdb_break_asap = 0;
-		return 0;
-	}
-	kgdb_register_io_module(&kgdb_io_ops);
+	spin_lock(&kgdb_registration_lock);
 
-	/* Execute any late init I/O routines. */
-	if (kgdb_io_ops.late_init)
-		kgdb_io_ops.late_init();
+	WARN_ON(kgdb_io_ops != old_kgdb_io_ops);
+	kgdb_io_ops = NULL;
 
-	if (kgdb_break_asap)
-		kgdb_initial_breakpoint();
+	spin_unlock(&kgdb_registration_lock);
 
-	return 0;
+	printk(KERN_INFO "kgdb: Unregistered I/O driver %s, debugger "
+	                 "disabled.\n", old_kgdb_io_ops->name);
 }
-late_initcall(kgdb_late_entry);
+EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
 
 /*
  * This function will generate a breakpoint exception.  It is used at the
@@ -2264,38 +2106,23 @@ kgdb_notify_reboot(struct notifier_block
 	if (!kgdb_connected || atomic_read(&debugger_active) != 0)
 		return 0;
 
-	if ((code == SYS_RESTART) || (code == SYS_HALT) ||
-						(code == SYS_POWER_OFF)) {
+	if (code == SYS_RESTART || code == SYS_HALT || code == SYS_POWER_OFF) {
 		local_irq_save(flags);
 		put_packet("X00");
+		kgdb_connected = 0;
 		local_irq_restore(flags);
 	}
 	return NOTIFY_DONE;
 }
 
-static int __init opt_kgdb_attachwait(char *str)
-{
-	attachwait = 1;
-
-	return 0;
-}
-
-static int __init opt_kgdb_enter(char *str)
+static int __init opt_kgdb_wait(char *str)
 {
-	/* We've already done this by an explicit breakpoint() call. */
-	if  (kgdb_internal_init_complete)
-		return 0;
-
-	kgdb_early_entry();
-	attachwait = 1;
+	kgdb_break_asap = 1;
 
 	if (kgdb_io_module_registered)
 		kgdb_initial_breakpoint();
-	else
-		kgdb_break_asap = 1;
 
 	return 0;
 }
 
-early_param("kgdbwait", opt_kgdb_enter);
-early_param("attachwait", opt_kgdb_attachwait);
+early_param("kgdbwait", opt_kgdb_wait);
Index: b/lib/Kconfig.kgdb
===================================================================
--- a/lib/Kconfig.kgdb
+++ b/lib/Kconfig.kgdb
@@ -15,126 +15,6 @@ config KGDB_ARCH_HAS_SHADOW_INFO
 	bool
 	depends on KGDB
 
-config SERIAL_POLL
-	bool
-
-choice
-	prompt "Method for KGDB communication"
-	depends on KGDB
-	default KGDBOC_NOMODULE
-	help
-	  There are a number of different ways in which you can communicate
-	  with KGDB.  The most common is via serial, with the 8250 driver
-	  (should your hardware have an 8250, or ns1655x style uart).
-	  You can elect to have one core I/O driver that is built into the
-	  kernel for debugging as the kernel is booting, or using only
-	  kernel modules.
-
-config KGDB_ONLY_MODULES
-	bool "KGDB: Use only kernel modules for I/O"
-	depends on MODULES
-	help
-	  Use only kernel modules to configure KGDB I/O after the
-	  kernel is booted.
-
-config KGDB_8250_NOMODULE
-	bool "KGDB: On generic serial port (8250)"
-	select KGDB_8250
-	help
-	  Uses generic serial port (8250) to communicate with the host
-	  GDB.  This is independent of the normal (SERIAL_8250) driver
-	  for this chipset.
-
-config KGDBOC_NOMODULE
-	bool "KGDB: On Console - in kernel"
-	select KGDBOC
-	select SERIAL_POLL
-	help
-	  Uses the SERIAL_POLL API to multiplex the console driver
-	  output with the debugger output when the debugger is active.
-	  To break into the debugger initially you must use the sysrq
-	  request with the "g" for gdb.
-
-endchoice
-
-config KGDBOC
-	tristate "KGDB: Share serial console and kgdb port" if !KGDBOC_NOMODULE
-	depends on m && KGDB
-	default m
-	select SERIAL_POLL
-	select MAGIC_SYSRQ
-	help
-	  Share a serial console with kgdb.  The sysrq-g must be used
-	  to break in initially.
-
-config KGDB_8250
-	tristate "KGDB: On generic serial port (8250)" if !KGDB_8250_NOMODULE
-	depends on m && KGDB_ONLY_MODULES
-	help
-	  Uses generic serial port (8250) to communicate with the host
-	  GDB.  This is independent of the normal (SERIAL_8250) driver
-	  for this chipset.
-
-config KGDB_SIMPLE_SERIAL
-	bool "Simple configuration of KGDB serial port"
-	depends on KGDB_8250_NOMODULE
-	default y
-	help
-	  If you say Y here, you will only have to pick the baud rate
-	  and port number that you wish to use for KGDB.  Note that this
-	  only works on architectures that register known serial ports
-	  early on.  If you say N, you will have to provide, either here
-	  or on the command line, the type (I/O or MMIO), IRQ and
-	  address to use.  If in doubt, say Y.
-
-config KGDB_SERIAL_STATIC
-	bool "Configure KGDB serial parameters statically"
-	depends on KGDB_8250
-	default n
-	help
-	  If you turn this on, you do not have to specify the kgdb
-	  serial paramters via kernel boot arguments.  It also means
-	  that kgdb will configure the serial port on boot.
-
-config KGDB_BAUDRATE
-	int "Debug serial port baud rate"
-	depends on KGDB_SERIAL_STATIC && KGDB_SIMPLE_SERIAL && KGDB_8250
-	default "115200"
-	help
-	  gdb and the kernel stub need to agree on the baud rate to be
-	  used.  Standard rates from 9600 to 115200 are allowed, and this
-	  may be overridden via the commandline.
-
-config KGDB_PORT_NUM
-	int "Serial port number for KGDB"
-	range 0 3
-	depends on KGDB_SERIAL_STATIC && KGDB_SIMPLE_SERIAL && KGDB_8250
-	default "0"
-	help
-	  Pick the port number (0 based) for KGDB to use.
-
-config KGDB_8250_CONF_STRING
-	string "Configuration string for KGDB"
-	depends on KGDB_SERIAL_STATIC && (KGDB_8250 = y) && \
-		!KGDB_SIMPLE_SERIAL && KGDB_8250
-	default "io,2f8,115200,3" if X86
-	help
-	  The format of this string should be <io or mmio>,
-	  <address>,<baud rate>,<irq>.  For example, on an i386 box,
-	  to use the serial port located at 0x2f8, IRQ 3, at 115200 baud
-	  use:  io,2f8,115200,3
-
-config KGDB_ATTACH_WAIT
-	bool "KGDB: Wait for debugger to attach on an unknown exception"
-	depends on KGDB
-	default (KGDB_8250 = y)
-	help
-	  If a panic occurs, or any kind of exception, the kgdb will
-	  stop and wait for a debugger to attach.  This sets the
-	  default behavior for waiting for the debugger to attach.  This
-	  value can also be changed at runtime through
-	  /sys/module/kgdb/parameters/attachwait
-
 config KGDB_CONSOLE
 	bool "KGDB: Console messages through gdb"
 	depends on KGDB
@@ -147,3 +27,36 @@ config KGDB_CONSOLE
 	  to crash, and typically reboot.  For this reason, it is preferable
 	  to use NETCONSOLE in conjunction with KGDBOE instead of
 	  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|mmap>,<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.
+
+config KGDBOC
+	tristate "KGDB: Share serial console and kgdb port"
+	depends on KGDB
+	select SERIAL_POLL
+	select MAGIC_SYSRQ
+	help
+	  Share a serial console with kgdb.  The sysrq-g must be used
+	  to break in initially.
Index: b/drivers/serial/kgdboc.c
===================================================================
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -16,8 +16,8 @@
 #include <linux/kernel.h>
 #include <linux/kgdb.h>
 #include <linux/tty.h>
+#include <linux/ctype.h>
 
-#define NOT_CONFIGURED_STRING "not_configured"
 #define MAX_KGDBOC_CONFIG_STR 40
 
 static struct kgdb_io kgdboc_io_ops;
@@ -27,7 +27,7 @@ static int configured = -1;
 
 MODULE_DESCRIPTION("KGDB Console TTY Driver");
 MODULE_LICENSE("GPL");
-static char config[MAX_KGDBOC_CONFIG_STR] = NOT_CONFIGURED_STRING;
+static char config[MAX_KGDBOC_CONFIG_STR];
 static struct kparam_string kps = {
 	.string = config,
 	.maxlen = MAX_KGDBOC_CONFIG_STR,
@@ -40,13 +40,9 @@ static int kgdboc_option_setup(char *opt
 {
 	if (strlen(opt) > MAX_KGDBOC_CONFIG_STR) {
 		printk(KERN_ERR "kgdboc: config string too long\n");
-		strcpy(config, NOT_CONFIGURED_STRING);
-		return 1;
+		return -ENOSPC;
 	}
-
-	/* If we're being given a new configuration, copy it in. */
-	if (opt != config)
-		strcpy(config, opt);
+	strcpy(config, opt);
 	return 0;
 }
 __setup("kgdboc=", kgdboc_option_setup);
@@ -54,18 +50,21 @@ __setup("kgdboc=", kgdboc_option_setup);
 static int configure_kgdboc(void)
 {
 	struct tty_driver *p;
-	int ret = 1;
+	int err;
 	char *str;
 	int tty_line = 0;
 
-	kgdboc_option_setup(config);
-	if (strcmp(config, NOT_CONFIGURED_STRING) == 0)
-		goto err;
+	err = kgdboc_option_setup(config);
+	if (err || !strlen(config) || isspace(config[0]))
+		goto noconfig;
+
+	err = -ENODEV;
 
 	/* Search through the tty devices to look for a match */
+	// FIXME: API violation, at least missing lock protection
 	list_for_each_entry(p, &tty_drivers, tty_drivers) {
-		if (!(p->type == TTY_DRIVER_TYPE_SERIAL &&
-			  strncmp(config, p->name, strlen(p->name)) == 0))
+		if (p->type != TTY_DRIVER_TYPE_SERIAL ||
+		    strncmp(config, p->name, strlen(p->name)) != 0)
 			continue;
 		str = config + strlen(p->name);
 		tty_line = simple_strtoul(str, &str, 10);
@@ -78,29 +77,24 @@ static int configure_kgdboc(void)
 			p->poll_init && !p->poll_init(p, tty_line, str)) {
 			kgdb_tty_driver = p;
 			kgdb_tty_line = tty_line;
-			ret = 0;
+			err = 0;
 			break;
 		}
 	}
-	if (ret) {
-		printk(KERN_ERR "kgdboc: invalid parmater: %s\n", config);
-		printk(KERN_ERR "Usage kgdboc=<serial_device>[,baud]\n");
-		goto err;
-	}
+	if (err)
+		goto noconfig;
 
-	if (kgdb_register_io_module(&kgdboc_io_ops)) {
-		printk(KERN_ERR "KGDB IO registration failed\n");
-		goto err;
-	}
-	configured = 1;
+	err = kgdb_register_io_module(&kgdboc_io_ops);
+	if (err)
+		goto noconfig;
 
-	printk(KERN_INFO "kgdboc: Debugging enabled\n");
+	configured = 1;
 	return 0;
 
-err:
-	strcpy(config, NOT_CONFIGURED_STRING);
+noconfig:
+	config[0] = 0;
 	configured = 0;
-	return -EINVAL;
+	return err;
 
 }
 
@@ -110,16 +104,13 @@ static int init_kgdboc(void)
 	if (configured == 1)
 		return 0;
 
-	if (configure_kgdboc())
-		printk(KERN_INFO "kgdboc: Driver loaded in"
-		" not_configured state\n");
-
-	return 0;
+	return configure_kgdboc();
 }
 
 static void cleanup_kgdboc(void)
 {
-	kgdb_unregister_io_module(&kgdboc_io_ops);
+	if (configured == 1)
+		kgdb_unregister_io_module(&kgdboc_io_ops);
 }
 
 static int kgdboc_get_char(void)
@@ -137,67 +128,30 @@ static void kgdboc_put_char(u8 chr)
 static int param_set_kgdboc_var(const char *kmessage,
 		struct kernel_param *kp)
 {
-	char kmessage_save[MAX_KGDBOC_CONFIG_STR];
-	int msg_len = strlen(kmessage);
-
-	if (msg_len + 1 > MAX_KGDBOC_CONFIG_STR) {
-		printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
-		       kp->name, MAX_KGDBOC_CONFIG_STR - 1);
+	if (strlen(kmessage) >= MAX_KGDBOC_CONFIG_STR) {
+		printk(KERN_ERR "kgdboc: config string too long\n");
 		return -ENOSPC;
 	}
 
 	/* Only copy in the string if the init function has not run yet */
 	if (configured < 0) {
-		strncpy(config, kmessage, sizeof(config));
+		strcpy(config, kmessage);
 		return 0;
 	}
 
 	if (kgdb_connected) {
 		printk(KERN_ERR "kgdboc: Cannot reconfigure while KGDB is "
 				"connected.\n");
-		return 0;
+		return -EBUSY;
 	}
 
-	/* Start the reconfiguration process by saving the old string */
-	strncpy(kmessage_save, config, sizeof(kmessage_save));
-
-
-	/* Copy in the new param and strip out invalid characters so we
-	 * can optionally specify the MAC.
-	 */
-	strncpy(config, kmessage, sizeof(config));
-	msg_len--;
-	while (msg_len > 0 &&
-			(config[msg_len] < ',' || config[msg_len] > 'f')) {
-		config[msg_len] = '\0';
-		msg_len--;
-	}
-
-	/* Check to see if we are unconfiguring the io module and that it
-	 * was in a fully configured state, as this is the only time that
-	 * netpoll_cleanup should get called
-	 */
-	if (configured == 1 && strcmp(config, NOT_CONFIGURED_STRING) == 0) {
-		printk(KERN_INFO "kgdboc: reverting to unconfigured state\n");
-		cleanup_kgdboc();
-		return 0;
-	} else
-		/* Go and configure with the new params. */
-		configure_kgdboc();
+	strcpy(config, kmessage);
 
 	if (configured == 1)
-		return 0;
+		cleanup_kgdboc();
 
-	/* If the new string was invalid, revert to the previous state, which
-	 * is at a minimum not_configured. */
-	strncpy(config, kmessage_save, sizeof(config));
-	if (strcmp(kmessage_save, NOT_CONFIGURED_STRING) != 0) {
-		printk(KERN_INFO "kgdboc: reverting to prior configuration\n");
-		/* revert back to the original config */
-		strncpy(config, kmessage_save, sizeof(config));
-		configure_kgdboc();
-	}
-	return 0;
+	/* Go and configure with the new params. */
+	return configure_kgdboc();
 }
 
 static void kgdboc_pre_exp_handler(void)
@@ -215,9 +169,9 @@ static void kgdboc_post_exp_handler(void
 }
 
 static struct kgdb_io kgdboc_io_ops = {
+	.name = "kgdboc",
 	.read_char = kgdboc_get_char,
 	.write_char = kgdboc_put_char,
-	.init = init_kgdboc,
 	.pre_exception = kgdboc_pre_exp_handler,
 	.post_exception = kgdboc_post_exp_handler,
 };
@@ -225,4 +179,4 @@ static struct kgdb_io kgdboc_io_ops = {
 module_init(init_kgdboc);
 module_exit(cleanup_kgdboc);
 module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
-MODULE_PARM_DESC(kgdboc, " kgdboc=<serial_device>[,baud]\n");
+MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] KGDB: Major refactoring
  2008-02-05 23:34 [PATCH 1/3] KGDB: Major refactoring Jan Kiszka
@ 2008-02-05 23:44 ` Maxim Levitsky
  2008-02-06  4:40 ` Jason Wessel
  2008-02-07  0:13 ` Ingo Molnar
  2 siblings, 0 replies; 7+ messages in thread
From: Maxim Levitsky @ 2008-02-05 23:44 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Jason Wessel, Ingo Molnar, Linux Kernel Mailing List,
	kgdb-bugreport, Thomas Gleixner, H. Peter Anvin

On Wednesday, 6 February 2008 01:34:13 Jan Kiszka wrote:
> As most changes are tightly coupled, this refactoring patch for
> KGDB_8250 as well as the core and the new KGDBOC driver comes as a
> single chunk. The changes are:
>  - Reorganized configuration: I/O drivers can be independently
>    configured as module or built-in
>  - Dynamic reconfiguration for KGDB_8250 (just like for KGDBOC)
>  - Reworked KGDB_8250 configuration string format
>  - attachwait removed, arming the debugger via assigning an I/O driver
>    implies "attachwait"
>  - Cleaned up I/O driver managment of the core
>  - Matured the various boot-up, configure, unconfigure code paths for
>    both I/O drivers
>  - IRQ vs. KGDB_CONSOLE-output SMP race fixed for KGDB_8250
>  - Reduced and cleaned up hooks into serial_core/8250
>  - Kconfig cleanups
> 
> What we no longer have:
>  - Simple serial configuration for _early_ debugging, use the io/mem
>    format instead or wait until the debugger is able to resolve "ttySx"
>    during late-init
> 
> To-do:
>  - KGDBOC does not yet cleanly interacts with the TTY subsystem to
>    attach to some console
> 
> Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
> 
> ---
>  drivers/serial/8250.c        |   56 +--
>  drivers/serial/8250_kgdb.c   |  731 +++++++++++++++++++------------------------
>  drivers/serial/Kconfig       |    3 
>  drivers/serial/kgdboc.c      |  118 ++----
>  drivers/serial/serial_core.c |    6 
>  include/linux/kgdb.h         |   20 -
>  kernel/kgdb.c                |  373 +++++----------------
>  lib/Kconfig.kgdb             |  153 +--------
>  8 files changed, 520 insertions(+), 940 deletions(-)
> 
> Index: b/drivers/serial/8250_kgdb.c
> ===================================================================
> --- a/drivers/serial/8250_kgdb.c
> +++ b/drivers/serial/8250_kgdb.c
> @@ -1,5 +1,5 @@
>  /*
> - * 8250 interface for kgdb.
> + * 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:
> @@ -12,143 +12,100 @@
>   * Robert Walsh <rjwalsh@durables.org>, wangdi <wangdi@clusterfs.com>,
>   * San Mehat, Tom Rini <trini@mvista.com>,
>   * Jason Wessel <jason.wessel@windriver.com>
> + *
> + * Refactoring and cleanup for initial merge:
> + * 2008 (c) Jan Kiszka <jan.kiszka@web.de>
> + *
> + * 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/tty.h>
> -#include <linux/serial.h>
>  #include <linux/serial_reg.h>
> -#include <linux/serialP.h>
>  #include <linux/ioport.h>
>  #include <linux/io.h>
> -#include <asm/serial.h>		/* For BASE_BAUD and SERIAL_PORT_DFNS */
> -
> -#include "8250.h"
> -
> -#define GDB_BUF_SIZE	512	/* power of 2, please */
> +#include <linux/ctype.h>
> +#include <asm/serial.h>		/* for BASE_BAUD */
>  
>  MODULE_DESCRIPTION("KGDB driver for the 8250");
>  MODULE_LICENSE("GPL");
> -/* These will conflict with early_param otherwise. */
> -#ifdef CONFIG_KGDB_8250_MODULE
> -static char config[256];
> -module_param_string(kgdb8250, config, 256, 0);
> -MODULE_PARM_DESC(kgdb8250,
> -		 " kgdb8250=<io or mmio>,<address>,<baud rate>,<irq>\n");
> -static struct kgdb_io local_kgdb_io_ops;
> -#endif				/* CONFIG_KGDB_8250_MODULE */
> -
> -#ifdef CONFIG_KGDB_BAUDRATE
> -static int kgdb8250_baud = CONFIG_KGDB_BAUDRATE;
> -#else
> -static int kgdb8250_baud;
> -#endif
> -#ifdef CONFIG_KGDB_PORT_NUM
> -static int kgdb8250_line = CONFIG_KGDB_PORT_NUM;
> -#else
> -static int kgdb8250_line = -1;
> -#endif
> -
> -/* Flag for if we need to call request_mem_region */
> -static int kgdb8250_needs_request_mem_region;
>  
> -static char kgdb8250_buf[GDB_BUF_SIZE];
> -static atomic_t kgdb8250_buf_in_cnt;
> -static int kgdb8250_buf_out_inx;
> -
> -/* Old-style serial definitions, if existant, and a counter. */
> -#ifdef CONFIG_KGDB_SIMPLE_SERIAL
> -static int __initdata should_copy_rs_table = 1;
> -static struct serial_state old_rs_table[] __initdata = {
> -#ifdef SERIAL_PORT_DFNS
> -	SERIAL_PORT_DFNS
> -#endif
> +#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,
>  };
> -#endif
>  
> -/* Our internal table of UARTS. */
> -#define UART_NR	CONFIG_SERIAL_8250_NR_UARTS
> -static struct uart_port kgdb8250_ports[UART_NR];
> +static int kgdb8250_baud;
> +static void *kgdb8250_addr;
> +static int kgdb8250_irq = -1;
> +static struct uart_port kgdb8250_port;
>  
> -static struct uart_port *current_port;
> +/* UART port we might have stolen from the 8250 driver */
> +static int hijacked_line;
>  
> -/* Base of the UART. */
> -static void *kgdb8250_addr;
> +static int late_init_passed;
> +static int fully_initialized;
> +static int buffered_char = -1;
> +
> +static struct kgdb_io kgdb8250_io_ops;	/* initialized later */
>  
> -/* Forward declarations. */
>  static int kgdb8250_uart_init(void);
> -static int __init kgdb_init_io(void);
> -static int __init kgdb8250_opt(char *str);
>  
> -/* These are much shorter calls to ioread8/iowrite8 that take into
> - * account our shifts, etc. */
> -static inline unsigned int kgdb_ioread(u8 mask)
> +static inline unsigned int kgdb8250_ioread(u8 mask)
>  {
> -	return ioread8(kgdb8250_addr + (mask << current_port->regshift));
> +	return ioread8(kgdb8250_addr + (mask << kgdb8250_port.regshift));
>  }
>  
> -static inline void kgdb_iowrite(u8 val, u8 mask)
> +static inline void kgdb8250_iowrite(u8 val, u8 mask)
>  {
> -	iowrite8(val, kgdb8250_addr + (mask << current_port->regshift));
> +	iowrite8(val, kgdb8250_addr + (mask << kgdb8250_port.regshift));
>  }
>  
>  /*
>   * Wait until the interface can accept a char, then write it.
>   */
> -static void kgdb_put_debug_char(u8 chr)
> +static void kgdb8250_put_debug_char(u8 chr)
>  {
> -	while (!(kgdb_ioread(UART_LSR) & UART_LSR_THRE)) ;
> +	while (!(kgdb8250_ioread(UART_LSR) & UART_LSR_THRE))
> +		cpu_relax();
>  
> -	kgdb_iowrite(chr, UART_TX);
> +	kgdb8250_iowrite(chr, UART_TX);
>  }
>  
>  /*
> - * Get a byte from the hardware data buffer and return it
> + * Get a byte from the hardware data buffer and return it.
>   */
> -static int read_data_bfr(void)
> +static int kgdb8250_get_debug_char(void)
>  {
> -	char it = kgdb_ioread(UART_LSR);
> +	unsigned int lsr;
>  
> -	if (it & UART_LSR_DR)
> -		return kgdb_ioread(UART_RX);
> +	while (1) {
> +		/* Did the interrupt handler catch something before us? */
> +		if (buffered_char >= 0)
> +			return xchg(&buffered_char, -1);
>  
> -	/*
> -	 * If we have a framing error assume somebody messed with
> -	 * our uart.  Reprogram it and send '-' both ways...
> -	 */
> -	if (it & 0xc) {
> -		kgdb8250_uart_init();
> -		kgdb_put_debug_char('-');
> -		return '-';
> -	}
> +		lsr = kgdb8250_ioread(UART_LSR);
> +		if (lsr & UART_LSR_DR)
> +			return kgdb8250_ioread(UART_RX);
>  
> -	return -1;
> -}
> -
> -/*
> - * Get a char if available, return -1 if nothing available.
> - * Empty the receive buffer first, then look at the interface hardware.
> - */
> -static int kgdb_get_debug_char(void)
> -{
> -	int retchr;
> +		/*
> +		 * 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 '-';
> +		}
>  
> -	/* intr routine has q'd chars */
> -	if (atomic_read(&kgdb8250_buf_in_cnt) != 0) {
> -		retchr = kgdb8250_buf[kgdb8250_buf_out_inx++];
> -		kgdb8250_buf_out_inx &= (GDB_BUF_SIZE - 1);
> -		atomic_dec(&kgdb8250_buf_in_cnt);
> -		return retchr;
> +		cpu_relax();
>  	}
> -
> -	do {
> -		retchr = read_data_bfr();
> -	} while (retchr < 0);
> -
> -	return retchr;
>  }
>  
>  /*
> @@ -157,77 +114,71 @@ static int kgdb_get_debug_char(void)
>   * 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)
> +static irqreturn_t kgdb8250_interrupt(int irq, void *dev_id)
>  {
> -	if (!(kgdb_ioread(UART_IIR) & UART_IIR_RDI))
> -		return IRQ_NONE;
> +	unsigned int iir = kgdb8250_ioread(UART_IIR);
> +	char c;
>  
> -	/* Throw away the data if another I/O routine is active. */
> -	if (kgdb_io_ops.read_char != kgdb_get_debug_char &&
> -	    (kgdb_ioread(UART_LSR) & UART_LSR_DR))
> -		kgdb_ioread(UART_RX);
> -	else
> -		breakpoint();
> +	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)
> +			breakpoint();
> +		else
> +			buffered_char = c;
> +	}
>  	return IRQ_HANDLED;
>  }
>  
>  /*
>   *  Initializes the UART.
>   *  Returns:
> - *	0 on success, 1 on failure.
> + *	0 on success, -errno on failure.
>   */
>  static int kgdb8250_uart_init(void)
>  {
>  	unsigned int ier;
> -	unsigned int base_baud = current_port->uartclk ?
> -		current_port->uartclk / 16 : BASE_BAUD;
> +	unsigned int base_baud = kgdb8250_port.uartclk ?
> +		kgdb8250_port.uartclk / 16 : BASE_BAUD;
>  
> -	/* test uart existance */
> -	if (kgdb_ioread(UART_LSR) == 0xff)
> -		return -1;
> +	/* Test UART existance. */
> +	if (kgdb8250_ioread(UART_LSR) == 0xff)
> +		return -EIO;
>  
> -	/* disable interrupts */
> -	kgdb_iowrite(0, UART_IER);
> +	/* Disable interrupts. */
> +	kgdb8250_iowrite(0, UART_IER);
>  
> -#if defined(CONFIG_ARCH_OMAP1510)
> +#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;
> -			kgdb_iowrite(1, UART_OMAP_OSC_12M_SEL);
> +			kgdb8250_iowrite(1, UART_OMAP_OSC_12M_SEL);
>  		} else
> -			kgdb_iowrite(0, UART_OMAP_OSC_12M_SEL);
> +			kgdb8250_iowrite(0, UART_OMAP_OSC_12M_SEL);
>  	}
>  #endif
> -	/* set DLAB */
> -	kgdb_iowrite(UART_LCR_DLAB, UART_LCR);
>  
> -	/* set baud */
> -	kgdb_iowrite((base_baud / kgdb8250_baud) & 0xff, UART_DLL);
> -	kgdb_iowrite((base_baud / kgdb8250_baud) >> 8, UART_DLM);
> -
> -	/* reset DLAB, set LCR */
> -	kgdb_iowrite(UART_LCR_WLEN8, UART_LCR);
> -
> -	/* set DTR and RTS */
> -	kgdb_iowrite(UART_MCR_OUT2 | UART_MCR_DTR | UART_MCR_RTS, UART_MCR);
> -
> -	/* setup fifo */
> -	kgdb_iowrite(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR
> -		| UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_8,
> -		UART_FCR);
> -
> -	/* clear pending interrupts */
> -	kgdb_ioread(UART_IIR);
> -	kgdb_ioread(UART_RX);
> -	kgdb_ioread(UART_LSR);
> -	kgdb_ioread(UART_MSR);
> -
> -	/* turn on RX interrupt only */
> -	kgdb_iowrite(UART_IER_RDI, UART_IER);
> +	/* 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.
> @@ -238,344 +189,308 @@ static int kgdb8250_uart_init(void)
>  	 * 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 = kgdb_ioread(UART_IER);
> -	kgdb_iowrite(ier & ~UART_IER_UUE, UART_IER);
> -	if (!(kgdb_ioread(UART_IER) & UART_IER_UUE)) {
> +	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.
>  		 */
> -		kgdb_iowrite(ier | UART_IER_UUE, UART_IER);
> -		if (kgdb_ioread(UART_IER) & UART_IER_UUE)
> -			/*
> -			 * It's an Xscale.
> -			 */
> +		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;
>  	}
> -	kgdb_iowrite(ier, UART_IER);
> +	kgdb8250_iowrite(ier, UART_IER);
> +
>  	return 0;
>  }
>  
>  /*
> - * Copy the old serial_state table to our uart_port table if we haven't
> - * had values specifically configured in.  We need to make sure this only
> - * happens once.
> + * Syntax for this cmdline option is:
> + *   <io|mmio|mmap>,<address>[/<regshift>],<baud rate>,<irq> or
> + *   ttyS<n>,<baud rate>
>   */
> -static void __init kgdb8250_copy_rs_table(void)
> +static int kgdb8250_parse_config(char *str)
>  {
> -#ifdef CONFIG_KGDB_SIMPLE_SERIAL
> -	int i;
> +	int line, err;
>  
> -	if (!should_copy_rs_table)
> -		return;
> +	/* Save the option string in case we fail and can retry later. */
> +	strncpy(config, str, KGD8250_MAX_CONFIG_STR-1);
>  
> -	for (i = 0; i < ARRAY_SIZE(old_rs_table) && i < UART_NR; i++) {
> -		if (kgdb8250_ports[i].iobase || kgdb8250_ports[i].irq ||
> -			kgdb8250_ports[i].membase)
> -			continue;
> -		kgdb8250_ports[i].iobase = old_rs_table[i].port;
> -		kgdb8250_ports[i].irq = irq_canonicalize(old_rs_table[i].irq);
> -		kgdb8250_ports[i].uartclk = old_rs_table[i].baud_base * 16;
> -		kgdb8250_ports[i].membase = old_rs_table[i].iomem_base;
> -		kgdb8250_ports[i].iotype = old_rs_table[i].io_type;
> -		kgdb8250_ports[i].regshift = old_rs_table[i].iomem_reg_shift;
> -		kgdb8250_ports[i].line = i;
> -	}
> +	/* Empty config or leading white space (like LF) means "disabled" */
> +	if (!strlen(config) || isspace(config[0]))
> +		return 0;
>  
> -	should_copy_rs_table = 0;
> -#endif
> -}
> +	if (!strncmp(str, "io", 2)) {
> +		kgdb8250_port.iotype = UPIO_PORT;
> +		str += 2;
> +	} else if (!strncmp(str, "mmap", 4)) {
> +		kgdb8250_port.iotype = UPIO_MEM;
> +		kgdb8250_port.flags |= UPF_IOREMAP;
> +		str += 4;
> +	} 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;
>  
> -/*
> - * Hookup our IRQ line now that it is safe to do so, after we grab any
> - * memory regions we might need to.  If we haven't been initialized yet,
> - * go ahead and copy the old_rs_table in.
> - */
> -static void __init kgdb8250_late_init(void)
> -{
> -	/* Setup the KGDB uart table if not already initialized */
> -	kgdb8250_copy_rs_table();
> +		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|mmap syntax for early init.\n",
> +			       line);
> +			return 0;
> +		}
>  
> -#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
> -	/* Take the port away from the main driver. */
> -	serial8250_unregister_by_port(current_port);
> +		if (*str != ',')
> +			return -EINVAL;
> +		str++;
>  
> -	/* Now reinit the port as the above has disabled things. */
> -	kgdb8250_uart_init();
> -#endif
> -	/* We may need to call request_mem_region() first. */
> -	if (kgdb8250_needs_request_mem_region)
> -		request_mem_region(current_port->mapbase,
> -				   8 << current_port->regshift, "kgdb");
> -	if (request_irq(current_port->irq, kgdb8250_interrupt, IRQF_SHARED,
> -			"GDB-stub", current_port) < 0)
> -		printk(KERN_ERR "KGDB failed to request the serial IRQ (%d)\n",
> -		       current_port->irq);
> -}
> -
> -static __init int kgdb_init_io(void)
> -{
> -	/* Setup the KGDB uart table if not already initialized */
> -	kgdb8250_copy_rs_table();
> -
> -	/* We're either a module and parse a config string, or we have a
> -	 * semi-static config. */
> -#ifdef CONFIG_KGDB_8250_MODULE
> -	if (strlen(config)) {
> -		if (kgdb8250_opt(config))
> +		kgdb8250_baud = simple_strtoul(str, &str, 10);
> +		if (!kgdb8250_baud)
>  			return -EINVAL;
> -	} else {
> -		printk(KERN_ERR "kgdb8250: argument error, usage: "
> -		       "kgdb8250=<io or mmio>,<address>,<baud rate>,<irq>\n");
> -		printk(KERN_ERR "kgdb8250: alt usage: "
> -		       "kgdb8250=<line #>,<baud rate>\n");
> +
> +		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 {
> +		if (kgdb8250_port.flags & UPF_IOREMAP)
> +			kgdb8250_port.mapbase =
> +				(unsigned long) simple_strtoul(str, &str, 16);
> +		else
> +			kgdb8250_port.membase =
> +				(void *) simple_strtoul(str, &str, 16);
> +	}
> +
> +	if (*str == '/') {
> +		str++;
> +		kgdb8250_port.regshift = simple_strtoul(str, &str, 10);
>  	}
> -#elif defined(CONFIG_KGDB_SIMPLE_SERIAL)
> -	if (kgdb8250_line < 0)
> +
> +	if (*str != ',')
>  		return -EINVAL;
> -	/* Setup our pointer to the serial port now. */
> -	current_port = &kgdb8250_ports[kgdb8250_line];
> -	if (!current_port->membase && !current_port->iobase &&
> -		!current_port->irq)
> -		serial8250_get_port_def(current_port, kgdb8250_line);
> -#elif defined(CONFIG_KGDB_8250_CONF_STRING)
> -	if (kgdb8250_opt(CONFIG_KGDB_8250_CONF_STRING))
> +	str++;
> +
> +	kgdb8250_baud = simple_strtoul(str, &str, 10);
> +	if (!kgdb8250_baud)
>  		return -EINVAL;
> -#else
> +
> +	if (*str != ',')
>  		return -EINVAL;
> -#endif
> +	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 (current_port->iotype) {
> +	switch (kgdb8250_port.iotype) {
>  	case UPIO_MEM:
> -		if (current_port->mapbase)
> -			kgdb8250_needs_request_mem_region = 1;
> -		if (current_port->flags & UPF_IOREMAP) {
> -			current_port->membase = ioremap(current_port->mapbase,
> -						8 << current_port->regshift);
> -			if (!current_port->membase)
> -				return -EIO;	/* Failed. */
> -		}
> -		kgdb8250_addr = current_port->membase;
> +		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(current_port->iobase,
> -					   8 << current_port->regshift);
> -		if (!kgdb8250_addr)
> -			return -EIO;	/* Failed. */
> +		kgdb8250_addr = ioport_map(kgdb8250_port.iobase,
> +					   8 << kgdb8250_port.regshift);
>  	}
> +	if (!kgdb8250_addr)
> +		return -EIO;
>  
> -	if (kgdb8250_uart_init() == -1) {
> -		printk(KERN_ERR "kgdb8250: init failed\n");
> +	if (kgdb8250_uart_init() < 0) {
> +		printk(KERN_ERR "kgdb8250: UART initialization failed\n");
>  		return -EIO;
>  	}
> -#ifdef CONFIG_KGDB_8250_MODULE
> -	/* Attach the kgdb irq. When this is built into the kernel, it
> -	 * is called as a part of late_init sequence.
> -	 */
> -	kgdb8250_late_init();
> -	if (kgdb_register_io_module(&local_kgdb_io_ops))
> -		return -EINVAL;
> -
> -	printk(KERN_INFO "kgdb8250: debugging enabled\n");
> -#endif				/* CONFIG_KGD_8250_MODULE */
>  
>  	return 0;
>  }
>  
> -#ifdef CONFIG_KGDB_8250_MODULE
> -/* If it is a module the kgdb_io_ops should be a static which
> - * is passed to the KGDB I/O initialization
> - */
> -static void kgdb8250_pre_exception_handler(void);
> -static void kgdb8250_post_exception_handler(void);
> +static int kgdb8250_late_init(void)
> +{
> +	int err;
>  
> -static struct kgdb_io local_kgdb_io_ops = {
> -#else				/* ! CONFIG_KGDB_8250_MODULE */
> -struct kgdb_io kgdb_io_ops = {
> -#endif				/* ! CONFIG_KGD_8250_MODULE */
> -	.read_char = kgdb_get_debug_char,
> -	.write_char = kgdb_put_debug_char,
> -	.init = kgdb_init_io,
> -	.late_init = kgdb8250_late_init,
> -#ifdef CONFIG_KGDB_8250_MODULE
> -	.pre_exception = kgdb8250_pre_exception_handler,
> -	.post_exception = kgdb8250_post_exception_handler,
> -#endif
> -};
> +	if (fully_initialized)
> +		return 0;
>  
> -/**
> - * 	kgdb8250_add_port - Define a serial port for use with KGDB
> - * 	@i: The index of the port being added
> - * 	@serial_req: The &struct uart_port describing the port
> - *
> - * 	On platforms where we must register the serial device
> - * 	dynamically, this is the best option if a platform also normally
> - * 	calls early_serial_setup().
> - */
> -void kgdb8250_add_port(int i, struct uart_port *serial_req)
> -{
> -	if (i >= UART_NR) {
> -		printk(KERN_ERR "KGDB dynamic uart registration failed"
> -		   "NR_UARTS is too small");
> -		return;
> +	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;
>  	}
>  
> -	/* Copy the whole thing over. */
> -	if (current_port != &kgdb8250_ports[i])
> -		memcpy(&kgdb8250_ports[i], serial_req,
> -		sizeof(struct uart_port));
> -}
> +	/* Take the port away from the main driver. */
> +	hijacked_line = serial8250_find_port(&kgdb8250_port);
> +	if (hijacked_line >= 0)
> +		serial8250_unregister_port(hijacked_line);
>  
> -/**
> - * 	kgdb8250_add_platform_port - Define a serial port for use with KGDB
> - * 	@i: The index of the port being added
> - * 	@p: The &struct plat_serial8250_port describing the port
> - *
> - * 	On platforms where we must register the serial device
> - * 	dynamically, this is the best option if a platform normally
> - * 	handles uart setup with an array of &struct plat_serial8250_port.
> - */
> -void __init kgdb8250_add_platform_port(int i, struct plat_serial8250_port *p)
> -{
> -	/* Make sure we've got the built-in data before we override. */
> -	kgdb8250_copy_rs_table();
> +	/* Now reinit the port as the above has disabled things. */
> +	kgdb8250_uart_init();
>  
> -	if (i >= UART_NR) {
> -		printk(KERN_ERR "KGDB dynamic uart registration failed"
> -		   "NR_UARTS is too small");
> -		return;
> +	/* Request memory/io regions that we use. */
> +	if (kgdb8250_port.flags & UPF_IOREMAP) {
> +		if (!request_mem_region(kgdb8250_port.mapbase,
> +					8 << kgdb8250_port.regshift, "kgdb"))
> +			goto rollback;
> +	} else if (kgdb8250_port.iotype == UPIO_PORT) {
> +		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;
>  	}
>  
> -	kgdb8250_ports[i].iobase = p->iobase;
> -	kgdb8250_ports[i].membase = p->membase;
> -	kgdb8250_ports[i].irq = p->irq;
> -	kgdb8250_ports[i].uartclk = p->uartclk;
> -	kgdb8250_ports[i].regshift = p->regshift;
> -	kgdb8250_ports[i].iotype = p->iotype;
> -	kgdb8250_ports[i].flags = p->flags;
> -	kgdb8250_ports[i].mapbase = p->mapbase;
> +	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;
>  }
>  
> -/*
> - * Syntax for this cmdline option is:
> - * kgdb8250=<io or mmio>,<address>,<baud rate>,<irq>"
> - */
> -static int __init kgdb8250_opt(char *str)
> +static void kgdb8250_cleanup(void)
>  {
> -	/* We'll fill out and use the first slot. */
> -	current_port = &kgdb8250_ports[0];
> +	void *ioaddr = kgdb8250_addr;
>  
> -	if (!strncmp(str, "io", 2)) {
> -		current_port->iotype = UPIO_PORT;
> -		str += 2;
> -	} else if (!strncmp(str, "mmap", 4)) {
> -		current_port->iotype = UPIO_MEM;
> -		current_port->flags |= UPF_IOREMAP;
> -		str += 4;
> -	} else if (!strncmp(str, "mmio", 4)) {
> -		current_port->iotype = UPIO_MEM;
> -		current_port->flags &= ~UPF_IOREMAP;
> -		str += 4;
> -	} else if (*str >= '0' || *str <= '9') {
> -		kgdb8250_line = *str - '0';
> -		/* UARTS in the list from 0 -> 9 */
> -		if (kgdb8250_line >= UART_NR)
> -			goto errout;
> -		current_port = &kgdb8250_ports[kgdb8250_line];
> -		if (serial8250_get_port_def(current_port, kgdb8250_line))
> -			goto errout;
> -		str++;
> -		if (*str != ',')
> -			goto errout;
> -		str++;
> -		kgdb8250_baud = simple_strtoul(str, &str, 10);
> -		if (!kgdb8250_baud)
> -			goto errout;
> -		if (*str == ',')
> -			goto errout;
> -		goto finish;
> -	} else
> -		goto errout;
> +	if (!kgdb8250_addr)
> +		return;
>  
> -	if (*str != ',')
> -		goto errout;
> -	str++;
> +	/* 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 (current_port->iotype == UPIO_PORT)
> -		current_port->iobase = simple_strtoul(str, &str, 16);
> -	else {
> -		if (current_port->flags & UPF_IOREMAP)
> -			current_port->mapbase =
> -				(unsigned long) simple_strtoul(str, &str, 16);
> -		else
> -			current_port->membase =
> -				(void *) simple_strtoul(str, &str, 16);
> +	if (!fully_initialized)
> +		return;
> +
> +	fully_initialized = 0;
> +
> +	if (kgdb8250_port.iotype == UPIO_PORT) {
> +		ioport_unmap(ioaddr);
> +		release_region(kgdb8250_port.iobase,
> +			       8 << kgdb8250_port.regshift);
> +	} else if (kgdb8250_port.flags & UPF_IOREMAP) {
> +		iounmap(kgdb8250_port.membase);
> +		release_mem_region(kgdb8250_port.mapbase,
> +				   8 << kgdb8250_port.regshift);
>  	}
>  
> -	if (*str != ',')
> -		goto errout;
> -	str++;
> +	/* Give the port back to the 8250 driver. */
> +	if (hijacked_line >= 0)
> +		serial8250_register_port(&kgdb8250_port);
> +}
>  
> -	kgdb8250_baud = simple_strtoul(str, &str, 10);
> -	if (!kgdb8250_baud)
> -		goto errout;
> +static int kgdb8250_set_config(const char *kmessage, struct kernel_param *kp)
> +{
> +	int err;
>  
> -	if (*str != ',')
> -		goto errout;
> -	str++;
> +	if (strlen(kmessage) >= KGD8250_MAX_CONFIG_STR) {
> +		printk(KERN_ERR "%s: config string too long.\n", kp->name);
> +		return -ENOSPC;
> +	}
>  
> -	current_port->irq = simple_strtoul(str, &str, 10);
> +	if (kgdb_connected) {
> +		printk(KERN_ERR "kgd8250: Cannot reconfigure while KGDB is "
> +				"connected.\n");
> +		return -EBUSY;
> +	}
>  
> -finish:
> -#ifdef CONFIG_KGDB_SIMPLE_SERIAL
> -	should_copy_rs_table = 0;
> -#endif
> +	if (kgdb8250_addr)
> +		kgdb8250_cleanup();
>  
> -	return 0;
> +	err = kgdb8250_parse_config((char *)kmessage);
> +
> +	if (err || !late_init_passed)
> +		return err;
>  
> -errout:
> -	printk(KERN_ERR "Invalid syntax for option kgdb8250=\n");
> -	return 1;
> +	/* Call the botton-half initialization as we are re-configuring. */
> +	return kgdb8250_late_init();
>  }
>  
> -#ifdef CONFIG_KGDB_8250_MODULE
>  static void kgdb8250_pre_exception_handler(void)
>  {
> -	if (!module_refcount(THIS_MODULE))
> +	if (!kgdb_connected)
>  		try_module_get(THIS_MODULE);
>  }
>  
>  static void kgdb8250_post_exception_handler(void)
>  {
> -	if (!kgdb_connected && module_refcount(THIS_MODULE))
> +	if (!kgdb_connected)
>  		module_put(THIS_MODULE);
>  }
>  
> -static void cleanup_kgdb8250(void)
> -{
> -	kgdb_unregister_io_module(&local_kgdb_io_ops);
> +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,
> +};
>  
> -	/* Clean up the irq and memory */
> -	free_irq(current_port->irq, current_port);
> +module_init(kgdb8250_late_init);
> +module_exit(kgdb8250_cleanup);
>  
> -	if (kgdb8250_needs_request_mem_region)
> -		release_mem_region(current_port->mapbase,
> -				   8 << current_port->regshift);
> -	/* Hook up the serial port back to what it was previously
> -	 * hooked up to.
> -	 */
> -#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
> -	/* Give the port back to the 8250 driver. */
> -	serial8250_register_port(current_port);
> -#endif
> -}
> +module_param_call(kgdb8250, kgdb8250_set_config, param_get_string, &kps, 0644);
> +MODULE_PARM_DESC(kgdb8250, "ttyS<n>,<baud rate>");
>  
> -module_init(kgdb_init_io);
> -module_exit(cleanup_kgdb8250);
> -#else				/* ! CONFIG_KGDB_8250_MODULE */
> -early_param("kgdb8250", kgdb8250_opt);
> -#endif				/* ! CONFIG_KGDB_8250_MODULE */
> +#ifdef CONFIG_KGDB_8250
> +early_param("kgdb8250", kgdb8250_parse_config);
> +#endif
> Index: b/drivers/serial/8250.c
> ===================================================================
> --- a/drivers/serial/8250.c
> +++ b/drivers/serial/8250.c
> @@ -2639,6 +2639,7 @@ int serial8250_find_port(struct uart_por
>  	}
>  	return -ENODEV;
>  }
> +EXPORT_SYMBOL_GPL(serial8250_find_port);
>  
>  #define SERIAL8250_CONSOLE	&serial8250_console
>  #else
> @@ -2926,51 +2927,28 @@ EXPORT_SYMBOL(serial8250_unregister_port
>   *  @line: specific serial line index
>   *
>   *  Return 0 if the port existed
> - *  Return 1 on failure
> + *  Return -errno on failure
>   */
> -
>  int serial8250_get_port_def(struct uart_port *port, int line)
>  {
> -	struct uart_8250_port *uart;
> +	struct uart_port *port8250 = &serial8250_ports[line].port;
>  
> -	if (line < 0 || line >= UART_NR)
> -		return 1;
> -	uart = &serial8250_ports[line];
> -	if (uart) {
> -		port->iobase = uart->port.iobase;
> -		port->membase = uart->port.membase;
> -		port->irq = uart->port.irq;
> -		port->uartclk = uart->port.uartclk;
> -		port->fifosize = uart->port.fifosize;
> -		port->regshift = uart->port.regshift;
> -		port->iotype = uart->port.iotype;
> -		port->flags = uart->port.flags;
> -		port->mapbase = uart->port.mapbase;
> -		port->dev =	uart->port.dev;
> -		return 0;
> -	}
> -	return 1;
> -}
> -EXPORT_SYMBOL(serial8250_get_port_def);
> -
> -/**
> - *	serial8250_unregister_by_port - remove a 16x50 serial port
> - *	at runtime.
> - *	@port: A &struct uart_port that describes the port to remove.
> - *
> - *	Remove one serial port.  This may not be called from interrupt
> - *	context.  We hand the port back to the our control.
> - */
> -void serial8250_unregister_by_port(struct uart_port *port)
> -{
> -	struct uart_8250_port *uart;
> -
> -	uart = serial8250_find_match_or_unused(port);
> +	if (!port8250->iobase && !port8250->membase)
> +		return -ENODEV;
>  
> -	if (uart)
> -		serial8250_unregister_port(uart->port.line);
> +	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(serial8250_unregister_by_port);
> +EXPORT_SYMBOL_GPL(serial8250_get_port_def);
>  
>  static int __init serial8250_init(void)
>  {
> Index: b/drivers/serial/Kconfig
> ===================================================================
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -942,6 +942,9 @@ config SERIAL_CORE
>  config SERIAL_CORE_CONSOLE
>  	bool
>  
> +config SERIAL_POLL
> +	bool
> +
>  config SERIAL_68328
>  	bool "68328 serial support"
>  	depends on M68328 || M68EZ328 || M68VZ328
> Index: b/drivers/serial/serial_core.c
> ===================================================================
> --- a/drivers/serial/serial_core.c
> +++ b/drivers/serial/serial_core.c
> @@ -2439,12 +2439,6 @@ int uart_add_one_port(struct uart_driver
>  	 */
>  	port->flags &= ~UPF_DEAD;
>  
> -#if defined(CONFIG_KGDB_8250)
> -	/* Add any 8250-like ports we find later. */
> -	if (port->type <= PORT_MAX_8250)
> -		kgdb8250_add_port(port->line, port);
> -#endif
> -
>   out:
>  	mutex_unlock(&state->mutex);
>  	mutex_unlock(&port_mutex);
> Index: b/include/linux/kgdb.h
> ===================================================================
> --- a/include/linux/kgdb.h
> +++ b/include/linux/kgdb.h
> @@ -233,6 +233,7 @@ struct kgdb_arch {
>  
>  /**
>   * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB.
> + * @name: Name of the I/O driver.
>   * @read_char: Pointer to a function that will return one char.
>   * @write_char: Pointer to a function that will write one char.
>   * @flush: Pointer to a function that will flush any pending writes.
> @@ -255,25 +256,20 @@ struct kgdb_arch {
>   * notified.
>   */
>  struct kgdb_io {
> -	int	(*read_char) (void);
> -	void	(*write_char) (u8);
> -	void	(*flush) (void);
> -	int	(*init) (void);
> -	void	(*late_init) (void);
> -	void	(*pre_exception) (void);
> -	void	(*post_exception) (void);
> +	const char	*name;
> +	int		(*read_char) (void);
> +	void		(*write_char) (u8);
> +	void		(*flush) (void);
> +	int		(*init) (void);
> +	void		(*pre_exception) (void);
> +	void		(*post_exception) (void);
>  };
>  
> -extern struct kgdb_io		kgdb_io_ops;
>  extern struct kgdb_arch		arch_kgdb_ops;
>  
>  int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops);
>  void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops);
>  
> -void kgdb8250_add_port(int i, struct uart_port *serial_req);
> -void __init
> -kgdb8250_add_platform_port(int i, struct plat_serial8250_port *serial_req);
> -
>  int kgdb_hex2long(char **ptr, long *long_val);
>  char *kgdb_mem2hex(char *mem, char *buf, int count);
>  char *kgdb_hex2mem(char *buf, char *mem, int count);
> Index: b/kernel/kgdb.c
> ===================================================================
> --- a/kernel/kgdb.c
> +++ b/kernel/kgdb.c
> @@ -53,8 +53,7 @@
>  #include <asm/atomic.h>
>  #include <asm/system.h>
>  
> -static int __initdata kgdb_internal_init_complete;
> -static int __initdata kgdb_break_asap;
> +static int kgdb_break_asap;
>  
>  struct kgdb_state {
>  	int			all_cpus_synced;
> @@ -89,30 +88,16 @@ int				kgdb_io_module_registered;
>  /* Guard for recursive entry */
>  static int			exception_level;
>  
> -#ifdef CONFIG_KGDB_ATTACH_WAIT
> -static int			attachwait = 1;
> -#else
> -static int			attachwait;
> -#endif
> -
> -module_param(attachwait, int, 0644);
> -MODULE_PARM_DESC(attachwait, "Wait for remote debugger after an exception");
> -
> -/* We provide a kgdb_io_ops structure that may be overriden. */
> -struct kgdb_io __weak		kgdb_io_ops;
> -EXPORT_SYMBOL_GPL(kgdb_io_ops);
> -
> -static struct kgdb_io		kgdb_io_ops_prev[KGDB_MAX_IO_HANDLERS];
> -
> -static int			kgdb_io_handler_cnt;
> +static struct kgdb_io		*kgdb_io_ops;
> +static DEFINE_SPINLOCK(kgdb_registration_lock);
>  
>  /*
>   * Holds information about breakpoints in a kernel. These breakpoints are
>   * added and removed by gdb.
>   */
> -struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS];
> -
> -struct kgdb_arch		*kgdb_ops = &arch_kgdb_ops;
> +struct kgdb_bkpt		kgdb_break[KGDB_MAX_BREAKPOINTS] = {
> +	[0 ... KGDB_MAX_BREAKPOINTS-1] = { .state = BP_UNDEFINED }
> +};
>  
>  /*
>   * KGDB locking is really nasty at places - but we really can only
> @@ -126,7 +111,9 @@ struct kgdb_arch		*kgdb_ops = &arch_kgdb
>  #define ROUNDUP_WAIT		640000	/* Arbitrary, increase if needed. */
>  #define BUF_THREAD_ID_SIZE	16
>  
> -static spinlock_t		slave_cpu_locks[NR_CPUS];
> +static spinlock_t		slave_cpu_locks[NR_CPUS] = {
> +	[0 ... NR_CPUS-1] = __SPIN_LOCK_UNLOCKED(slave_cpu_locks)
> +};
>  static atomic_t			cpu_in_debugger[NR_CPUS];
>  atomic_t			kgdb_setting_breakpoint;
>  
> @@ -185,7 +172,7 @@ int __weak kgdb_arch_set_breakpoint(unsi
>  	if (kgdb_get_mem((char *)addr, saved_instr, BREAK_INSTR_SIZE) != 0)
>  		return -1;
>  
> -	if (kgdb_set_mem((char *)addr, kgdb_ops->gdb_bpt_instr,
> +	if (kgdb_set_mem((char *)addr, arch_kgdb_ops.gdb_bpt_instr,
>  						BREAK_INSTR_SIZE) != 0)
>  		return -1;
>  	return 0;
> @@ -228,14 +215,12 @@ static void get_packet(char *buffer)
>  	int count;
>  	char ch;
>  
> -	if (!kgdb_io_ops.read_char)
> -		return;
>  	do {
>  		/*
>  		 * Spin and wait around for the start character, ignore all
>  		 * other characters:
>  		 */
> -		while ((ch = (kgdb_io_ops.read_char())) != '$')
> +		while ((ch = (kgdb_io_ops->read_char())) != '$')
>  			/* nothing */;
>  
>  		kgdb_connected = 1;
> @@ -248,7 +233,7 @@ static void get_packet(char *buffer)
>  		 * now, read until a # or end of buffer is found:
>  		 */
>  		while (count < (BUFMAX - 1)) {
> -			ch = kgdb_io_ops.read_char();
> +			ch = kgdb_io_ops->read_char();
>  			if (ch == '#')
>  				break;
>  			checksum = checksum + ch;
> @@ -258,17 +243,17 @@ static void get_packet(char *buffer)
>  		buffer[count] = 0;
>  
>  		if (ch == '#') {
> -			xmitcsum = hex(kgdb_io_ops.read_char()) << 4;
> -			xmitcsum += hex(kgdb_io_ops.read_char());
> +			xmitcsum = hex(kgdb_io_ops->read_char()) << 4;
> +			xmitcsum += hex(kgdb_io_ops->read_char());
>  
>  			if (checksum != xmitcsum)
>  				/* failed checksum */
> -				kgdb_io_ops.write_char('-');
> +				kgdb_io_ops->write_char('-');
>  			else
>  				/* successful transfer */
> -				kgdb_io_ops.write_char('+');
> -			if (kgdb_io_ops.flush)
> -				kgdb_io_ops.flush();
> +				kgdb_io_ops->write_char('+');
> +			if (kgdb_io_ops->flush)
> +				kgdb_io_ops->flush();
>  		}
>  	} while (checksum != xmitcsum);
>  }
> @@ -283,34 +268,31 @@ static void put_packet(char *buffer)
>  	int count;
>  	char ch;
>  
> -	if (!kgdb_io_ops.write_char)
> -		return;
> -
>  	/*
>  	 * $<packet info>#<checksum>.
>  	 */
>  	while (1) {
> -		kgdb_io_ops.write_char('$');
> +		kgdb_io_ops->write_char('$');
>  		checksum = 0;
>  		count = 0;
>  
>  		while ((ch = buffer[count])) {
> -			kgdb_io_ops.write_char(ch);
> +			kgdb_io_ops->write_char(ch);
>  			checksum += ch;
>  			count++;
>  		}
>  
> -		kgdb_io_ops.write_char('#');
> -		kgdb_io_ops.write_char(hexchars[checksum >> 4]);
> -		kgdb_io_ops.write_char(hexchars[checksum % 16]);
> -		if (kgdb_io_ops.flush)
> -			kgdb_io_ops.flush();
> +		kgdb_io_ops->write_char('#');
> +		kgdb_io_ops->write_char(hexchars[checksum >> 4]);
> +		kgdb_io_ops->write_char(hexchars[checksum % 16]);
> +		if (kgdb_io_ops->flush)
> +			kgdb_io_ops->flush();
>  
>  		/* Now see what we get in reply. */
> -		ch = kgdb_io_ops.read_char();
> +		ch = kgdb_io_ops->read_char();
>  
>  		if (ch == 3)
> -			ch = kgdb_io_ops.read_char();
> +			ch = kgdb_io_ops->read_char();
>  
>  		/* If we get an ACK, we are done. */
>  		if (ch == '+')
> @@ -323,9 +305,9 @@ static void put_packet(char *buffer)
>  		 * packet.
>  		 */
>  		if (ch == '$') {
> -			kgdb_io_ops.write_char('-');
> -			if (kgdb_io_ops.flush)
> -				kgdb_io_ops.flush();
> +			kgdb_io_ops->write_char('-');
> +			if (kgdb_io_ops->flush)
> +				kgdb_io_ops->flush();
>  			return;
>  		}
>  	}
> @@ -705,10 +687,10 @@ static struct task_struct *getthread(str
>  		return current;
>  
>  	if (num_online_cpus() && (tid >= pid_max + num_online_cpus() +
> -							kgdb_ops->shadowth))
> +							arch_kgdb_ops.shadowth))
>  		return NULL;
>  
> -	if (kgdb_ops->shadowth && (tid >= pid_max + num_online_cpus())) {
> +	if (arch_kgdb_ops.shadowth && (tid >= pid_max + num_online_cpus())) {
>  		return kgdb_get_shadow_thread(regs, tid - pid_max -
>  					      num_online_cpus());
>  	}
> @@ -809,8 +791,8 @@ static void kgdb_wait(struct pt_regs *re
>  	kgdb_info[cpu].task = NULL;
>  
>  	/* fix up hardware debug registers on local cpu */
> -	if (kgdb_ops->correct_hw_break)
> -		kgdb_ops->correct_hw_break();
> +	if (arch_kgdb_ops.correct_hw_break)
> +		arch_kgdb_ops.correct_hw_break();
>  
>  	/* Signal the master CPU that we are done: */
>  	atomic_set(&cpu_in_debugger[cpu], 0);
> @@ -1013,8 +995,8 @@ int remove_all_break(void)
>  	}
>  
>  	/* Clear hardware breakpoints. */
> -	if (kgdb_ops->remove_all_hw_break)
> -		kgdb_ops->remove_all_hw_break();
> +	if (arch_kgdb_ops.remove_all_hw_break)
> +		arch_kgdb_ops.remove_all_hw_break();
>  
>  	return 0;
>  }
> @@ -1073,14 +1055,12 @@ static void kgdb_msg_write(const char *s
>   */
>  int kgdb_io_ready(int print_wait)
>  {
> -	if (!kgdb_io_ops.read_char)
> +	if (!kgdb_io_ops)
>  		return 0;
>  	if (kgdb_connected)
>  		return 1;
>  	if (atomic_read(&kgdb_setting_breakpoint))
>  		return 1;
> -	if (!attachwait)
> -		return 0;
>  	if (print_wait)
>  		printk(KERN_CRIT "KGDB: Waiting for remote debugger\n");
>  	return 1;
> @@ -1147,7 +1127,7 @@ static void gdb_cmd_getregs(struct kgdb_
>  	 * in __schedule() sleeping, since all other CPUs
>  	 * are in kgdb_wait, and thus have debuggerinfo.
>  	 */
> -	if (kgdb_ops->shadowth &&
> +	if (arch_kgdb_ops.shadowth &&
>  			ks->kgdb_usethreadid >= pid_max + num_online_cpus()) {
>  
>  		shadowregs = kgdb_shadow_regs(ks->linux_regs,
> @@ -1279,7 +1259,7 @@ static int gdb_cmd_reboot(struct kgdb_st
>  /* Handle the 'q' query packets */
>  static void gdb_cmd_query(struct kgdb_state *ks)
>  {
> -	int numshadowth = num_online_cpus() + kgdb_ops->shadowth;
> +	int numshadowth = num_online_cpus() + arch_kgdb_ops.shadowth;
>  	struct task_struct *thread;
>  	unsigned char thref[8];
>  	char *ptr;
> @@ -1430,7 +1410,7 @@ static void gdb_cmd_break(struct kgdb_st
>  	unsigned long length;
>  	int error = 0;
>  
> -	if (kgdb_ops->set_hw_breakpoint && *bpt_type >= '1') {
> +	if (arch_kgdb_ops.set_hw_breakpoint && *bpt_type >= '1') {
>  		/* Unsupported */
>  		if (*bpt_type > '4')
>  			return;
> @@ -1444,7 +1424,7 @@ static void gdb_cmd_break(struct kgdb_st
>  	 * Test if this is a hardware breakpoint, and
>  	 * if we support it:
>  	 */
> -	if (*bpt_type == '1' && !(kgdb_ops->flags & KGDB_HW_BREAKPOINT))
> +	if (*bpt_type == '1' && !(arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT))
>  		/* Unsupported. */
>  		return;
>  
> @@ -1469,10 +1449,10 @@ static void gdb_cmd_break(struct kgdb_st
>  	else if (remcom_in_buffer[0] == 'z' && *bpt_type == '0')
>  		error = kgdb_remove_sw_break(addr);
>  	else if (remcom_in_buffer[0] == 'Z')
> -		error = kgdb_ops->set_hw_breakpoint(addr,
> +		error = arch_kgdb_ops.set_hw_breakpoint(addr,
>  			(int)length, *bpt_type);
>  	else if (remcom_in_buffer[0] == 'z')
> -		error = kgdb_ops->remove_hw_breakpoint(addr,
> +		error = arch_kgdb_ops.remove_hw_breakpoint(addr,
>  			(int) length, *bpt_type);
>  
>  	if (error == 0)
> @@ -1486,7 +1466,6 @@ static int gdb_cmd_exception_pass(struct
>  {
>  	/* C09 == pass exception
>  	 * C15 == detach kgdb, pass exception
> -	 * C30 == detach kgdb, stop attachwait, pass exception
>  	 */
>  	if (remcom_in_buffer[1] == '0' && remcom_in_buffer[2] == '9') {
>  
> @@ -1501,14 +1480,6 @@ static int gdb_cmd_exception_pass(struct
>  		kgdb_connected = 0;
>  		return 1;
>  
> -	} else if (remcom_in_buffer[1] == '3' && remcom_in_buffer[2] == '0') {
> -
> -		ks->pass_exception = 1;
> -		attachwait = 0;
> -		remcom_in_buffer[0] = 'D';
> -		remove_all_break();
> -		kgdb_connected = 0;
> -		return 1;
>  	} else {
>  		error_packet(remcom_out_buffer, -EINVAL);
>  		return 0;
> @@ -1557,7 +1528,7 @@ static int gdb_serial_stub(struct kgdb_s
>  	ks->kgdb_usethreadid = shadow_pid(kgdb_info[ks->cpu].task->pid);
>  	ks->pass_exception = 0;
>  
> -	while (kgdb_io_ops.read_char) {
> +	while (1) {
>  		error = 0;
>  
>  		/* Clear the out buffer. */
> @@ -1713,8 +1684,7 @@ kgdb_handle_exception(int evector, int s
>  	struct kgdb_state *ks = &kgdb_var;
>  	unsigned long flags;
>  	int error = 0;
> -	unsigned i;
> -	int cpu;
> +	int i, cpu;
>  
>  	ks->cpu			= raw_smp_processor_id();
>  	ks->all_cpus_synced	= 0;
> @@ -1788,8 +1758,8 @@ acquirelock:
>  		goto kgdb_restore;
>  
>  	/* Call the I/O driver's pre_exception routine */
> -	if (kgdb_io_ops.pre_exception)
> -		kgdb_io_ops.pre_exception();
> +	if (kgdb_io_ops->pre_exception)
> +		kgdb_io_ops->pre_exception();
>  
>  	kgdb_info[ks->cpu].debuggerinfo = ks->linux_regs;
>  	kgdb_info[ks->cpu].task = current;
> @@ -1847,15 +1817,15 @@ acquirelock:
>  	error = gdb_serial_stub(ks);
>  
>  	/* Call the I/O driver's post_exception routine */
> -	if (kgdb_io_ops.post_exception)
> -		kgdb_io_ops.post_exception();
> +	if (kgdb_io_ops->post_exception)
> +		kgdb_io_ops->post_exception();
>  
>  	kgdb_info[ks->cpu].debuggerinfo = NULL;
>  	kgdb_info[ks->cpu].task = NULL;
>  	atomic_set(&cpu_in_debugger[ks->cpu], 0);
>  
>  	if (!debugger_step || !kgdb_contthread) {
> -		for (i = 0; i < NR_CPUS; i++)
> +		for (i = NR_CPUS-1; i >= 0; i--)
>  			spin_unlock(&slave_cpu_locks[i]);
>  		/*
>  		 * Wait till all the CPUs have quit
> @@ -1968,32 +1938,10 @@ static struct console kgdbcons = {
>  };
>  #endif
>  
> -/*
> - * Initialization that needs to be done in either of our entry points.
> - */
> -static void __init kgdb_internal_init(void)
> -{
> -	int i;
> -
> -	if (kgdb_internal_init_complete)
> -		return;
> -	/* Initialize our spinlocks. */
> -	for (i = 0; i < NR_CPUS; i++)
> -		spin_lock_init(&slave_cpu_locks[i]);
> -
> -	for (i = 0; i < KGDB_MAX_BREAKPOINTS; i++)
> -		kgdb_break[i].state = BP_UNDEFINED;
> -
> -	/* Initialize the I/O handles */
> -	memset(&kgdb_io_ops_prev, 0, sizeof(kgdb_io_ops_prev));
> -
> -	kgdb_internal_init_complete = 1;
> -}
> -
>  #ifdef CONFIG_MAGIC_SYSRQ
>  static void sysrq_handle_gdb(int key, struct tty_struct *tty)
>  {
> -	if (!kgdb_io_ops.read_char) {
> +	if (!kgdb_io_ops) {
>  		printk(KERN_CRIT "ERROR: No KGDB I/O module available\n");
>  		return;
>  	}
> @@ -2061,180 +2009,74 @@ static void kgdb_unregister_hooks(void)
>  	}
>  }
>  
> -int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops)
> +static void kgdb_initial_breakpoint(void)
>  {
> +	kgdb_break_asap = 0;
>  
> -	if (!local_kgdb_io_ops->init)
> -		return -EINVAL;
> -	if (kgdb_connected) {
> -		printk(KERN_ERR "kgdb: Cannot load I/O module while KGDB "
> -		       "connected.\n");
> -		return -EINVAL;
> -	}
> +	printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
> +	breakpoint();
> +}
>  
> -	/* Save the old values so they can be restored */
> -	if (kgdb_io_handler_cnt >= KGDB_MAX_IO_HANDLERS) {
> -		printk(KERN_ERR "kgdb: No more I/O handles available.\n");
> -		return -EINVAL;
> -	}
> +int kgdb_register_io_module(struct kgdb_io *new_kgdb_io_ops)
> +{
> +	int err;
>  
> -	/*
> -	 * Check to see if there is an existing driver and if so save its
> -	 * values.  Also check to make sure the same driver was not trying
> -	 * to re-register.
> -	 */
> -	if (kgdb_io_ops.read_char != NULL &&
> -		kgdb_io_ops.read_char != local_kgdb_io_ops->read_char) {
> -		memcpy(&kgdb_io_ops_prev[kgdb_io_handler_cnt],
> -		       &kgdb_io_ops, sizeof(struct kgdb_io));
> -		kgdb_io_handler_cnt++;
> -	}
> +	spin_lock(&kgdb_registration_lock);
>  
> -	/* Initialize the io values for this module */
> -	memcpy(&kgdb_io_ops, local_kgdb_io_ops, sizeof(struct kgdb_io));
> +	if (kgdb_io_ops) {
> +		spin_unlock(&kgdb_registration_lock);
>  
> -	/* Make the call to register kgdb if is not initialized */
> -	kgdb_register_hooks();
> +		printk(KERN_ERR "kgdb: Another I/O driver is already "
> +				"registered with KGDB.\n");
> +		return -EBUSY;
> +	}
>  
> -	return 0;
> -}
> -EXPORT_SYMBOL_GPL(kgdb_register_io_module);
> +	if (new_kgdb_io_ops->init) {
> +		err = new_kgdb_io_ops->init();
> +		if (err) {
> +			spin_unlock(&kgdb_registration_lock);
> +			return err;
> +		}
> +	}
>  
> -void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops)
> -{
> -	int i;
> +	kgdb_io_ops = new_kgdb_io_ops;
>  
> -	/*
> -	 * Unregister KGDB if there were no other prior io hooks, else
> -	 * restore the io hooks.
> -	 */
> -	if (kgdb_io_handler_cnt > 0 && kgdb_io_ops_prev[0].read_char != NULL) {
> -		/*
> -		 * First check if the hook that is in use is the one being
> -		 * removed:
> -		 */
> -		if (kgdb_io_ops.read_char == local_kgdb_io_ops->read_char) {
> -			/*
> -			 * Set 'i' to the value of where the list should be
> -			 * shifed:
> -			 */
> -			i = kgdb_io_handler_cnt - 1;
> -			memcpy(&kgdb_io_ops, &kgdb_io_ops_prev[i],
> -			       sizeof(struct kgdb_io));
> -		} else {
> -			/*
> -			 * Simple case to remove an entry for an I/O handler
> -			 * that is not in use:
> -			 */
> -			for (i = 0; i < kgdb_io_handler_cnt; i++) {
> -				if (kgdb_io_ops_prev[i].read_char ==
> -				    local_kgdb_io_ops->read_char)
> -					break;
> -			}
> -		}
> +	spin_unlock(&kgdb_registration_lock);
>  
> -		/*
> -		 * Shift all the entries in the handler array so it is
> -		 * ordered from oldest to newest.
> -		 */
> -		kgdb_io_handler_cnt--;
> -		for (; i < kgdb_io_handler_cnt; i++) {
> -			memcpy(&kgdb_io_ops_prev[i], &kgdb_io_ops_prev[i + 1],
> -			       sizeof(struct kgdb_io));
> -		}
> +	printk(KERN_INFO "kgdb: Registered I/O driver %s.\n",
> +	       new_kgdb_io_ops->name);
>  
> -		/*
> -		 * Handle the case if we are on the last element and set it
> -		 * to NULL;
> -		 */
> -		memset(&kgdb_io_ops_prev[kgdb_io_handler_cnt], 0,
> -				sizeof(struct kgdb_io));
> +	/* Arm KGDB now. */
> +	kgdb_register_hooks();
>  
> -		if (kgdb_connected) {
> -			printk(KERN_ERR "kgdb: WARNING: I/O method changed "
> -			       "while kgdb was connected state.\n");
> -		}
> -	} else {
> -		/*
> -		 * KGDB is no longer able to communicate out, so
> -		 * unregister our hooks and reset state:
> -		 */
> -		kgdb_unregister_hooks();
> -		if (kgdb_connected) {
> -			printk(KERN_CRIT "kgdb: I/O module was unloaded while "
> -					"a debugging session was running.  "
> -					"KGDB will be reset.\n");
> -			if (remove_all_break() < 0)
> -				printk(KERN_CRIT "kgdb: Reset failed.\n");
> -			kgdb_connected = 0;
> -		}
> -		memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io));
> -	}
> -}
> -EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
> +	if (kgdb_break_asap)
> +		kgdb_initial_breakpoint();
>  
> -static void __init kgdb_initial_breakpoint(void)
> -{
> -	printk(KERN_CRIT "kgdb: Waiting for connection from remote gdb...\n");
> -	breakpoint();
> +	return 0;
>  }
> +EXPORT_SYMBOL_GPL(kgdb_register_io_module);
>  
> -/*
> - * This function can be called very early, either via early_param() or
> - * an explicit breakpoint() early on.
> - */
> -static void __init kgdb_early_entry(void)
> +void kgdb_unregister_io_module(struct kgdb_io *old_kgdb_io_ops)
>  {
> -	/*
> -	 * Initialize the KGDB I/O module
> -	 * For early entry kgdb_io_ops.init must be defined
> -	 */
> -	if (!kgdb_io_ops.init || kgdb_io_ops.init()) {
> -		printk(KERN_INFO "kgdb: Defering I/O setup to late init.\n");
> -		return;
> -	}
> -	kgdb_internal_init();
> -	kgdb_register_io_module(&kgdb_io_ops);
> -}
> +	BUG_ON(kgdb_connected);
>  
> -/*
> - * This function will always be invoked to make sure that KGDB will grab
> - * what it needs to so that if something happens while the system is
> - * running, KGDB will get involved.  If kgdb_early_entry() has already
> - * been invoked, there is little we need to do.
> - */
> -static int __init kgdb_late_entry(void)
> -{
>  	/*
> -	 * Late entry may be the first entry, so all initialization
> -	 * routines must be called here as well as the early entry
> +	 * KGDB is no longer able to communicate out, so
> +	 * unregister our hooks and reset state.
>  	 */
> -	kgdb_internal_init();
> +	kgdb_unregister_hooks();
>  
> -	if (!kgdb_io_module_registered &&
> -		(!kgdb_io_ops.init || kgdb_io_ops.init())) {
> -		/*
> -		 * When KGDB allows I/O via modules and the core I/O init
> -		 * fails KGDB must default to defering the I/O setup, and
> -		 * appropriately print an error about it.
> -		 */
> -		printk(KERN_INFO "kgdb: Defering I/O setup to module.\n");
> -		memset(&kgdb_io_ops, 0, sizeof(struct kgdb_io));
> -		kgdb_break_asap = 0;
> -		return 0;
> -	}
> -	kgdb_register_io_module(&kgdb_io_ops);
> +	spin_lock(&kgdb_registration_lock);
>  
> -	/* Execute any late init I/O routines. */
> -	if (kgdb_io_ops.late_init)
> -		kgdb_io_ops.late_init();
> +	WARN_ON(kgdb_io_ops != old_kgdb_io_ops);
> +	kgdb_io_ops = NULL;
>  
> -	if (kgdb_break_asap)
> -		kgdb_initial_breakpoint();
> +	spin_unlock(&kgdb_registration_lock);
>  
> -	return 0;
> +	printk(KERN_INFO "kgdb: Unregistered I/O driver %s, debugger "
> +	                 "disabled.\n", old_kgdb_io_ops->name);
>  }
> -late_initcall(kgdb_late_entry);
> +EXPORT_SYMBOL_GPL(kgdb_unregister_io_module);
>  
>  /*
>   * This function will generate a breakpoint exception.  It is used at the
> @@ -2264,38 +2106,23 @@ kgdb_notify_reboot(struct notifier_block
>  	if (!kgdb_connected || atomic_read(&debugger_active) != 0)
>  		return 0;
>  
> -	if ((code == SYS_RESTART) || (code == SYS_HALT) ||
> -						(code == SYS_POWER_OFF)) {
> +	if (code == SYS_RESTART || code == SYS_HALT || code == SYS_POWER_OFF) {
>  		local_irq_save(flags);
>  		put_packet("X00");
> +		kgdb_connected = 0;
>  		local_irq_restore(flags);
>  	}
>  	return NOTIFY_DONE;
>  }
>  
> -static int __init opt_kgdb_attachwait(char *str)
> -{
> -	attachwait = 1;
> -
> -	return 0;
> -}
> -
> -static int __init opt_kgdb_enter(char *str)
> +static int __init opt_kgdb_wait(char *str)
>  {
> -	/* We've already done this by an explicit breakpoint() call. */
> -	if  (kgdb_internal_init_complete)
> -		return 0;
> -
> -	kgdb_early_entry();
> -	attachwait = 1;
> +	kgdb_break_asap = 1;
>  
>  	if (kgdb_io_module_registered)
>  		kgdb_initial_breakpoint();
> -	else
> -		kgdb_break_asap = 1;
>  
>  	return 0;
>  }
>  
> -early_param("kgdbwait", opt_kgdb_enter);
> -early_param("attachwait", opt_kgdb_attachwait);
> +early_param("kgdbwait", opt_kgdb_wait);
> Index: b/lib/Kconfig.kgdb
> ===================================================================
> --- a/lib/Kconfig.kgdb
> +++ b/lib/Kconfig.kgdb
> @@ -15,126 +15,6 @@ config KGDB_ARCH_HAS_SHADOW_INFO
>  	bool
>  	depends on KGDB
>  
> -config SERIAL_POLL
> -	bool
> -
> -choice
> -	prompt "Method for KGDB communication"
> -	depends on KGDB
> -	default KGDBOC_NOMODULE
> -	help
> -	  There are a number of different ways in which you can communicate
> -	  with KGDB.  The most common is via serial, with the 8250 driver
> -	  (should your hardware have an 8250, or ns1655x style uart).
> -	  You can elect to have one core I/O driver that is built into the
> -	  kernel for debugging as the kernel is booting, or using only
> -	  kernel modules.
> -
> -config KGDB_ONLY_MODULES
> -	bool "KGDB: Use only kernel modules for I/O"
> -	depends on MODULES
> -	help
> -	  Use only kernel modules to configure KGDB I/O after the
> -	  kernel is booted.
> -
> -config KGDB_8250_NOMODULE
> -	bool "KGDB: On generic serial port (8250)"
> -	select KGDB_8250
> -	help
> -	  Uses generic serial port (8250) to communicate with the host
> -	  GDB.  This is independent of the normal (SERIAL_8250) driver
> -	  for this chipset.
> -
> -config KGDBOC_NOMODULE
> -	bool "KGDB: On Console - in kernel"
> -	select KGDBOC
> -	select SERIAL_POLL
> -	help
> -	  Uses the SERIAL_POLL API to multiplex the console driver
> -	  output with the debugger output when the debugger is active.
> -	  To break into the debugger initially you must use the sysrq
> -	  request with the "g" for gdb.
> -
> -endchoice
> -
> -config KGDBOC
> -	tristate "KGDB: Share serial console and kgdb port" if !KGDBOC_NOMODULE
> -	depends on m && KGDB
> -	default m
> -	select SERIAL_POLL
> -	select MAGIC_SYSRQ
> -	help
> -	  Share a serial console with kgdb.  The sysrq-g must be used
> -	  to break in initially.
> -
> -config KGDB_8250
> -	tristate "KGDB: On generic serial port (8250)" if !KGDB_8250_NOMODULE
> -	depends on m && KGDB_ONLY_MODULES
> -	help
> -	  Uses generic serial port (8250) to communicate with the host
> -	  GDB.  This is independent of the normal (SERIAL_8250) driver
> -	  for this chipset.
> -
> -config KGDB_SIMPLE_SERIAL
> -	bool "Simple configuration of KGDB serial port"
> -	depends on KGDB_8250_NOMODULE
> -	default y
> -	help
> -	  If you say Y here, you will only have to pick the baud rate
> -	  and port number that you wish to use for KGDB.  Note that this
> -	  only works on architectures that register known serial ports
> -	  early on.  If you say N, you will have to provide, either here
> -	  or on the command line, the type (I/O or MMIO), IRQ and
> -	  address to use.  If in doubt, say Y.
> -
> -config KGDB_SERIAL_STATIC
> -	bool "Configure KGDB serial parameters statically"
> -	depends on KGDB_8250
> -	default n
> -	help
> -	  If you turn this on, you do not have to specify the kgdb
> -	  serial paramters via kernel boot arguments.  It also means
> -	  that kgdb will configure the serial port on boot.
> -
> -config KGDB_BAUDRATE
> -	int "Debug serial port baud rate"
> -	depends on KGDB_SERIAL_STATIC && KGDB_SIMPLE_SERIAL && KGDB_8250
> -	default "115200"
> -	help
> -	  gdb and the kernel stub need to agree on the baud rate to be
> -	  used.  Standard rates from 9600 to 115200 are allowed, and this
> -	  may be overridden via the commandline.
> -
> -config KGDB_PORT_NUM
> -	int "Serial port number for KGDB"
> -	range 0 3
> -	depends on KGDB_SERIAL_STATIC && KGDB_SIMPLE_SERIAL && KGDB_8250
> -	default "0"
> -	help
> -	  Pick the port number (0 based) for KGDB to use.
> -
> -config KGDB_8250_CONF_STRING
> -	string "Configuration string for KGDB"
> -	depends on KGDB_SERIAL_STATIC && (KGDB_8250 = y) && \
> -		!KGDB_SIMPLE_SERIAL && KGDB_8250
> -	default "io,2f8,115200,3" if X86
> -	help
> -	  The format of this string should be <io or mmio>,
> -	  <address>,<baud rate>,<irq>.  For example, on an i386 box,
> -	  to use the serial port located at 0x2f8, IRQ 3, at 115200 baud
> -	  use:  io,2f8,115200,3
> -
> -config KGDB_ATTACH_WAIT
> -	bool "KGDB: Wait for debugger to attach on an unknown exception"
> -	depends on KGDB
> -	default (KGDB_8250 = y)
> -	help
> -	  If a panic occurs, or any kind of exception, the kgdb will
> -	  stop and wait for a debugger to attach.  This sets the
> -	  default behavior for waiting for the debugger to attach.  This
> -	  value can also be changed at runtime through
> -	  /sys/module/kgdb/parameters/attachwait
> -
>  config KGDB_CONSOLE
>  	bool "KGDB: Console messages through gdb"
>  	depends on KGDB
> @@ -147,3 +27,36 @@ config KGDB_CONSOLE
>  	  to crash, and typically reboot.  For this reason, it is preferable
>  	  to use NETCONSOLE in conjunction with KGDBOE instead of
>  	  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|mmap>,<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.
> +
> +config KGDBOC
> +	tristate "KGDB: Share serial console and kgdb port"
> +	depends on KGDB
> +	select SERIAL_POLL
> +	select MAGIC_SYSRQ
> +	help
> +	  Share a serial console with kgdb.  The sysrq-g must be used
> +	  to break in initially.
> Index: b/drivers/serial/kgdboc.c
> ===================================================================
> --- a/drivers/serial/kgdboc.c
> +++ b/drivers/serial/kgdboc.c
> @@ -16,8 +16,8 @@
>  #include <linux/kernel.h>
>  #include <linux/kgdb.h>
>  #include <linux/tty.h>
> +#include <linux/ctype.h>
>  
> -#define NOT_CONFIGURED_STRING "not_configured"
>  #define MAX_KGDBOC_CONFIG_STR 40
>  
>  static struct kgdb_io kgdboc_io_ops;
> @@ -27,7 +27,7 @@ static int configured = -1;
>  
>  MODULE_DESCRIPTION("KGDB Console TTY Driver");
>  MODULE_LICENSE("GPL");
> -static char config[MAX_KGDBOC_CONFIG_STR] = NOT_CONFIGURED_STRING;
> +static char config[MAX_KGDBOC_CONFIG_STR];
>  static struct kparam_string kps = {
>  	.string = config,
>  	.maxlen = MAX_KGDBOC_CONFIG_STR,
> @@ -40,13 +40,9 @@ static int kgdboc_option_setup(char *opt
>  {
>  	if (strlen(opt) > MAX_KGDBOC_CONFIG_STR) {
>  		printk(KERN_ERR "kgdboc: config string too long\n");
> -		strcpy(config, NOT_CONFIGURED_STRING);
> -		return 1;
> +		return -ENOSPC;
>  	}
> -
> -	/* If we're being given a new configuration, copy it in. */
> -	if (opt != config)
> -		strcpy(config, opt);
> +	strcpy(config, opt);
>  	return 0;
>  }
>  __setup("kgdboc=", kgdboc_option_setup);
> @@ -54,18 +50,21 @@ __setup("kgdboc=", kgdboc_option_setup);
>  static int configure_kgdboc(void)
>  {
>  	struct tty_driver *p;
> -	int ret = 1;
> +	int err;
>  	char *str;
>  	int tty_line = 0;
>  
> -	kgdboc_option_setup(config);
> -	if (strcmp(config, NOT_CONFIGURED_STRING) == 0)
> -		goto err;
> +	err = kgdboc_option_setup(config);
> +	if (err || !strlen(config) || isspace(config[0]))
> +		goto noconfig;
> +
> +	err = -ENODEV;
>  
>  	/* Search through the tty devices to look for a match */
> +	// FIXME: API violation, at least missing lock protection
>  	list_for_each_entry(p, &tty_drivers, tty_drivers) {
> -		if (!(p->type == TTY_DRIVER_TYPE_SERIAL &&
> -			  strncmp(config, p->name, strlen(p->name)) == 0))
> +		if (p->type != TTY_DRIVER_TYPE_SERIAL ||
> +		    strncmp(config, p->name, strlen(p->name)) != 0)
>  			continue;
>  		str = config + strlen(p->name);
>  		tty_line = simple_strtoul(str, &str, 10);
> @@ -78,29 +77,24 @@ static int configure_kgdboc(void)
>  			p->poll_init && !p->poll_init(p, tty_line, str)) {
>  			kgdb_tty_driver = p;
>  			kgdb_tty_line = tty_line;
> -			ret = 0;
> +			err = 0;
>  			break;
>  		}
>  	}
> -	if (ret) {
> -		printk(KERN_ERR "kgdboc: invalid parmater: %s\n", config);
> -		printk(KERN_ERR "Usage kgdboc=<serial_device>[,baud]\n");
> -		goto err;
> -	}
> +	if (err)
> +		goto noconfig;
>  
> -	if (kgdb_register_io_module(&kgdboc_io_ops)) {
> -		printk(KERN_ERR "KGDB IO registration failed\n");
> -		goto err;
> -	}
> -	configured = 1;
> +	err = kgdb_register_io_module(&kgdboc_io_ops);
> +	if (err)
> +		goto noconfig;
>  
> -	printk(KERN_INFO "kgdboc: Debugging enabled\n");
> +	configured = 1;
>  	return 0;
>  
> -err:
> -	strcpy(config, NOT_CONFIGURED_STRING);
> +noconfig:
> +	config[0] = 0;
>  	configured = 0;
> -	return -EINVAL;
> +	return err;
>  
>  }
>  
> @@ -110,16 +104,13 @@ static int init_kgdboc(void)
>  	if (configured == 1)
>  		return 0;
>  
> -	if (configure_kgdboc())
> -		printk(KERN_INFO "kgdboc: Driver loaded in"
> -		" not_configured state\n");
> -
> -	return 0;
> +	return configure_kgdboc();
>  }
>  
>  static void cleanup_kgdboc(void)
>  {
> -	kgdb_unregister_io_module(&kgdboc_io_ops);
> +	if (configured == 1)
> +		kgdb_unregister_io_module(&kgdboc_io_ops);
>  }
>  
>  static int kgdboc_get_char(void)
> @@ -137,67 +128,30 @@ static void kgdboc_put_char(u8 chr)
>  static int param_set_kgdboc_var(const char *kmessage,
>  		struct kernel_param *kp)
>  {
> -	char kmessage_save[MAX_KGDBOC_CONFIG_STR];
> -	int msg_len = strlen(kmessage);
> -
> -	if (msg_len + 1 > MAX_KGDBOC_CONFIG_STR) {
> -		printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
> -		       kp->name, MAX_KGDBOC_CONFIG_STR - 1);
> +	if (strlen(kmessage) >= MAX_KGDBOC_CONFIG_STR) {
> +		printk(KERN_ERR "kgdboc: config string too long\n");
>  		return -ENOSPC;
>  	}
>  
>  	/* Only copy in the string if the init function has not run yet */
>  	if (configured < 0) {
> -		strncpy(config, kmessage, sizeof(config));
> +		strcpy(config, kmessage);
>  		return 0;
>  	}
>  
>  	if (kgdb_connected) {
>  		printk(KERN_ERR "kgdboc: Cannot reconfigure while KGDB is "
>  				"connected.\n");
> -		return 0;
> +		return -EBUSY;
>  	}
>  
> -	/* Start the reconfiguration process by saving the old string */
> -	strncpy(kmessage_save, config, sizeof(kmessage_save));
> -
> -
> -	/* Copy in the new param and strip out invalid characters so we
> -	 * can optionally specify the MAC.
> -	 */
> -	strncpy(config, kmessage, sizeof(config));
> -	msg_len--;
> -	while (msg_len > 0 &&
> -			(config[msg_len] < ',' || config[msg_len] > 'f')) {
> -		config[msg_len] = '\0';
> -		msg_len--;
> -	}
> -
> -	/* Check to see if we are unconfiguring the io module and that it
> -	 * was in a fully configured state, as this is the only time that
> -	 * netpoll_cleanup should get called
> -	 */
> -	if (configured == 1 && strcmp(config, NOT_CONFIGURED_STRING) == 0) {
> -		printk(KERN_INFO "kgdboc: reverting to unconfigured state\n");
> -		cleanup_kgdboc();
> -		return 0;
> -	} else
> -		/* Go and configure with the new params. */
> -		configure_kgdboc();
> +	strcpy(config, kmessage);
>  
>  	if (configured == 1)
> -		return 0;
> +		cleanup_kgdboc();
>  
> -	/* If the new string was invalid, revert to the previous state, which
> -	 * is at a minimum not_configured. */
> -	strncpy(config, kmessage_save, sizeof(config));
> -	if (strcmp(kmessage_save, NOT_CONFIGURED_STRING) != 0) {
> -		printk(KERN_INFO "kgdboc: reverting to prior configuration\n");
> -		/* revert back to the original config */
> -		strncpy(config, kmessage_save, sizeof(config));
> -		configure_kgdboc();
> -	}
> -	return 0;
> +	/* Go and configure with the new params. */
> +	return configure_kgdboc();
>  }
>  
>  static void kgdboc_pre_exp_handler(void)
> @@ -215,9 +169,9 @@ static void kgdboc_post_exp_handler(void
>  }
>  
>  static struct kgdb_io kgdboc_io_ops = {
> +	.name = "kgdboc",
>  	.read_char = kgdboc_get_char,
>  	.write_char = kgdboc_put_char,
> -	.init = init_kgdboc,
>  	.pre_exception = kgdboc_pre_exp_handler,
>  	.post_exception = kgdboc_post_exp_handler,
>  };
> @@ -225,4 +179,4 @@ static struct kgdb_io kgdboc_io_ops = {
>  module_init(init_kgdboc);
>  module_exit(cleanup_kgdboc);
>  module_param_call(kgdboc, param_set_kgdboc_var, param_get_string, &kps, 0644);
> -MODULE_PARM_DESC(kgdboc, " kgdboc=<serial_device>[,baud]\n");
> +MODULE_PARM_DESC(kgdboc, "<serial_device>[,baud]");
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

As one of the users who likes to see kgdb in mainline, can I ask what
should I expect, when do you think it will be ready for mainline inclusion?

Best regards,
	Maxim Levitsky

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] KGDB: Major refactoring
  2008-02-05 23:34 [PATCH 1/3] KGDB: Major refactoring Jan Kiszka
  2008-02-05 23:44 ` Maxim Levitsky
@ 2008-02-06  4:40 ` Jason Wessel
  2008-02-07  0:13 ` Ingo Molnar
  2 siblings, 0 replies; 7+ messages in thread
From: Jason Wessel @ 2008-02-06  4:40 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Ingo Molnar, Linux Kernel Mailing List, kgdb-bugreport,
	Thomas Gleixner, H. Peter Anvin

Jan Kiszka wrote:
> As most changes are tightly coupled, this refactoring patch for
> KGDB_8250 as well as the core and the new KGDBOC driver comes as a
> single chunk. The changes are:
>  - Reorganized configuration: I/O drivers can be independently
>    configured as module or built-in
>  - Dynamic reconfiguration for KGDB_8250 (just like for KGDBOC)
>  - Reworked KGDB_8250 configuration string format
>  - attachwait removed, arming the debugger via assigning an I/O driver
>    implies "attachwait"
>  - Cleaned up I/O driver managment of the core
>  - Matured the various boot-up, configure, unconfigure code paths for
>    both I/O drivers
>  - IRQ vs. KGDB_CONSOLE-output SMP race fixed for KGDB_8250
>  - Reduced and cleaned up hooks into serial_core/8250
>  - Kconfig cleanups
>
> What we no longer have:
>  - Simple serial configuration for _early_ debugging, use the io/mem
>    format instead or wait until the debugger is able to resolve "ttySx"
>    during late-init
>
> To-do:
>  - KGDBOC does not yet cleanly interacts with the TTY subsystem to
>    attach to some console
>
> Signed-off-by: Jan Kiszka <jan.kiszka@web.de>
>   

Jan,

I pulled in all your changes and made some minor white space fixes. 

I started the 2.6.25 branch with all Ingo's changes, your changes and
several additional patches I received.

http://git.kernel.org/?p=linux/kernel/git/jwessel/linux-2.6-kgdb.git;a=summary

Thanks,
Jason.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] KGDB: Major refactoring
  2008-02-05 23:34 [PATCH 1/3] KGDB: Major refactoring Jan Kiszka
  2008-02-05 23:44 ` Maxim Levitsky
  2008-02-06  4:40 ` Jason Wessel
@ 2008-02-07  0:13 ` Ingo Molnar
  2008-02-07  0:31   ` Jason Wessel
  2 siblings, 1 reply; 7+ messages in thread
From: Ingo Molnar @ 2008-02-07  0:13 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Jason Wessel, Linux Kernel Mailing List, kgdb-bugreport,
	Thomas Gleixner, H. Peter Anvin


* Jan Kiszka <jan.kiszka@web.de> wrote:

> As most changes are tightly coupled, this refactoring patch for
> KGDB_8250 as well as the core and the new KGDBOC driver comes as a
> single chunk. The changes are:
>  - Reorganized configuration: I/O drivers can be independently
>    configured as module or built-in
>  - Dynamic reconfiguration for KGDB_8250 (just like for KGDBOC)
>  - Reworked KGDB_8250 configuration string format
>  - attachwait removed, arming the debugger via assigning an I/O driver
>    implies "attachwait"
>  - Cleaned up I/O driver managment of the core
>  - Matured the various boot-up, configure, unconfigure code paths for
>    both I/O drivers
>  - IRQ vs. KGDB_CONSOLE-output SMP race fixed for KGDB_8250
>  - Reduced and cleaned up hooks into serial_core/8250
>  - Kconfig cleanups

great stuff! I've picked these cleanups up into x86.git. (will pick up 
Jason's commits too)

Could you try something else too perhaps, which would be way useful for 
me: to add a sysctl flag (or something like that) to change kgdboc to 
accept a Ctrl-C and break into kgdb mode? [this means a simple Ctrl-C on 
a kgdboc line would break into KGDB as well - but that would be an 
acceptable price.] Right now kgdboc just hangs when gdb attaches - i 
have to generate a SysRq sequence via a terminal emulator to break it 
into KGDB mode.

This would make kgdboc way more practical without having to resort to a 
protocol splitting proxy, etc.

	Ingo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] KGDB: Major refactoring
  2008-02-07  0:13 ` Ingo Molnar
@ 2008-02-07  0:31   ` Jason Wessel
  2008-02-07  7:47     ` Jan Kiszka
  2008-02-07 12:13     ` Ingo Molnar
  0 siblings, 2 replies; 7+ messages in thread
From: Jason Wessel @ 2008-02-07  0:31 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Jan Kiszka, Linux Kernel Mailing List, kgdb-bugreport,
	Thomas Gleixner, H. Peter Anvin

Ingo Molnar wrote:
> * Jan Kiszka <jan.kiszka@web.de> wrote:
>
>   
>> As most changes are tightly coupled, this refactoring patch for
>> KGDB_8250 as well as the core and the new KGDBOC driver comes as a
>> single chunk. The changes are:
>>  - Reorganized configuration: I/O drivers can be independently
>>    configured as module or built-in
>>  - Dynamic reconfiguration for KGDB_8250 (just like for KGDBOC)
>>  - Reworked KGDB_8250 configuration string format
>>  - attachwait removed, arming the debugger via assigning an I/O driver
>>    implies "attachwait"
>>  - Cleaned up I/O driver managment of the core
>>  - Matured the various boot-up, configure, unconfigure code paths for
>>    both I/O drivers
>>  - IRQ vs. KGDB_CONSOLE-output SMP race fixed for KGDB_8250
>>  - Reduced and cleaned up hooks into serial_core/8250
>>  - Kconfig cleanups
>>     
>
> great stuff! I've picked these cleanups up into x86.git. (will pick up 
> Jason's commits too)
>
> Could you try something else too perhaps, which would be way useful for 
> me: to add a sysctl flag (or something like that) to change kgdboc to 
> accept a Ctrl-C and break into kgdb mode? [this means a simple Ctrl-C on 
> a kgdboc line would break into KGDB as well - but that would be an 
> acceptable price.] Right now kgdboc just hangs when gdb attaches - i 
> have to generate a SysRq sequence via a terminal emulator to break it 
> into KGDB mode.
>   

FYI, even if you were to hack in a control-c vs sysrq, gdb will still
hang on connect because it does not issue a break of any kind when it
connects.  It assumes the connection is in a usable state.

The proxy spliter automatically sends the break (or in the current case
the sysrq g)
> This would make kgdboc way more practical without having to resort to a 
> protocol splitting proxy, etc.
>
> 	Ingo
>   


Jason.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] KGDB: Major refactoring
  2008-02-07  0:31   ` Jason Wessel
@ 2008-02-07  7:47     ` Jan Kiszka
  2008-02-07 12:13     ` Ingo Molnar
  1 sibling, 0 replies; 7+ messages in thread
From: Jan Kiszka @ 2008-02-07  7:47 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Ingo Molnar, Linux Kernel Mailing List, kgdb-bugreport,
	Thomas Gleixner, H. Peter Anvin

[-- Attachment #1: Type: text/plain, Size: 2260 bytes --]

Jason Wessel wrote:
> Ingo Molnar wrote:
>> * Jan Kiszka <jan.kiszka@web.de> wrote:
>>
>>   
>>> As most changes are tightly coupled, this refactoring patch for
>>> KGDB_8250 as well as the core and the new KGDBOC driver comes as a
>>> single chunk. The changes are:
>>>  - Reorganized configuration: I/O drivers can be independently
>>>    configured as module or built-in
>>>  - Dynamic reconfiguration for KGDB_8250 (just like for KGDBOC)
>>>  - Reworked KGDB_8250 configuration string format
>>>  - attachwait removed, arming the debugger via assigning an I/O driver
>>>    implies "attachwait"
>>>  - Cleaned up I/O driver managment of the core
>>>  - Matured the various boot-up, configure, unconfigure code paths for
>>>    both I/O drivers
>>>  - IRQ vs. KGDB_CONSOLE-output SMP race fixed for KGDB_8250
>>>  - Reduced and cleaned up hooks into serial_core/8250
>>>  - Kconfig cleanups
>>>     
>> great stuff! I've picked these cleanups up into x86.git. (will pick up 
>> Jason's commits too)
>>
>> Could you try something else too perhaps, which would be way useful for 
>> me: to add a sysctl flag (or something like that) to change kgdboc to 
>> accept a Ctrl-C and break into kgdb mode? [this means a simple Ctrl-C on 
>> a kgdboc line would break into KGDB as well - but that would be an 
>> acceptable price.] Right now kgdboc just hangs when gdb attaches - i 
>> have to generate a SysRq sequence via a terminal emulator to break it 
>> into KGDB mode.
>>   
> 
> FYI, even if you were to hack in a control-c vs sysrq, gdb will still

And quite a bit of "hacking" would be required here, because the sysrq
hook is built upon the assumption that a hardware break starts the
sequence, not that just a single special character comes in. Changing
this means changing the drivers, not just some central hook function.

> hang on connect because it does not issue a break of any kind when it
> connects.  It assumes the connection is in a usable state.
> 
> The proxy spliter automatically sends the break (or in the current case
> the sysrq g)
>> This would make kgdboc way more practical without having to resort to a 
>> protocol splitting proxy, etc.
>>
>> 	Ingo
>>   
> 
> 
> Jason.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 254 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/3] KGDB: Major refactoring
  2008-02-07  0:31   ` Jason Wessel
  2008-02-07  7:47     ` Jan Kiszka
@ 2008-02-07 12:13     ` Ingo Molnar
  1 sibling, 0 replies; 7+ messages in thread
From: Ingo Molnar @ 2008-02-07 12:13 UTC (permalink / raw)
  To: Jason Wessel
  Cc: Jan Kiszka, Linux Kernel Mailing List, kgdb-bugreport,
	Thomas Gleixner, H. Peter Anvin


* Jason Wessel <jason.wessel@windriver.com> wrote:

> > Could you try something else too perhaps, which would be way useful 
> > for me: to add a sysctl flag (or something like that) to change 
> > kgdboc to accept a Ctrl-C and break into kgdb mode? [this means a 
> > simple Ctrl-C on a kgdboc line would break into KGDB as well - but 
> > that would be an acceptable price.] Right now kgdboc just hangs when 
> > gdb attaches - i have to generate a SysRq sequence via a terminal 
> > emulator to break it into KGDB mode.
> 
> FYI, even if you were to hack in a control-c vs sysrq, gdb will still 
> hang on connect because it does not issue a break of any kind when it 
> connects.  It assumes the connection is in a usable state.

sigh. That's quite a usability barrier IMHO.

> The proxy spliter automatically sends the break (or in the current 
> case the sysrq g)

any link to the proxy splitter? Googling for "kgdb proxy splitter" did 
not yield anything obviously on-topic.

	Ingo

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2008-02-07 12:14 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-02-05 23:34 [PATCH 1/3] KGDB: Major refactoring Jan Kiszka
2008-02-05 23:44 ` Maxim Levitsky
2008-02-06  4:40 ` Jason Wessel
2008-02-07  0:13 ` Ingo Molnar
2008-02-07  0:31   ` Jason Wessel
2008-02-07  7:47     ` Jan Kiszka
2008-02-07 12:13     ` Ingo Molnar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).