diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-06-13 17:35:04 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2008-06-13 17:35:04 +1000 |
commit | 2b0192c782bb535c1e3628d33145868cdc43b906 (patch) | |
tree | 9b670ae0d752a6fa95e6ed1840b24c5b356b029e /drivers | |
parent | 275b34ffeb552da9122cf494a0fdcc1bf00aa0d0 (diff) | |
parent | 451c9aab655120c602a68812e547efaaac1884a6 (diff) |
Merge commit 'kgdb/kgdb-next'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 95 | ||||
-rw-r--r-- | drivers/serial/mpsc.c | 139 |
2 files changed, 232 insertions, 2 deletions
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a19dc7ef8861..d7c31efdc799 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -257,6 +257,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 */ @@ -278,6 +282,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 */ @@ -309,7 +319,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); @@ -916,6 +931,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, @@ -933,6 +1022,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 }; #ifdef CONFIG_PPC_CPM_NEW_BINDING diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c index e8819c43f57d..4f967ea9192c 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,124 @@ 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 +1670,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 }; /* |