diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-09-10 10:25:18 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2013-09-11 22:41:22 +0000 |
commit | af12f2f58c001dfa999591c29b055b7ba95379ba (patch) | |
tree | 48867e99e48a62ae818b177cd45b1519d6ceaf5b /common/uart_buffering.c | |
parent | 6b1dace9f456d5b1b160402866045c3659e665e0 (diff) | |
download | chrome-ec-af12f2f58c001dfa999591c29b055b7ba95379ba.tar.gz |
stm32: Support DMA-based UART output
This reduces the number of UART interrupts by a factor of 12, and
reduces the overall interrupt rate on STM32 by a factor of 2.
BUG=chrome-os-partner:20485
BRANCH=none (not required for pit branch)
TEST=Boot pit. Ctrl+Q pauses debug output; Ctrl+S resumes it.
'crash divzero' still prints a full crash dump.
And util/makeall.sh passes builds all platforms and passes tests.
Change-Id: I86993e14b436150298dcb2c6d29086cc3c9db418
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/168814
Diffstat (limited to 'common/uart_buffering.c')
-rw-r--r-- | common/uart_buffering.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/common/uart_buffering.c b/common/uart_buffering.c index 1394b3d457..3a55d10631 100644 --- a/common/uart_buffering.c +++ b/common/uart_buffering.c @@ -65,11 +65,59 @@ static int __tx_char(void *context, int c) return 0; } +#ifdef CONFIG_UART_TX_DMA + +/** + * Process UART output via DMA + */ +static void uart_process_output_dma(void) +{ + /* Size of current DMA transfer */ + static int tx_dma_in_progress; + + /* + * Get head pointer now, to avoid math problems if some other task + * or interrupt adds output during this call. + */ + int head = tx_buf_head; + + /* If DMA is still busy, nothing to do. */ + if(!uart_tx_dma_ready()) + return; + + /* If a previous DMA transfer completed, free up the buffer it used */ + if (tx_dma_in_progress) { + tx_buf_tail = (tx_buf_tail + tx_dma_in_progress) & + (CONFIG_UART_TX_BUF_SIZE - 1); + tx_dma_in_progress = 0; + } + + /* Disable DMA-done interrupt if nothing to send */ + if(head == tx_buf_tail) { + uart_tx_stop(); + return; + } + + /* + * Get the largest contiguous block of output. If the transmit buffer + * wraps, only use the part before the wrap. + */ + tx_dma_in_progress = (head > tx_buf_tail ? head : + CONFIG_UART_TX_BUF_SIZE) - tx_buf_tail; + + uart_tx_dma_start((char *)(tx_buf + tx_buf_tail), tx_dma_in_progress); +} + +#endif /* CONFIG_UART_TX_DMA */ + void uart_process_output(void) { if (uart_suspended) return; +#ifdef CONFIG_UART_TX_DMA + uart_process_output_dma(); +#else /* 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]); @@ -79,6 +127,7 @@ void uart_process_output(void) /* If output buffer is empty, disable transmit interrupt */ if (tx_buf_tail == tx_buf_head) uart_tx_stop(); +#endif } void uart_process_input(void) |