MIPS: GIC: Fix GICBIS macro
authorJeffrey Deans <jeffrey.deans@imgtec.com>
Thu, 17 Jul 2014 08:20:59 +0000 (09:20 +0100)
committerRalf Baechle <ralf@linux-mips.org>
Fri, 1 Aug 2014 22:06:41 +0000 (00:06 +0200)
The GICBIS macro could update the GIC registers incorrectly, depending
on the data value passed in:

* Bits were only OR'd into the register data, so register fields could
  not be cleared.

* Bits were OR'd into the register data without masking the data to the
  correct field width, corrupting adjacent bits.

Signed-off-by: Jeffrey Deans <jeffrey.deans@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/7378/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
arch/mips/include/asm/gic.h

index 8b30befd99d6fb89612251868bee5489969b5b9f..3f20b2111d56c3ad8b653f0bbab81d3d14d46ba9 100644 (file)
 #ifdef GICISBYTELITTLEENDIAN
 #define GICREAD(reg, data)     ((data) = (reg), (data) = le32_to_cpu(data))
 #define GICWRITE(reg, data)    ((reg) = cpu_to_le32(data))
-#define GICBIS(reg, bits)                      \
-       ({unsigned int data;                    \
-               GICREAD(reg, data);             \
-               data |= bits;                   \
-               GICWRITE(reg, data);            \
-       })
-
 #else
 #define GICREAD(reg, data)     ((data) = (reg))
 #define GICWRITE(reg, data)    ((reg) = (data))
-#define GICBIS(reg, bits)      ((reg) |= (bits))
 #endif
+#define GICBIS(reg, mask, bits)                        \
+       do { u32 data;                          \
+               GICREAD((reg), data);           \
+               data &= ~(mask);                \
+               data |= ((bits) & (mask));      \
+               GICWRITE((reg), data);          \
+       } while (0)
 
 
 /* GIC Address Space */
 #define GIC_SH_SET_POLARITY_OFS                0x0100
 #define GIC_SET_POLARITY(intr, pol) \
        GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_POLARITY_OFS + \
-               GIC_INTR_OFS(intr)), (pol) << GIC_INTR_BIT(intr))
+               GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \
+               (pol) << GIC_INTR_BIT(intr))
 
 /* Triggering : Reset Value is always 0 */
 #define GIC_SH_SET_TRIGGER_OFS         0x0180
 #define GIC_SET_TRIGGER(intr, trig) \
        GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_TRIGGER_OFS + \
-               GIC_INTR_OFS(intr)), (trig) << GIC_INTR_BIT(intr))
+               GIC_INTR_OFS(intr)), (1 << GIC_INTR_BIT(intr)), \
+               (trig) << GIC_INTR_BIT(intr))
 
 /* Mask manipulation */
 #define GIC_SH_SMASK_OFS               0x0380