|
@@ -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
|
|
|
};
|
|
|
|
|
|
/*
|