summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-23 11:59:37 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-23 11:59:37 -0700
commit0f6e38a6381446eff5175b77d1094834a633a90f (patch)
treee5295c372b6a73fa84b4d14b86ea9fa626d3f030 /drivers
parente669e8179d364bb11ed51504e1a1c60830bff4c5 (diff)
parent3b216c9ed347924efb5e7a66b3257c40a5596d30 (diff)
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jwessel/linux-2.6-kgdb: kgdb: kgdboc console poll hooks for mpsc uart kgdb: kgdboc console poll hooks for cpm uart kgdb, powerpc: arch specific powerpc kgdb support kgdb: support for ARCH=arm kgdb: remove unused HAVE_ARCH_KGDB_SHADOW_INFO config variable
Diffstat (limited to 'drivers')
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c95
-rw-r--r--drivers/serial/mpsc.c148
2 files changed, 241 insertions, 2 deletions
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 93e407ee08b9..1ff80de177db 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -201,6 +201,10 @@ static void cpm_uart_int_tx(struct uart_port *port)
cpm_uart_tx_pump(port);
}
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
/*
* Receive characters
*/
@@ -222,6 +226,12 @@ static void cpm_uart_int_rx(struct uart_port *port)
*/
bdp = pinfo->rx_cur;
for (;;) {
+#ifdef CONFIG_CONSOLE_POLL
+ if (unlikely(serial_polled)) {
+ serial_polled = 0;
+ return;
+ }
+#endif
/* get status */
status = in_be16(&bdp->cbd_sc);
/* If this one is empty, return happy */
@@ -253,7 +263,12 @@ static void cpm_uart_int_rx(struct uart_port *port)
goto handle_error;
if (uart_handle_sysrq_char(port, ch))
continue;
-
+#ifdef CONFIG_CONSOLE_POLL
+ if (unlikely(serial_polled)) {
+ serial_polled = 0;
+ return;
+ }
+#endif
error_return:
tty_insert_flip_char(tty, ch, flg);
@@ -865,6 +880,80 @@ static void cpm_uart_config_port(struct uart_port *port, int flags)
cpm_uart_request_port(port);
}
}
+
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+#define GDB_BUF_SIZE 512 /* power of 2, please */
+
+static char poll_buf[GDB_BUF_SIZE];
+static char *pollp;
+static int poll_chars;
+
+static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
+{
+ u_char c, *cp;
+ volatile cbd_t *bdp;
+ int i;
+
+ /* 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, pinfo);
+
+ if (obuf) {
+ i = c = bdp->cbd_datlen;
+ while (i-- > 0)
+ *obuf++ = *cp++;
+ } else
+ c = *cp;
+ bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
+ 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;
+}
+
+static int cpm_get_poll_char(struct uart_port *port)
+{
+ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+ if (!serial_polled) {
+ serial_polled = 1;
+ poll_chars = 0;
+ }
+ if (poll_chars <= 0) {
+ poll_chars = poll_wait_key(poll_buf, pinfo);
+ pollp = poll_buf;
+ }
+ poll_chars--;
+ return *pollp++;
+}
+
+static void cpm_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+ static char ch[2];
+
+ ch[0] = (char)c;
+ cpm_uart_early_write(pinfo->port.line, ch, 1);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
static struct uart_ops cpm_uart_pops = {
.tx_empty = cpm_uart_tx_empty,
.set_mctrl = cpm_uart_set_mctrl,
@@ -882,6 +971,10 @@ static struct uart_ops cpm_uart_pops = {
.request_port = cpm_uart_request_port,
.config_port = cpm_uart_config_port,
.verify_port = cpm_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = cpm_get_poll_char,
+ .poll_put_char = cpm_put_poll_char,
+#endif
};
struct uart_cpm_port cpm_uart_ports[UART_NR];
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index c9f53e71f252..61d3ade5286c 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -921,6 +921,10 @@ static int mpsc_make_ready(struct mpsc_port_info *pi)
return 0;
}
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
/*
******************************************************************************
*
@@ -956,7 +960,12 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
& SDMA_DESC_CMDSTAT_O)) {
bytes_in = be16_to_cpu(rxre->bytecnt);
-
+#ifdef CONFIG_CONSOLE_POLL
+ if (unlikely(serial_polled)) {
+ serial_polled = 0;
+ return 0;
+ }
+#endif
/* Following use of tty struct directly is deprecated */
if (unlikely(tty_buffer_request_room(tty, bytes_in)
< bytes_in)) {
@@ -1017,6 +1026,12 @@ static int mpsc_rx_intr(struct mpsc_port_info *pi)
if (uart_handle_sysrq_char(&pi->port, *bp)) {
bp++;
bytes_in--;
+#ifdef CONFIG_CONSOLE_POLL
+ if (unlikely(serial_polled)) {
+ serial_polled = 0;
+ return 0;
+ }
+#endif
goto next_frame;
}
@@ -1519,6 +1534,133 @@ static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
return rc;
}
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+static char poll_buf[2048];
+static int poll_ptr;
+static int poll_cnt;
+static void mpsc_put_poll_char(struct uart_port *port,
+ unsigned char c);
+
+static int mpsc_get_poll_char(struct uart_port *port)
+{
+ struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+ struct mpsc_rx_desc *rxre;
+ u32 cmdstat, bytes_in, i;
+ u8 *bp;
+
+ if (!serial_polled)
+ serial_polled = 1;
+
+ pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
+
+ if (poll_cnt) {
+ poll_cnt--;
+ return poll_buf[poll_ptr++];
+ }
+ poll_ptr = 0;
+ poll_cnt = 0;
+
+ while (poll_cnt == 0) {
+ rxre = (struct mpsc_rx_desc *)(pi->rxr +
+ (pi->rxr_posn*MPSC_RXRE_SIZE));
+ dma_cache_sync(pi->port.dev, (void *)rxre,
+ MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+ invalidate_dcache_range((ulong)rxre,
+ (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+ /*
+ * Loop through Rx descriptors handling ones that have
+ * been completed.
+ */
+ while (poll_cnt == 0 &&
+ !((cmdstat = be32_to_cpu(rxre->cmdstat)) &
+ SDMA_DESC_CMDSTAT_O)){
+ bytes_in = be16_to_cpu(rxre->bytecnt);
+ bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
+ dma_cache_sync(pi->port.dev, (void *) bp,
+ MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+ invalidate_dcache_range((ulong)bp,
+ (ulong)bp + MPSC_RXBE_SIZE);
+#endif
+ if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
+ SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
+ !(cmdstat & pi->port.ignore_status_mask)) {
+ poll_buf[poll_cnt] = *bp;
+ poll_cnt++;
+ } else {
+ for (i = 0; i < bytes_in; i++) {
+ poll_buf[poll_cnt] = *bp++;
+ poll_cnt++;
+ }
+ pi->port.icount.rx += bytes_in;
+ }
+ rxre->bytecnt = cpu_to_be16(0);
+ wmb();
+ rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
+ SDMA_DESC_CMDSTAT_EI |
+ SDMA_DESC_CMDSTAT_F |
+ SDMA_DESC_CMDSTAT_L);
+ wmb();
+ dma_cache_sync(pi->port.dev, (void *)rxre,
+ MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+ flush_dcache_range((ulong)rxre,
+ (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+
+ /* Advance to next descriptor */
+ pi->rxr_posn = (pi->rxr_posn + 1) &
+ (MPSC_RXR_ENTRIES - 1);
+ rxre = (struct mpsc_rx_desc *)(pi->rxr +
+ (pi->rxr_posn * MPSC_RXRE_SIZE));
+ dma_cache_sync(pi->port.dev, (void *)rxre,
+ MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
+ if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
+ invalidate_dcache_range((ulong)rxre,
+ (ulong)rxre + MPSC_RXRE_SIZE);
+#endif
+ }
+
+ /* Restart rx engine, if its stopped */
+ if ((readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_ERD) == 0)
+ mpsc_start_rx(pi);
+ }
+ if (poll_cnt) {
+ poll_cnt--;
+ return poll_buf[poll_ptr++];
+ }
+
+ return 0;
+}
+
+
+static void mpsc_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
+ u32 data;
+
+ data = readl(pi->mpsc_base + MPSC_MPCR);
+ writeb(c, pi->mpsc_base + MPSC_CHR_1);
+ mb();
+ data = readl(pi->mpsc_base + MPSC_CHR_2);
+ data |= MPSC_CHR_2_TTCS;
+ writel(data, pi->mpsc_base + MPSC_CHR_2);
+ mb();
+
+ while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_TTCS);
+}
+#endif
static struct uart_ops mpsc_pops = {
.tx_empty = mpsc_tx_empty,
@@ -1537,6 +1679,10 @@ static struct uart_ops mpsc_pops = {
.request_port = mpsc_request_port,
.config_port = mpsc_config_port,
.verify_port = mpsc_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = mpsc_get_poll_char,
+ .poll_put_char = mpsc_put_poll_char,
+#endif
};
/*