diff options
author | Andrew Boie <andrew.p.boie@intel.com> | 2016-12-02 14:04:47 -0800 |
---|---|---|
committer | Anas Nashif <nashif@linux.intel.com> | 2016-12-03 00:05:35 +0000 |
commit | 18928e7f60e5458387d59d725e36c5421c4e68c0 (patch) | |
tree | 4b34be722b9b18cf29326707027867ba2c47d103 | |
parent | d39e0a92c45deb1e5b439826f2f12d53a69c3618 (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.h | 35 |
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 } |