LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
From: Jan Kiszka <jan.kiszka@web.de>
To: Jason Wessel <jason.wessel@windriver.com>, Ingo Molnar <mingo@elte.hu>
Cc: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>,
	kgdb-bugreport@lists.sourceforge.net,
	Thomas Gleixner <tglx@linutronix.de>,
	"H. Peter Anvin" <hpa@zytor.com>
Subject: [PATCH 1/3] KGDB: Major refactoring
Date: Wed, 06 Feb 2008 00:34:13 +0100	[thread overview]
Message-ID: <47A8F275.9090901@web.de> (raw)

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]");

             reply	other threads:[~2008-02-05 23:34 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-02-05 23:34 Jan Kiszka [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47A8F275.9090901@web.de \
    --to=jan.kiszka@web.de \
    --cc=hpa@zytor.com \
    --cc=jason.wessel@windriver.com \
    --cc=kgdb-bugreport@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=tglx@linutronix.de \
    --subject='Re: [PATCH 1/3] KGDB: Major refactoring' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

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).