diff options
| -rw-r--r-- | drivers/char/cyclades.c | 6 | ||||
| -rw-r--r-- | drivers/char/esp.c | 4 | ||||
| -rw-r--r-- | drivers/char/tty_io.c | 77 | ||||
| -rw-r--r-- | include/linux/kbd_kern.h | 5 | ||||
| -rw-r--r-- | include/linux/tty.h | 2 | ||||
| -rw-r--r-- | include/linux/tty_flip.h | 7 |
6 files changed, 68 insertions, 33 deletions
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 39c61a71176e..cc7acf877dc0 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c | |||
| @@ -1233,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 1233 | } | 1233 | } |
| 1234 | info->idle_stats.recv_idle = jiffies; | 1234 | info->idle_stats.recv_idle = jiffies; |
| 1235 | } | 1235 | } |
| 1236 | schedule_delayed_work(&tty->buf.work, 1); | 1236 | tty_schedule_flip(tty); |
| 1237 | } | 1237 | } |
| 1238 | /* end of service */ | 1238 | /* end of service */ |
| 1239 | cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); | 1239 | cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f)); |
| @@ -1606,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info, | |||
| 1606 | } | 1606 | } |
| 1607 | #endif | 1607 | #endif |
| 1608 | info->idle_stats.recv_idle = jiffies; | 1608 | info->idle_stats.recv_idle = jiffies; |
| 1609 | schedule_delayed_work(&tty->buf.work, 1); | 1609 | tty_schedule_flip(tty); |
| 1610 | } | 1610 | } |
| 1611 | /* Update rx_get */ | 1611 | /* Update rx_get */ |
| 1612 | cy_writel(&buf_ctrl->rx_get, new_rx_get); | 1612 | cy_writel(&buf_ctrl->rx_get, new_rx_get); |
| @@ -1809,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo) | |||
| 1809 | if(delta_count) | 1809 | if(delta_count) |
| 1810 | cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); | 1810 | cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP); |
| 1811 | if(special_count) | 1811 | if(special_count) |
| 1812 | schedule_delayed_work(&tty->buf.work, 1); | 1812 | tty_schedule_flip(tty); |
| 1813 | } | 1813 | } |
| 1814 | } | 1814 | } |
| 1815 | 1815 | ||
diff --git a/drivers/char/esp.c b/drivers/char/esp.c index 3f3ac039f4d9..57539d8f9f7c 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c | |||
| @@ -359,7 +359,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) | |||
| 359 | } | 359 | } |
| 360 | } | 360 | } |
| 361 | 361 | ||
| 362 | schedule_delayed_work(&tty->buf.work, 1); | 362 | tty_schedule_flip(tty); |
| 363 | 363 | ||
| 364 | info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; | 364 | info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; |
| 365 | release_pio_buffer(pio_buf); | 365 | release_pio_buffer(pio_buf); |
| @@ -426,7 +426,7 @@ static inline void receive_chars_dma_done(struct esp_struct *info, | |||
| 426 | } | 426 | } |
| 427 | tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag); | 427 | tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag); |
| 428 | } | 428 | } |
| 429 | schedule_delayed_work(&tty->buf.work, 1); | 429 | tty_schedule_flip(tty); |
| 430 | } | 430 | } |
| 431 | 431 | ||
| 432 | if (dma_bytes != num_bytes) { | 432 | if (dma_bytes != num_bytes) { |
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index eb8b5be4e249..076e07c1da38 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty) | |||
| 253 | 253 | ||
| 254 | static void tty_buffer_init(struct tty_struct *tty) | 254 | static void tty_buffer_init(struct tty_struct *tty) |
| 255 | { | 255 | { |
| 256 | spin_lock_init(&tty->buf.lock); | ||
| 256 | tty->buf.head = NULL; | 257 | tty->buf.head = NULL; |
| 257 | tty->buf.tail = NULL; | 258 | tty->buf.tail = NULL; |
| 258 | tty->buf.free = NULL; | 259 | tty->buf.free = NULL; |
| @@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size) | |||
| 266 | p->used = 0; | 267 | p->used = 0; |
| 267 | p->size = size; | 268 | p->size = size; |
| 268 | p->next = NULL; | 269 | p->next = NULL; |
| 270 | p->active = 0; | ||
| 269 | p->char_buf_ptr = (char *)(p->data); | 271 | p->char_buf_ptr = (char *)(p->data); |
| 270 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; | 272 | p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; |
| 271 | /* printk("Flip create %p\n", p); */ | 273 | /* printk("Flip create %p\n", p); */ |
| @@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) | |||
| 312 | 314 | ||
| 313 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) | 315 | int tty_buffer_request_room(struct tty_struct *tty, size_t size) |
| 314 | { | 316 | { |
| 315 | struct tty_buffer *b = tty->buf.tail, *n; | 317 | struct tty_buffer *b, *n; |
| 316 | int left = 0; | 318 | int left; |
| 319 | unsigned long flags; | ||
| 320 | |||
| 321 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
| 317 | 322 | ||
| 318 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to | 323 | /* OPTIMISATION: We could keep a per tty "zero" sized buffer to |
| 319 | remove this conditional if its worth it. This would be invisible | 324 | remove this conditional if its worth it. This would be invisible |
| 320 | to the callers */ | 325 | to the callers */ |
| 321 | if(b != NULL) | 326 | if ((b = tty->buf.tail) != NULL) { |
| 322 | left = b->size - b->used; | 327 | left = b->size - b->used; |
| 323 | if(left >= size) | 328 | b->active = 1; |
| 324 | return size; | 329 | } else |
| 325 | /* This is the slow path - looking for new buffers to use */ | 330 | left = 0; |
| 326 | n = tty_buffer_find(tty, size); | 331 | |
| 327 | if(n == NULL) | 332 | if (left < size) { |
| 328 | return left; | 333 | /* This is the slow path - looking for new buffers to use */ |
| 329 | if(b != NULL) | 334 | if ((n = tty_buffer_find(tty, size)) != NULL) { |
| 330 | b->next = n; | 335 | if (b != NULL) { |
| 331 | else | 336 | b->next = n; |
| 332 | tty->buf.head = n; | 337 | b->active = 0; |
| 333 | tty->buf.tail = n; | 338 | } else |
| 339 | tty->buf.head = n; | ||
| 340 | tty->buf.tail = n; | ||
| 341 | n->active = 1; | ||
| 342 | } else | ||
| 343 | size = left; | ||
| 344 | } | ||
| 345 | |||
| 346 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
| 334 | return size; | 347 | return size; |
| 335 | } | 348 | } |
| 336 | 349 | ||
| @@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags); | |||
| 396 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) | 409 | int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size) |
| 397 | { | 410 | { |
| 398 | int space = tty_buffer_request_room(tty, size); | 411 | int space = tty_buffer_request_room(tty, size); |
| 399 | struct tty_buffer *tb = tty->buf.tail; | 412 | if (likely(space)) { |
| 400 | *chars = tb->char_buf_ptr + tb->used; | 413 | struct tty_buffer *tb = tty->buf.tail; |
| 401 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); | 414 | *chars = tb->char_buf_ptr + tb->used; |
| 402 | tb->used += space; | 415 | memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); |
| 416 | tb->used += space; | ||
| 417 | } | ||
| 403 | return space; | 418 | return space; |
| 404 | } | 419 | } |
| 405 | 420 | ||
| @@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); | |||
| 416 | int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) | 431 | int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) |
| 417 | { | 432 | { |
| 418 | int space = tty_buffer_request_room(tty, size); | 433 | int space = tty_buffer_request_room(tty, size); |
| 419 | struct tty_buffer *tb = tty->buf.tail; | 434 | if (likely(space)) { |
| 420 | *chars = tb->char_buf_ptr + tb->used; | 435 | struct tty_buffer *tb = tty->buf.tail; |
| 421 | *flags = tb->flag_buf_ptr + tb->used; | 436 | *chars = tb->char_buf_ptr + tb->used; |
| 422 | tb->used += space; | 437 | *flags = tb->flag_buf_ptr + tb->used; |
| 438 | tb->used += space; | ||
| 439 | } | ||
| 423 | return space; | 440 | return space; |
| 424 | } | 441 | } |
| 425 | 442 | ||
| @@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_) | |||
| 2747 | schedule_delayed_work(&tty->buf.work, 1); | 2764 | schedule_delayed_work(&tty->buf.work, 1); |
| 2748 | goto out; | 2765 | goto out; |
| 2749 | } | 2766 | } |
| 2750 | spin_lock_irqsave(&tty->read_lock, flags); | 2767 | spin_lock_irqsave(&tty->buf.lock, flags); |
| 2751 | while((tbuf = tty->buf.head) != NULL) { | 2768 | while((tbuf = tty->buf.head) != NULL && !tbuf->active) { |
| 2752 | tty->buf.head = tbuf->next; | 2769 | tty->buf.head = tbuf->next; |
| 2753 | if (tty->buf.head == NULL) | 2770 | if (tty->buf.head == NULL) |
| 2754 | tty->buf.tail = NULL; | 2771 | tty->buf.tail = NULL; |
| 2755 | spin_unlock_irqrestore(&tty->read_lock, flags); | 2772 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
| 2756 | /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ | 2773 | /* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */ |
| 2757 | disc->receive_buf(tty, tbuf->char_buf_ptr, | 2774 | disc->receive_buf(tty, tbuf->char_buf_ptr, |
| 2758 | tbuf->flag_buf_ptr, | 2775 | tbuf->flag_buf_ptr, |
| 2759 | tbuf->used); | 2776 | tbuf->used); |
| 2760 | spin_lock_irqsave(&tty->read_lock, flags); | 2777 | spin_lock_irqsave(&tty->buf.lock, flags); |
| 2761 | tty_buffer_free(tty, tbuf); | 2778 | tty_buffer_free(tty, tbuf); |
| 2762 | } | 2779 | } |
| 2763 | spin_unlock_irqrestore(&tty->read_lock, flags); | 2780 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
| 2764 | out: | 2781 | out: |
| 2765 | tty_ldisc_deref(disc); | 2782 | tty_ldisc_deref(disc); |
| 2766 | } | 2783 | } |
| @@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate); | |||
| 2852 | 2869 | ||
| 2853 | void tty_flip_buffer_push(struct tty_struct *tty) | 2870 | void tty_flip_buffer_push(struct tty_struct *tty) |
| 2854 | { | 2871 | { |
| 2872 | unsigned long flags; | ||
| 2873 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
| 2874 | if (tty->buf.tail != NULL) | ||
| 2875 | tty->buf.tail->active = 0; | ||
| 2876 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
| 2877 | |||
| 2855 | if (tty->low_latency) | 2878 | if (tty->low_latency) |
| 2856 | flush_to_ldisc((void *) tty); | 2879 | flush_to_ldisc((void *) tty); |
| 2857 | else | 2880 | else |
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h index 45f625d7d0b2..3aed37314ab8 100644 --- a/include/linux/kbd_kern.h +++ b/include/linux/kbd_kern.h | |||
| @@ -151,6 +151,11 @@ extern unsigned int keymap_count; | |||
| 151 | 151 | ||
| 152 | static inline void con_schedule_flip(struct tty_struct *t) | 152 | static inline void con_schedule_flip(struct tty_struct *t) |
| 153 | { | 153 | { |
| 154 | unsigned long flags; | ||
| 155 | spin_lock_irqsave(&t->buf.lock, flags); | ||
| 156 | if (t->buf.tail != NULL) | ||
| 157 | t->buf.tail->active = 0; | ||
| 158 | spin_unlock_irqrestore(&t->buf.lock, flags); | ||
| 154 | schedule_work(&t->buf.work); | 159 | schedule_work(&t->buf.work); |
| 155 | } | 160 | } |
| 156 | 161 | ||
diff --git a/include/linux/tty.h b/include/linux/tty.h index 3787102e4b12..a7bd3b4558d2 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
| @@ -57,6 +57,7 @@ struct tty_buffer { | |||
| 57 | unsigned char *flag_buf_ptr; | 57 | unsigned char *flag_buf_ptr; |
| 58 | int used; | 58 | int used; |
| 59 | int size; | 59 | int size; |
| 60 | int active; | ||
| 60 | /* Data points here */ | 61 | /* Data points here */ |
| 61 | unsigned long data[0]; | 62 | unsigned long data[0]; |
| 62 | }; | 63 | }; |
| @@ -64,6 +65,7 @@ struct tty_buffer { | |||
| 64 | struct tty_bufhead { | 65 | struct tty_bufhead { |
| 65 | struct work_struct work; | 66 | struct work_struct work; |
| 66 | struct semaphore pty_sem; | 67 | struct semaphore pty_sem; |
| 68 | spinlock_t lock; | ||
| 67 | struct tty_buffer *head; /* Queue head */ | 69 | struct tty_buffer *head; /* Queue head */ |
| 68 | struct tty_buffer *tail; /* Active buffer */ | 70 | struct tty_buffer *tail; /* Active buffer */ |
| 69 | struct tty_buffer *free; /* Free queue head */ | 71 | struct tty_buffer *free; /* Free queue head */ |
diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index be1400e82482..82961eb19888 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h | |||
| @@ -17,7 +17,7 @@ _INLINE_ int tty_insert_flip_char(struct tty_struct *tty, | |||
| 17 | unsigned char ch, char flag) | 17 | unsigned char ch, char flag) |
| 18 | { | 18 | { |
| 19 | struct tty_buffer *tb = tty->buf.tail; | 19 | struct tty_buffer *tb = tty->buf.tail; |
| 20 | if (tb && tb->used < tb->size) { | 20 | if (tb && tb->active && tb->used < tb->size) { |
| 21 | tb->flag_buf_ptr[tb->used] = flag; | 21 | tb->flag_buf_ptr[tb->used] = flag; |
| 22 | tb->char_buf_ptr[tb->used++] = ch; | 22 | tb->char_buf_ptr[tb->used++] = ch; |
| 23 | return 1; | 23 | return 1; |
| @@ -27,6 +27,11 @@ _INLINE_ int tty_insert_flip_char(struct tty_struct *tty, | |||
| 27 | 27 | ||
| 28 | _INLINE_ void tty_schedule_flip(struct tty_struct *tty) | 28 | _INLINE_ void tty_schedule_flip(struct tty_struct *tty) |
| 29 | { | 29 | { |
| 30 | unsigned long flags; | ||
| 31 | spin_lock_irqsave(&tty->buf.lock, flags); | ||
| 32 | if (tty->buf.tail != NULL) | ||
| 33 | tty->buf.tail->active = 0; | ||
| 34 | spin_unlock_irqrestore(&tty->buf.lock, flags); | ||
| 30 | schedule_delayed_work(&tty->buf.work, 1); | 35 | schedule_delayed_work(&tty->buf.work, 1); |
| 31 | } | 36 | } |
| 32 | 37 | ||
