Commit 656d9125 authored by Martin Schwidefsky's avatar Martin Schwidefsky

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 2320c579
...@@ -87,6 +87,7 @@ struct raw3215_info { ...@@ -87,6 +87,7 @@ struct raw3215_info {
struct tty_struct *tty; /* pointer to tty structure if present */ struct tty_struct *tty; /* pointer to tty structure if present */
struct raw3215_req *queued_read; /* pointer to queued read requests */ struct raw3215_req *queued_read; /* pointer to queued read requests */
struct raw3215_req *queued_write;/* pointer to queued write requests */ struct raw3215_req *queued_write;/* pointer to queued write requests */
struct tasklet_struct tlet; /* tasklet to invoke tty_wakeup */
wait_queue_head_t empty_wait; /* wait queue for flushing */ wait_queue_head_t empty_wait; /* wait queue for flushing */
struct timer_list timer; /* timer for delayed output */ struct timer_list timer; /* timer for delayed output */
int line_pos; /* position on the line (for tabs) */ int line_pos; /* position on the line (for tabs) */
...@@ -333,20 +334,24 @@ static inline void raw3215_try_io(struct raw3215_info *raw) ...@@ -333,20 +334,24 @@ static inline void raw3215_try_io(struct raw3215_info *raw)
} }
} }
/*
* Call tty_wakeup from tasklet context
*/
static void raw3215_wakeup(unsigned long data)
{
struct raw3215_info *raw = (struct raw3215_info *) data;
tty_wakeup(raw->tty);
}
/* /*
* Try to start the next IO and wake up processes waiting on the tty. * Try to start the next IO and wake up processes waiting on the tty.
*/ */
static void raw3215_next_io(struct raw3215_info *raw) static void raw3215_next_io(struct raw3215_info *raw)
{ {
struct tty_struct *tty;
raw3215_mk_write_req(raw); raw3215_mk_write_req(raw);
raw3215_try_io(raw); raw3215_try_io(raw);
tty = raw->tty; if (raw->tty && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE)
if (tty != NULL && tasklet_schedule(&raw->tlet);
RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) {
tty_wakeup(tty);
}
} }
/* /*
...@@ -682,6 +687,7 @@ static int raw3215_probe (struct ccw_device *cdev) ...@@ -682,6 +687,7 @@ static int raw3215_probe (struct ccw_device *cdev)
return -ENOMEM; return -ENOMEM;
} }
init_waitqueue_head(&raw->empty_wait); init_waitqueue_head(&raw->empty_wait);
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
dev_set_drvdata(&cdev->dev, raw); dev_set_drvdata(&cdev->dev, raw);
cdev->handler = raw3215_irq; cdev->handler = raw3215_irq;
...@@ -901,6 +907,7 @@ static int __init con3215_init(void) ...@@ -901,6 +907,7 @@ static int __init con3215_init(void)
raw->flags |= RAW3215_FIXED; raw->flags |= RAW3215_FIXED;
init_waitqueue_head(&raw->empty_wait); init_waitqueue_head(&raw->empty_wait);
tasklet_init(&raw->tlet, raw3215_wakeup, (unsigned long) raw);
/* Request the console irq */ /* Request the console irq */
if (raw3215_startup(raw) != 0) { if (raw3215_startup(raw) != 0) {
...@@ -966,6 +973,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp) ...@@ -966,6 +973,7 @@ static void tty3215_close(struct tty_struct *tty, struct file * filp)
tty->closing = 1; tty->closing = 1;
/* Shutdown the terminal */ /* Shutdown the terminal */
raw3215_shutdown(raw); raw3215_shutdown(raw);
tasklet_kill(&raw->tlet);
tty->closing = 0; tty->closing = 0;
raw->tty = NULL; raw->tty = NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment