aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/char/con3215.c
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2012-02-17 04:29:22 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-02-17 04:29:33 -0500
commit656d9125376006cf696b0836f1c6723a892629ca (patch)
tree0e5c7b817c01c408dc6edf28602c31a8b4fef299 /drivers/s390/char/con3215.c
parent2320c5793790fcda80e6dcc088dbda86040235e5 (diff)
[S390] 3215 deadlock with tty_wakeup
The 3215 driver calls tty_wakeup from irq context while holding the device spinlock. If printk is called by any function on the callchain starting from tty_wakeup the system deadlocks on the device spinlock. Using a tasklet to call tty_wakup solves the problem. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/char/con3215.c')
-rw-r--r--drivers/s390/char/con3215.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 934458ad55e5..e71a50d4b221 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -87,6 +87,7 @@ struct raw3215_info {
87 struct tty_struct *tty; /* pointer to tty structure if present */ 87 struct tty_struct *tty; /* pointer to tty structure if present */
88 struct raw3215_req *queued_read; /* pointer to queued read requests */ 88 struct raw3215_req *queued_read; /* pointer to queued read requests */
89 struct raw3215_req *queued_write;/* pointer to queued write requests */ 89 struct raw3215_req *queued_write;/* pointer to queued write requests */
90 struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
90 wait_queue_head_t empty_wait; /* wait queue for flushing */ 91 wait_queue_head_t empty_wait; /* wait queue for flushing */
91 struct timer_list timer; /* timer for delayed output */ 92 struct timer_list timer; /* timer for delayed output */
92 int line_pos; /* position on the line (for tabs) */ 93 int line_pos; /* position on the line (for tabs) */
@@ -334,19 +335,23 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
334} 335}
335 336
336/* 337/*
338 * Call tty_wakeup from tasklet context
339 */
340static void raw3215_wakeup(unsigned long data)
341{
342 struct raw3215_info *raw = (struct raw3215_info *) data;
343 tty_wakeup(raw->tty);
344}
345
346/*
337 * Try to start the next IO and wake up processes waiting on the tty. 347 * Try to start the next IO and wake up processes waiting on the tty.
338 */ 348 */
339static void raw3215_next_io(struct raw3215_info *raw) 349static void raw3215_next_io(struct raw3215_info *raw)
340{ 350{
341 struct tty_struct *tty;
342
343 raw3215_mk_write_req(raw); 351 raw3215_mk_write_req(raw);
344 raw3215_try_io(raw); 352 raw3215_try_io(raw);
345 tty = raw->tty; 353 if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
346 if (tty != NULL && 354 tasklet_schedule(&raw->tlet);
347 RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
348 tty_wakeup(tty);
349 }
350} 355}
351 356
352/* 357/*
@@ -682,6 +687,7 @@ static int raw3215_probe (struct ccw_device *cdev)
682 return -ENOMEM; 687 return -ENOMEM;
683 } 688 }
684 init_waitqueue_head(&raw->empty_wait); 689 init_waitqueue_head(&raw->empty_wait);
690 tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
685 691
686 dev_set_drvdata(&cdev->dev, raw); 692 dev_set_drvdata(&cdev->dev, raw);
687 cdev->handler = raw3215_irq; 693 cdev->handler = raw3215_irq;
@@ -901,6 +907,7 @@ static int __init con3215_init(void)
901 907
902 raw->flags |= RAW3215_FIXED; 908 raw->flags |= RAW3215_FIXED;
903 init_waitqueue_head(&raw->empty_wait); 909 init_waitqueue_head(&raw->empty_wait);
910 tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
904 911
905 /* Request the console irq */ 912 /* Request the console irq */
906 if (raw3215_startup(raw) != 0) { 913 if (raw3215_startup(raw) != 0) {
@@ -966,6 +973,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
966 tty->closing = 1; 973 tty->closing = 1;
967 /* Shutdown the terminal */ 974 /* Shutdown the terminal */
968 raw3215_shutdown(raw); 975 raw3215_shutdown(raw);
976 tasklet_kill(&raw->tlet);
969 tty->closing = 0; 977 tty->closing = 0;
970 raw->tty = NULL; 978 raw->tty = NULL;
971} 979}