summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Boie <andrew.p.boie@intel.com>2016-12-02 14:04:47 -0800
committerAnas Nashif <nashif@linux.intel.com>2016-12-03 00:05:35 +0000
commit18928e7f60e5458387d59d725e36c5421c4e68c0 (patch)
tree4b34be722b9b18cf29326707027867ba2c47d103
parentd39e0a92c45deb1e5b439826f2f12d53a69c3618 (diff)
nios2: fix irq_lock/unlock ordering bug
Memory accesses could be reordered before an irq_lock() or after an irq_unlock() without the memory barriers. See commit 15bc537712abaeb5dfbb27ced924fe6ccc1f611c for the ARM fix for a complete description of the issue and fix. Change-Id: I1d96fe0088d90150f0888c2893d017155fc0a0a7 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com> (cherry picked from commit bba445b31ff2ed815a1953d3d74d0daca1d7e993)
-rw-r--r--include/arch/nios2/arch.h35
1 files changed, 21 insertions, 14 deletions
diff --git a/include/arch/nios2/arch.h b/include/arch/nios2/arch.h
index 7a98c1524..cc33f2a95 100644
--- a/include/arch/nios2/arch.h
+++ b/include/arch/nios2/arch.h
@@ -94,10 +94,15 @@ typedef unsigned int vaddr_t;
static ALWAYS_INLINE unsigned int _arch_irq_lock(void)
{
- unsigned int key;
+ unsigned int key, tmp;
- key = _nios2_creg_read(NIOS2_CR_STATUS);
- _nios2_creg_write(NIOS2_CR_STATUS, key & ~NIOS2_STATUS_PIE_MSK);
+ __asm__ volatile (
+ "rdctl %[key], status\n\t"
+ "movi %[tmp], -2\n\t"
+ "and %[tmp], %[key], %[tmp]\n\t"
+ "wrctl status, %[tmp]\n\t"
+ : [key] "=r" (key), [tmp] "=r" (tmp)
+ : : "memory");
return key;
}
@@ -117,18 +122,20 @@ static ALWAYS_INLINE void _arch_irq_unlock(unsigned int key)
(defined ALT_CPU_EIC_PRESENT) || \
(defined ALT_CPU_MMU_PRESENT) || \
(defined ALT_CPU_MPU_PRESENT)
- uint32_t status_reg;
-
- /* Interrupts were already locked when irq_lock() was called,
- * so don't do anything
- */
- if (!(key & NIOS2_STATUS_PIE_MSK))
- return;
-
- status_reg = _nios2_creg_read(NIOS2_CR_STATUS);
- _nios2_creg_write(NIOS2_CR_STATUS, status_reg | NIOS2_STATUS_PIE_MSK);
+ __asm__ volatile (
+ "andi %[key], %[key], 1\n\t"
+ "beq %[key], zero, 1f\n\t"
+ "rdctl %[key], status\n\t"
+ "ori %[key], %[key], 1\n\t"
+ "wrctl status, %[key]\n\t"
+ "1:\n\t"
+ : [key] "+r" (key)
+ : : "memory");
#else
- _nios2_creg_write(NIOS2_CR_STATUS, key);
+ __asm__ volatile (
+ "wrctl status, %[key]"
+ : : [key] "r" (key)
+ : "memory");
#endif
}