[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <200802060144.28441.maximlevitsky@gmail.com>
Date: Wed, 6 Feb 2008 01:44:28 +0200
From: Maxim Levitsky <maximlevitsky@...il.com>
To: Jan Kiszka <jan.kiszka@....de>
Cc: Jason Wessel <jason.wessel@...driver.com>,
Ingo Molnar <mingo@...e.hu>,
Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
kgdb-bugreport@...ts.sourceforge.net,
Thomas Gleixner <tglx@...utronix.de>,
"H. Peter Anvin" <hpa@...or.com>
Subject: Re: [PATCH 1/3] KGDB: Major refactoring
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@....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@...ables.org>, wangdi <wangdi@...sterfs.com>,
> * San Mehat, Tom Rini <trini@...sta.com>,
> * Jason Wessel <jason.wessel@...driver.com>
> + *
> + * Refactoring and cleanup for initial merge:
> + * 2008 (c) Jan Kiszka <jan.kiszka@....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@...r.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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists