This adds basic KGDB support for both arch/ppc and arch/powerpc. On the arch/ppc side, most platforms work. A number of people worked on various parts of this code (Scott Hall, Frank Rowand, Takeharu KATO, Geoff Levand, Vitaly Bordug) in addition to myself. The arch/powerpc code doesn't work yet, but is the old ppc64 version from Frank Rowand. Signed-off-by: Vitaly Bordug Signed-off-by: Tom Rini arch/ppc/kernel/ppc-stub.c | 867 ------------------- linux-2.6.17/arch/powerpc/Kconfig.debug | 50 - linux-2.6.17/arch/powerpc/kernel/Makefile | 1 linux-2.6.17/arch/powerpc/kernel/kgdb.c | 423 +++++++++ linux-2.6.17/arch/powerpc/kernel/setup_32.c | 16 linux-2.6.17/arch/powerpc/mm/fault.c | 8 linux-2.6.17/arch/powerpc/platforms/powermac/setup.c | 4 linux-2.6.17/arch/ppc/Kconfig.debug | 36 linux-2.6.17/arch/ppc/kernel/kgdb.c | 329 +++++++ linux-2.6.17/arch/ppc/kernel/setup.c | 16 linux-2.6.17/arch/ppc/mm/fault.c | 9 linux-2.6.17/arch/ppc/platforms/4xx/bubinga.c | 23 linux-2.6.17/arch/ppc/platforms/4xx/ebony.c | 27 linux-2.6.17/arch/ppc/platforms/4xx/ocotea.c | 26 linux-2.6.17/arch/ppc/platforms/4xx/xilinx_ml300.c | 18 linux-2.6.17/arch/ppc/platforms/85xx/sbc8560.c | 32 linux-2.6.17/arch/ppc/platforms/chestnut.c | 5 linux-2.6.17/arch/ppc/platforms/pplus.c | 3 linux-2.6.17/arch/ppc/platforms/sandpoint.c | 3 linux-2.6.17/arch/ppc/platforms/spruce.c | 21 linux-2.6.17/arch/ppc/syslib/Makefile | 1 linux-2.6.17/arch/ppc/syslib/gen550.h | 1 linux-2.6.17/arch/ppc/syslib/ibm44x_common.c | 3 linux-2.6.17/arch/ppc/syslib/mv64x60.c | 55 + linux-2.6.17/arch/ppc/syslib/mv64x60_dbg.c | 52 - linux-2.6.17/arch/ppc/syslib/ppc85xx_setup.c | 13 linux-2.6.17/drivers/serial/Makefile | 1 linux-2.6.17/drivers/serial/cpm_uart/Makefile | 1 linux-2.6.17/drivers/serial/cpm_uart/cpm_uart.h | 37 linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_core.c | 99 +- linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_cpm1.c | 28 linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_cpm2.c | 4 linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_kgdb.c | 195 ++++ linux-2.6.17/drivers/serial/mpsc.c | 5 linux-2.6.17/drivers/serial/mpsc_kgdb.c | 299 ++++++ linux-2.6.17/include/asm-powerpc/kgdb.h | 73 + linux-2.6.17/include/asm-ppc/kgdb.h | 59 - linux-2.6.17/include/asm-ppc/machdep.h | 2 linux-2.6.17/include/asm-ppc/mv64x60.h | 2 linux-2.6.17/include/asm-ppc/mv64x60_defs.h | 3 linux-2.6.17/lib/Kconfig.debug | 18 41 files changed, 1664 insertions(+), 1204 deletions(-) Index: linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_core.c =================================================================== --- linux-2.6.17.orig/drivers/serial/cpm_uart/cpm_uart_core.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_core.c 2006-09-14 17:39:18.000000000 +0100 @@ -1070,22 +1070,17 @@ int cpm_uart_drv_get_platform_data(struc return 0; } -#ifdef CONFIG_SERIAL_CPM_CONSOLE -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * Note that this is called with interrupts already disabled - */ -static void cpm_uart_console_write(struct console *co, const char *s, +void cpm_uart_early_write(int index, const char *s, u_int count) { - struct uart_cpm_port *pinfo = - &cpm_uart_ports[cpm_uart_port_map[co->index]]; + struct uart_cpm_port *pinfo; unsigned int i; volatile cbd_t *bdp, *bdbase; volatile unsigned char *cp; + BUG_ON(index>UART_NR); + pinfo = &cpm_uart_ports[index]; + /* Get the address of the host memory buffer. */ bdp = pinfo->tx_cur; @@ -1149,16 +1144,11 @@ static void cpm_uart_console_write(struc pinfo->tx_cur = (volatile cbd_t *) bdp; } - -static int __init cpm_uart_console_setup(struct console *co, char *options) +int cpm_uart_early_setup(int index, int early) { + int ret; struct uart_port *port; struct uart_cpm_port *pinfo; - int baud = 38400; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - int ret; struct fs_uart_platform_info *pdata; struct platform_device* pdev = early_uart_get_pdev(co->index); @@ -1169,8 +1159,9 @@ static int __init cpm_uart_console_setup cpm_uart_init_portdesc(); } + BUG_ON(index>UART_NR); port = - (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; + (struct uart_port *)&cpm_uart_ports[index]; pinfo = (struct uart_cpm_port *)port; if (!pdev) { if (pinfo->set_lineif) @@ -1184,19 +1175,6 @@ static int __init cpm_uart_console_setup cpm_uart_drv_get_platform_data(pdev, 1); } - pinfo->flags |= FLAG_CONSOLE; - - if (options) { - uart_parse_options(options, &baud, &parity, &bits, &flow); - } else { - bd_t *bd = (bd_t *) __res; - - if (bd->bi_baudrate) - baud = bd->bi_baudrate; - else - baud = 9600; - } - if (IS_SMC(pinfo)) { pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX); pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN); @@ -1204,8 +1182,7 @@ static int __init cpm_uart_console_setup pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX); pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); } - - ret = cpm_uart_allocbuf(pinfo, 1); + ret = cpm_uart_allocbuf(pinfo, early); if (ret) return ret; @@ -1217,6 +1194,56 @@ static int __init cpm_uart_console_setup else cpm_uart_init_scc(pinfo); + return 0; +} + +#ifdef CONFIG_SERIAL_CPM_CONSOLE +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * Note that this is called with interrupts already disabled + */ + +static void cpm_uart_console_write(struct console *co, const char *s, + u_int count) +{ + cpm_uart_early_write(cpm_uart_port_map[co->index],s,count); +} + +/* + * Setup console. Be careful is called early ! + */ +static int __init cpm_uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + struct uart_cpm_port *pinfo; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + int ret; + + port = + (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; + pinfo = (struct uart_cpm_port *)port; + + pinfo->flags |= FLAG_CONSOLE; + + if (options) { + uart_parse_options(options, &baud, &parity, &bits, &flow); + } else { + bd_t *bd = (bd_t *) __res; + + if (bd->bi_baudrate) + baud = bd->bi_baudrate; + else + baud = 9600; + } + + ret = cpm_uart_early_setup(cpm_uart_port_map[co->index], 1); + if(ret) + return ret; uart_set_options(port, co, baud, parity, bits, flow); return 0; @@ -1364,6 +1391,12 @@ static int cpm_uart_init(void) { for (i = 0; i < cpm_uart_nr; i++) { int con = cpm_uart_port_map[i]; + +#ifdef CONFIG_KGDB_CPM_UART + /* We are not interested in ports yet utilized by kgdb */ + if(con == KGDB_PINFO_INDEX) + continue; +#endif cpm_uart_ports[con].port.line = i; cpm_uart_ports[con].port.flags = UPF_BOOT_AUTOCONF; uart_add_one_port(&cpm_reg, &cpm_uart_ports[con].port); Index: linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_kgdb.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_kgdb.c 2006-09-14 17:39:18.000000000 +0100 @@ -0,0 +1,195 @@ +/* + * drivers/serial/cpm_uart/cpm_uart_kgdb.c + * + * CPM UART interface for kgdb. + * + * Author: Vitaly Bordug + * + * Used some bits from drivers/serial/kgdb_8250.c as a template + * + * 2005 (c) MontaVista Software, Inc. 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include /* For BASE_BAUD and SERIAL_PORT_DFNS */ + +#include "cpm_uart.h" + +#define GDB_BUF_SIZE 512 /* power of 2, please */ + + +static char kgdb_buf[GDB_BUF_SIZE], *kgdbp; +static int kgdb_chars; + +/* Forward declarations. */ + +/* + * Receive character from the serial port. This only works well + * before the port is initialize for real use. + */ +static int kgdb_wait_key(char *obuf) +{ + struct uart_cpm_port *pinfo; + + u_char c, *cp; + volatile cbd_t *bdp; + int i; + + pinfo = &cpm_uart_ports[KGDB_PINFO_INDEX]; + + /* Get the address of the host memory buffer. + */ + bdp = pinfo->rx_cur; + while (bdp->cbd_sc & BD_SC_EMPTY); + + /* If the buffer address is in the CPM DPRAM, don't + * convert it. + */ + cp = cpm2cpu_addr(bdp->cbd_bufaddr); + + if (obuf) { + i = c = bdp->cbd_datlen; + while (i-- > 0) + { + *obuf++ = *cp++; + } + } else { + c = *cp; + } + bdp->cbd_sc |= BD_SC_EMPTY; + + if (bdp->cbd_sc & BD_SC_WRAP) { + bdp = pinfo->rx_bd_base; + } else { + bdp++; + } + pinfo->rx_cur = (cbd_t *)bdp; + + return((int)c); +} + + +/* + * Wait until the interface can accept a char, then write it. + */ +static void +kgdb_put_debug_char(int chr) +{ + static char ch[2]; + ch[0]=(char)chr; + cpm_uart_early_write(KGDB_PINFO_INDEX, ch, 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) +{ + if (kgdb_chars<=0) { + kgdb_chars = kgdb_wait_key(kgdb_buf); + kgdbp = kgdb_buf; + } + kgdb_chars--; + + return (*kgdbp++); +} + +static void termios_set_options(int index, + int baud, int parity, int bits, int flow) +{ + struct termios termios; + struct uart_port *port; + struct uart_cpm_port *pinfo; + + BUG_ON(index>UART_NR); + + port = + (struct uart_port *)&cpm_uart_ports[index]; + pinfo = (struct uart_cpm_port *)port; + + /* + * Ensure that the serial console lock is initialised + * early. + */ + spin_lock_init(&port->lock); + + memset(&termios, 0, sizeof(struct termios)); + + termios.c_cflag = CREAD | HUPCL | CLOCAL; + + termios.c_cflag |= baud; + + if (bits == 7) + termios.c_cflag |= CS7; + else + termios.c_cflag |= CS8; + + switch (parity) { + case 'o': case 'O': + termios.c_cflag |= PARODD; + /*fall through*/ + case 'e': case 'E': + termios.c_cflag |= PARENB; + break; + } + + if (flow == 'r') + termios.c_cflag |= CRTSCTS; + + port->ops->set_termios(port, &termios, NULL); +} + +/* + * Returns: + * 0 on success, 1 on failure. + */ +static int kgdb_init(void) +{ + struct uart_port *port; + struct uart_cpm_port *pinfo; + + int use_bootmem = 0; /* use dma by default */ + + if(!cpm_uart_nr) + { + use_bootmem = 1; + cpm_uart_init_portdesc(); + } + port = (struct uart_port *)&cpm_uart_ports[KGDB_PINFO_INDEX]; + pinfo = (struct uart_cpm_port *)port; + + if (cpm_uart_early_setup(KGDB_PINFO_INDEX, use_bootmem)) + return 1; + + termios_set_options(KGDB_PINFO_INDEX, KGDB_BAUD,'n',8,'n'); + if (IS_SMC(pinfo)) + pinfo->smcp->smc_smcm |= SMCM_TX; + else + pinfo->sccp->scc_sccm |= UART_SCCM_TX; + + return 0; +} + + +struct kgdb_io kgdb_io_ops = { + .read_char = kgdb_get_debug_char, + .write_char = kgdb_put_debug_char, + .init = kgdb_init, +}; + Index: linux-2.6.17/drivers/serial/cpm_uart/Makefile =================================================================== --- linux-2.6.17.orig/drivers/serial/cpm_uart/Makefile 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/drivers/serial/cpm_uart/Makefile 2006-09-14 17:39:18.000000000 +0100 @@ -7,5 +7,6 @@ obj-$(CONFIG_SERIAL_CPM) += cpm_uart.o # Select the correct platform objects. cpm_uart-objs-$(CONFIG_CPM2) += cpm_uart_cpm2.o cpm_uart-objs-$(CONFIG_8xx) += cpm_uart_cpm1.o +cpm_uart-objs-$(CONFIG_KGDB_CPM_UART) += cpm_uart_kgdb.o cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y) Index: linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_cpm1.c =================================================================== --- linux-2.6.17.orig/drivers/serial/cpm_uart/cpm_uart_cpm1.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_cpm1.c 2006-09-14 17:39:18.000000000 +0100 @@ -52,6 +52,7 @@ void cpm_line_cr_cmd(int line, int cmd) { ushort val; volatile cpm8xx_t *cp = cpmp; + unsigned *bcsr_io; switch (line) { case UART_SMC1: @@ -94,12 +95,35 @@ void scc1_lineif(struct uart_cpm_port *p { /* XXX SCC1: insert port configuration here */ pinfo->brg = 1; + +#if defined (CONFIG_MPC885ADS) || defined (CONFIG_MPC86XADS) + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_RS232EN_1); + iounmap(bcsr_io); +#endif } void scc2_lineif(struct uart_cpm_port *pinfo) { /* XXX SCC2: insert port configuration here */ pinfo->brg = 2; + unsigned *bcsr_io; + +#if defined (CONFIG_MPC885ADS) || defined (CONFIG_MPC86XADS) + bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); + + if (bcsr_io == NULL) { + printk(KERN_CRIT "Could not remap BCSR\n"); + return; + } + out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_RS232EN_2); + iounmap(bcsr_io); +#endif } void scc3_lineif(struct uart_cpm_port *pinfo) @@ -188,6 +212,10 @@ int cpm_uart_init_portdesc(void) { pr_debug("CPM uart[-]:init portdesc\n"); + /* Check if we have called this yet. This may happen if early kgdb + breakpoint is on */ + if(cpm_uart_nr) + return 0; cpm_uart_nr = 0; #ifdef CONFIG_SERIAL_CPM_SMC1 cpm_uart_ports[UART_SMC1].smcp = &cpmp->cp_smc[0]; Index: linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_cpm2.c =================================================================== --- linux-2.6.17.orig/drivers/serial/cpm_uart/cpm_uart_cpm2.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/drivers/serial/cpm_uart/cpm_uart_cpm2.c 2006-09-14 17:39:18.000000000 +0100 @@ -256,6 +256,10 @@ int cpm_uart_init_portdesc(void) { pr_debug("CPM uart[-]:init portdesc\n"); + /* Check if we have called this yet. This may happen if early kgdb + breakpoint is on */ + if(cpm_uart_nr) + return 0; cpm_uart_nr = 0; #ifdef CONFIG_SERIAL_CPM_SMC1 cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0]; Index: linux-2.6.17/drivers/serial/cpm_uart/cpm_uart.h =================================================================== --- linux-2.6.17.orig/drivers/serial/cpm_uart/cpm_uart.h 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/drivers/serial/cpm_uart/cpm_uart.h 2006-09-14 17:39:18.000000000 +0100 @@ -51,6 +51,39 @@ #define SCC_WAIT_CLOSING 100 +#ifdef CONFIG_KGDB_CPM_UART + +/* Speed of the debug UART. */ +#if defined(CONFIG_KGDB_9600BAUD) +#define KGDB_BAUD B9600 +#elif defined(CONFIG_KGDB_19200BAUD) +#define KGDB_BAUD B19200 +#elif defined(CONFIG_KGDB_38400BAUD) +#define KGDB_BAUD B38400 +#elif defined(CONFIG_KGDB_57600BAUD) +#define KGDB_BAUD B57600 +#else +#define KGDB_BAUD B115200 /* Start with this if not given */ +#endif + +#ifdef CONFIG_KGDB_CPM_UART_SCC1 +#define KGDB_PINFO_INDEX UART_SCC1 +#elif CONFIG_KGDB_CPM_UART_SCC2 +#define KGDB_PINFO_INDEX UART_SCC2 +#elif CONFIG_KGDB_CPM_UART_SCC3 +#define KGDB_PINFO_INDEX UART_SCC3 +#elif CONFIG_KGDB_CPM_UART_SCC4 +#define KGDB_PINFO_INDEX UART_SCC4 +#elif CONFIG_KGDB_CPM_UART_SMC1 +#define KGDB_PINFO_INDEX UART_SMC1 +#elif CONFIG_KGDB_CPM_UART_SMC2 +#define KGDB_PINFO_INDEX UART_SMC2 +#else +#error The S(M)CC for kgdb console is undefined +#endif + +#endif /* CONFIG_KGDB_CPM_UART */ + struct uart_cpm_port { struct uart_port port; u16 rx_nrfifos; @@ -87,6 +120,9 @@ extern int cpm_uart_port_map[UART_NR]; extern int cpm_uart_nr; extern struct uart_cpm_port cpm_uart_ports[UART_NR]; +void cpm_uart_early_write(int index, const char *s, u_int count); +int cpm_uart_early_setup(int index,int early); + /* these are located in their respective files */ void cpm_line_cr_cmd(int line, int cmd); int cpm_uart_init_portdesc(void); @@ -133,5 +169,4 @@ static inline void *cpm2cpu_addr(unsigne return 0; } - #endif /* CPM_UART_H */ Index: linux-2.6.17/drivers/serial/mpsc_kgdb.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/drivers/serial/mpsc_kgdb.c 2006-09-14 17:39:18.000000000 +0100 @@ -0,0 +1,299 @@ +/* + * drivers/serial/mpsc_kgdb.c + * + * KGDB driver for the Marvell MultiProtocol Serial Controller (MPCS) + * + * Based on the polled boot loader driver by Ajit Prem (ajit.prem@motorola.com) + * + * Author: Randy Vinson + * + * 2005 (c) MontaVista Software, Inc. + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpsc.h" + +/* Speed of the UART. */ +static int kgdbmpsc_baud = CONFIG_KGDB_BAUDRATE; + +/* Index of the UART, matches ttyMX naming. */ +static int kgdbmpsc_ttyMM = CONFIG_KGDB_PORT_NUM; + +#define MPSC_INTR_REG_SELECT(x) ((x) + (8 * kgdbmpsc_ttyMM)) + +static int kgdbmpsc_init(void); + +static struct platform_device mpsc_dev, shared_dev; + +static void __iomem *mpsc_base; +static void __iomem *brg_base; +static void __iomem *routing_base; +static void __iomem *sdma_base; + +static unsigned int mpsc_irq; + +static void kgdb_write_debug_char(int c) +{ + u32 data; + + data = readl(mpsc_base + MPSC_MPCR); + writeb(c, mpsc_base + MPSC_CHR_1); + mb(); + data = readl(mpsc_base + MPSC_CHR_2); + data |= MPSC_CHR_2_TTCS; + writel(data, mpsc_base + MPSC_CHR_2); + mb(); + + while (readl(mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS) ; +} + +static int kgdb_get_debug_char(void) +{ + unsigned char c; + + while (!(readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)) & + MPSC_INTR_CAUSE_RCC)) ; + + c = readb(mpsc_base + MPSC_CHR_10 + (1 << 1)); + mb(); + writeb(c, mpsc_base + MPSC_CHR_10 + (1 << 1)); + mb(); + writel(~MPSC_INTR_CAUSE_RCC, sdma_base + + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)); + return (c); +} + +/* + * This is the receiver interrupt routine for the GDB stub. + * All that we need to do is verify that the interrupt happened on the + * line we're in charge of. If this is true, schedule a breakpoint and + * return. + */ +static irqreturn_t +kgdbmpsc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (irq != mpsc_irq) + return IRQ_NONE; + /* + * If there is some other CPU in KGDB then this is a + * spurious interrupt. so return without even checking a byte + */ + if (atomic_read(&debugger_active)) + return IRQ_NONE; + + if (readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)) & + MPSC_INTR_CAUSE_RCC) + breakpoint(); + + return IRQ_HANDLED; +} + +static int __init kgdbmpsc_init(void) +{ + struct mpsc_pdata *pdata; + u32 cdv; + + if (!brg_base || !mpsc_base || !routing_base || !sdma_base) + return -1; + + /* Set MPSC Routing to enable both ports */ + writel(0x0, routing_base + MPSC_MRR); + + /* MPSC 0/1 Rx & Tx get clocks BRG0/1 */ + writel(0x00000100, routing_base + MPSC_RCRR); + writel(0x00000100, routing_base + MPSC_TCRR); + + /* Disable all MPSC interrupts and clear any pending interrupts */ + writel(0, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK)); + writel(0, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_CAUSE)); + + pdata = (struct mpsc_pdata *)mpsc_dev.dev.platform_data; + + /* cdv = (clock/(2*16*baud rate)) for 16X mode. */ + cdv = ((pdata->brg_clk_freq / (32 * kgdbmpsc_baud)) - 1); + writel((pdata->brg_clk_src << 18) | (1 << 16) | cdv, + brg_base + BRG_BCR); + + /* Put MPSC into UART mode, no null modem, 16x clock mode */ + writel(0x000004c4, mpsc_base + MPSC_MMCRL); + writel(0x04400400, mpsc_base + MPSC_MMCRH); + + writel(0, mpsc_base + MPSC_CHR_1); + writel(0, mpsc_base + MPSC_CHR_9); + writel(0, mpsc_base + MPSC_CHR_10); + writel(4, mpsc_base + MPSC_CHR_3); + writel(0x20000000, mpsc_base + MPSC_CHR_4); + writel(0x9000, mpsc_base + MPSC_CHR_5); + writel(0, mpsc_base + MPSC_CHR_6); + writel(0, mpsc_base + MPSC_CHR_7); + writel(0, mpsc_base + MPSC_CHR_8); + + /* 8 data bits, 1 stop bit */ + writel((3 << 12), mpsc_base + MPSC_MPCR); + + /* Enter "hunt" mode */ + writel((1 << 31), mpsc_base + MPSC_CHR_2); + + udelay(100); + return 0; +} + +static void __iomem *__init +kgdbmpsc_map_resource(struct platform_device *pd, int type, int num) +{ + void __iomem *base = NULL; + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, num))) + base = ioremap(r->start, r->end - r->start + 1); + return base; +} + +static void __iomem *__init +kgdbmpsc_unmap_resource(struct platform_device *pd, int type, int num, + void __iomem * base) +{ + if (base) + iounmap(base); + return NULL; +} + +static void __init +kgdbmpsc_reserve_resource(struct platform_device *pd, int type, int num) +{ + struct resource *r; + + if ((r = platform_get_resource(pd, IORESOURCE_MEM, num))) + request_mem_region(r->start, r->end - r->start + 1, "kgdb"); +} + +static int __init kgdbmpsc_local_init(void) +{ + if (!mpsc_dev.num_resources || !shared_dev.num_resources) + return 1; /* failure */ + + mpsc_base = kgdbmpsc_map_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BASE_ORDER); + brg_base = kgdbmpsc_map_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BRG_BASE_ORDER); + + /* get the platform data for the shared registers and get them mapped */ + routing_base = kgdbmpsc_map_resource(&shared_dev, + IORESOURCE_MEM, + MPSC_ROUTING_BASE_ORDER); + sdma_base = + kgdbmpsc_map_resource(&shared_dev, IORESOURCE_MEM, + MPSC_SDMA_INTR_BASE_ORDER); + + mpsc_irq = platform_get_irq(&mpsc_dev, 1); + + if (mpsc_base && brg_base && routing_base && sdma_base) + return 0; /* success */ + + return 1; /* failure */ +} + +static void __init kgdbmpsc_local_exit(void) +{ + if (sdma_base) + sdma_base = kgdbmpsc_unmap_resource(&shared_dev, IORESOURCE_MEM, + MPSC_SDMA_INTR_BASE_ORDER, + sdma_base); + if (routing_base) + routing_base = kgdbmpsc_unmap_resource(&shared_dev, + IORESOURCE_MEM, + MPSC_ROUTING_BASE_ORDER, + routing_base); + if (brg_base) + brg_base = kgdbmpsc_unmap_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BRG_BASE_ORDER, + brg_base); + if (mpsc_base) + mpsc_base = kgdbmpsc_unmap_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BASE_ORDER, mpsc_base); +} + +static void __init kgdbmpsc_update_pdata(struct platform_device *pdev) +{ + + snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s%u", pdev->name, pdev->id); +} + +static int __init kgdbmpsc_pdev_init(void) +{ + struct platform_device *pdev; + + /* get the platform data for the specified port. */ + pdev = mv64x60_early_get_pdev_data(MPSC_CTLR_NAME, kgdbmpsc_ttyMM, 1); + if (pdev) { + memcpy(&mpsc_dev, pdev, sizeof(struct platform_device)); + if (platform_notify) { + kgdbmpsc_update_pdata(&mpsc_dev); + platform_notify(&mpsc_dev.dev); + } + + /* get the platform data for the shared registers. */ + pdev = mv64x60_early_get_pdev_data(MPSC_SHARED_NAME, 0, 0); + if (pdev) { + memcpy(&shared_dev, pdev, + sizeof(struct platform_device)); + if (platform_notify) { + kgdbmpsc_update_pdata(&shared_dev); + platform_notify(&shared_dev.dev); + } + } + } + return 0; +} + +postcore_initcall(kgdbmpsc_pdev_init); + +static int __init kgdbmpsc_init_io(void) +{ + + kgdbmpsc_pdev_init(); + + if (kgdbmpsc_local_init()) { + kgdbmpsc_local_exit(); + return -1; + } + + if (kgdbmpsc_init() == -1) + return -1; + return 0; +} + +static void __init kgdbmpsc_hookup_irq(void) +{ + unsigned int msk; + if (!request_irq(mpsc_irq, kgdbmpsc_interrupt, 0, "kgdb mpsc", NULL)) { + /* Enable interrupt */ + msk = readl(sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK)); + msk |= MPSC_INTR_CAUSE_RCC; + writel(msk, sdma_base + MPSC_INTR_REG_SELECT(MPSC_INTR_MASK)); + + kgdbmpsc_reserve_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BASE_ORDER); + kgdbmpsc_reserve_resource(&mpsc_dev, IORESOURCE_MEM, + MPSC_BRG_BASE_ORDER); + } +} + +struct kgdb_io kgdb_io_ops = { + .read_char = kgdb_get_debug_char, + .write_char = kgdb_write_debug_char, + .init = kgdbmpsc_init_io, + .late_init = kgdbmpsc_hookup_irq, +}; Index: linux-2.6.17/drivers/serial/Makefile =================================================================== --- linux-2.6.17.orig/drivers/serial/Makefile 2006-09-14 17:37:14.000000000 +0100 +++ linux-2.6.17/drivers/serial/Makefile 2006-09-14 17:39:18.000000000 +0100 @@ -47,6 +47,7 @@ obj-$(CONFIG_SERIAL_IMX) += imx.o obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o obj-$(CONFIG_SERIAL_ICOM) += icom.o obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o +obj-$(CONFIG_KGDB_MPSC) += mpsc_kgdb.o obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_JSM) += jsm/ Index: linux-2.6.17/arch/ppc/Kconfig.debug =================================================================== --- linux-2.6.17.orig/arch/ppc/Kconfig.debug 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/Kconfig.debug 2006-09-14 17:39:18.000000000 +0100 @@ -2,42 +2,6 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config KGDB - bool "Include kgdb kernel debugger" - depends on DEBUG_KERNEL && (BROKEN || PPC_GEN550 || 4xx) - select DEBUG_INFO - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -choice - prompt "Serial Port" - depends on KGDB - default KGDB_TTYS1 - -config KGDB_TTYS0 - bool "ttyS0" - -config KGDB_TTYS1 - bool "ttyS1" - -config KGDB_TTYS2 - bool "ttyS2" - -config KGDB_TTYS3 - bool "ttyS3" - -endchoice - -config KGDB_CONSOLE - bool "Enable serial console thru kgdb port" - depends on KGDB && 8xx || CPM2 - help - If you enable this, all serial console messages will be sent - over the gdb stub. - If unsure, say N. - config XMON bool "Include xmon kernel debugger" depends on DEBUG_KERNEL Index: linux-2.6.17/arch/ppc/platforms/4xx/xilinx_ml300.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/4xx/xilinx_ml300.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/4xx/xilinx_ml300.c 2006-09-14 17:39:18.000000000 +0100 @@ -41,9 +41,6 @@ * ppc4xx_map_io arch/ppc/syslib/ppc4xx_setup.c * start_kernel init/main.c * setup_arch arch/ppc/kernel/setup.c - * #if defined(CONFIG_KGDB) - * *ppc_md.kgdb_map_scc() == gen550_kgdb_map_scc - * #endif * *ppc_md.setup_arch == ml300_setup_arch this file * ppc4xx_setup_arch arch/ppc/syslib/ppc4xx_setup.c * ppc4xx_find_bridges arch/ppc/syslib/ppc405_pci.c @@ -117,7 +114,6 @@ ml300_early_serial_init(int num, struct void __init ml300_early_serial_map(void) { -#ifdef CONFIG_SERIAL_8250 struct plat_serial8250_port *pdata; int i = 0; @@ -129,7 +125,14 @@ ml300_early_serial_map(void) pdata++; i++; } -#endif /* CONFIG_SERIAL_8250 */ +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) + printk("Early serial init of port %d failed\n", i); +#endif + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(i, &port) +#endif } void __init @@ -165,9 +168,4 @@ platform_init(unsigned long r3, unsigned #if defined(XPAR_POWER_0_POWERDOWN_BASEADDR) ppc_md.power_off = xilinx_power_off; #endif - -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = ml300_early_serial_map; -#endif } - Index: linux-2.6.17/arch/ppc/platforms/4xx/bubinga.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/4xx/bubinga.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/4xx/bubinga.c 2006-09-14 17:39:18.000000000 +0100 @@ -4,7 +4,7 @@ * Author: SAW (IBM), derived from walnut.c. * Maintained by MontaVista Software * - * 2003 (c) MontaVista Softare Inc. This file is licensed under the + * 2003-2004 (c) MontaVista Softare Inc. 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. @@ -100,17 +100,26 @@ bubinga_early_serial_map(void) port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.line = 0; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 0 failed\n"); - } +#endif + +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif port.membase = (void*)ACTING_UART1_IO_BASE; port.irq = ACTING_UART1_INT; port.line = 1; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 1 failed\n"); - } +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &port); +#endif } void __init @@ -255,8 +264,4 @@ platform_init(unsigned long r3, unsigned ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; #endif -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = bubinga_early_serial_map; -#endif } - Index: linux-2.6.17/arch/ppc/platforms/4xx/ebony.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/4xx/ebony.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/4xx/ebony.c 2006-09-14 17:39:18.000000000 +0100 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -226,14 +227,20 @@ ebony_early_serial_map(void) port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.line = 0; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 0 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(0, &port); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) /* Purge TLB entry added in head_44x.S for early serial access */ _tlbie(UART0_IO_BASE); #endif @@ -243,14 +250,18 @@ ebony_early_serial_map(void) port.uartclk = clocks.uart1; port.line = 1; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 1) printk("Early serial init of port 1 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(1, &port); #endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &port); +#endif } static void __init @@ -327,8 +338,4 @@ void __init platform_init(unsigned long ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = ebony_early_serial_map; -#endif } - Index: linux-2.6.17/arch/ppc/platforms/4xx/ocotea.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/4xx/ocotea.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/4xx/ocotea.c 2006-09-14 17:39:18.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -249,14 +250,20 @@ ocotea_early_serial_map(void) port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; port.line = 0; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 0) printk("Early serial init of port 0 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(0, &port); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) /* Purge TLB entry added in head_44x.S for early serial access */ _tlbie(UART0_IO_BASE); #endif @@ -266,14 +273,18 @@ ocotea_early_serial_map(void) port.uartclk = clocks.uart1; port.line = 1; - if (early_serial_setup(&port) != 0) { +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&port) != 1) printk("Early serial init of port 1 failed\n"); - } +#endif -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#ifdef CONFIG_SERIAL_TEXT_DEBUG /* Configure debug serial access */ gen550_init(1, &port); #endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &port); +#endif } static void __init @@ -343,8 +354,5 @@ void __init platform_init(unsigned long ppc_md.nvram_read_val = todc_direct_read_val; ppc_md.nvram_write_val = todc_direct_write_val; -#ifdef CONFIG_KGDB - ppc_md.early_serial_map = ocotea_early_serial_map; -#endif ppc_md.init = ocotea_init; } Index: linux-2.6.17/arch/ppc/platforms/chestnut.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/chestnut.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/chestnut.c 2006-09-14 17:39:18.000000000 +0100 @@ -492,7 +492,7 @@ chestnut_power_off(void) static void __init chestnut_map_io(void) { -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) io_block_mapping(CHESTNUT_UART_BASE, CHESTNUT_UART_BASE, 0x100000, _PAGE_IO); #endif @@ -566,9 +566,6 @@ platform_init(unsigned long r3, unsigned #if defined(CONFIG_SERIAL_TEXT_DEBUG) ppc_md.progress = gen550_progress; #endif -#if defined(CONFIG_KGDB) - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif if (ppc_md.progress) ppc_md.progress("chestnut_init(): exit", 0); Index: linux-2.6.17/arch/ppc/platforms/sandpoint.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/sandpoint.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/sandpoint.c 2006-09-14 17:39:18.000000000 +0100 @@ -730,9 +730,6 @@ platform_init(unsigned long r3, unsigned ppc_md.nvram_read_val = todc_mc146818_read_val; ppc_md.nvram_write_val = todc_mc146818_write_val; -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif Index: linux-2.6.17/arch/ppc/platforms/pplus.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/pplus.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/pplus.c 2006-09-14 17:39:18.000000000 +0100 @@ -893,9 +893,6 @@ platform_init(unsigned long r3, unsigned #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_TEXT_DEBUG */ -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif #ifdef CONFIG_SMP smp_ops = &pplus_smp_ops; #endif /* CONFIG_SMP */ Index: linux-2.6.17/arch/ppc/platforms/spruce.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/spruce.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/spruce.c 2006-09-14 17:39:18.000000000 +0100 @@ -178,26 +178,32 @@ spruce_early_serial_map(void) serial_req.membase = (u_char *)UART0_IO_BASE; serial_req.regshift = 0; -#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) - gen550_init(0, &serial_req); -#endif #ifdef CONFIG_SERIAL_8250 if (early_serial_setup(&serial_req) != 0) printk("Early serial init of port 0 failed\n"); #endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &serial_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &port); +#endif /* Assume early_serial_setup() doesn't modify serial_req */ serial_req.line = 1; serial_req.irq = UART1_INT; serial_req.membase = (u_char *)UART1_IO_BASE; -#if defined(CONFIG_KGDB) || defined(CONFIG_SERIAL_TEXT_DEBUG) - gen550_init(1, &serial_req); -#endif #ifdef CONFIG_SERIAL_8250 if (early_serial_setup(&serial_req) != 0) printk("Early serial init of port 1 failed\n"); #endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(1, &serial_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &serial_req); +#endif } TODC_ALLOC(); @@ -316,7 +322,4 @@ platform_init(unsigned long r3, unsigned #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_TEXT_DEBUG */ -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif } Index: linux-2.6.17/arch/ppc/platforms/85xx/sbc8560.c =================================================================== --- linux-2.6.17.orig/arch/ppc/platforms/85xx/sbc8560.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/platforms/85xx/sbc8560.c 2006-09-14 17:39:18.000000000 +0100 @@ -50,7 +50,6 @@ #include #include -#ifdef CONFIG_SERIAL_8250 static void __init sbc8560_early_serial_map(void) { @@ -66,12 +65,16 @@ sbc8560_early_serial_map(void) uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART0_SIZE); uart_req.type = PORT_16650; -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) - gen550_init(0, &uart_req); +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&uart_req) != 0) + printk("Early serial init of port 0 failed\n"); +#endif +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &uart_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &uart_req); #endif - - if (early_serial_setup(&uart_req) != 0) - printk("Early serial init of port 0 failed\n"); /* Assume early_serial_setup() doesn't modify uart_req */ uart_req.line = 1; @@ -79,14 +82,17 @@ sbc8560_early_serial_map(void) uart_req.membase = ioremap(uart_req.mapbase, MPC85xx_UART1_SIZE); uart_req.irq = MPC85xx_IRQ_EXT10; -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) - gen550_init(1, &uart_req); +#ifdef CONFIG_SERIAL_8250 + if (early_serial_setup(&uart_req) != 0) + printk("Early serial init of port 0 failed\n"); #endif - - if (early_serial_setup(&uart_req) != 0) - printk("Early serial init of port 1 failed\n"); -} +#ifdef CONFIG_SERIAL_TEXT_DEBUG + gen550_init(0, &uart_req); +#endif +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &uart_req); #endif +} /* ************************************************************************ * @@ -115,9 +121,7 @@ sbc8560_setup_arch(void) /* setup PCI host bridges */ mpc85xx_setup_hose(); #endif -#ifdef CONFIG_SERIAL_8250 sbc8560_early_serial_map(); -#endif #ifdef CONFIG_SERIAL_TEXT_DEBUG /* Invalidate the entry we stole earlier the serial ports * should be properly mapped */ Index: linux-2.6.17/arch/ppc/syslib/mv64x60_dbg.c =================================================================== --- linux-2.6.17.orig/arch/ppc/syslib/mv64x60_dbg.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/syslib/mv64x60_dbg.c 2006-09-14 17:39:18.000000000 +0100 @@ -34,7 +34,7 @@ static struct mv64x60_handle mv64x60_dbg void mv64x60_progress_init(u32 base) { - mv64x60_dbg_bh.v_base = base; + mv64x60_dbg_bh.v_base = (void*)base; return; } @@ -69,53 +69,3 @@ mv64x60_mpsc_progress(char *s, unsigned return; } #endif /* CONFIG_SERIAL_TEXT_DEBUG */ - - -#if defined(CONFIG_KGDB) - -#if defined(CONFIG_KGDB_TTYS0) -#define KGDB_PORT 0 -#elif defined(CONFIG_KGDB_TTYS1) -#define KGDB_PORT 1 -#else -#error "Invalid kgdb_tty port" -#endif - -void -putDebugChar(unsigned char c) -{ - mv64x60_polled_putc(KGDB_PORT, (char)c); -} - -int -getDebugChar(void) -{ - unsigned char c; - - while (!mv64x60_polled_getc(KGDB_PORT, &c)); - return (int)c; -} - -void -putDebugString(char* str) -{ - while (*str != '\0') { - putDebugChar(*str); - str++; - } - putDebugChar('\r'); - return; -} - -void -kgdb_interruptible(int enable) -{ -} - -void -kgdb_map_scc(void) -{ - if (ppc_md.early_serial_map) - ppc_md.early_serial_map(); -} -#endif /* CONFIG_KGDB */ Index: linux-2.6.17/arch/ppc/syslib/ppc85xx_setup.c =================================================================== --- linux-2.6.17.orig/arch/ppc/syslib/ppc85xx_setup.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/syslib/ppc85xx_setup.c 2006-09-14 17:39:18.000000000 +0100 @@ -69,7 +69,6 @@ mpc85xx_calibrate_decr(void) mtspr(SPRN_TCR, TCR_DIE); } -#ifdef CONFIG_SERIAL_8250 void __init mpc85xx_early_serial_map(void) { @@ -85,7 +84,7 @@ mpc85xx_early_serial_map(void) pdata[0].mapbase += binfo->bi_immr_base; pdata[0].membase = ioremap(pdata[0].mapbase, MPC85xx_UART0_SIZE); -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) memset(&serial_req, 0, sizeof (serial_req)); serial_req.iotype = UPIO_MEM; serial_req.mapbase = pdata[0].mapbase; @@ -93,18 +92,24 @@ mpc85xx_early_serial_map(void) serial_req.regshift = 0; gen550_init(0, &serial_req); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(0, &serial_req); +#endif #endif pdata[1].uartclk = binfo->bi_busfreq; pdata[1].mapbase += binfo->bi_immr_base; pdata[1].membase = ioremap(pdata[1].mapbase, MPC85xx_UART0_SIZE); -#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB) +#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB_8250) /* Assume gen550_init() doesn't modify serial_req */ serial_req.mapbase = pdata[1].mapbase; serial_req.membase = pdata[1].membase; gen550_init(1, &serial_req); +#ifdef CONFIG_KGDB_8250 + kgdb8250_add_port(1, &serial_req); +#endif #endif } #endif @@ -363,5 +368,3 @@ mpc85xx_setup_hose(void) return; } #endif /* CONFIG_PCI */ - - Index: linux-2.6.17/arch/ppc/syslib/mv64x60.c =================================================================== --- linux-2.6.17.orig/arch/ppc/syslib/mv64x60.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/syslib/mv64x60.c 2006-09-14 17:39:18.000000000 +0100 @@ -241,6 +241,12 @@ static struct resource mv64x60_mpsc0_res .end = MV64x60_IRQ_SDMA_0, .flags = IORESOURCE_IRQ, }, + [4] = { + .name = "mpsc 0 irq", + .start = MV64x60_IRQ_MPSC_0, + .end = MV64x60_IRQ_MPSC_0, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device mpsc0_device = { @@ -298,6 +304,12 @@ static struct resource mv64x60_mpsc1_res .end = MV64360_IRQ_SDMA_1, .flags = IORESOURCE_IRQ, }, + [4] = { + .name = "mpsc 1 irq", + .start = MV64360_IRQ_MPSC_1, + .end = MV64360_IRQ_MPSC_1, + .flags = IORESOURCE_IRQ, + }, }; static struct platform_device mpsc1_device = { @@ -1426,12 +1438,46 @@ mv64x60_pd_fixup(struct mv64x60_handle * static int __init mv64x60_add_pds(void) { - return platform_add_devices(mv64x60_pd_devs, - ARRAY_SIZE(mv64x60_pd_devs)); + int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(mv64x60_pd_devs); i++) { + if (mv64x60_pd_devs[i]) { + ret = platform_device_register(mv64x60_pd_devs[i]); + } + if (ret) { + while (--i >= 0) + platform_device_unregister(mv64x60_pd_devs[i]); + break; + } + } + return ret; } arch_initcall(mv64x60_add_pds); /* + * mv64x60_early_get_pdev_data() + * + * Get the data associated with a platform device by name and number. + */ +struct platform_device * __init +mv64x60_early_get_pdev_data(const char *name, int id, int remove) +{ + int i; + struct platform_device *pdev; + + for (i = 0; i id == id && + !strcmp(pdev->name, name)) { + if (remove) + mv64x60_pd_devs[i] = NULL; + return pdev; + } + } + return NULL; +} + +/* ***************************************************************************** * * GT64260-Specific Routines @@ -1764,6 +1810,11 @@ gt64260a_chip_specific_init(struct mv64x r->start = MV64x60_IRQ_SDMA_0; r->end = MV64x60_IRQ_SDMA_0; } + if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 1)) + != NULL) { + r->start = GT64260_IRQ_MPSC_1; + r->end = GT64260_IRQ_MPSC_1; + } #endif } Index: linux-2.6.17/arch/ppc/syslib/Makefile =================================================================== --- linux-2.6.17.orig/arch/ppc/syslib/Makefile 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/syslib/Makefile 2006-09-14 17:39:18.000000000 +0100 @@ -76,7 +76,6 @@ obj-$(CONFIG_PCI_8260) += m82xx_pci.o p obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o ifeq ($(CONFIG_PPC_GEN550),y) -obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o endif ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y) Index: linux-2.6.17/arch/ppc/syslib/gen550.h =================================================================== --- linux-2.6.17.orig/arch/ppc/syslib/gen550.h 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/syslib/gen550.h 2006-09-14 17:39:18.000000000 +0100 @@ -11,4 +11,3 @@ extern void gen550_progress(char *, unsigned short); extern void gen550_init(int, struct uart_port *); -extern void gen550_kgdb_map_scc(void); Index: linux-2.6.17/arch/ppc/syslib/ibm44x_common.c =================================================================== --- linux-2.6.17.orig/arch/ppc/syslib/ibm44x_common.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/syslib/ibm44x_common.c 2006-09-14 17:39:18.000000000 +0100 @@ -192,9 +192,6 @@ void __init ibm44x_platform_init(unsigne #ifdef CONFIG_SERIAL_TEXT_DEBUG ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_TEXT_DEBUG */ -#ifdef CONFIG_KGDB - ppc_md.kgdb_map_scc = gen550_kgdb_map_scc; -#endif /* * The Abatron BDI JTAG debugger does not tolerate others Index: linux-2.6.17/arch/ppc/mm/fault.c =================================================================== --- linux-2.6.17.orig/arch/ppc/mm/fault.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/mm/fault.c 2006-09-14 17:39:18.000000000 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -329,6 +330,14 @@ bad_page_fault(struct pt_regs *regs, uns return; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) { + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ + } +#endif + /* kernel has accessed a bad area */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_kernel_faults) Index: linux-2.6.17/arch/ppc/kernel/kgdb.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/arch/ppc/kernel/kgdb.c 2006-09-14 17:39:18.000000000 +0100 @@ -0,0 +1,329 @@ +/* + * arch/ppc/kernel/kgdb.c + * + * PowerPC backend to the KGDB stub. + * + * Maintainer: Tom Rini + * + * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu) + * Copyright (C) 2003 Timesys Corporation. + * 2004 (c) MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This table contains the mapping between PowerPC hardware trap types, and + * signals, which are primarily what GDB understands. GDB and the kernel + * don't always agree on values, so we use constants taken from gdb-6.2. + */ +static struct hard_trap_info +{ + unsigned int tt; /* Trap type code for powerpc */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { +#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) + { 0x0100, 0x02 /* SIGINT */ }, /* critical input interrupt */ + { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ + { 0x0300, 0x0b /* SIGSEGV */ }, /* data storage */ + { 0x0400, 0x0a /* SIGBUS */ }, /* instruction storage */ + { 0x0500, 0x02 /* SIGINT */ }, /* interrupt */ + { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */ + { 0x0700, 0x04 /* SIGILL */ }, /* program */ + { 0x0800, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0900, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0a00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0b00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0c00, 0x14 /* SIGCHLD */ }, /* syscall */ + { 0x0d00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0e00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0f00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x2002, 0x05 /* SIGTRAP */}, /* debug */ +#else + { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ + { 0x0300, 0x0b /* SIGSEGV */ }, /* address error (store) */ + { 0x0400, 0x0a /* SIGBUS */ }, /* instruction bus error */ + { 0x0500, 0x02 /* SIGINT */ }, /* interrupt */ + { 0x0600, 0x0a /* SIGBUS */ }, /* alingment */ + { 0x0700, 0x05 /* SIGTRAP */ }, /* breakpoint trap */ + { 0x0800, 0x08 /* SIGFPE */}, /* fpu unavail */ + { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ + { 0x0a00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0b00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0c00, 0x14 /* SIGCHLD */ }, /* syscall */ + { 0x0d00, 0x05 /* SIGTRAP */ }, /* single-step/watch */ + { 0x0e00, 0x08 /* SIGFPE */ }, /* fp assist */ +#endif + { 0x0000, 0x000 } /* Must be last */ +}; + +extern atomic_t cpu_doing_single_step; + +static int computeSignal(unsigned int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +/* KGDB functions to use existing PowerPC hooks. */ +static void kgdb_debugger(struct pt_regs *regs) +{ + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); +} + +static int kgdb_breakpoint(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + + if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) + regs->nip += 4; + + return 1; +} + +static int kgdb_singlestep(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + return 1; +} + +int kgdb_iabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +int kgdb_dabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + unsigned long *ptr = gdb_regs; + + memset(gdb_regs, 0, MAXREG * 4); + + for (reg = 0; reg < 32; reg++) + *(ptr++) = regs->gpr[reg]; + +#ifndef CONFIG_E500 + for (reg = 0; reg < 64; reg++) + *(ptr++) = 0; +#else + for (reg = 0; reg < 32; reg++) + *(ptr++) = current->thread.evr[reg]; +#endif + + *(ptr++) = regs->nip; + *(ptr++) = regs->msr; + *(ptr++) = regs->ccr; + *(ptr++) = regs->link; + *(ptr++) = regs->ctr; + *(ptr++) = regs->xer; + +#ifdef CONFIG_SPE + /* u64 acc */ + *(ptr++) = (current->thread.acc >> 32); + *(ptr++) = (current->thread.acc & 0xffffffff); + *(ptr++) = current->thread.spefscr; +#endif +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + + STACK_FRAME_OVERHEAD); + int reg; + unsigned long *ptr = gdb_regs; + + memset(gdb_regs, 0, MAXREG * 4); + + /* Regs GPR0-2 */ + for (reg = 0; reg < 3; reg++) + *(ptr++) = regs->gpr[reg]; + + /* Regs GPR3-13 are not saved */ + for (reg = 3; reg < 14; reg++) + *(ptr++) = 0; + + /* Regs GPR14-31 */ + for (reg = 14; reg < 32; reg++) + *(ptr++) = regs->gpr[reg]; + +#ifndef CONFIG_E500 + for (reg = 0; reg < 64; reg++) + *(ptr++) = 0; +#else + for (reg = 0; reg < 32; reg++) + *(ptr++) = current->thread.evr[reg]; +#endif + + *(ptr++) = regs->nip; + *(ptr++) = regs->msr; + *(ptr++) = regs->ccr; + *(ptr++) = regs->link; + *(ptr++) = regs->ctr; + *(ptr++) = regs->xer; + +#ifdef CONFIG_SPE + /* u64 acc */ + *(ptr++) = (current->thread.acc >> 32); + *(ptr++) = (current->thread.acc & 0xffffffff); + *(ptr++) = current->thread.spefscr; +#endif +} + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + unsigned long *ptr = gdb_regs; +#ifdef CONFIG_SPE + union { + u32 v32[2]; + u64 v64; + } u; +#endif + + for (reg = 0; reg < 32; reg++) + regs->gpr[reg] = *(ptr++); + +#ifndef CONFIG_E500 + for (reg = 0; reg < 64; reg++) + ptr++; +#else + for (reg = 0; reg < 32; reg++) + current->thread.evr[reg] = *(ptr++); +#endif + + regs->nip = *(ptr++); + regs->msr = *(ptr++); + regs->ccr = *(ptr++); + regs->link = *(ptr++); + regs->ctr = *(ptr++); + regs->xer = *(ptr++); + +#ifdef CONFIG_SPE + /* u64 acc */ + u.v32[0] = *(ptr++); + u.v32[1] = *(ptr++); + current->thread.acc = u.v64; + current->thread.spefscr = *(ptr++); +#endif +} + +/* + * Save/restore state in case a memory access causes a fault. + */ +int kgdb_fault_setjmp(unsigned long *curr_context) +{ + __asm__ __volatile__("mflr 0; stw 0,0(%0);" + "stw 1,4(%0); stw 2,8(%0);" + "mfcr 0; stw 0,12(%0);" + "stmw 13,16(%0)"::"r"(curr_context)); + return 0; +} + +void kgdb_fault_longjmp(unsigned long *curr_context) +{ + __asm__ __volatile__("lmw 13,16(%0);" + "lwz 0,12(%0); mtcrf 0x38,0;" + "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" + "mtlr 0; mr 3,1"::"r"(curr_context)); +} + +/* + * This function does PoerPC specific procesing for interfacing to gdb. + */ +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr; + + switch (remcom_in_buffer[0]) + { + /* + * sAA..AA Step one instruction from AA..AA + * This will return an error to gdb .. + */ + case 's': + case 'c': + /* handle the optional parameter */ + if (kgdb_hex2long (&ptr, &addr)) + linux_regs->nip = addr; + + atomic_set(&cpu_doing_single_step, -1); + /* set the trace bit if we're stepping */ + if (remcom_in_buffer[0] == 's') { +#if defined (CONFIG_40x) || defined(CONFIG_BOOKE) + mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | + DBCR0_IC | DBCR0_IDM); + linux_regs->msr |= MSR_DE; +#else + linux_regs->msr |= MSR_SE; +#endif + debugger_step = 1; + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + } + return 0; + } + + return -1; +} + +/* + * Global data + */ +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08}, +}; + +int kgdb_arch_init(void) +{ + debugger = kgdb_debugger; + debugger_bpt = kgdb_breakpoint; + debugger_sstep = kgdb_singlestep; + debugger_iabr_match = kgdb_iabr_match; + debugger_dabr_match = kgdb_dabr_match; + + return 0; +} + +arch_initcall(kgdb_arch_init); Index: linux-2.6.17/arch/ppc/kernel/ppc-stub.c =================================================================== --- linux-2.6.17.orig/arch/ppc/kernel/ppc-stub.c 2006-09-14 17:36:59.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,866 +0,0 @@ -/* - * ppc-stub.c: KGDB support for the Linux kernel. - * - * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC - * some stuff borrowed from Paul Mackerras' xmon - * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu) - * - * Modifications to run under Linux - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * This file originally came from the gdb sources, and the - * copyright notices have been retained below. - */ - -/**************************************************************************** - - THIS SOFTWARE IS NOT COPYRIGHTED - - HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or its performance and the - user accepts the software "AS IS" with all faults. - - HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD - TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -****************************************************************************/ - -/**************************************************************************** - * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ - * - * Module name: remcom.c $ - * Revision: 1.34 $ - * Date: 91/03/09 12:29:49 $ - * Contributor: Lake Stevens Instrument Division$ - * - * Description: low level support for gdb debugger. $ - * - * Considerations: only works on target hardware $ - * - * Written by: Glenn Engel $ - * ModuleState: Experimental $ - * - * NOTES: See Below $ - * - * Modified for SPARC by Stu Grossman, Cygnus Support. - * - * This code has been extensively tested on the Fujitsu SPARClite demo board. - * - * To enable debugger support, two things need to happen. One, a - * call to set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). Breakpoint() - * simulates a breakpoint by executing a trap #1. - * - ************* - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * bBB..BB Set baud rate to BB..BB OK or BNN, then sets - * baud rate - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $#. - * - * where - * :: - * :: > - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -void breakinst(void); - -/* - * BUFMAX defines the maximum number of characters in inbound/outbound buffers - * at least NUMREGBYTES*2 are needed for register packets - */ -#define BUFMAX 2048 -static char remcomInBuffer[BUFMAX]; -static char remcomOutBuffer[BUFMAX]; - -static int initialized; -static int kgdb_active; -static int kgdb_started; -static u_int fault_jmp_buf[100]; -static int kdebug; - - -static const char hexchars[]="0123456789abcdef"; - -/* Place where we save old trap entries for restoration - sparc*/ -/* struct tt_entry kgdb_savettable[256]; */ -/* typedef void (*trapfunc_t)(void); */ - -static void kgdb_fault_handler(struct pt_regs *regs); -static int handle_exception (struct pt_regs *regs); - -#if 0 -/* Install an exception handler for kgdb */ -static void exceptionHandler(int tnum, unsigned int *tfunc) -{ - /* We are dorking with a live trap table, all irqs off */ -} -#endif - -int -kgdb_setjmp(long *buf) -{ - asm ("mflr 0; stw 0,0(%0);" - "stw 1,4(%0); stw 2,8(%0);" - "mfcr 0; stw 0,12(%0);" - "stmw 13,16(%0)" - : : "r" (buf)); - /* XXX should save fp regs as well */ - return 0; -} -void -kgdb_longjmp(long *buf, int val) -{ - if (val == 0) - val = 1; - asm ("lmw 13,16(%0);" - "lwz 0,12(%0); mtcrf 0x38,0;" - "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" - "mtlr 0; mr 3,%1" - : : "r" (buf), "r" (val)); -} -/* Convert ch from a hex digit to an int */ -static int -hex(unsigned char ch) -{ - if (ch >= 'a' && ch <= 'f') - return ch-'a'+10; - if (ch >= '0' && ch <= '9') - return ch-'0'; - if (ch >= 'A' && ch <= 'F') - return ch-'A'+10; - return -1; -} - -/* Convert the memory pointed to by mem into hex, placing result in buf. - * Return a pointer to the last char put in buf (null), in case of mem fault, - * return 0. - */ -static unsigned char * -mem2hex(const char *mem, char *buf, int count) -{ - unsigned char ch; - unsigned short tmp_s; - unsigned long tmp_l; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - - /* Accessing 16 bit and 32 bit objects in a single - ** load instruction is required to avoid bad side - ** effects for some IO registers. - */ - - if ((count == 2) && (((long)mem & 1) == 0)) { - tmp_s = *(unsigned short *)mem; - mem += 2; - *buf++ = hexchars[(tmp_s >> 12) & 0xf]; - *buf++ = hexchars[(tmp_s >> 8) & 0xf]; - *buf++ = hexchars[(tmp_s >> 4) & 0xf]; - *buf++ = hexchars[tmp_s & 0xf]; - - } else if ((count == 4) && (((long)mem & 3) == 0)) { - tmp_l = *(unsigned int *)mem; - mem += 4; - *buf++ = hexchars[(tmp_l >> 28) & 0xf]; - *buf++ = hexchars[(tmp_l >> 24) & 0xf]; - *buf++ = hexchars[(tmp_l >> 20) & 0xf]; - *buf++ = hexchars[(tmp_l >> 16) & 0xf]; - *buf++ = hexchars[(tmp_l >> 12) & 0xf]; - *buf++ = hexchars[(tmp_l >> 8) & 0xf]; - *buf++ = hexchars[(tmp_l >> 4) & 0xf]; - *buf++ = hexchars[tmp_l & 0xf]; - - } else { - while (count-- > 0) { - ch = *mem++; - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch & 0xf]; - } - } - - } else { - /* error condition */ - } - debugger_fault_handler = NULL; - *buf = 0; - return buf; -} - -/* convert the hex array pointed to by buf into binary to be placed in mem - * return a pointer to the character AFTER the last byte written. -*/ -static char * -hex2mem(char *buf, char *mem, int count) -{ - unsigned char ch; - int i; - char *orig_mem; - unsigned short tmp_s; - unsigned long tmp_l; - - orig_mem = mem; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - - /* Accessing 16 bit and 32 bit objects in a single - ** store instruction is required to avoid bad side - ** effects for some IO registers. - */ - - if ((count == 2) && (((long)mem & 1) == 0)) { - tmp_s = hex(*buf++) << 12; - tmp_s |= hex(*buf++) << 8; - tmp_s |= hex(*buf++) << 4; - tmp_s |= hex(*buf++); - - *(unsigned short *)mem = tmp_s; - mem += 2; - - } else if ((count == 4) && (((long)mem & 3) == 0)) { - tmp_l = hex(*buf++) << 28; - tmp_l |= hex(*buf++) << 24; - tmp_l |= hex(*buf++) << 20; - tmp_l |= hex(*buf++) << 16; - tmp_l |= hex(*buf++) << 12; - tmp_l |= hex(*buf++) << 8; - tmp_l |= hex(*buf++) << 4; - tmp_l |= hex(*buf++); - - *(unsigned long *)mem = tmp_l; - mem += 4; - - } else { - for (i=0; i# */ -static void -getpacket(char *buffer) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - unsigned char ch; - - do { - /* wait around for the start character, ignore all other - * characters */ - while ((ch = (getDebugChar() & 0x7f)) != '$') ; - - checksum = 0; - xmitcsum = -1; - - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) { - ch = getDebugChar() & 0x7f; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - if (count >= BUFMAX) - continue; - - buffer[count] = 0; - - if (ch == '#') { - xmitcsum = hex(getDebugChar() & 0x7f) << 4; - xmitcsum |= hex(getDebugChar() & 0x7f); - if (checksum != xmitcsum) - putDebugChar('-'); /* failed checksum */ - else { - putDebugChar('+'); /* successful transfer */ - /* if a sequence char is present, reply the ID */ - if (buffer[2] == ':') { - putDebugChar(buffer[0]); - putDebugChar(buffer[1]); - /* remove sequence chars from buffer */ - count = strlen(buffer); - for (i=3; i <= count; i++) - buffer[i-3] = buffer[i]; - } - } - } - } while (checksum != xmitcsum); -} - -/* send the packet in buffer. */ -static void putpacket(unsigned char *buffer) -{ - unsigned char checksum; - int count; - unsigned char ch, recv; - - /* $#. */ - do { - putDebugChar('$'); - checksum = 0; - count = 0; - - while ((ch = buffer[count])) { - putDebugChar(ch); - checksum += ch; - count += 1; - } - - putDebugChar('#'); - putDebugChar(hexchars[checksum >> 4]); - putDebugChar(hexchars[checksum & 0xf]); - recv = getDebugChar(); - } while ((recv & 0x7f) != '+'); -} - -static void kgdb_flush_cache_all(void) -{ - flush_instruction_cache(); -} - -/* Set up exception handlers for tracing and breakpoints - * [could be called kgdb_init()] - */ -void set_debug_traps(void) -{ -#if 0 - unsigned char c; - - save_and_cli(flags); - - /* In case GDB is started before us, ack any packets (presumably - * "$?#xx") sitting there. - * - * I've found this code causes more problems than it solves, - * so that's why it's commented out. GDB seems to work fine - * now starting either before or after the kernel -bwb - */ - - while((c = getDebugChar()) != '$'); - while((c = getDebugChar()) != '#'); - c = getDebugChar(); /* eat first csum byte */ - c = getDebugChar(); /* eat second csum byte */ - putDebugChar('+'); /* ack it */ -#endif - debugger = kgdb; - debugger_bpt = kgdb_bpt; - debugger_sstep = kgdb_sstep; - debugger_iabr_match = kgdb_iabr_match; - debugger_dabr_match = kgdb_dabr_match; - - initialized = 1; -} - -static void kgdb_fault_handler(struct pt_regs *regs) -{ - kgdb_longjmp((long*)fault_jmp_buf, 1); -} - -int kgdb_bpt(struct pt_regs *regs) -{ - return handle_exception(regs); -} - -int kgdb_sstep(struct pt_regs *regs) -{ - return handle_exception(regs); -} - -void kgdb(struct pt_regs *regs) -{ - handle_exception(regs); -} - -int kgdb_iabr_match(struct pt_regs *regs) -{ - printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n"); - return handle_exception(regs); -} - -int kgdb_dabr_match(struct pt_regs *regs) -{ - printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n"); - return handle_exception(regs); -} - -/* Convert the hardware trap type code to a unix signal number. */ -/* - * This table contains the mapping between PowerPC hardware trap types, and - * signals, which are primarily what GDB understands. - */ -static struct hard_trap_info -{ - unsigned int tt; /* Trap type code for powerpc */ - unsigned char signo; /* Signal that we map this trap into */ -} hard_trap_info[] = { -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - { 0x100, SIGINT }, /* critical input interrupt */ - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* data storage */ - { 0x400, SIGBUS }, /* instruction storage */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alignment */ - { 0x700, SIGILL }, /* program */ - { 0x800, SIGILL }, /* reserved */ - { 0x900, SIGILL }, /* reserved */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGILL }, /* reserved */ - { 0xe00, SIGILL }, /* reserved */ - { 0xf00, SIGILL }, /* reserved */ - /* - ** 0x1000 PIT - ** 0x1010 FIT - ** 0x1020 watchdog - ** 0x1100 data TLB miss - ** 0x1200 instruction TLB miss - */ - { 0x2002, SIGTRAP}, /* debug */ -#else - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* address error (store) */ - { 0x400, SIGBUS }, /* instruction bus error */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alingment */ - { 0x700, SIGTRAP }, /* breakpoint trap */ - { 0x800, SIGFPE }, /* fpu unavail */ - { 0x900, SIGALRM }, /* decrementer */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGTRAP }, /* single-step/watch */ - { 0xe00, SIGFPE }, /* fp assist */ -#endif - { 0, 0} /* Must be last */ - -}; - -static int computeSignal(unsigned int tt) -{ - struct hard_trap_info *ht; - - for (ht = hard_trap_info; ht->tt && ht->signo; ht++) - if (ht->tt == tt) - return ht->signo; - - return SIGHUP; /* default for things we don't know about */ -} - -#define PC_REGNUM 64 -#define SP_REGNUM 1 - -/* - * This function does all command processing for interfacing to gdb. - */ -static int -handle_exception (struct pt_regs *regs) -{ - int sigval; - int addr; - int length; - char *ptr; - unsigned int msr; - - /* We don't handle user-mode breakpoints. */ - if (user_mode(regs)) - return 0; - - if (debugger_fault_handler) { - debugger_fault_handler(regs); - panic("kgdb longjump failed!\n"); - } - if (kgdb_active) { - printk(KERN_ERR "interrupt while in kgdb, returning\n"); - return 0; - } - - kgdb_active = 1; - kgdb_started = 1; - -#ifdef KGDB_DEBUG - printk("kgdb: entering handle_exception; trap [0x%x]\n", - (unsigned int)regs->trap); -#endif - - kgdb_interruptible(0); - lock_kernel(); - msr = mfmsr(); - mtmsr(msr & ~MSR_EE); /* disable interrupts */ - - if (regs->nip == (unsigned long)breakinst) { - /* Skip over breakpoint trap insn */ - regs->nip += 4; - } - - /* reply to host that an exception has occurred */ - sigval = computeSignal(regs->trap); - ptr = remcomOutBuffer; - - *ptr++ = 'T'; - *ptr++ = hexchars[sigval >> 4]; - *ptr++ = hexchars[sigval & 0xf]; - *ptr++ = hexchars[PC_REGNUM >> 4]; - *ptr++ = hexchars[PC_REGNUM & 0xf]; - *ptr++ = ':'; - ptr = mem2hex((char *)®s->nip, ptr, 4); - *ptr++ = ';'; - *ptr++ = hexchars[SP_REGNUM >> 4]; - *ptr++ = hexchars[SP_REGNUM & 0xf]; - *ptr++ = ':'; - ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); - *ptr++ = ';'; - *ptr++ = 0; - - putpacket(remcomOutBuffer); - if (kdebug) - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - - /* XXX We may want to add some features dealing with poking the - * XXX page tables, ... (look at sparc-stub.c for more info) - * XXX also required hacking to the gdb sources directly... - */ - - while (1) { - remcomOutBuffer[0] = 0; - - getpacket(remcomInBuffer); - switch (remcomInBuffer[0]) { - case '?': /* report most recent signal */ - remcomOutBuffer[0] = 'S'; - remcomOutBuffer[1] = hexchars[sigval >> 4]; - remcomOutBuffer[2] = hexchars[sigval & 0xf]; - remcomOutBuffer[3] = 0; - break; -#if 0 - case 'q': /* this screws up gdb for some reason...*/ - { - extern long _start, sdata, __bss_start; - - ptr = &remcomInBuffer[1]; - if (strncmp(ptr, "Offsets", 7) != 0) - break; - - ptr = remcomOutBuffer; - sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", - &_start, &sdata, &__bss_start); - break; - } -#endif - case 'd': - /* toggle debug flag */ - kdebug ^= 1; - break; - - case 'g': /* return the value of the CPU registers. - * some of them are non-PowerPC names :( - * they are stored in gdb like: - * struct { - * u32 gpr[32]; - * f64 fpr[32]; - * u32 pc, ps, cnd, lr; (ps=msr) - * u32 cnt, xer, mq; - * } - */ - { - int i; - ptr = remcomOutBuffer; - /* General Purpose Regs */ - ptr = mem2hex((char *)regs, ptr, 32 * 4); - /* Floating Point Regs - FIXME */ - /*ptr = mem2hex((char *), ptr, 32 * 8);*/ - for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ - ptr[i] = '0'; - } - ptr += 32*8*2; - /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ - ptr = mem2hex((char *)®s->nip, ptr, 4); - ptr = mem2hex((char *)®s->msr, ptr, 4); - ptr = mem2hex((char *)®s->ccr, ptr, 4); - ptr = mem2hex((char *)®s->link, ptr, 4); - ptr = mem2hex((char *)®s->ctr, ptr, 4); - ptr = mem2hex((char *)®s->xer, ptr, 4); - } - break; - - case 'G': /* set the value of the CPU registers */ - { - ptr = &remcomInBuffer[1]; - - /* - * If the stack pointer has moved, you should pray. - * (cause only god can help you). - */ - - /* General Purpose Regs */ - hex2mem(ptr, (char *)regs, 32 * 4); - - /* Floating Point Regs - FIXME?? */ - /*ptr = hex2mem(ptr, ??, 32 * 8);*/ - ptr += 32*8*2; - - /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ - ptr = hex2mem(ptr, (char *)®s->nip, 4); - ptr = hex2mem(ptr, (char *)®s->msr, 4); - ptr = hex2mem(ptr, (char *)®s->ccr, 4); - ptr = hex2mem(ptr, (char *)®s->link, 4); - ptr = hex2mem(ptr, (char *)®s->ctr, 4); - ptr = hex2mem(ptr, (char *)®s->xer, 4); - - strcpy(remcomOutBuffer,"OK"); - } - break; - case 'H': - /* don't do anything, yet, just acknowledge */ - hexToInt(&ptr, &addr); - strcpy(remcomOutBuffer,"OK"); - break; - - case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ - /* Try to read %x,%x. */ - - ptr = &remcomInBuffer[1]; - - if (hexToInt(&ptr, &addr) && *ptr++ == ',' - && hexToInt(&ptr, &length)) { - if (mem2hex((char *)addr, remcomOutBuffer, - length)) - break; - strcpy(remcomOutBuffer, "E03"); - } else - strcpy(remcomOutBuffer, "E01"); - break; - - case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ - /* Try to read '%x,%x:'. */ - - ptr = &remcomInBuffer[1]; - - if (hexToInt(&ptr, &addr) && *ptr++ == ',' - && hexToInt(&ptr, &length) - && *ptr++ == ':') { - if (hex2mem(ptr, (char *)addr, length)) - strcpy(remcomOutBuffer, "OK"); - else - strcpy(remcomOutBuffer, "E03"); - flush_icache_range(addr, addr+length); - } else - strcpy(remcomOutBuffer, "E02"); - break; - - - case 'k': /* kill the program, actually just continue */ - case 'c': /* cAA..AA Continue; address AA..AA optional */ - /* try to read optional parameter, pc unchanged if no parm */ - - ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr, &addr)) - regs->nip = addr; - -/* Need to flush the instruction cache here, as we may have deposited a - * breakpoint, and the icache probably has no way of knowing that a data ref to - * some location may have changed something that is in the instruction cache. - */ - kgdb_flush_cache_all(); - mtmsr(msr); - - kgdb_interruptible(1); - unlock_kernel(); - kgdb_active = 0; - if (kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - return 1; - - case 's': - kgdb_flush_cache_all(); -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC); - regs->msr |= MSR_DE; -#else - regs->msr |= MSR_SE; -#endif - unlock_kernel(); - kgdb_active = 0; - if (kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - return 1; - - case 'r': /* Reset (if user process..exit ???)*/ - panic("kgdb reset."); - break; - } /* switch */ - if (remcomOutBuffer[0] && kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - /* reply to the request */ - putpacket(remcomOutBuffer); - } /* while(1) */ -} - -/* This function will generate a breakpoint exception. It is used at the - beginning of a program to sync up with a debugger and can be used - otherwise as a quick means to stop program execution and "break" into - the debugger. */ - -void -breakpoint(void) -{ - if (!initialized) { - printk("breakpoint() called b4 kgdb init\n"); - return; - } - - asm(" .globl breakinst \n\ - breakinst: .long 0x7d821008"); -} - -#ifdef CONFIG_KGDB_CONSOLE -/* Output string in GDB O-packet format if GDB has connected. If nothing - output, returns 0 (caller must then handle output). */ -int -kgdb_output_string (const char* s, unsigned int count) -{ - char buffer[512]; - - if (!kgdb_started) - return 0; - - count = (count <= (sizeof(buffer) / 2 - 2)) - ? count : (sizeof(buffer) / 2 - 2); - - buffer[0] = 'O'; - mem2hex (s, &buffer[1], count); - putpacket(buffer); - - return 1; -} -#endif - -static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) -{ - printk("Entering GDB stub\n"); - breakpoint(); -} -static struct sysrq_key_op sysrq_gdb_op = { - .handler = sysrq_handle_gdb, - .help_msg = "Gdb", - .action_msg = "GDB", -}; - -static int gdb_register_sysrq(void) -{ - printk("Registering GDB sysrq handler\n"); - register_sysrq_key('g', &sysrq_gdb_op); - return 0; -} -module_init(gdb_register_sysrq); Index: linux-2.6.17/arch/ppc/kernel/setup.c =================================================================== --- linux-2.6.17.orig/arch/ppc/kernel/setup.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/ppc/kernel/setup.c 2006-09-14 17:39:18.000000000 +0100 @@ -47,10 +47,6 @@ #include #endif -#if defined CONFIG_KGDB -#include -#endif - extern void platform_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); extern void identify_cpu(unsigned long offset, unsigned long cpu); @@ -504,18 +500,6 @@ void __init setup_arch(char **cmdline_p) #endif /* CONFIG_XMON */ if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); -#if defined(CONFIG_KGDB) - if (ppc_md.kgdb_map_scc) - ppc_md.kgdb_map_scc(); - set_debug_traps(); - if (strstr(cmd_line, "gdb")) { - if (ppc_md.progress) - ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); - printk("kgdb breakpoint activated\n"); - breakpoint(); - } -#endif - /* * Set cache line size based on type of cpu as a default. * Systems with OF can look in the properties on the cpu node(s) Index: linux-2.6.17/arch/powerpc/Kconfig.debug =================================================================== --- linux-2.6.17.orig/arch/powerpc/Kconfig.debug 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/powerpc/Kconfig.debug 2006-09-14 17:39:18.000000000 +0100 @@ -18,52 +18,9 @@ config DEBUG_STACK_USAGE This option will slow down process creation somewhat. -config DEBUGGER - bool "Enable debugger hooks" - depends on DEBUG_KERNEL - help - Include in-kernel hooks for kernel debuggers. Unless you are - intending to debug the kernel, say N here. - -config KGDB - bool "Include kgdb kernel debugger" - depends on DEBUGGER && (BROKEN || PPC_GEN550 || 4xx) - select DEBUG_INFO - help - Include in-kernel hooks for kgdb, the Linux kernel source level - debugger. See for more information. - Unless you are intending to debug the kernel, say N here. - -choice - prompt "Serial Port" - depends on KGDB - default KGDB_TTYS1 - -config KGDB_TTYS0 - bool "ttyS0" - -config KGDB_TTYS1 - bool "ttyS1" - -config KGDB_TTYS2 - bool "ttyS2" - -config KGDB_TTYS3 - bool "ttyS3" - -endchoice - -config KGDB_CONSOLE - bool "Enable serial console thru kgdb port" - depends on KGDB && 8xx || CPM2 - help - If you enable this, all serial console messages will be sent - over the gdb stub. - If unsure, say N. - config XMON bool "Include xmon kernel debugger" - depends on DEBUGGER && !PPC_ISERIES + depends on DEBUG_KERNEL && !PPC_ISERIES help Include in-kernel hooks for the xmon kernel monitor/debugger. Unless you are intending to debug the kernel, say N here. @@ -82,6 +39,11 @@ config XMON_DEFAULT xmon is normally disabled unless booted with 'xmon=on'. Use 'xmon=off' to disable xmon init during runtime. +config DEBUGGER + bool + depends on KGDB || XMON + default y + config IRQSTACKS bool "Use separate kernel stacks when processing interrupts" depends on PPC64 Index: linux-2.6.17/arch/powerpc/platforms/powermac/setup.c =================================================================== --- linux-2.6.17.orig/arch/powerpc/platforms/powermac/setup.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/powerpc/platforms/powermac/setup.c 2006-09-14 17:39:18.000000000 +0100 @@ -319,10 +319,6 @@ static void __init pmac_setup_arch(void) l2cr_init(); #endif /* CONFIG_PPC32 */ -#ifdef CONFIG_KGDB - zs_kgdb_hook(0); -#endif - find_via_cuda(); find_via_pmu(); smu_init(); Index: linux-2.6.17/arch/powerpc/mm/fault.c =================================================================== --- linux-2.6.17.orig/arch/powerpc/mm/fault.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/powerpc/mm/fault.c 2006-09-14 17:39:18.000000000 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -424,6 +425,13 @@ void bad_page_fault(struct pt_regs *regs return; } +#ifdef CONFIG_KGDB + if (atomic_read(&debugger_active) && kgdb_may_fault) + /* Restore our previous state. */ + kgdb_fault_longjmp(kgdb_fault_jmp_regs); + /* Not reached. */ +#endif + /* kernel has accessed a bad area */ printk(KERN_ALERT "Unable to handle kernel paging request for "); Index: linux-2.6.17/arch/powerpc/kernel/kgdb.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/arch/powerpc/kernel/kgdb.c 2006-09-14 17:39:18.000000000 +0100 @@ -0,0 +1,423 @@ +/* + * arch/ppc64/kernel/kgdb.c + * + * PowerPC64 backend to the KGDB stub. + * + * Maintainer: Tom Rini + * + * Copied from arch/ppc/kernel/kgdb.c, updated for ppc64 + * + * Copyright (C) 1996 Paul Mackerras (setjmp/longjmp) + * 1998 (c) Michael AK Tesch (tesch@cs.wisc.edu) + * Copyright (C) 2003 Timesys Corporation. + * 2004 (c) MontaVista Software, Inc. + * 2005 (c) MontaVista Software, Inc. + * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com) + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program as licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This table contains the mapping between PowerPC64 hardware trap types, and + * signals, which are primarily what GDB understands. GDB and the kernel + * don't always agree on values, so we use constants taken from gdb-6.2. + */ +static struct hard_trap_info +{ + unsigned int tt; /* Trap type code for powerpc */ + unsigned char signo; /* Signal that we map this trap into */ +} hard_trap_info[] = { + { 0x0100, 0x02 /* SIGINT */ }, /* system reset */ + { 0x0200, 0x0b /* SIGSEGV */ }, /* machine check */ + { 0x0300, 0x0b /* SIGSEGV */ }, /* data access */ + { 0x0380, 0x0b /* SIGSEGV */ }, /* data SLB access */ + { 0x0400, 0x0a /* SIGBUS */ }, /* instruction access */ + { 0x0480, 0x0a /* SIGBUS */ }, /* instruction segment */ + { 0x0500, 0x02 /* SIGINT */ }, /* interrupt */ + { 0x0600, 0x0a /* SIGBUS */ }, /* alignment */ + { 0x0700, 0x04 /* SIGILL */ }, /* program */ + { 0x0800, 0x08 /* SIGFPE */ }, /* fpu unavailable */ + { 0x0900, 0x0e /* SIGALRM */ }, /* decrementer */ + { 0x0a00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0b00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0c00, 0x14 /* SIGCHLD */ }, /* syscall */ + { 0x0d00, 0x05 /* SIGTRAP */ }, /* single step */ + { 0x0e00, 0x04 /* SIGILL */ }, /* reserved */ + { 0x0f00, 0x04 /* SIGILL */ }, /* performance monitor */ + { 0x0f20, 0x08 /* SIGFPE */ }, /* altivec unavailable */ + { 0x1300, 0x05 /* SIGTRAP */ }, /* instruction address break */ + { 0x1500, 0x04 /* SIGILL */ }, /* soft patch */ + { 0x1600, 0x04 /* SIGILL */ }, /* maintenance */ + { 0x1700, 0x04 /* SIGILL */ }, /* altivec assist */ + { 0x1800, 0x04 /* SIGILL */ }, /* thermal */ + { 0x0000, 0x000 } /* Must be last */ +}; + +extern atomic_t cpu_doing_single_step; + +static int computeSignal(unsigned int tt) +{ + struct hard_trap_info *ht; + + for (ht = hard_trap_info; ht->tt && ht->signo; ht++) + if (ht->tt == tt) + return ht->signo; + + return SIGHUP; /* default for things we don't know about */ +} + +static int kgdb_call_nmi_hook(struct pt_regs *regs) +{ + kgdb_nmihook(smp_processor_id(), regs); + return 0; +} + +#ifdef CONFIG_SMP +void kgdb_roundup_cpus(unsigned long flags) +{ + smp_send_debugger_break(MSG_ALL_BUT_SELF); +} +#endif + +/* KGDB functions to use existing PowerPC64 hooks. */ +static int kgdb_debugger(struct pt_regs *regs) +{ + return kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); +} + +static int kgdb_breakpoint(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + + if (*(u32 *) (regs->nip) == *(u32 *) (&arch_kgdb_ops.gdb_bpt_instr)) + regs->nip += 4; + + return 1; +} + +static int kgdb_singlestep(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, SIGTRAP, 0, regs); + return 1; +} + +int kgdb_iabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +int kgdb_dabr_match(struct pt_regs *regs) +{ + if (user_mode(regs)) + return 0; + + kgdb_handle_exception(0, computeSignal(TRAP(regs)), 0, regs); + return 1; +} + +#define PACK64(ptr,src) do { *(ptr++) = (src); } while(0) + +#define PACK32(ptr,src) do { \ + u32 *ptr32; \ + ptr32 = (u32 *)ptr; \ + *(ptr32++) = (src); \ + ptr = (unsigned long *)ptr32; \ + } while(0) + +void regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + unsigned long *ptr = gdb_regs; + + memset(gdb_regs, 0, NUMREGBYTES); + + for (reg = 0; reg < 32; reg++) + PACK64(ptr, regs->gpr[reg]); + + /* fp registers not used by kernel, leave zero */ + ptr += 32; + + PACK64(ptr, regs->nip); + PACK64(ptr, regs->msr); + PACK32(ptr, regs->ccr); + PACK64(ptr, regs->link); + PACK64(ptr, regs->ctr); + PACK32(ptr, regs->xer); + +#if 0 + Following are in struct thread_struct, not struct pt_regs, + ignoring for now since kernel does not use them. Would it + make sense to get them from the thread that kgdb is set to? + + If this code is enabled, update the definition of NUMREGBYTES to + include the vector registers and vector state registers. + + PACK32(ptr, p->thread->fpscr); + + /* vr registers not used by kernel, leave zero */ + ptr += 64; + + PACK32(ptr, p->thread->vscr); + PACK32(ptr, p->thread->vrsave); +#else + /* fpscr not used by kernel, leave zero */ + PACK32(ptr, 0); +#endif + + BUG_ON((unsigned long)ptr > + (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); +} + +void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) +{ + struct pt_regs *regs = (struct pt_regs *)(p->thread.ksp + + STACK_FRAME_OVERHEAD); + int reg; + unsigned long *ptr = gdb_regs; + + memset(gdb_regs, 0, NUMREGBYTES); + + /* Regs GPR0-2 */ + for (reg = 0; reg < 3; reg++) + PACK64(ptr, regs->gpr[reg]); + + /* Regs GPR3-13 are caller saved, not in regs->gpr[] */ + for (reg = 3; reg < 14; reg++) + PACK64(ptr, 0); + + /* Regs GPR14-31 */ + for (reg = 14; reg < 32; reg++) + PACK64(ptr, regs->gpr[reg]); + + /* fp registers not used by kernel, leave zero */ + ptr += 32; + + PACK64(ptr, regs->nip); + PACK64(ptr, regs->msr); + PACK32(ptr, regs->ccr); + PACK64(ptr, regs->link); + PACK64(ptr, regs->ctr); + PACK32(ptr, regs->xer); + +#if 0 + Following are in struct thread_struct, not struct pt_regs, + ignoring for now since kernel does not use them. Would it + make sense to get them from the thread that kgdb is set to? + + If this code is enabled, update the definition of NUMREGBYTES to + include the vector registers and vector state registers. + + PACK32(ptr, p->thread->fpscr); + + /* vr registers not used by kernel, leave zero */ + ptr += 64; + + PACK32(ptr, p->thread->vscr); + PACK32(ptr, p->thread->vrsave); +#else + /* fpscr not used by kernel, leave zero */ + PACK32(ptr, 0); +#endif + + BUG_ON((unsigned long)ptr > + (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); +} + +#define UNPACK64(dest,ptr) do { dest = *(ptr++); } while(0) + +#define UNPACK32(dest,ptr) do { \ + u32 *ptr32; \ + ptr32 = (u32 *)ptr; \ + dest = *(ptr32++); \ + ptr = (unsigned long *)ptr32; \ + } while(0) + +void gdb_regs_to_regs(unsigned long *gdb_regs, struct pt_regs *regs) +{ + int reg; + unsigned long *ptr = gdb_regs; + + for (reg = 0; reg < 32; reg++) + UNPACK64(regs->gpr[reg], ptr); + + /* fp registers not used by kernel, leave zero */ + ptr += 32; + + UNPACK64(regs->nip, ptr); + UNPACK64(regs->msr, ptr); + UNPACK32(regs->ccr, ptr); + UNPACK64(regs->link, ptr); + UNPACK64(regs->ctr, ptr); + UNPACK32(regs->xer, ptr); + +#if 0 + Following are in struct thread_struct, not struct pt_regs, + ignoring for now since kernel does not use them. Would it + make sense to get them from the thread that kgdb is set to? + + If this code is enabled, update the definition of NUMREGBYTES to + include the vector registers and vector state registers. + + /* fpscr, vscr, vrsave not used by kernel, leave unchanged */ + + UNPACK32(p->thread->fpscr, ptr); + + /* vr registers not used by kernel, leave zero */ + ptr += 64; + + UNPACK32(p->thread->vscr, ptr); + UNPACK32(p->thread->vrsave, ptr); +#endif + + BUG_ON((unsigned long)ptr > + (unsigned long)(((void *)gdb_regs) + NUMREGBYTES)); +} + +/* + * This function does PowerPC64 specific procesing for interfacing to gdb. + */ +int kgdb_arch_handle_exception(int vector, int signo, int err_code, + char *remcom_in_buffer, char *remcom_out_buffer, + struct pt_regs *linux_regs) +{ + char *ptr = &remcom_in_buffer[1]; + unsigned long addr; + + switch (remcom_in_buffer[0]) { + /* + * sAA..AA Step one instruction from AA..AA + * This will return an error to gdb .. + */ + case 's': + case 'c': + /* handle the optional parameter */ + if (kgdb_hex2long(&ptr, &addr)) + linux_regs->nip = addr; + + atomic_set(&cpu_doing_single_step, -1); + /* set the trace bit if we're stepping */ + if (remcom_in_buffer[0] == 's') { + linux_regs->msr |= MSR_SE; + debugger_step = 1; + if (kgdb_contthread) + atomic_set(&cpu_doing_single_step, + smp_processor_id()); + } + return 0; + } + + return -1; +} + +int kgdb_fault_setjmp(unsigned long *curr_context) +{ + __asm__ __volatile__("mflr 0; std 0,0(%0)\n\ + std 1,8(%0)\n\ + std 2,16(%0)\n\ + mfcr 0; std 0,24(%0)\n\ + std 13,32(%0)\n\ + std 14,40(%0)\n\ + std 15,48(%0)\n\ + std 16,56(%0)\n\ + std 17,64(%0)\n\ + std 18,72(%0)\n\ + std 19,80(%0)\n\ + std 20,88(%0)\n\ + std 21,96(%0)\n\ + std 22,104(%0)\n\ + std 23,112(%0)\n\ + std 24,120(%0)\n\ + std 25,128(%0)\n\ + std 26,136(%0)\n\ + std 27,144(%0)\n\ + std 28,152(%0)\n\ + std 29,160(%0)\n\ + std 30,168(%0)\n\ + std 31,176(%0)\n" : : "r" (curr_context)); + return 0; +} + +void kgdb_fault_longjmp(unsigned long *curr_context) +{ + __asm__ __volatile__("ld 13,32(%0)\n\ + ld 14,40(%0)\n\ + ld 15,48(%0)\n\ + ld 16,56(%0)\n\ + ld 17,64(%0)\n\ + ld 18,72(%0)\n\ + ld 19,80(%0)\n\ + ld 20,88(%0)\n\ + ld 21,96(%0)\n\ + ld 22,104(%0)\n\ + ld 23,112(%0)\n\ + ld 24,120(%0)\n\ + ld 25,128(%0)\n\ + ld 26,136(%0)\n\ + ld 27,144(%0)\n\ + ld 28,152(%0)\n\ + ld 29,160(%0)\n\ + ld 30,168(%0)\n\ + ld 31,176(%0)\n\ + ld 0,24(%0)\n\ + mtcrf 0x38,0\n\ + ld 0,0(%0)\n\ + ld 1,8(%0)\n\ + ld 2,16(%0)\n\ + mtlr 0\n\ + mr 3,1\n" : : "r" (curr_context)); +} + +/* + * Global data + */ +struct kgdb_arch arch_kgdb_ops = { + .gdb_bpt_instr = {0x7d, 0x82, 0x10, 0x08}, +}; + +int kgdb_not_implemented(struct pt_regs *regs) +{ + return 0; +} + +int kgdb_arch_init(void) +{ +#ifdef CONFIG_XMON +#error Both XMON and KGDB selected in .config. Unselect one of them. +#endif + + __debugger_ipi = kgdb_call_nmi_hook; + __debugger = kgdb_debugger; + __debugger_bpt = kgdb_breakpoint; + __debugger_sstep = kgdb_singlestep; + __debugger_iabr_match = kgdb_iabr_match; + __debugger_dabr_match = kgdb_dabr_match; + __debugger_fault_handler = kgdb_not_implemented; + + return 0; +} + +arch_initcall(kgdb_arch_init); Index: linux-2.6.17/arch/powerpc/kernel/setup_32.c =================================================================== --- linux-2.6.17.orig/arch/powerpc/kernel/setup_32.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/arch/powerpc/kernel/setup_32.c 2006-09-14 17:39:18.000000000 +0100 @@ -45,10 +45,6 @@ #define DBG(fmt...) -#if defined CONFIG_KGDB -#include -#endif - extern void bootx_init(unsigned long r4, unsigned long phys); struct ide_machdep_calls ppc_ide_md; @@ -248,18 +244,6 @@ void __init setup_arch(char **cmdline_p) /* Register early console */ register_early_udbg_console(); -#if defined(CONFIG_KGDB) - if (ppc_md.kgdb_map_scc) - ppc_md.kgdb_map_scc(); - set_debug_traps(); - if (strstr(cmd_line, "gdb")) { - if (ppc_md.progress) - ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); - printk("kgdb breakpoint activated\n"); - breakpoint(); - } -#endif - /* * Set cache line size based on type of cpu as a default. * Systems with OF can look in the properties on the cpu node(s) Index: linux-2.6.17/arch/powerpc/kernel/Makefile =================================================================== --- linux-2.6.17.orig/arch/powerpc/kernel/Makefile 2006-09-14 17:37:10.000000000 +0100 +++ linux-2.6.17/arch/powerpc/kernel/Makefile 2006-09-14 17:39:18.000000000 +0100 @@ -60,6 +60,7 @@ obj-$(CONFIG_BOOTX_TEXT) += btext.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_KPROBES) += kprobes.o obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o +obj-$(CONFIG_KGDB) += kgdb.o module-$(CONFIG_PPC64) += module_64.o obj-$(CONFIG_MODULES) += $(module-y) Index: linux-2.6.17/lib/Kconfig.debug =================================================================== --- linux-2.6.17.orig/lib/Kconfig.debug 2006-09-14 17:38:40.000000000 +0100 +++ linux-2.6.17/lib/Kconfig.debug 2006-09-14 17:39:18.000000000 +0100 @@ -378,7 +378,7 @@ config WANT_EXTRA_DEBUG_INFORMATION config KGDB bool "KGDB: kernel debugging with remote gdb" select WANT_EXTRA_DEBUG_INFORMATION - depends on DEBUG_KERNEL && (X86) + depends on DEBUG_KERNEL && (X86 || PPC) help If you say Y here, it will be possible to remotely debug the kernel using gdb. It is strongly suggested that you enable @@ -404,6 +404,8 @@ choice prompt "Method for KGDB communication" depends on KGDB default KGDB_8250_NOMODULE + default KGDB_MPSC if SERIAL_MPSC + default KGDB_CPM_UART if (8xx || 8260) 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 @@ -440,6 +442,20 @@ config KGDBOE_NOMODULE In order for this to work, the ethernet interface specified must support the NETPOLL API, and this must be initialized at boot. See the documentation for syntax. + +config KGDB_MPSC + bool "KGDB on MV64x60 MPSC" + depends on SERIAL_MPSC + help + Uses a Marvell GT64260B or MV64x60 Multi-Purpose Serial + Controller (MPSC) channel. Note that the GT64260A is not + supported. + +config KGDB_CPM_UART + bool "KGDB: On CPM UART" + depends on PPC && (CPM2 || 8xx) + help + Uses CPM UART to communicate with the host GDB. endchoice config KGDBOE Index: linux-2.6.17/include/asm-ppc/machdep.h =================================================================== --- linux-2.6.17.orig/include/asm-ppc/machdep.h 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/include/asm-ppc/machdep.h 2006-09-14 17:39:18.000000000 +0100 @@ -72,9 +72,7 @@ struct machdep_calls { unsigned long (*find_end_of_memory)(void); void (*setup_io_mappings)(void); - void (*early_serial_map)(void); void (*progress)(char *, unsigned short); - void (*kgdb_map_scc)(void); unsigned char (*nvram_read_val)(int addr); void (*nvram_write_val)(int addr, unsigned char val); Index: linux-2.6.17/include/asm-ppc/kgdb.h =================================================================== --- linux-2.6.17.orig/include/asm-ppc/kgdb.h 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/include/asm-ppc/kgdb.h 2006-09-14 17:39:18.000000000 +0100 @@ -1,57 +1,18 @@ -/* - * kgdb.h: Defines and declarations for serial line source level - * remote debugging of the Linux kernel using gdb. - * - * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ #ifdef __KERNEL__ -#ifndef _PPC_KGDB_H -#define _PPC_KGDB_H - +#ifndef __PPC_KGDB_H__ +#define __PPC_KGDB_H__ +#include #ifndef __ASSEMBLY__ - -/* Things specific to the gen550 backend. */ -struct uart_port; - -extern void gen550_progress(char *, unsigned short); -extern void gen550_kgdb_map_scc(void); -extern void gen550_init(int, struct uart_port *); - -/* Things specific to the pmac backend. */ -extern void zs_kgdb_hook(int tty_num); - -/* To init the kgdb engine. (called by serial hook)*/ -extern void set_debug_traps(void); - -/* To enter the debugger explicitly. */ -extern void breakpoint(void); - -/* For taking exceptions - * these are defined in traps.c - */ -extern int (*debugger)(struct pt_regs *regs); + /* For taking exceptions + * these are defined in traps.c + */ +struct pt_regs; +extern void (*debugger)(struct pt_regs *regs); extern int (*debugger_bpt)(struct pt_regs *regs); extern int (*debugger_sstep)(struct pt_regs *regs); extern int (*debugger_iabr_match)(struct pt_regs *regs); extern int (*debugger_dabr_match)(struct pt_regs *regs); extern void (*debugger_fault_handler)(struct pt_regs *regs); - -/* What we bring to the party */ -int kgdb_bpt(struct pt_regs *regs); -int kgdb_sstep(struct pt_regs *regs); -void kgdb(struct pt_regs *regs); -int kgdb_iabr_match(struct pt_regs *regs); -int kgdb_dabr_match(struct pt_regs *regs); - -/* - * external low-level support routines (ie macserial.c) - */ -extern void kgdb_interruptible(int); /* control interrupts from serial */ -extern void putDebugChar(char); /* write a single character */ -extern char getDebugChar(void); /* read and return a single char */ - -#endif /* !(__ASSEMBLY__) */ -#endif /* !(_PPC_KGDB_H) */ +#endif /* !__ASSEMBLY__ */ +#endif /* __PPC_KGDB_H__ */ #endif /* __KERNEL__ */ Index: linux-2.6.17/include/asm-ppc/mv64x60.h =================================================================== --- linux-2.6.17.orig/include/asm-ppc/mv64x60.h 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/include/asm-ppc/mv64x60.h 2006-09-14 17:39:18.000000000 +0100 @@ -348,6 +348,8 @@ u32 mv64x60_calc_mem_size(struct mv64x60 void mv64x60_progress_init(u32 base); void mv64x60_mpsc_progress(char *s, unsigned short hex); +struct platform_device * mv64x60_early_get_pdev_data(const char *name, + int id, int remove); extern struct mv64x60_32bit_window gt64260_32bit_windows[MV64x60_32BIT_WIN_COUNT]; Index: linux-2.6.17/include/asm-ppc/mv64x60_defs.h =================================================================== --- linux-2.6.17.orig/include/asm-ppc/mv64x60_defs.h 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/include/asm-ppc/mv64x60_defs.h 2006-09-14 17:39:18.000000000 +0100 @@ -57,7 +57,8 @@ #define MV64x60_IRQ_I2C 37 #define MV64x60_IRQ_BRG 39 #define MV64x60_IRQ_MPSC_0 40 -#define MV64x60_IRQ_MPSC_1 42 +#define MV64360_IRQ_MPSC_1 41 +#define GT64260_IRQ_MPSC_1 42 #define MV64x60_IRQ_COMM 43 #define MV64x60_IRQ_P0_GPP_0_7 56 #define MV64x60_IRQ_P0_GPP_8_15 57 Index: linux-2.6.17/include/asm-powerpc/kgdb.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.17/include/asm-powerpc/kgdb.h 2006-09-14 17:39:18.000000000 +0100 @@ -0,0 +1,73 @@ +/* + * include/asm-powerpc/kgdb.h + * + * The PowerPC (32/64) specific defines / externs for KGDB. Based on + * the previous 32bit and 64bit specific files, which had the following + * copyrights: + * + * PPC64 Mods (C) 2005 Frank Rowand (frowand@mvista.com) + * PPC Mods (C) 2004 Tom Rini (trini@mvista.com) + * PPC Mods (C) 2003 John Whitney (john.whitney@timesys.com) + * PPC Mods (C) 1998 Michael Tesch (tesch@cs.wisc.edu) + * + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Author: Tom Rini + * + * 2006 (c) MontaVista Software, Inc. 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. + */ +#ifdef __KERNEL__ +#ifndef __POWERPC_KGDB_H__ +#define __POWERPC_KGDB_H__ + +#ifndef __ASSEMBLY__ + +#define BREAK_INSTR_SIZE 4 +#define BUFMAX ((NUMREGBYTES * 2) + 512) +#define OUTBUFMAX ((NUMREGBYTES * 2) + 512) +#define BREAKPOINT() asm(".long 0x7d821008"); /* twge r2, r2 */ +#define CACHE_FLUSH_IS_SAFE 1 + +/* The number bytes of registers we have to save depends on a few + * things. For 64bit we default to not including vector registers and + * vector state registers. */ +#ifdef CONFIG_PPC64 +/* + * 64 bit (8 byte) registers: + * 32 gpr, 32 fpr, nip, msr, link, ctr + * 32 bit (4 byte) registers: + * ccr, xer, fpscr + */ +#define NUMREGBYTES ((68 * 8) + (3 * 4)) +#if 0 +/* The following adds in vector registers and vector state registers. */ +/* 128 bit (16 byte) registers: + * 32 vr + * 64 bit (8 byte) registers: + * 32 gpr, 32 fpr, nip, msr, link, ctr + * 32 bit (4 byte) registers: + * ccr, xer, fpscr, vscr, vrsave + */ +#define NUMREGBYTES ((128 * 16) + (68 * 8) + (5 * 4)) +#endif +#define NUMCRITREGBYTES 184 +#else /* CONFIG_PPC32 */ +/* On non-E500 family PPC32 we determine the size by picking the last + * register we need, but on E500 we skip sections so we list what we + * need to store, and add it up. */ +#ifndef CONFIG_E500 +#define MAXREG (PT_FPSCR+1) +#else +/* 32 GPRs (8 bytes), nip, msr, ccr, link, ctr, xer, acc (8 bytes), spefscr*/ +#define MAXREG ((32*2)+6+2+1) +#endif +#define NUMREGBYTES (MAXREG * sizeof(int)) +/* CR/LR, R1, R2, R13-R31 inclusive. */ +#define NUMCRITREGBYTES (23 * sizeof(int)) +#endif /* 32/64 */ +#endif /* !(__ASSEMBLY__) */ +#endif /* !__POWERPC_KGDB_H__ */ +#endif /* __KERNEL__ */ Index: linux-2.6.17/drivers/serial/mpsc.c =================================================================== --- linux-2.6.17.orig/drivers/serial/mpsc.c 2006-09-14 17:36:59.000000000 +0100 +++ linux-2.6.17/drivers/serial/mpsc.c 2006-09-14 17:39:18.000000000 +0100 @@ -242,6 +242,11 @@ struct mpsc_port_info *mpsc_device_remov #define MPSC_RCRR 0x0004 #define MPSC_TCRR 0x0008 +/* MPSC Interrupt registers (offset from MV64x60_SDMA_INTR_OFFSET) */ +#define MPSC_INTR_CAUSE 0x0004 +#define MPSC_INTR_MASK 0x0084 +#define MPSC_INTR_CAUSE_RCC (1<<6) + /* Serial DMA Controller Interface Registers */ #define SDMA_SDC 0x0000 #define SDMA_SDCM 0x0008