aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Fulghum <paulkf@microgate.com>2008-07-22 06:21:55 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-22 16:03:29 -0400
commit403214d0ad9b2b9e46c89a5b4b513c910c89068d (patch)
tree5d7725b1254f4106a8688497094cb1bd34b75921
parente5590717afd5fb6f494323206a1a35ea25610c2d (diff)
synclink_gt: improve TIOCOUTQ accuracy
Improve the accuracy of TIOCOUTQ value as implemented in chars_in_buffer() method by walking and counting tx DMA buffers, reading controller tx FIFO level and accounting for controller tx shift register. The greatly improves application control of transmit latency at lower data rates. Signed-off-by: Paul Fulghum <paulkf@microgate.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/synclink_gt.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 3cfc9e1f8882..8511e2e43c18 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -214,6 +214,7 @@ struct slgt_desc
214 char *buf; /* virtual address of data buffer */ 214 char *buf; /* virtual address of data buffer */
215 unsigned int pdesc; /* physical address of this descriptor */ 215 unsigned int pdesc; /* physical address of this descriptor */
216 dma_addr_t buf_dma_addr; 216 dma_addr_t buf_dma_addr;
217 unsigned short buf_count;
217}; 218};
218 219
219#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b)) 220#define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))
@@ -466,6 +467,7 @@ static void tx_start(struct slgt_info *info);
466static void tx_stop(struct slgt_info *info); 467static void tx_stop(struct slgt_info *info);
467static void tx_set_idle(struct slgt_info *info); 468static void tx_set_idle(struct slgt_info *info);
468static unsigned int free_tbuf_count(struct slgt_info *info); 469static unsigned int free_tbuf_count(struct slgt_info *info);
470static unsigned int tbuf_bytes(struct slgt_info *info);
469static void reset_tbufs(struct slgt_info *info); 471static void reset_tbufs(struct slgt_info *info);
470static void tdma_reset(struct slgt_info *info); 472static void tdma_reset(struct slgt_info *info);
471static void tdma_start(struct slgt_info *info); 473static void tdma_start(struct slgt_info *info);
@@ -1388,10 +1390,12 @@ done:
1388static int chars_in_buffer(struct tty_struct *tty) 1390static int chars_in_buffer(struct tty_struct *tty)
1389{ 1391{
1390 struct slgt_info *info = tty->driver_data; 1392 struct slgt_info *info = tty->driver_data;
1393 int count;
1391 if (sanity_check(info, tty->name, "chars_in_buffer")) 1394 if (sanity_check(info, tty->name, "chars_in_buffer"))
1392 return 0; 1395 return 0;
1393 DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count)); 1396 count = tbuf_bytes(info);
1394 return info->tx_count; 1397 DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count));
1398 return count;
1395} 1399}
1396 1400
1397/* 1401/*
@@ -4671,6 +4675,56 @@ static unsigned int free_tbuf_count(struct slgt_info *info)
4671} 4675}
4672 4676
4673/* 4677/*
4678 * return number of bytes in unsent transmit DMA buffers
4679 * and the serial controller tx FIFO
4680 */
4681static unsigned int tbuf_bytes(struct slgt_info *info)
4682{
4683 unsigned int total_count = 0;
4684 unsigned int i = info->tbuf_current;
4685 unsigned int reg_value;
4686 unsigned int count;
4687 unsigned int active_buf_count = 0;
4688
4689 /*
4690 * Add descriptor counts for all tx DMA buffers.
4691 * If count is zero (cleared by DMA controller after read),
4692 * the buffer is complete or is actively being read from.
4693 *
4694 * Record buf_count of last buffer with zero count starting
4695 * from current ring position. buf_count is mirror
4696 * copy of count and is not cleared by serial controller.
4697 * If DMA controller is active, that buffer is actively
4698 * being read so add to total.
4699 */
4700 do {
4701 count = desc_count(info->tbufs[i]);
4702 if (count)
4703 total_count += count;
4704 else if (!total_count)
4705 active_buf_count = info->tbufs[i].buf_count;
4706 if (++i == info->tbuf_count)
4707 i = 0;
4708 } while (i != info->tbuf_current);
4709
4710 /* read tx DMA status register */
4711 reg_value = rd_reg32(info, TDCSR);
4712
4713 /* if tx DMA active, last zero count buffer is in use */
4714 if (reg_value & BIT0)
4715 total_count += active_buf_count;
4716
4717 /* add tx FIFO count = reg_value[15..8] */
4718 total_count += (reg_value >> 8) & 0xff;
4719
4720 /* if transmitter active add one byte for shift register */
4721 if (info->tx_active)
4722 total_count++;
4723
4724 return total_count;
4725}
4726
4727/*
4674 * load transmit DMA buffer(s) with data 4728 * load transmit DMA buffer(s) with data
4675 */ 4729 */
4676static void tx_load(struct slgt_info *info, const char *buf, unsigned int size) 4730static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
@@ -4708,6 +4762,7 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
4708 set_desc_eof(*d, 0); 4762 set_desc_eof(*d, 0);
4709 4763
4710 set_desc_count(*d, count); 4764 set_desc_count(*d, count);
4765 d->buf_count = count;
4711 } 4766 }
4712 4767
4713 info->tbuf_current = i; 4768 info->tbuf_current = i;