Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / include / asm-mips / interrupt.h
index e8357f5..4bb9c06 100644 (file)
 #ifndef _ASM_INTERRUPT_H
 #define _ASM_INTERRUPT_H
 
+#include <linux/config.h>
 #include <asm/hazards.h>
 
 __asm__ (
-       ".macro\tlocal_irq_enable\n\t"
-       ".set\tpush\n\t"
-       ".set\treorder\n\t"
-       ".set\tnoat\n\t"
-       "mfc0\t$1,$12\n\t"
-       "ori\t$1,0x1f\n\t"
-       "xori\t$1,0x1e\n\t"
-       "mtc0\t$1,$12\n\t"
-       "irq_enable_hazard\n\t"
-       ".set\tpop\n\t"
-       ".endm");
+       "       .macro  local_irq_enable                                \n"
+       "       .set    push                                            \n"
+       "       .set    reorder                                         \n"
+       "       .set    noat                                            \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+       "       mfc0    $1, $2, 1       # SMTC - clear TCStatus.IXMT    \n"
+       "       ori     $1, 0x400                                       \n"
+       "       xori    $1, 0x400                                       \n"
+       "       mtc0    $1, $2, 1                                       \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+       "       ei                                                      \n"
+#else
+       "       mfc0    $1,$12                                          \n"
+       "       ori     $1,0x1f                                         \n"
+       "       xori    $1,0x1e                                         \n"
+       "       mtc0    $1,$12                                          \n"
+#endif
+       "       irq_enable_hazard                                       \n"
+       "       .set    pop                                             \n"
+       "       .endm");
 
 static inline void local_irq_enable(void)
 {
@@ -42,18 +52,38 @@ static inline void local_irq_enable(void)
  * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
  * no nops at all.
  */
+/*
+ * For TX49, operating only IE bit is not enough.
+ *
+ * If mfc0 $12 follows store and the mfc0 is last instruction of a
+ * page and fetching the next instruction causes TLB miss, the result
+ * of the mfc0 might wrongly contain EXL bit.
+ *
+ * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008
+ *
+ * Workaround: mask EXL bit of the result or place a nop before mfc0.
+ */
 __asm__ (
-       ".macro\tlocal_irq_disable\n\t"
-       ".set\tpush\n\t"
-       ".set\tnoat\n\t"
-       "mfc0\t$1,$12\n\t"
-       "ori\t$1,1\n\t"
-       "xori\t$1,1\n\t"
-       ".set\tnoreorder\n\t"
-       "mtc0\t$1,$12\n\t"
-       "irq_disable_hazard\n\t"
-       ".set\tpop\n\t"
-       ".endm");
+       "       .macro  local_irq_disable\n"
+       "       .set    push                                            \n"
+       "       .set    noat                                            \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+       "       mfc0    $1, $2, 1                                       \n"
+       "       ori     $1, 0x400                                       \n"
+       "       .set    noreorder                                       \n"
+       "       mtc0    $1, $2, 1                                       \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+       "       di                                                      \n"
+#else
+       "       mfc0    $1,$12                                          \n"
+       "       ori     $1,0x1f                                         \n"
+       "       xori    $1,0x1f                                         \n"
+       "       .set    noreorder                                       \n"
+       "       mtc0    $1,$12                                          \n"
+#endif
+       "       irq_disable_hazard                                      \n"
+       "       .set    pop                                             \n"
+       "       .endm                                                   \n");
 
 static inline void local_irq_disable(void)
 {
@@ -65,12 +95,16 @@ static inline void local_irq_disable(void)
 }
 
 __asm__ (
-       ".macro\tlocal_save_flags flags\n\t"
-       ".set\tpush\n\t"
-       ".set\treorder\n\t"
-       "mfc0\t\\flags, $12\n\t"
-       ".set\tpop\n\t"
-       ".endm");
+       "       .macro  local_save_flags flags                          \n"
+       "       .set    push                                            \n"
+       "       .set    reorder                                         \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+       "       mfc0    \\flags, $2, 1                                  \n"
+#else
+       "       mfc0    \\flags, $12                                    \n"
+#endif
+       "       .set    pop                                             \n"
+       "       .endm                                                   \n");
 
 #define local_save_flags(x)                                            \
 __asm__ __volatile__(                                                  \
@@ -78,18 +112,29 @@ __asm__ __volatile__(                                                      \
        : "=r" (x))
 
 __asm__ (
-       ".macro\tlocal_irq_save result\n\t"
-       ".set\tpush\n\t"
-       ".set\treorder\n\t"
-       ".set\tnoat\n\t"
-       "mfc0\t\\result, $12\n\t"
-       "ori\t$1, \\result, 1\n\t"
-       "xori\t$1, 1\n\t"
-       ".set\tnoreorder\n\t"
-       "mtc0\t$1, $12\n\t"
-       "irq_disable_hazard\n\t"
-       ".set\tpop\n\t"
-       ".endm");
+       "       .macro  local_irq_save result                           \n"
+       "       .set    push                                            \n"
+       "       .set    reorder                                         \n"
+       "       .set    noat                                            \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+       "       mfc0    \\result, $2, 1                                 \n"
+       "       ori     $1, \\result, 0x400                             \n"
+       "       .set    noreorder                                       \n"
+       "       mtc0    $1, $2, 1                                       \n"
+       "       andi    \\result, \\result, 0x400                       \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+       "       di      \\result                                        \n"
+       "       andi    \\result, 1                                     \n"
+#else
+       "       mfc0    \\result, $12                                   \n"
+       "       ori     $1, \\result, 0x1f                              \n"
+       "       xori    $1, 0x1f                                        \n"
+       "       .set    noreorder                                       \n"
+       "       mtc0    $1, $12                                         \n"
+#endif
+       "       irq_disable_hazard                                      \n"
+       "       .set    pop                                             \n"
+       "       .endm                                                   \n");
 
 #define local_irq_save(x)                                              \
 __asm__ __volatile__(                                                  \
@@ -99,19 +144,44 @@ __asm__ __volatile__(                                                      \
        : "memory")
 
 __asm__ (
-       ".macro\tlocal_irq_restore flags\n\t"
-       ".set\tnoreorder\n\t"
-       ".set\tnoat\n\t"
-       "mfc0\t$1, $12\n\t"
-       "andi\t\\flags, 1\n\t"
-       "ori\t$1, 1\n\t"
-       "xori\t$1, 1\n\t"
-       "or\t\\flags, $1\n\t"
-       "mtc0\t\\flags, $12\n\t"
-       "irq_disable_hazard\n\t"
-       ".set\tat\n\t"
-       ".set\treorder\n\t"
-       ".endm");
+       "       .macro  local_irq_restore flags                         \n"
+       "       .set    push                                            \n"
+       "       .set    noreorder                                       \n"
+       "       .set    noat                                            \n"
+#ifdef CONFIG_MIPS_MT_SMTC
+       "mfc0   $1, $2, 1                                               \n"
+       "andi   \\flags, 0x400                                          \n"
+       "ori    $1, 0x400                                               \n"
+       "xori   $1, 0x400                                               \n"
+       "or     \\flags, $1                                             \n"
+       "mtc0   \\flags, $2, 1                                          \n"
+#elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU)
+       /*
+        * Slow, but doesn't suffer from a relativly unlikely race
+        * condition we're having since days 1.
+        */
+       "       beqz    \\flags, 1f                                     \n"
+       "        di                                                     \n"
+       "       ei                                                      \n"
+       "1:                                                             \n"
+#elif defined(CONFIG_CPU_MIPSR2)
+       /*
+        * Fast, dangerous.  Life is fun, life is good.
+        */
+       "       mfc0    $1, $12                                         \n"
+       "       ins     $1, \\flags, 0, 1                               \n"
+       "       mtc0    $1, $12                                         \n"
+#else
+       "       mfc0    $1, $12                                         \n"
+       "       andi    \\flags, 1                                      \n"
+       "       ori     $1, 0x1f                                        \n"
+       "       xori    $1, 0x1f                                        \n"
+       "       or      \\flags, $1                                     \n"
+       "       mtc0    \\flags, $12                                    \n"
+#endif
+       "       irq_disable_hazard                                      \n"
+       "       .set    pop                                             \n"
+       "       .endm                                                   \n");
 
 #define local_irq_restore(flags)                                       \
 do {                                                                   \
@@ -124,11 +194,29 @@ do {                                                                      \
                : "memory");                                            \
 } while(0)
 
-#define irqs_disabled()                                                        \
-({                                                                     \
-       unsigned long flags;                                            \
-       local_save_flags(flags);                                        \
-       !(flags & 1);                                                   \
-})
+static inline int irqs_disabled(void)
+{
+#ifdef CONFIG_MIPS_MT_SMTC
+       /*
+        * SMTC model uses TCStatus.IXMT to disable interrupts for a thread/CPU
+        */
+       unsigned long __result;
+
+       __asm__ __volatile__(
+       "       .set    noreorder                                       \n"
+       "       mfc0    %0, $2, 1                                       \n"
+       "       andi    %0, 0x400                                       \n"
+       "       slt     %0, $0, %0                                      \n"
+       "       .set    reorder                                         \n"
+       : "=r" (__result));
+
+       return __result;
+#else
+       unsigned long flags;
+       local_save_flags(flags);
+
+       return !(flags & 1);
+#endif
+}
 
 #endif /* _ASM_INTERRUPT_H */