aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorCyrille Pitchen <cyrille.pitchen@atmel.com>2014-10-20 13:12:20 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-06 17:57:18 -0500
commit66f37aafd6a6177287334397c59d7a727d16cd24 (patch)
tree71e9e7240611ad2908229e3518202bb7bb184fe1 /drivers
parenta7ae7f8243b15cd65b5811de031eb4f8413b3e6f (diff)
tty/serial: at91: fix rx ring buffer management
This patch swaps the use "tail" and "head" to fit the semantic of the linux circular buffer documentation: - head: the point at which the producer (the DMA controller) inserts items. - tail: the point at which the consumer (the serial framework) finds the next item. Besides the former code of the rx ring buffer didn't manage the case where head < tail, which might lead to loss of data. To fix this bug the data are now sent from the DMA buffer to the serial framework in two steps: 1 - First, we test if head < tail. If so, we copy the data from tail to the end of the DMA buffer then reset tail to zero. 2 - Finally, we copy data from tail to head then set tail to head. In addition, since tty_insert_flip_string() may now be called twice, atmel_flip_buffer_rx_dma() becomes less efficient than moving the calls dma_sync_sg_for_cpu(), dma_sync_sg_for_device(), tty_insert_flip_string() and tty_flip_buffer_push() directly into atmel_rx_from_dma(). Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> Acked-by: Nicolas Ferre <nicolas.ferre@atmel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/tty/serial/atmel_serial.c94
1 files changed, 55 insertions, 39 deletions
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 8a84034d130c..9eb624a22431 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -880,32 +880,6 @@ chan_err:
880 return -EINVAL; 880 return -EINVAL;
881} 881}
882 882
883static void atmel_flip_buffer_rx_dma(struct uart_port *port,
884 char *buf, size_t count)
885{
886 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
887 struct tty_port *tport = &port->state->port;
888
889 dma_sync_sg_for_cpu(port->dev,
890 &atmel_port->sg_rx,
891 1,
892 DMA_DEV_TO_MEM);
893
894 tty_insert_flip_string(tport, buf, count);
895
896 dma_sync_sg_for_device(port->dev,
897 &atmel_port->sg_rx,
898 1,
899 DMA_DEV_TO_MEM);
900 /*
901 * Drop the lock here since it might end up calling
902 * uart_start(), which takes the lock.
903 */
904 spin_unlock(&port->lock);
905 tty_flip_buffer_push(tport);
906 spin_lock(&port->lock);
907}
908
909static void atmel_complete_rx_dma(void *arg) 883static void atmel_complete_rx_dma(void *arg)
910{ 884{
911 struct uart_port *port = arg; 885 struct uart_port *port = arg;
@@ -934,11 +908,12 @@ static void atmel_release_rx_dma(struct uart_port *port)
934static void atmel_rx_from_dma(struct uart_port *port) 908static void atmel_rx_from_dma(struct uart_port *port)
935{ 909{
936 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); 910 struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
911 struct tty_port *tport = &port->state->port;
937 struct circ_buf *ring = &atmel_port->rx_ring; 912 struct circ_buf *ring = &atmel_port->rx_ring;
938 struct dma_chan *chan = atmel_port->chan_rx; 913 struct dma_chan *chan = atmel_port->chan_rx;
939 struct dma_tx_state state; 914 struct dma_tx_state state;
940 enum dma_status dmastat; 915 enum dma_status dmastat;
941 size_t pending, count; 916 size_t count;
942 917
943 918
944 /* Reset the UART timeout early so that we don't miss one */ 919 /* Reset the UART timeout early so that we don't miss one */
@@ -953,27 +928,68 @@ static void atmel_rx_from_dma(struct uart_port *port)
953 tasklet_schedule(&atmel_port->tasklet); 928 tasklet_schedule(&atmel_port->tasklet);
954 return; 929 return;
955 } 930 }
956 /* current transfer size should no larger than dma buffer */
957 pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
958 BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
959 931
932 /* CPU claims ownership of RX DMA buffer */
933 dma_sync_sg_for_cpu(port->dev,
934 &atmel_port->sg_rx,
935 1,
936 DMA_DEV_TO_MEM);
937
938 /*
939 * ring->head points to the end of data already written by the DMA.
940 * ring->tail points to the beginning of data to be read by the
941 * framework.
942 * The current transfer size should not be larger than the dma buffer
943 * length.
944 */
945 ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue;
946 BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx));
960 /* 947 /*
961 * This will take the chars we have so far, 948 * At this point ring->head may point to the first byte right after the
962 * ring->head will record the transfer size, only new bytes come 949 * last byte of the dma buffer:
963 * will insert into the framework. 950 * 0 <= ring->head <= sg_dma_len(&atmel_port->sg_rx)
951 *
952 * However ring->tail must always points inside the dma buffer:
953 * 0 <= ring->tail <= sg_dma_len(&atmel_port->sg_rx) - 1
954 *
955 * Since we use a ring buffer, we have to handle the case
956 * where head is lower than tail. In such a case, we first read from
957 * tail to the end of the buffer then reset tail.
964 */ 958 */
965 if (pending > ring->head) { 959 if (ring->head < ring->tail) {
966 count = pending - ring->head; 960 count = sg_dma_len(&atmel_port->sg_rx) - ring->tail;
967 961
968 atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count); 962 tty_insert_flip_string(tport, ring->buf + ring->tail, count);
963 ring->tail = 0;
964 port->icount.rx += count;
965 }
969 966
970 ring->head += count; 967 /* Finally we read data from tail to head */
971 if (ring->head == sg_dma_len(&atmel_port->sg_rx)) 968 if (ring->tail < ring->head) {
972 ring->head = 0; 969 count = ring->head - ring->tail;
973 970
971 tty_insert_flip_string(tport, ring->buf + ring->tail, count);
972 /* Wrap ring->head if needed */
973 if (ring->head >= sg_dma_len(&atmel_port->sg_rx))
974 ring->head = 0;
975 ring->tail = ring->head;
974 port->icount.rx += count; 976 port->icount.rx += count;
975 } 977 }
976 978
979 /* USART retreives ownership of RX DMA buffer */
980 dma_sync_sg_for_device(port->dev,
981 &atmel_port->sg_rx,
982 1,
983 DMA_DEV_TO_MEM);
984
985 /*
986 * Drop the lock here since it might end up calling
987 * uart_start(), which takes the lock.
988 */
989 spin_unlock(&port->lock);
990 tty_flip_buffer_push(tport);
991 spin_lock(&port->lock);
992
977 UART_PUT_IER(port, ATMEL_US_TIMEOUT); 993 UART_PUT_IER(port, ATMEL_US_TIMEOUT);
978} 994}
979 995