From 1e0f2bb69f73b87e49aa15ba00d60a18736bc0b6 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 12 Jun 2018 11:38:05 +1000 Subject: 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 --- cf-code/cf-fsi-fw.S | 23 +++++++---------------- 1 file 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) -- cgit v1.2.1