aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/n_tty.c
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-06-15 10:04:26 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-23 20:02:21 -0400
commitcbfd0340ae1993378fd47179db949e050e16e697 (patch)
treee7663ed78f91daf7e1d441d28e2644d0dffeded5 /drivers/tty/n_tty.c
parent019ebdf9f26fd2e43b9e1af576835183e95dc82e (diff)
n_tty: Process echoes in blocks
Byte-by-byte echo output is painfully slow, requiring a lock/unlock cycle for every input byte. Instead, perform the echo output in blocks of 256 characters, and at least once per flip buffer receive. Enough space is reserved in the echo buffer to guarantee a full block can be saved without overrunning the echo output. Overrun is prevented by discarding the oldest echoes until enough space exists in the echo buffer to receive at least a full block of new echoes. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/n_tty.c')
-rw-r--r--drivers/tty/n_tty.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 0f76b9096840..20983afb6086 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -74,6 +74,11 @@
74#define ECHO_OP_SET_CANON_COL 0x81 74#define ECHO_OP_SET_CANON_COL 0x81
75#define ECHO_OP_ERASE_TAB 0x82 75#define ECHO_OP_ERASE_TAB 0x82
76 76
77#define ECHO_COMMIT_WATERMARK 256
78#define ECHO_BLOCK 256
79#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
80
81
77#undef N_TTY_TRACE 82#undef N_TTY_TRACE
78#ifdef N_TTY_TRACE 83#ifdef N_TTY_TRACE
79# define n_tty_trace(f, args...) trace_printk(f, ##args) 84# define n_tty_trace(f, args...) trace_printk(f, ##args)
@@ -766,15 +771,40 @@ static void __process_echoes(struct tty_struct *tty)
766 } 771 }
767 } 772 }
768 773
774 /* If the echo buffer is nearly full (so that the possibility exists
775 * of echo overrun before the next commit), then discard enough
776 * data at the tail to prevent a subsequent overrun */
777 while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) {
778 if (echo_buf(ldata, tail == ECHO_OP_START)) {
779 if (echo_buf(ldata, tail) == ECHO_OP_ERASE_TAB)
780 tail += 3;
781 else
782 tail += 2;
783 } else
784 tail++;
785 }
786
769 ldata->echo_tail = tail; 787 ldata->echo_tail = tail;
770} 788}
771 789
772static void commit_echoes(struct tty_struct *tty) 790static void commit_echoes(struct tty_struct *tty)
773{ 791{
774 struct n_tty_data *ldata = tty->disc_data; 792 struct n_tty_data *ldata = tty->disc_data;
793 size_t nr, old;
794 size_t head;
795
796 head = ldata->echo_head;
797 old = ldata->echo_commit - ldata->echo_tail;
798
799 /* Process committed echoes if the accumulated # of bytes
800 * is over the threshold (and try again each time another
801 * block is accumulated) */
802 nr = head - ldata->echo_tail;
803 if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK))
804 return;
775 805
776 mutex_lock(&ldata->output_lock); 806 mutex_lock(&ldata->output_lock);
777 ldata->echo_commit = ldata->echo_head; 807 ldata->echo_commit = head;
778 __process_echoes(tty); 808 __process_echoes(tty);
779 mutex_unlock(&ldata->output_lock); 809 mutex_unlock(&ldata->output_lock);
780 810
@@ -797,37 +827,29 @@ static void process_echoes(struct tty_struct *tty)
797 tty->ops->flush_chars(tty); 827 tty->ops->flush_chars(tty);
798} 828}
799 829
830static void flush_echoes(struct tty_struct *tty)
831{
832 struct n_tty_data *ldata = tty->disc_data;
833
834 if (!L_ECHO(tty) || ldata->echo_commit == ldata->echo_head)
835 return;
836
837 mutex_lock(&ldata->output_lock);
838 ldata->echo_commit = ldata->echo_head;
839 __process_echoes(tty);
840 mutex_unlock(&ldata->output_lock);
841}
842
800/** 843/**
801 * add_echo_byte - add a byte to the echo buffer 844 * add_echo_byte - add a byte to the echo buffer
802 * @c: unicode byte to echo 845 * @c: unicode byte to echo
803 * @ldata: n_tty data 846 * @ldata: n_tty data
804 * 847 *
805 * Add a character or operation byte to the echo buffer. 848 * Add a character or operation byte to the echo buffer.
806 *
807 * Locks: may claim output_lock to prevent concurrent modify of
808 * echo_tail by process_echoes().
809 */ 849 */
810 850
811static void add_echo_byte(unsigned char c, struct n_tty_data *ldata) 851static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata)
812{ 852{
813 if (ldata->echo_head - ldata->echo_tail == N_TTY_BUF_SIZE) {
814 size_t head = ldata->echo_head;
815
816 mutex_lock(&ldata->output_lock);
817 /*
818 * Since the buffer start position needs to be advanced,
819 * be sure to step by a whole operation byte group.
820 */
821 if (echo_buf(ldata, head) == ECHO_OP_START) {
822 if (echo_buf(ldata, head + 1) == ECHO_OP_ERASE_TAB)
823 ldata->echo_tail += 3;
824 else
825 ldata->echo_tail += 2;
826 } else
827 ldata->echo_tail++;
828 mutex_unlock(&ldata->output_lock);
829 }
830
831 *echo_buf_addr(ldata, ldata->echo_head++) = c; 853 *echo_buf_addr(ldata, ldata->echo_head++) = c;
832} 854}
833 855
@@ -1515,6 +1537,8 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
1515 break; 1537 break;
1516 } 1538 }
1517 } 1539 }
1540
1541 flush_echoes(tty);
1518 if (tty->ops->flush_chars) 1542 if (tty->ops->flush_chars)
1519 tty->ops->flush_chars(tty); 1543 tty->ops->flush_chars(tty);
1520 } 1544 }