diff options
author | Jan Glauber <jang@linux.vnet.ibm.com> | 2011-01-05 12:47:49 +0100 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2011-01-05 12:47:28 +0100 |
commit | 4f325184f2d4c1f2258873b2a333005dc4dfcbc0 (patch) | |
tree | e69a7940ca8d51a6e1f639cf4df0b5e33925d357 /drivers/s390/cio/qdio_main.c | |
parent | 078f8ecaa30718694d1e13d9f415b7ce75b3c968 (diff) | |
download | linux-4f325184f2d4c1f2258873b2a333005dc4dfcbc0.tar.bz2 |
[S390] qdio: prevent race for shared indicators
If the shared indicator is used the following race leads to
an inbound stall:
Device CPU0 CPU1
========================================================
non-shared DSCI =>1
ALSI => 1
Thin INT
ALSI => 0
non-shared DSCI
tasklets scheduled
shared DSCI => 1
ALSI => 1
shared DSCI => 0
ALSI ? -> set
Thin INT
ALSI => 0
ALSI was set,
shared DSCI => 1
After that no more interrupts occur because the DSCI is still set.
Fix that race by only resetting the shared DSCI if it was actually
set so the tasklets for all shared devices are scheduled and will
run after the interrupt.
Signed-off-by: Jan Glauber <jang@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/qdio_main.c')
-rw-r--r-- | drivers/s390/cio/qdio_main.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 194ea8c182b2..6621de94f3ad 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1552,7 +1552,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) WARN_ON(queue_irqs_enabled(q)); - if (!shared_ind(q->irq_ptr)) + if (!shared_ind(q->irq_ptr->dsci)) xchg(q->irq_ptr->dsci, 0); qdio_stop_polling(q); @@ -1562,7 +1562,7 @@ int qdio_start_irq(struct ccw_device *cdev, int nr) * We need to check again to not lose initiative after * resetting the ACK state. */ - if (!shared_ind(q->irq_ptr) && *q->irq_ptr->dsci) + if (!shared_ind(q->irq_ptr->dsci) && *q->irq_ptr->dsci) goto rescan; if (!qdio_inbound_q_done(q)) goto rescan; |