From patchwork Fri Sep 30 11:24:21 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konrad Eisele X-Patchwork-Id: 117131 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 2FE05B6F7F for ; Fri, 30 Sep 2011 22:06:22 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932120Ab1I3MGS (ORCPT ); Fri, 30 Sep 2011 08:06:18 -0400 Received: from mail202c2.megamailservers.com ([69.49.111.103]:53074 "EHLO mail202c2.megamailservers.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758511Ab1I3MGQ (ORCPT ); Fri, 30 Sep 2011 08:06:16 -0400 X-Greylist: delayed 2245 seconds by postgrey-1.27 at vger.kernel.org; Fri, 30 Sep 2011 08:06:10 EDT X-Authenticated-User: konrad.gaisler.com Received: from localhost.localdomain (gaisler.se [92.33.28.242]) (authenticated bits=0) by mail202c2.megamailservers.com (8.13.6/8.13.1) with ESMTP id p8UBUZkO028441; Fri, 30 Sep 2011 07:30:41 -0400 From: Konrad Eisele To: davem@davemloft.net Cc: sparclinux@vger.kernel.org Subject: [PATCH 2/4] apbuart: add support for virtual KGDB<->GRMON channel Date: Fri, 30 Sep 2011 13:24:21 +0200 Message-Id: <1317381862-24939-3-git-send-email-konrad@gaisler.com> X-Mailer: git-send-email 1.6.4.1 In-Reply-To: <1317381862-24939-1-git-send-email-konrad@gaisler.com> References: <1317381862-24939-1-git-send-email-konrad@gaisler.com> X-CSC: 0 X-CHA: v=1.1 cv=t6P6ZnH7F4B+FTDzBT2sv7Wly1PyMf9jGdjNuUfj6/c= c=1 sm=1 a=BzMK5cQDNJAA:10 a=U62ajLuCel8A:10 a=jXKJviUpWSOlMmIvGrHOfw==:17 a=ebG-ZW-8AAAA:8 a=GQjqg2efc5UVNbjzfUwA:9 a=RGyzl4kBycSdrG8IQnYA:7 a=cCYF7-FHeg4A:10 a=jXKJviUpWSOlMmIvGrHOfw==:117 Sender: sparclinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: sparclinux@vger.kernel.org Add support for a virtual GRMON<->KGDB channel that is created using share memory polling by GRMON. Start GRMON with the option "-vchannel" to enable polling. This feature enables connecting to KGDB without having an hardware serial connection, but using GRMON as an tunnel. Reorder Makefile addition so that apbuart.o gets inserted before kgdboc.o. Add Kconfig option SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL to enable the feature. Signed-off-by: Konrad Eisele --- drivers/tty/serial/Kconfig | 12 ++++ drivers/tty/serial/Makefile | 2 +- drivers/tty/serial/apbuart.c | 133 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 128 insertions(+), 19 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b3692e6..896042b 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1526,6 +1526,18 @@ config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE help Support for running a console on the GRLIB APBUART +config SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL + bool "Virtual channel created by GRMON to communicate with KGDB" + depends on SERIAL_GRLIB_GAISLER_APBUART=y + default y + help + Add support for a virtual GRMON<->KGDB channel that + is created using share memory polling by GRMON. Start + GRMON with the option "-vchannel" to enable polling. This + feature enables connecting to KGDB without having an hardware + serial connection, but using GRMON as an tunnel. Also + enable KGDB_SERIAL_CONSOLE to use this feature. + config SERIAL_ALTERA_JTAGUART tristate "Altera JTAG UART support" select SERIAL_CORE diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index cb2628f..ea3fc05 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -81,10 +81,10 @@ obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o +obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o -obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 5f40f42..38eb8cc 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -124,7 +124,6 @@ static void apbuart_rx_chars(struct uart_port *port) uart_insert_char(port, rsr, UART_STATUS_OE, ch, flag); - ignore_char: status = UART_GET_STATUS(port); } @@ -350,11 +349,88 @@ static struct uart_ops grlib_apbuart_ops = { .config_port = apbuart_config_port, .verify_port = apbuart_verify_port, #ifdef CONFIG_CONSOLE_POLL - .poll_get_char = apbuart_poll_get_char, - .poll_put_char = apbuart_poll_put_char, -#endif + .poll_get_char = apbuart_poll_get_char, + .poll_put_char = apbuart_poll_put_char, +#endif +}; + +#undef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL_HAS +#if defined(CONFIG_SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL) && defined(CONFIG_SPARC_LEON) && defined(CONFIG_CONSOLE_POLL) +#define CONFIG_SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL_HAS +#include + +/* + * Use a memory array that is continuously read/written by GRMON + * as a communication channel. GRMON will test for the existence + * of symbol apbuart_grmon_vchannel. If present the "shared memory" + * of apbuart_grmon_vchannel will be used to comunicate with linux. + * apbuart_grmon_vchannel is only used for KGDB polling communication. + */ +unsigned int apbuart_grmon_vchannel[4] = { 0, 0, 0, 0 }; + +EXPORT_SYMBOL(apbuart_grmon_vchannel); + +static void apbuart_set_termios_v(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + return; +} + +unsigned char apbuart_poll_get_char_v_b[4]; +unsigned char apbuart_poll_get_char_v_c = 0; +static int apbuart_poll_get_char_v(struct uart_port *port) +{ + int c = NO_POLL_CHAR, cnt, i; + if (apbuart_poll_get_char_v_c) { + apbuart_poll_get_char_v_c--; + c = apbuart_poll_get_char_v_b[0] & 0xff; + for (i = 0; i < apbuart_poll_get_char_v_c; i++) { + apbuart_poll_get_char_v_b[i] = + apbuart_poll_get_char_v_b[i + 1]; + } + } + + /* + * poll for new char GRMON from. When grmon has a new char it + * will set write it into apbuart_grmon_vchannel[0] and then + * set apbuart_grmon_vchannel[1] + */ + else if ((cnt = LEON3_BYPASS_LOAD_PA(__pa(&apbuart_grmon_vchannel[1])))) { + unsigned int ar = + LEON3_BYPASS_LOAD_PA(__pa(&apbuart_grmon_vchannel[0])); + LEON_BYPASS_STORE_PA(__pa(&apbuart_grmon_vchannel[1]), 0); + c = ar & 0xff; + for (i = 1; i < cnt; i++) { + apbuart_poll_get_char_v_b[apbuart_poll_get_char_v_c++] = + (ar >> (8 * i)) & 0xff; + } + } + + return c; +} +static void apbuart_console_putchar_v(struct uart_port *port, unsigned char ch) +{ + /* + * poll for GRMON readout. When grmon has read apbuart_grmon_vchannel[3] + * it will clear apbuart_grmon_vchannel[2] + */ + while (LEON3_BYPASS_LOAD_PA(__pa(&apbuart_grmon_vchannel[2]))) { + } + LEON_BYPASS_STORE_PA(__pa(&apbuart_grmon_vchannel[3]), ch & 0xff); + LEON_BYPASS_STORE_PA(__pa(&apbuart_grmon_vchannel[2]), 1); + return; +} + +static struct uart_ops grlib_apbuart_v_ops = { + .set_termios = apbuart_set_termios_v, + .poll_get_char = apbuart_poll_get_char_v, + .poll_put_char = apbuart_console_putchar_v, }; +static struct uart_port grlib_apbuart_vport; +#endif + static struct uart_port grlib_apbuart_ports[UART_NR]; static struct device_node *grlib_apbuart_nodes[UART_NR]; @@ -423,7 +499,6 @@ static void apbuart_flush_fifo(struct uart_port *port) UART_GET_CHAR(port); } - /* ======================================================================== */ /* Console driver, if enabled */ /* ======================================================================== */ @@ -551,7 +626,6 @@ static struct console grlib_apbuart_console = { .data = &grlib_apbuart_driver, }; - static int grlib_apbuart_configure(void); static int __init apbuart_console_init(void) @@ -579,7 +653,6 @@ static struct uart_driver grlib_apbuart_driver = { .cons = APBUART_CONSOLE, }; - /* ======================================================================== */ /* OF Platform Driver */ /* ======================================================================== */ @@ -598,12 +671,12 @@ static int __devinit apbuart_probe(struct platform_device *op) port->dev = &op->dev; port->irq = op->archdata.irqs[0]; - uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *) port); + uart_add_one_port(&grlib_apbuart_driver, (struct uart_port *)port); - apbuart_flush_fifo((struct uart_port *) port); + apbuart_flush_fifo((struct uart_port *)port); printk(KERN_INFO "grlib-apbuart at 0x%llx, irq %d\n", - (unsigned long long) port->mapbase, port->irq); + (unsigned long long)port->mapbase, port->irq); return 0; } @@ -620,13 +693,12 @@ static struct of_device_id __initdata apbuart_match[] = { static struct platform_driver grlib_apbuart_of_driver = { .probe = apbuart_probe, .driver = { - .owner = THIS_MODULE, - .name = "grlib-apbuart", - .of_match_table = apbuart_match, - }, + .owner = THIS_MODULE, + .name = "grlib-apbuart", + .of_match_table = apbuart_match, + }, }; - static int grlib_apbuart_configure(void) { struct device_node *np; @@ -641,7 +713,7 @@ static int grlib_apbuart_configure(void) ampopts = of_get_property(np, "ampopts", NULL); if (ampopts && (*ampopts == 0)) - continue; /* Ignore if used by another OS instance */ + continue; /* Ignore if used by another OS instance */ regs = of_get_property(np, "reg", NULL); /* Frequency of APB Bus is frequency of UART */ freq_hz = of_get_property(np, "freq", NULL); @@ -656,14 +728,16 @@ static int grlib_apbuart_configure(void) port = &grlib_apbuart_ports[line]; port->mapbase = addr; - port->membase = ioremap(addr, sizeof(struct grlib_apbuart_regs_map)); + port->membase = + ioremap(addr, sizeof(struct grlib_apbuart_regs_map)); port->irq = 0; port->iotype = UPIO_MEM; port->ops = &grlib_apbuart_ops; port->flags = UPF_BOOT_AUTOCONF; port->line = line; port->uartclk = *freq_hz; - port->fifosize = apbuart_scan_fifo_size((struct uart_port *) port, line); + port->fifosize = + apbuart_scan_fifo_size((struct uart_port *)port, line); line++; /* We support maximum UART_NR uarts ... */ @@ -671,6 +745,18 @@ static int grlib_apbuart_configure(void) break; } +#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL_HAS + grlib_apbuart_vport.mapbase = 0; + grlib_apbuart_vport.membase = 0; + grlib_apbuart_vport.irq = 0; + grlib_apbuart_vport.iotype = UPIO_MEM; + grlib_apbuart_vport.ops = &grlib_apbuart_v_ops; + grlib_apbuart_vport.flags = UPF_BOOT_AUTOCONF; + grlib_apbuart_vport.line = line; + grlib_apbuart_vport.fifosize = 0; + line++; +#endif + grlib_apbuart_driver.nr = grlib_apbuart_port_nr = line; return line ? 0 : -ENODEV; } @@ -702,6 +788,17 @@ static int __init grlib_apbuart_init(void) uart_unregister_driver(&grlib_apbuart_driver); return ret; } +#ifdef CONFIG_SERIAL_GRLIB_GAISLER_APBUART_GRMON_VIRTUAL_HAS + + /* register an extra virtual port that is used for + * GRMON<->KGDB communication */ + uart_add_one_port(&grlib_apbuart_driver, + (struct uart_port *)&grlib_apbuart_vport); + printk(KERN_INFO + "apbuart: virtual KGDB channel for grmon, use cmdline arg \"kgdboc=kms,ttyS%d,38400\".\napbuart: Use option \"-vchannel\" when starting GRMON.\napbuart: apbuart_grmon_vchannel at pa:0x%x\n", + grlib_apbuart_vport.line, (int)__pa(&apbuart_grmon_vchannel)); + +#endif return ret; }