[PATCH 11/30] leon, apbuart: support termios task driven mode

Daniel Hellstrom daniel at gaisler.com
Thu Apr 13 19:31:20 UTC 2017


From: Martin Aberg <maberg at gaisler.com>

The APBUART control register can be updated from both ISR and task context so
the device must be locked when manipulating the register.
There is also a scenario with RX FIFO interrupts where a few characters can be
in the FIFO without generating interrupt.
---
 c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c | 64 +++++++++++++++++------
 1 file changed, 48 insertions(+), 16 deletions(-)

diff --git a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
index 379d9ff..28066a3 100644
--- a/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
+++ b/c/src/lib/libbsp/sparc/shared/uart/apbuart_cons.c
@@ -358,8 +358,8 @@ static int apbuart_info(
 
 	if (priv->mode == TERMIOS_POLLED)
 		str1 = "TERMIOS_POLLED";
-	else if (priv->mode == TERMIOS_TASK_DRIVEN)
-		str1 = "TERMIOS_TASK_DRIVEN";
+	else if (priv->mode == TERMIOS_IRQ_DRIVEN)
+		str1 = "TERMIOS_IRQ_DRIVEN";
 	else if (priv->mode == TERMIOS_TASK_DRIVEN)
 		str1 = "TERMIOS_TASK_DRIVEN";
 	else
@@ -489,7 +489,8 @@ static void last_close(
 	if (uart->mode != TERMIOS_POLLED) {
 		/* Turn off RX interrupts */
 		rtems_termios_device_lock_acquire(base, &lock_context);
-		uart->regs->ctrl &= ~(APBUART_CTRL_RI | APBUART_CTRL_RF);
+		uart->regs->ctrl &=
+			~(APBUART_CTRL_DI | APBUART_CTRL_RI | APBUART_CTRL_RF);
 		rtems_termios_device_lock_release(base, &lock_context);
 
 		/**** Flush device ****/
@@ -515,29 +516,50 @@ static int read_polled(rtems_termios_device_context *base)
 	return apbuart_inbyte_nonblocking(uart->regs);
 }
 
+/* This function is called from TERMIOS rxdaemon task without device lock. */
 static int read_task(rtems_termios_device_context *base)
 {
+	rtems_interrupt_lock_context lock_context;
 	struct apbuart_priv *uart = base_get_priv(base);
-	int c, tot;
-	char buf[32];
+	struct apbuart_regs *regs = uart->regs;
+	int cnt;
+	char buf[33];
 	struct rtems_termios_tty *tty;
+	uint32_t ctrl_add;
 
+	ctrl_add = APBUART_CTRL_RI;
+	if (uart->cap & CAP_DI) {
+		ctrl_add |= (APBUART_CTRL_DI | APBUART_CTRL_RF);
+	}
 	tty = uart->tty;
-	tot = 0;
-	while ((c=apbuart_inbyte_nonblocking(uart->regs)) != EOF) {
-		buf[tot] = c;
-		tot++;
-		if (tot > 31) {
-			rtems_termios_enqueue_raw_characters(tty, buf, tot);
-			tot = 0;
+	do {
+		cnt = 0;
+		while (
+			(regs->status & APBUART_STATUS_DR) &&
+			(cnt < sizeof(buf))
+		) {
+			buf[cnt] = regs->data;
+			cnt++;
+		}
+		if (0 < cnt) {
+			/* Tell termios layer about new characters */
+			rtems_termios_enqueue_raw_characters(tty, &buf[0], cnt);
 		}
-	}
-	if (tot > 0)
-		rtems_termios_enqueue_raw_characters(tty, buf, tot);
+
+		/*
+		 * Turn on RX interrupts. A new character in FIFO now may not
+		 * cause interrupt so we must check data ready again
+		 * afterwards.
+		 */
+		rtems_termios_device_lock_acquire(base, &lock_context);
+		regs->ctrl |= ctrl_add;
+		rtems_termios_device_lock_release(base, &lock_context);
+	} while (regs->status & APBUART_STATUS_DR);
 
 	return EOF;
 }
 
+
 struct apbuart_baud {
 	unsigned int num;
 	unsigned int baud;
@@ -779,6 +801,7 @@ static void write_interrupt(
 static void apbuart_cons_isr(void *arg)
 {
 	rtems_termios_tty *tty = arg;
+	rtems_termios_device_context *base;
 	struct console_dev *condev = rtems_termios_get_device_context(tty);
 	struct apbuart_priv *uart = condev_get_priv(condev);
 	struct apbuart_regs *regs = uart->regs;
@@ -787,7 +810,16 @@ static void apbuart_cons_isr(void *arg)
 	int cnt;
 
 	if (uart->mode == TERMIOS_TASK_DRIVEN) {
-		if ((status=regs->status) & APBUART_STATUS_DR) {
+		if ((status = regs->status) & APBUART_STATUS_DR) {
+			rtems_interrupt_lock_context lock_context;
+
+			/* Turn off RX interrupts */
+			base = rtems_termios_get_device_context(tty);
+			rtems_termios_device_lock_acquire(base, &lock_context);
+			regs->ctrl &=
+			    ~(APBUART_CTRL_DI | APBUART_CTRL_RI |
+			      APBUART_CTRL_RF);
+			rtems_termios_device_lock_release(base, &lock_context);
 			/* Activate termios RX daemon task */
 			rtems_termios_rxirq_occured(tty);
 		}
-- 
2.7.4



More information about the devel mailing list