fb:support 180 degree rotate
[firefly-linux-kernel-4.4.55.git] / drivers / char / tty_buffer.c
index 66fa4e10d76bd47e1192a4593a488e8491e09b68..9605ee5b931e4ea98bd461d45ddd75c5dfebf7d6 100644 (file)
@@ -247,7 +247,8 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
 {
        int copied = 0;
        do {
-               int space = tty_buffer_request_room(tty, size - copied);
+               int goal = min(size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
                struct tty_buffer *tb = tty->buf.tail;
                /* If there is no space then tb may be NULL */
                if (unlikely(space == 0))
@@ -283,7 +284,8 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
 {
        int copied = 0;
        do {
-               int space = tty_buffer_request_room(tty, size - copied);
+               int goal = min(size - copied, TTY_BUFFER_PAGE);
+               int space = tty_buffer_request_room(tty, goal);
                struct tty_buffer *tb = tty->buf.tail;
                /* If there is no space then tb may be NULL */
                if (unlikely(space == 0))
@@ -410,7 +412,8 @@ static void flush_to_ldisc(struct work_struct *work)
        spin_lock_irqsave(&tty->buf.lock, flags);
 
        if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
-               struct tty_buffer *head;
+               struct tty_buffer *head, *tail = tty->buf.tail;
+               int seen_tail = 0;
                while ((head = tty->buf.head) != NULL) {
                        int count;
                        char *char_buf;
@@ -420,6 +423,15 @@ static void flush_to_ldisc(struct work_struct *work)
                        if (!count) {
                                if (head->next == NULL)
                                        break;
+                               /*
+                                 There's a possibility tty might get new buffer
+                                 added during the unlock window below. We could
+                                 end up spinning in here forever hogging the CPU
+                                 completely. To avoid this let's have a rest each
+                                 time we processed the tail buffer.
+                               */
+                               if (tail == head)
+                                       seen_tail = 1;
                                tty->buf.head = head->next;
                                tty_buffer_free(tty, head);
                                continue;
@@ -429,7 +441,7 @@ static void flush_to_ldisc(struct work_struct *work)
                           line discipline as we want to empty the queue */
                        if (test_bit(TTY_FLUSHPENDING, &tty->flags))
                                break;
-                       if (!tty->receive_room) {
+                       if (!tty->receive_room || seen_tail) {
                                schedule_delayed_work(&tty->buf.work, 1);
                                break;
                        }