From 6b1dace9f456d5b1b160402866045c3659e665e0 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Tue, 10 Sep 2013 10:09:41 -0700 Subject: Split uart_process() into input and output processing This is a precursor to DMA-based UART transfers, which require different processing for DMA vs PIO output types. BUG=chrome-os-partner:20485 BRANCH=pit TEST=Boot pit; verify EC console still works. Change-Id: I6d6f55561eeebe9bd2928b2bfb25278c86f689d1 Signed-off-by: Randall Spangler Reviewed-on: https://chromium-review.googlesource.com/168811 Reviewed-by: Bill Richardson --- chip/host/uart.c | 7 +++-- chip/lm4/uart.c | 3 +- chip/stm32/uart.c | 3 +- common/uart_buffering.c | 79 +++++++++++++++++++------------------------------ include/uart.h | 16 ++++++---- 5 files changed, 51 insertions(+), 57 deletions(-) diff --git a/chip/host/uart.c b/chip/host/uart.c index b6369df426..770ea8c0ef 100644 --- a/chip/host/uart.c +++ b/chip/host/uart.c @@ -69,8 +69,10 @@ static void trigger_interrupt(void) * TODO: Check global interrupt status when we have * interrupt support. */ - if (!int_disabled) - uart_process(); + if (!int_disabled) { + uart_process_input(); + uart_process_output(); + } } int uart_init_done(void) @@ -185,5 +187,6 @@ void *uart_monitor_stdin(void *d) void uart_init(void) { pthread_create(&input_thread, NULL, uart_monitor_stdin, NULL); + stopped = 1; /* Not transmitting yet */ init_done = 1; } diff --git a/chip/lm4/uart.c b/chip/lm4/uart.c index 17443d9848..c7d320928c 100644 --- a/chip/lm4/uart.c +++ b/chip/lm4/uart.c @@ -103,7 +103,8 @@ static void uart_ec_interrupt(void) /* Read input FIFO until empty, then fill output FIFO */ - uart_process(); + uart_process_input(); + uart_process_output(); } DECLARE_IRQ(LM4_IRQ_UART0, uart_ec_interrupt, 1); diff --git a/chip/stm32/uart.c b/chip/stm32/uart.c index dab5231845..42461b2a90 100644 --- a/chip/stm32/uart.c +++ b/chip/stm32/uart.c @@ -96,7 +96,8 @@ static void uart_interrupt(void) STM32_USART_CR1(UARTN) &= ~STM32_USART_CR1_TXEIE; /* Read input FIFO until empty, then fill output FIFO */ - uart_process(); + uart_process_input(); + uart_process_output(); /* * Re-enable TX empty interrupt only if it was not disabled by diff --git a/common/uart_buffering.c b/common/uart_buffering.c index 2ccb967e81..1394b3d457 100644 --- a/common/uart_buffering.c +++ b/common/uart_buffering.c @@ -65,23 +65,23 @@ static int __tx_char(void *context, int c) return 0; } -/** - * Copy output from buffer until TX fifo full or output buffer empty. - * - * May be called from interrupt context. - */ -static void fill_tx_fifo(void) +void uart_process_output(void) { + if (uart_suspended) + return; + + /* Copy output from buffer until TX fifo full or output buffer empty */ while (uart_tx_ready() && (tx_buf_head != tx_buf_tail)) { uart_write_char(tx_buf[tx_buf_tail]); tx_buf_tail = TX_BUF_NEXT(tx_buf_tail); } + + /* If output buffer is empty, disable transmit interrupt */ + if (tx_buf_tail == tx_buf_head) + uart_tx_stop(); } -/** - * Helper for UART processing. - */ -void uart_process(void) +void uart_process_input(void) { int got_input = 0; @@ -110,16 +110,6 @@ void uart_process(void) if (got_input) console_has_input(); - - if (uart_suspended) - return; - - /* Copy output from buffer until TX fifo full or output buffer empty */ - fill_tx_fifo(); - - /* If output buffer is empty, disable transmit interrupt */ - if (tx_buf_tail == tx_buf_head) - uart_tx_stop(); } int uart_putc(int c) @@ -174,34 +164,27 @@ void uart_flush_output(void) if (uart_suspended) return; - /* - * If we're in interrupt context, copy output explicitly, since the - * UART interrupt may not be able to preempt this one. - */ - if (in_interrupt_context()) { - do { - /* Copy until TX fifo full or output buffer empty */ - fill_tx_fifo(); - - /* Wait for transmit FIFO empty */ - uart_tx_flush(); - } while (tx_buf_head != tx_buf_tail); - return; - } - - /* Wait for buffer to empty */ + /* Loop until buffer is empty */ while (tx_buf_head != tx_buf_tail) { - /* - * It's possible we're in some other interrupt, and the - * previous context was doing a printf() or puts() but hadn't - * enabled the UART interrupt. Check if the interrupt is - * disabled, and if so, re-enable and trigger it. Note that - * this check is inside the while loop, so we'll be safe even - * if the context switches away from us to another partial - * printf() and back. - */ - if (uart_tx_stopped()) + if (in_interrupt_context()) { + /* + * Explicitly process UART output, since the UART + * interrupt may not be able to preempt the interrupt + * we're in now. + */ + uart_process_output(); + } else if (uart_tx_stopped()) { + /* + * It's possible we switched from a previous context + * which was doing a printf() or puts() but hadn't + * enabled the UART interrupt. Check if the interrupt + * is disabled, and if so, re-enable and trigger it. + * Note that this check is inside the while loop, so + * we'll be safe even if the context switches away from + * us to another partial printf() and back. + */ uart_tx_start(); + } } /* Wait for transmit FIFO empty */ @@ -214,7 +197,7 @@ void uart_flush_input(void) uart_disable_interrupt(); /* Empty the hardware FIFO */ - uart_process(); + uart_process_input(); /* Clear the input buffer */ rx_buf_tail = rx_buf_head; @@ -231,7 +214,7 @@ int uart_getc(void) uart_disable_interrupt(); /* Call interrupt handler to empty the hardware FIFO */ - uart_process(); + uart_process_input(); if (rx_buf_tail == rx_buf_head) { c = -1; /* No pending input */ diff --git a/include/uart.h b/include/uart.h index 05d4aee036..fa50645270 100644 --- a/include/uart.h +++ b/include/uart.h @@ -178,14 +178,20 @@ void uart_tx_stop(void); int uart_tx_stopped(void); /** - * Helper for UART processing. + * Helper for processing UART input. * - * Reads the input FIFO until empty, then fills the output FIFO until the - * transmit buffer is empty or the FIFO full. + * Reads the input FIFO until empty. Intended to be called from the driver + * interrupt handler. + */ +void uart_process_input(void); + +/** + * Helper for processing UART output. * - * Designed to be called from the driver interrupt handler. + * Fills the output FIFO until the transmit buffer is empty or the FIFO full. + * Intended to be called from the driver interrupt handler. */ -void uart_process(void); +void uart_process_output(void); /* * COMx functions -- cgit v1.2.1