aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/hvc/hvsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/hvc/hvsi.c')
-rw-r--r--drivers/tty/hvc/hvsi.c128
1 files changed, 54 insertions, 74 deletions
diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c
index a7488b748647..6f5bc49c441f 100644
--- a/drivers/tty/hvc/hvsi.c
+++ b/drivers/tty/hvc/hvsi.c
@@ -69,14 +69,13 @@
69#define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) 69#define __ALIGNED__ __attribute__((__aligned__(sizeof(long))))
70 70
71struct hvsi_struct { 71struct hvsi_struct {
72 struct tty_port port;
72 struct delayed_work writer; 73 struct delayed_work writer;
73 struct work_struct handshaker; 74 struct work_struct handshaker;
74 wait_queue_head_t emptyq; /* woken when outbuf is emptied */ 75 wait_queue_head_t emptyq; /* woken when outbuf is emptied */
75 wait_queue_head_t stateq; /* woken when HVSI state changes */ 76 wait_queue_head_t stateq; /* woken when HVSI state changes */
76 spinlock_t lock; 77 spinlock_t lock;
77 int index; 78 int index;
78 struct tty_struct *tty;
79 int count;
80 uint8_t throttle_buf[128]; 79 uint8_t throttle_buf[128];
81 uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ 80 uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */
82 /* inbuf is for packet reassembly. leave a little room for leftovers. */ 81 /* inbuf is for packet reassembly. leave a little room for leftovers. */
@@ -237,7 +236,7 @@ static int hvsi_read(struct hvsi_struct *hp, char *buf, int count)
237} 236}
238 237
239static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, 238static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
240 struct tty_struct **to_hangup, struct hvsi_struct **to_handshake) 239 struct tty_struct *tty, struct hvsi_struct **to_handshake)
241{ 240{
242 struct hvsi_control *header = (struct hvsi_control *)packet; 241 struct hvsi_control *header = (struct hvsi_control *)packet;
243 242
@@ -247,9 +246,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
247 /* CD went away; no more connection */ 246 /* CD went away; no more connection */
248 pr_debug("hvsi%i: CD dropped\n", hp->index); 247 pr_debug("hvsi%i: CD dropped\n", hp->index);
249 hp->mctrl &= TIOCM_CD; 248 hp->mctrl &= TIOCM_CD;
250 /* If userland hasn't done an open(2) yet, hp->tty is NULL. */ 249 if (tty && !C_CLOCAL(tty))
251 if (hp->tty && !(hp->tty->flags & CLOCAL)) 250 tty_hangup(tty);
252 *to_hangup = hp->tty;
253 } 251 }
254 break; 252 break;
255 case VSV_CLOSE_PROTOCOL: 253 case VSV_CLOSE_PROTOCOL:
@@ -331,7 +329,8 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet)
331 } 329 }
332} 330}
333 331
334static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) 332static void hvsi_insert_chars(struct hvsi_struct *hp, struct tty_struct *tty,
333 const char *buf, int len)
335{ 334{
336 int i; 335 int i;
337 336
@@ -347,7 +346,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
347 continue; 346 continue;
348 } 347 }
349#endif /* CONFIG_MAGIC_SYSRQ */ 348#endif /* CONFIG_MAGIC_SYSRQ */
350 tty_insert_flip_char(hp->tty, c, 0); 349 tty_insert_flip_char(tty, c, 0);
351 } 350 }
352} 351}
353 352
@@ -360,7 +359,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
360 * revisited. 359 * revisited.
361 */ 360 */
362#define TTY_THRESHOLD_THROTTLE 128 361#define TTY_THRESHOLD_THROTTLE 128
363static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, 362static bool hvsi_recv_data(struct hvsi_struct *hp, struct tty_struct *tty,
364 const uint8_t *packet) 363 const uint8_t *packet)
365{ 364{
366 const struct hvsi_header *header = (const struct hvsi_header *)packet; 365 const struct hvsi_header *header = (const struct hvsi_header *)packet;
@@ -371,14 +370,14 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
371 pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data); 370 pr_debug("queueing %i chars '%.*s'\n", datalen, datalen, data);
372 371
373 if (datalen == 0) 372 if (datalen == 0)
374 return NULL; 373 return false;
375 374
376 if (overflow > 0) { 375 if (overflow > 0) {
377 pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); 376 pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
378 datalen = TTY_THRESHOLD_THROTTLE; 377 datalen = TTY_THRESHOLD_THROTTLE;
379 } 378 }
380 379
381 hvsi_insert_chars(hp, data, datalen); 380 hvsi_insert_chars(hp, tty, data, datalen);
382 381
383 if (overflow > 0) { 382 if (overflow > 0) {
384 /* 383 /*
@@ -390,7 +389,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
390 hp->n_throttle = overflow; 389 hp->n_throttle = overflow;
391 } 390 }
392 391
393 return hp->tty; 392 return true;
394} 393}
395 394
396/* 395/*
@@ -399,14 +398,13 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp,
399 * machine during console handshaking (in which case tty = NULL and we ignore 398 * machine during console handshaking (in which case tty = NULL and we ignore
400 * incoming data). 399 * incoming data).
401 */ 400 */
402static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, 401static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct *tty,
403 struct tty_struct **hangup, struct hvsi_struct **handshake) 402 struct hvsi_struct **handshake)
404{ 403{
405 uint8_t *packet = hp->inbuf; 404 uint8_t *packet = hp->inbuf;
406 int chunklen; 405 int chunklen;
406 bool flip = false;
407 407
408 *flip = NULL;
409 *hangup = NULL;
410 *handshake = NULL; 408 *handshake = NULL;
411 409
412 chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); 410 chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
@@ -440,12 +438,12 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
440 case VS_DATA_PACKET_HEADER: 438 case VS_DATA_PACKET_HEADER:
441 if (!is_open(hp)) 439 if (!is_open(hp))
442 break; 440 break;
443 if (hp->tty == NULL) 441 if (tty == NULL)
444 break; /* no tty buffer to put data in */ 442 break; /* no tty buffer to put data in */
445 *flip = hvsi_recv_data(hp, packet); 443 flip = hvsi_recv_data(hp, tty, packet);
446 break; 444 break;
447 case VS_CONTROL_PACKET_HEADER: 445 case VS_CONTROL_PACKET_HEADER:
448 hvsi_recv_control(hp, packet, hangup, handshake); 446 hvsi_recv_control(hp, packet, tty, handshake);
449 break; 447 break;
450 case VS_QUERY_RESPONSE_PACKET_HEADER: 448 case VS_QUERY_RESPONSE_PACKET_HEADER:
451 hvsi_recv_response(hp, packet); 449 hvsi_recv_response(hp, packet);
@@ -462,28 +460,26 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip,
462 460
463 packet += len_packet(packet); 461 packet += len_packet(packet);
464 462
465 if (*hangup || *handshake) { 463 if (*handshake) {
466 pr_debug("%s: hangup or handshake\n", __func__); 464 pr_debug("%s: handshake\n", __func__);
467 /*
468 * we need to send the hangup now before receiving any more data.
469 * If we get "data, hangup, data", we can't deliver the second
470 * data before the hangup.
471 */
472 break; 465 break;
473 } 466 }
474 } 467 }
475 468
476 compact_inbuf(hp, packet); 469 compact_inbuf(hp, packet);
477 470
471 if (flip)
472 tty_flip_buffer_push(tty);
473
478 return 1; 474 return 1;
479} 475}
480 476
481static void hvsi_send_overflow(struct hvsi_struct *hp) 477static void hvsi_send_overflow(struct hvsi_struct *hp, struct tty_struct *tty)
482{ 478{
483 pr_debug("%s: delivering %i bytes overflow\n", __func__, 479 pr_debug("%s: delivering %i bytes overflow\n", __func__,
484 hp->n_throttle); 480 hp->n_throttle);
485 481
486 hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); 482 hvsi_insert_chars(hp, tty, hp->throttle_buf, hp->n_throttle);
487 hp->n_throttle = 0; 483 hp->n_throttle = 0;
488} 484}
489 485
@@ -494,35 +490,20 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
494static irqreturn_t hvsi_interrupt(int irq, void *arg) 490static irqreturn_t hvsi_interrupt(int irq, void *arg)
495{ 491{
496 struct hvsi_struct *hp = (struct hvsi_struct *)arg; 492 struct hvsi_struct *hp = (struct hvsi_struct *)arg;
497 struct tty_struct *flip;
498 struct tty_struct *hangup;
499 struct hvsi_struct *handshake; 493 struct hvsi_struct *handshake;
494 struct tty_struct *tty;
500 unsigned long flags; 495 unsigned long flags;
501 int again = 1; 496 int again = 1;
502 497
503 pr_debug("%s\n", __func__); 498 pr_debug("%s\n", __func__);
504 499
500 tty = tty_port_tty_get(&hp->port);
501
505 while (again) { 502 while (again) {
506 spin_lock_irqsave(&hp->lock, flags); 503 spin_lock_irqsave(&hp->lock, flags);
507 again = hvsi_load_chunk(hp, &flip, &hangup, &handshake); 504 again = hvsi_load_chunk(hp, tty, &handshake);
508 spin_unlock_irqrestore(&hp->lock, flags); 505 spin_unlock_irqrestore(&hp->lock, flags);
509 506
510 /*
511 * we have to call tty_flip_buffer_push() and tty_hangup() outside our
512 * spinlock. But we also have to keep going until we've read all the
513 * available data.
514 */
515
516 if (flip) {
517 /* there was data put in the tty flip buffer */
518 tty_flip_buffer_push(flip);
519 flip = NULL;
520 }
521
522 if (hangup) {
523 tty_hangup(hangup);
524 }
525
526 if (handshake) { 507 if (handshake) {
527 pr_debug("hvsi%i: attempting re-handshake\n", handshake->index); 508 pr_debug("hvsi%i: attempting re-handshake\n", handshake->index);
528 schedule_work(&handshake->handshaker); 509 schedule_work(&handshake->handshaker);
@@ -530,18 +511,15 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg)
530 } 511 }
531 512
532 spin_lock_irqsave(&hp->lock, flags); 513 spin_lock_irqsave(&hp->lock, flags);
533 if (hp->tty && hp->n_throttle 514 if (tty && hp->n_throttle && !test_bit(TTY_THROTTLED, &tty->flags)) {
534 && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { 515 /* we weren't hung up and we weren't throttled, so we can
535 /* we weren't hung up and we weren't throttled, so we can deliver the 516 * deliver the rest now */
536 * rest now */ 517 hvsi_send_overflow(hp, tty);
537 flip = hp->tty; 518 tty_flip_buffer_push(tty);
538 hvsi_send_overflow(hp);
539 } 519 }
540 spin_unlock_irqrestore(&hp->lock, flags); 520 spin_unlock_irqrestore(&hp->lock, flags);
541 521
542 if (flip) { 522 tty_kref_put(tty);
543 tty_flip_buffer_push(flip);
544 }
545 523
546 return IRQ_HANDLED; 524 return IRQ_HANDLED;
547} 525}
@@ -749,9 +727,9 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
749 if (hp->state == HVSI_FSP_DIED) 727 if (hp->state == HVSI_FSP_DIED)
750 return -EIO; 728 return -EIO;
751 729
730 tty_port_tty_set(&hp->port, tty);
752 spin_lock_irqsave(&hp->lock, flags); 731 spin_lock_irqsave(&hp->lock, flags);
753 hp->tty = tty; 732 hp->port.count++;
754 hp->count++;
755 atomic_set(&hp->seqno, 0); 733 atomic_set(&hp->seqno, 0);
756 h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); 734 h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
757 spin_unlock_irqrestore(&hp->lock, flags); 735 spin_unlock_irqrestore(&hp->lock, flags);
@@ -808,8 +786,8 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
808 786
809 spin_lock_irqsave(&hp->lock, flags); 787 spin_lock_irqsave(&hp->lock, flags);
810 788
811 if (--hp->count == 0) { 789 if (--hp->port.count == 0) {
812 hp->tty = NULL; 790 tty_port_tty_set(&hp->port, NULL);
813 hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */ 791 hp->inbuf_end = hp->inbuf; /* discard remaining partial packets */
814 792
815 /* only close down connection if it is not the console */ 793 /* only close down connection if it is not the console */
@@ -841,9 +819,9 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp)
841 819
842 spin_lock_irqsave(&hp->lock, flags); 820 spin_lock_irqsave(&hp->lock, flags);
843 } 821 }
844 } else if (hp->count < 0) 822 } else if (hp->port.count < 0)
845 printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n", 823 printk(KERN_ERR "hvsi_close %lu: oops, count is %d\n",
846 hp - hvsi_ports, hp->count); 824 hp - hvsi_ports, hp->port.count);
847 825
848 spin_unlock_irqrestore(&hp->lock, flags); 826 spin_unlock_irqrestore(&hp->lock, flags);
849} 827}
@@ -855,12 +833,11 @@ static void hvsi_hangup(struct tty_struct *tty)
855 833
856 pr_debug("%s\n", __func__); 834 pr_debug("%s\n", __func__);
857 835
858 spin_lock_irqsave(&hp->lock, flags); 836 tty_port_tty_set(&hp->port, NULL);
859 837
860 hp->count = 0; 838 spin_lock_irqsave(&hp->lock, flags);
839 hp->port.count = 0;
861 hp->n_outbuf = 0; 840 hp->n_outbuf = 0;
862 hp->tty = NULL;
863
864 spin_unlock_irqrestore(&hp->lock, flags); 841 spin_unlock_irqrestore(&hp->lock, flags);
865} 842}
866 843
@@ -888,6 +865,7 @@ static void hvsi_write_worker(struct work_struct *work)
888{ 865{
889 struct hvsi_struct *hp = 866 struct hvsi_struct *hp =
890 container_of(work, struct hvsi_struct, writer.work); 867 container_of(work, struct hvsi_struct, writer.work);
868 struct tty_struct *tty;
891 unsigned long flags; 869 unsigned long flags;
892#ifdef DEBUG 870#ifdef DEBUG
893 static long start_j = 0; 871 static long start_j = 0;
@@ -921,7 +899,11 @@ static void hvsi_write_worker(struct work_struct *work)
921 start_j = 0; 899 start_j = 0;
922#endif /* DEBUG */ 900#endif /* DEBUG */
923 wake_up_all(&hp->emptyq); 901 wake_up_all(&hp->emptyq);
924 tty_wakeup(hp->tty); 902 tty = tty_port_tty_get(&hp->port);
903 if (tty) {
904 tty_wakeup(tty);
905 tty_kref_put(tty);
906 }
925 } 907 }
926 908
927out: 909out:
@@ -966,8 +948,8 @@ static int hvsi_write(struct tty_struct *tty,
966 * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls 948 * and hvsi_write_worker will be scheduled. subsequent hvsi_write() calls
967 * will see there is no room in outbuf and return. 949 * will see there is no room in outbuf and return.
968 */ 950 */
969 while ((count > 0) && (hvsi_write_room(hp->tty) > 0)) { 951 while ((count > 0) && (hvsi_write_room(tty) > 0)) {
970 int chunksize = min(count, hvsi_write_room(hp->tty)); 952 int chunksize = min(count, hvsi_write_room(tty));
971 953
972 BUG_ON(hp->n_outbuf < 0); 954 BUG_ON(hp->n_outbuf < 0);
973 memcpy(hp->outbuf + hp->n_outbuf, source, chunksize); 955 memcpy(hp->outbuf + hp->n_outbuf, source, chunksize);
@@ -1014,19 +996,16 @@ static void hvsi_unthrottle(struct tty_struct *tty)
1014{ 996{
1015 struct hvsi_struct *hp = tty->driver_data; 997 struct hvsi_struct *hp = tty->driver_data;
1016 unsigned long flags; 998 unsigned long flags;
1017 int shouldflip = 0;
1018 999
1019 pr_debug("%s\n", __func__); 1000 pr_debug("%s\n", __func__);
1020 1001
1021 spin_lock_irqsave(&hp->lock, flags); 1002 spin_lock_irqsave(&hp->lock, flags);
1022 if (hp->n_throttle) { 1003 if (hp->n_throttle) {
1023 hvsi_send_overflow(hp); 1004 hvsi_send_overflow(hp, tty);
1024 shouldflip = 1; 1005 tty_flip_buffer_push(tty);
1025 } 1006 }
1026 spin_unlock_irqrestore(&hp->lock, flags); 1007 spin_unlock_irqrestore(&hp->lock, flags);
1027 1008
1028 if (shouldflip)
1029 tty_flip_buffer_push(hp->tty);
1030 1009
1031 h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); 1010 h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE);
1032} 1011}
@@ -1228,6 +1207,7 @@ static int __init hvsi_console_init(void)
1228 init_waitqueue_head(&hp->emptyq); 1207 init_waitqueue_head(&hp->emptyq);
1229 init_waitqueue_head(&hp->stateq); 1208 init_waitqueue_head(&hp->stateq);
1230 spin_lock_init(&hp->lock); 1209 spin_lock_init(&hp->lock);
1210 tty_port_init(&hp->port);
1231 hp->index = hvsi_count; 1211 hp->index = hvsi_count;
1232 hp->inbuf_end = hp->inbuf; 1212 hp->inbuf_end = hp->inbuf;
1233 hp->state = HVSI_CLOSED; 1213 hp->state = HVSI_CLOSED;