aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChanho Min <chanho.min@lge.com>2013-03-27 05:38:11 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-03-29 12:20:05 -0400
commitcb06ff102e2d79a82cf780aa5e6947b2e0529ac0 (patch)
treed911b0dff244219c60a7b94391f7c47bc0e9e758
parente302cd932094fa59463b5891814d2a5ace56cfc1 (diff)
ARM: PL011: Add support for Rx DMA buffer polling.
In DMA support, The received data is not pushed to tty until the DMA buffer is filled. But some megabyte rate chips such as BT expect fast response and data should be pushed immediately. In order to fix this issue, We suggest the use of the timer for polling DMA buffer. In our test, no data loss occurred at high-baudrate as compared with interrupt- driven (We tested with 3Mbps). We changes: - We add timer for polling. If we set poll_timer to 10, every 10ms, timer handler checks the residue in the dma buffer and transfer data to the tty. Also, last_residue is updated for the next polling. - poll_timeout is used to prevent the timer's system cost. If poll_timeout is set to 3000 and no data is received in 3 seconds, we inactivate poll timer and driver falls back to interrupt-driven. When data is received again in FIFO and UART irq is occurred, we switch back to DMA mode and start polling. - We use consistent DMA mappings to avoid from the frequent cache operation of the timer function for default. - pl011_dma_rx_chars is modified. the pending size is recalculated because data can be taken by polling. - the polling time is adjusted if dma rx poll is enabled but no rate is specified. Ideal polling interval to push 1 character at every interval is the reciprocal of 'baud rate / 10 line bits per character / 1000 ms per sec'. But It is very aggressive to system. Experimentally, '10000000 / baud' is suitable to receive dozens of characters. the poll rate can be specified statically by dma_rx_poll_rate of the platform data as well. Changes compared to v1: - Use of consistent DMA mappings. - Added dma_rx_poll_rate in platform data to specify the polling interval. - Added dma_rx_poll_timeout in platform data to specify the polling timeout. Changes compared to v2: - Use of consistent DMA mappings for default. - Added dma_rx_poll_enable in platform data to adjust the polling time according to the baud rate. - remove unnecessary lock from the polling function. Signed-off-by: Chanho Min <chanho.min@lge.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/serial/amba-pl011.c157
-rw-r--r--include/linux/amba/serial.h3
2 files changed, 141 insertions, 19 deletions
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 3ea5408fcbeb..b031abf43a7a 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -29,6 +29,7 @@
29 * and hooked into this driver. 29 * and hooked into this driver.
30 */ 30 */
31 31
32
32#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) 33#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
33#define SUPPORT_SYSRQ 34#define SUPPORT_SYSRQ
34#endif 35#endif
@@ -117,6 +118,12 @@ struct pl011_dmarx_data {
117 struct pl011_sgbuf sgbuf_b; 118 struct pl011_sgbuf sgbuf_b;
118 dma_cookie_t cookie; 119 dma_cookie_t cookie;
119 bool running; 120 bool running;
121 struct timer_list timer;
122 unsigned int last_residue;
123 unsigned long last_jiffies;
124 bool auto_poll_rate;
125 unsigned int poll_rate;
126 unsigned int poll_timeout;
120}; 127};
121 128
122struct pl011_dmatx_data { 129struct pl011_dmatx_data {
@@ -223,16 +230,18 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap)
223static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg, 230static int pl011_sgbuf_init(struct dma_chan *chan, struct pl011_sgbuf *sg,
224 enum dma_data_direction dir) 231 enum dma_data_direction dir)
225{ 232{
226 sg->buf = kmalloc(PL011_DMA_BUFFER_SIZE, GFP_KERNEL); 233 dma_addr_t dma_addr;
234
235 sg->buf = dma_alloc_coherent(chan->device->dev,
236 PL011_DMA_BUFFER_SIZE, &dma_addr, GFP_KERNEL);
227 if (!sg->buf) 237 if (!sg->buf)
228 return -ENOMEM; 238 return -ENOMEM;
229 239
230 sg_init_one(&sg->sg, sg->buf, PL011_DMA_BUFFER_SIZE); 240 sg_init_table(&sg->sg, 1);
241 sg_set_page(&sg->sg, phys_to_page(dma_addr),
242 PL011_DMA_BUFFER_SIZE, offset_in_page(dma_addr));
243 sg_dma_address(&sg->sg) = dma_addr;
231 244
232 if (dma_map_sg(chan->device->dev, &sg->sg, 1, dir) != 1) {
233 kfree(sg->buf);
234 return -EINVAL;
235 }
236 return 0; 245 return 0;
237} 246}
238 247
@@ -240,8 +249,9 @@ static void pl011_sgbuf_free(struct dma_chan *chan, struct pl011_sgbuf *sg,
240 enum dma_data_direction dir) 249 enum dma_data_direction dir)
241{ 250{
242 if (sg->buf) { 251 if (sg->buf) {
243 dma_unmap_sg(chan->device->dev, &sg->sg, 1, dir); 252 dma_free_coherent(chan->device->dev,
244 kfree(sg->buf); 253 PL011_DMA_BUFFER_SIZE, sg->buf,
254 sg_dma_address(&sg->sg));
245 } 255 }
246} 256}
247 257
@@ -300,6 +310,29 @@ static void pl011_dma_probe_initcall(struct uart_amba_port *uap)
300 dmaengine_slave_config(chan, &rx_conf); 310 dmaengine_slave_config(chan, &rx_conf);
301 uap->dmarx.chan = chan; 311 uap->dmarx.chan = chan;
302 312
313 if (plat->dma_rx_poll_enable) {
314 /* Set poll rate if specified. */
315 if (plat->dma_rx_poll_rate) {
316 uap->dmarx.auto_poll_rate = false;
317 uap->dmarx.poll_rate = plat->dma_rx_poll_rate;
318 } else {
319 /*
320 * 100 ms defaults to poll rate if not
321 * specified. This will be adjusted with
322 * the baud rate at set_termios.
323 */
324 uap->dmarx.auto_poll_rate = true;
325 uap->dmarx.poll_rate = 100;
326 }
327 /* 3 secs defaults poll_timeout if not specified. */
328 if (plat->dma_rx_poll_timeout)
329 uap->dmarx.poll_timeout =
330 plat->dma_rx_poll_timeout;
331 else
332 uap->dmarx.poll_timeout = 3000;
333 } else
334 uap->dmarx.auto_poll_rate = false;
335
303 dev_info(uap->port.dev, "DMA channel RX %s\n", 336 dev_info(uap->port.dev, "DMA channel RX %s\n",
304 dma_chan_name(uap->dmarx.chan)); 337 dma_chan_name(uap->dmarx.chan));
305 } 338 }
@@ -701,24 +734,30 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
701 struct tty_port *port = &uap->port.state->port; 734 struct tty_port *port = &uap->port.state->port;
702 struct pl011_sgbuf *sgbuf = use_buf_b ? 735 struct pl011_sgbuf *sgbuf = use_buf_b ?
703 &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a; 736 &uap->dmarx.sgbuf_b : &uap->dmarx.sgbuf_a;
704 struct device *dev = uap->dmarx.chan->device->dev;
705 int dma_count = 0; 737 int dma_count = 0;
706 u32 fifotaken = 0; /* only used for vdbg() */ 738 u32 fifotaken = 0; /* only used for vdbg() */
707 739
708 /* Pick everything from the DMA first */ 740 struct pl011_dmarx_data *dmarx = &uap->dmarx;
741 int dmataken = 0;
742
743 if (uap->dmarx.poll_rate) {
744 /* The data can be taken by polling */
745 dmataken = sgbuf->sg.length - dmarx->last_residue;
746 /* Recalculate the pending size */
747 if (pending >= dmataken)
748 pending -= dmataken;
749 }
750
751 /* Pick the remain data from the DMA */
709 if (pending) { 752 if (pending) {
710 /* Sync in buffer */
711 dma_sync_sg_for_cpu(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
712 753
713 /* 754 /*
714 * First take all chars in the DMA pipe, then look in the FIFO. 755 * First take all chars in the DMA pipe, then look in the FIFO.
715 * Note that tty_insert_flip_buf() tries to take as many chars 756 * Note that tty_insert_flip_buf() tries to take as many chars
716 * as it can. 757 * as it can.
717 */ 758 */
718 dma_count = tty_insert_flip_string(port, sgbuf->buf, pending); 759 dma_count = tty_insert_flip_string(port, sgbuf->buf + dmataken,
719 760 pending);
720 /* Return buffer to device */
721 dma_sync_sg_for_device(dev, &sgbuf->sg, 1, DMA_FROM_DEVICE);
722 761
723 uap->port.icount.rx += dma_count; 762 uap->port.icount.rx += dma_count;
724 if (dma_count < pending) 763 if (dma_count < pending)
@@ -726,6 +765,10 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap,
726 "couldn't insert all characters (TTY is full?)\n"); 765 "couldn't insert all characters (TTY is full?)\n");
727 } 766 }
728 767
768 /* Reset the last_residue for Rx DMA poll */
769 if (uap->dmarx.poll_rate)
770 dmarx->last_residue = sgbuf->sg.length;
771
729 /* 772 /*
730 * Only continue with trying to read the FIFO if all DMA chars have 773 * Only continue with trying to read the FIFO if all DMA chars have
731 * been taken first. 774 * been taken first.
@@ -865,6 +908,57 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap)
865 writew(uap->dmacr, uap->port.membase + UART011_DMACR); 908 writew(uap->dmacr, uap->port.membase + UART011_DMACR);
866} 909}
867 910
911/*
912 * Timer handler for Rx DMA polling.
913 * Every polling, It checks the residue in the dma buffer and transfer
914 * data to the tty. Also, last_residue is updated for the next polling.
915 */
916static void pl011_dma_rx_poll(unsigned long args)
917{
918 struct uart_amba_port *uap = (struct uart_amba_port *)args;
919 struct tty_port *port = &uap->port.state->port;
920 struct pl011_dmarx_data *dmarx = &uap->dmarx;
921 struct dma_chan *rxchan = uap->dmarx.chan;
922 unsigned long flags = 0;