From: Vitaly Bordug <vbordug@ru.mvista.com>
To: Chris <chris@2net.co.uk>
Cc: linuxppc-embedded list <linuxppc-embedded@ozlabs.org>
Subject: Re: kgdb support in Linux 2.6 for 8xx
Date: Fri, 21 Oct 2005 16:15:09 +0400 [thread overview]
Message-ID: <4358DBCD.8090709@ru.mvista.com> (raw)
In-Reply-To: <4358C4AC.2070900@2net.co.uk>
[-- Attachment #1: Type: text/plain, Size: 1068 bytes --]
Hi!
Chris wrote:
> Hi,
>
> It would be nice to be able to do some kernel debugging on my TQM823L
> board running 2.6 (2.6.13.1, to be exact). I have two questions
>
> 1. Has anyone got kgdboe working in this configuration? If so, could you
> give me a pointer to a patch?
>
Not exactly. I have implemented support for KGDB on cpm_uart driven
boards (most of 8xx use it), but it is only tested on 827x family.
Anyway, 8xx should work with minimal changes.
> 2. kgdb over serial is lacking the getDebugChar and putDebugChar
> functions that used to be in 8xx_io/uart.c. Has anyone done any work on
> merging them into 2.6?
>
There is a kgdb community project - http://kgdb.sf.net. The attached
patch is for this one (it has been submitted but not in the CVS so far).
> [OK, that's actually three questions. One just crept in]
>
> Thanks in advance,
> Chris
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
>
--
Sincerely,
Vitaly
[-- Attachment #2: cpm_uart_kgdb.patch --]
[-- Type: text/x-patch, Size: 14395 bytes --]
This add support for KGDB using cpm_uart driver.
Should work on all the boards utilizing it, tested on 8272ADS.
Index: linux-2.6.13.1/drivers/serial/cpm_uart/Makefile
===================================================================
--- linux-2.6.13.1.orig/drivers/serial/cpm_uart/Makefile
+++ linux-2.6.13.1/drivers/serial/cpm_uart/Makefile
@@ -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_kgdb.o
cpm_uart-objs := cpm_uart_core.o $(cpm_uart-objs-y)
Index: linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart.h
===================================================================
--- linux-2.6.13.1.orig/drivers/serial/cpm_uart/cpm_uart.h
+++ linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart.h
@@ -42,6 +42,38 @@
#define SCC_WAIT_CLOSING 100
+#ifdef CONFIG_KGDB
+
+/* 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
+#error The S(M)CC for kgdb console is undefined
+#endif
+
+#endif /* CONFIG_KGDB */
+
struct uart_cpm_port {
struct uart_port port;
u16 rx_nrfifos;
@@ -77,6 +109,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);
@@ -90,4 +125,19 @@ void scc2_lineif(struct uart_cpm_port *p
void scc3_lineif(struct uart_cpm_port *pinfo);
void scc4_lineif(struct uart_cpm_port *pinfo);
+static inline unsigned long cpu2cpm_addr(void *addr)
+{
+ if ((unsigned long)addr >= CPM_ADDR)
+ return (unsigned long)addr;
+ return virt_to_bus(addr);
+}
+
+static inline void *cpm2cpu_addr(unsigned long addr)
+{
+ if (addr >= CPM_ADDR)
+ return (void *)addr;
+ return bus_to_virt(addr);
+}
+
+
#endif /* CPM_UART_H */
Index: linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart_core.c
===================================================================
--- linux-2.6.13.1.orig/drivers/serial/cpm_uart/cpm_uart_core.c
+++ linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -71,20 +71,6 @@ static void cpm_uart_initbd(struct uart_
/**************************************************************/
-static inline unsigned long cpu2cpm_addr(void *addr)
-{
- if ((unsigned long)addr >= CPM_ADDR)
- return (unsigned long)addr;
- return virt_to_bus(addr);
-}
-
-static inline void *cpm2cpu_addr(unsigned long addr)
-{
- if (addr >= CPM_ADDR)
- return (void *)addr;
- return bus_to_virt(addr);
-}
-
/*
* Check, if transmit buffers are processed
*/
@@ -992,22 +978,17 @@ struct uart_cpm_port cpm_uart_ports[UART
},
};
-#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;
@@ -1071,36 +1052,16 @@ static void cpm_uart_console_write(struc
pinfo->tx_cur = (volatile cbd_t *) bdp;
}
-/*
- * Setup console. Be careful is called early !
- */
-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;
+ 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;
-
- 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;
- }
-
/*
* Setup any port IO, connect any baud rate generators,
* etc. This is expected to be handled by board
@@ -1108,7 +1069,6 @@ static int __init cpm_uart_console_setup
*/
if (pinfo->set_lineif)
pinfo->set_lineif(pinfo);
-
if (IS_SMC(pinfo)) {
pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
@@ -1116,8 +1076,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;
@@ -1129,6 +1088,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;
@@ -1190,6 +1199,10 @@ static int __init cpm_uart_init(void)
for (i = 0; i < cpm_uart_nr; i++) {
int con = cpm_uart_port_map[i];
+
+ /* We are not interested in ports yet utilized by kgdb */
+ if(con == KGDB_PINFO_INDEX)
+ continue;
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.13.1/drivers/serial/cpm_uart/cpm_uart_cpm2.c
===================================================================
--- linux-2.6.13.1.orig/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -252,6 +252,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.13.1/lib/Kconfig.debug
===================================================================
--- linux-2.6.13.1.orig/lib/Kconfig.debug
+++ linux-2.6.13.1/lib/Kconfig.debug
@@ -196,6 +196,7 @@ choice
default KGDB_8250_NOMODULE
default KGDB_SIBYTE if SIBYTE_SB1xxx_SOC
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
@@ -221,6 +222,11 @@ config KGDB_8250_NOMODULE
GDB. This is independent of the normal (SERIAL_8250) driver
for this chipset.
+config KGDB_CPM_UART
+ bool "KGDB: On CPM UART"
+ help
+ Uses CPM UART to communicate with the host GDB.
+
config KGDBOE_NOMODULE
bool "KGDB: On ethernet - in kernel"
select KGDBOE
@@ -247,6 +253,62 @@ config KGDB_SIBYTE
endchoice
+choice
+ prompt " SCC/SMC for KGDB console"
+ depends on KGDB_CPM_UART
+ default KGDB_CPM_UART_SCC4 if ADS8272
+
+config KGDB_CPM_UART_SCC1
+ bool "Use SCC1 for KGDB"
+ depends on SERIAL_CPM_SCC1
+
+config KGDB_CPM_UART_SCC2
+ bool "Use SCC2 for KGDB"
+ depends on SERIAL_CPM_SCC2
+
+config KGDB_CPM_UART_SCC3
+ bool "Use SCC3 for KGDB"
+ depends on SERIAL_CPM_SCC3
+
+config KGDB_CPM_UART_SCC4
+ bool "Use SCC4 for KGDB"
+ depends on SERIAL_CPM_SCC4
+
+config KGDB_CPM_UART_SMC1
+ bool "Use SMC1 for KGDB"
+ depends on SERIAL_CPM_SMC1
+
+config KGDB_CPM_UART_SMC2
+ bool "Use SMC2 for KGDB"
+ depends on SERIAL_CPM_SMC2
+
+endchoice
+
+choice
+ depends on KGDB && !KGDB_ETH
+ prompt "Debug serial port BAUD"
+ default KGDB_115200BAUD
+ help
+ gdb and the kernel stub need to agree on the baud rate to be
+ used. Standard rates from 9600 to 115200 are allowed, and this
+ may be overridden via the commandline.
+
+config KGDB_9600BAUD
+ bool "9600"
+
+config KGDB_19200BAUD
+ bool "19200"
+
+config KGDB_38400BAUD
+ bool "38400"
+
+config KGDB_57600BAUD
+ bool "57600"
+
+config KGDB_115200BAUD
+ bool "115200"
+endchoice
+
config KGDBOE
tristate "KGDB: On ethernet" if !KGDBOE_NOMODULE
depends on m && KGDB_ONLY_MODULES
Index: linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart_kgdb.c
===================================================================
--- /dev/null
+++ linux-2.6.13.1/drivers/serial/cpm_uart/cpm_uart_kgdb.c
@@ -0,0 +1,191 @@
+/*
+ * drivers/serial/cpm_uart/cpm_uart_kgdb.c
+ *
+ * CPM UART interface for kgdb.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 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 <linux/kgdb.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include <asm/io.h>
+#include <asm/serial.h> /* 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');
+ 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,
+};
+
prev parent reply other threads:[~2005-10-21 12:15 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-10-21 10:36 kgdb support in Linux 2.6 for 8xx Chris
2005-10-21 12:15 ` Vitaly Bordug [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4358DBCD.8090709@ru.mvista.com \
--to=vbordug@ru.mvista.com \
--cc=chris@2net.co.uk \
--cc=linuxppc-embedded@ozlabs.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).