summaryrefslogtreecommitdiffstats
path: root/drivers/macintosh
diff options
context:
space:
mode:
authorFinn Thain <fthain@telegraphics.com.au>2017-01-01 01:56:26 +0100
committerMichael Ellerman <mpe@ellerman.id.au>2017-02-07 06:56:21 +0100
commita64662432200f8af6f67cd3664885a323f6a2f2d (patch)
treeaac25458e8f5b21ec642515b52d8aed8d240cf0b /drivers/macintosh
parentvia-cuda: Fix re-initialization of reply_ptr and reading_reply (diff)
downloadlinux-a64662432200f8af6f67cd3664885a323f6a2f2d.tar.xz
linux-a64662432200f8af6f67cd3664885a323f6a2f2d.zip
via-cuda: Avoid TREQ race condition
When a read transaction completes, one of several things will happen: a new transfer is started by the driver, a new transfer request is raised by the Cuda (i.e. TREQ asserted), or both happen at once. When both happen at once, there is a race condition between the TREQ test in the read_done state and the same test in cuda_start(). Moreover, the former test uses a stale TREQ value. Theoretically, this can result in the undesirable outcome that the interrupt handler completes with the state machine 'idle' when it should instead start the next transaction. Avoid this race by calling cuda_start() first and then confirming that it succeeded. If not, test the current TREQ value before entering the 'reading' state. Tested-by: Stan Johnson <userm57@yahoo.com> Signed-off-by: Finn Thain <fthain@telegraphics.com.au> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Diffstat (limited to 'drivers/macintosh')
-rw-r--r--drivers/macintosh/via-cuda.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index ae3da6b95229..32126958ac66 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -605,12 +605,11 @@ cuda_interrupt(int irq, void *arg)
memcpy(ibuf, cuda_rbuf, ibuf_len);
}
reply_ptr = cuda_rbuf;
- if (TREQ_asserted(status)) {
+ cuda_state = idle;
+ cuda_start();
+ if (cuda_state == idle && TREQ_asserted(in_8(&via[B]))) {
assert_TIP();
cuda_state = reading;
- } else {
- cuda_state = idle;
- cuda_start();
}
break;