diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2018-06-12 11:38:05 +1000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2018-06-12 11:38:05 +1000 |
commit | 1e0f2bb69f73b87e49aa15ba00d60a18736bc0b6 (patch) | |
tree | a434c5021a148fe5c7c38889f2c2cc904ffc2a32 /cf-code | |
parent | 8028b238dd950e62ddd4c2336c7aac1e1a01400e (diff) | |
download | cf-fsi-1e0f2bb69f73b87e49aa15ba00d60a18736bc0b6.tar.gz cf-fsi-1e0f2bb69f73b87e49aa15ba00d60a18736bc0b6.zip |
Fix interrupt race
The current sequence is possible in the main command loop
and in the arbitration sequence:
- STOP enables interrupt and stops execution
- Interrupt occurs (stale from previous command)
- No command (or arbitration response)
- Command is written
- Interrupt occurs again, is taken, does nothing
- STOP executes, doesn't wake up
We need to ensure that we only take the interrupt on
STOP, so we need to re-mask after every STOP. (We could
alternatively modify the SR in the interrupt stack to
return from the handler with IRQs disabled but this is
easier).
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'cf-code')
-rw-r--r-- | cf-code/cf-fsi-fw.S | 23 |
1 files changed, 7 insertions, 16 deletions
diff --git a/cf-code/cf-fsi-fw.S b/cf-code/cf-fsi-fw.S index 44a02d2..14b80d2 100644 --- a/cf-code/cf-fsi-fw.S +++ b/cf-code/cf-fsi-fw.S @@ -259,7 +259,7 @@ _start: move.l %a0,(0x46*4) /* Mask interrupts */ - move.w #0x2000,%sr + move.w #0x2007,%sr /* Configure GPIOs to output */ bsr config_gpio_out @@ -271,25 +271,21 @@ _start: * Main command loop */ main_loop: + /* Reset trace pointer */ +#ifdef ENABLE_TRACE lea %a1@(TRACEBUF),%a3 - - /* Wait arbitration request or command - * - * Note: This can run with interrupts enabled as a result of - * the stop op, so %d0 can be clobbered at any time. - */ +#endif + /* Wait arbitration request or command */ 1: move.b %a1@(ARB_REG),%d2 bne arbitration_request move.l %a1@(CMD_STAT_REG),%d2 tst.b %d2 bne command_request stop #0x2000 + move.w #0x2007,%sr bra 1b arbitration_request: - /* Mask interrupts */ - move.w #0x2007,%sr - /* Ack request */ move.b #ARB_ARM_ACK,%a1@(ARB_REG) @@ -297,9 +293,6 @@ arbitration_request: 0: move.b %a1@(ARB_REG),%d1 bne 1f - /* Mask interrupts */ - move.w #0x2007,%sr - /* Got it, re-load the GPIO caches */ move.l %a5@(0),%DCLK move.l %a4@(0),%DDAT @@ -314,12 +307,10 @@ arbitration_request: /* Wait, we'll get an interrupt when the host clears it */ 1: stop #0x2000 + move.w #0x2007,%sr bra 0b command_request: - /* Mask interrupts */ - move.w #0x2007,%sr - /* Clear the command/status register */ moveq.l #0,%d0 move.l %d0,%a1@(CMD_STAT_REG) |