1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003 by Ralf Baechle 7 * Copyright (C) 1996 by Paul M. Antoine 8 * Copyright (C) 1999 Silicon Graphics 9 * Copyright (C) 2000 MIPS Technologies, Inc. 10 */ 11 #ifndef _ASM_IRQFLAGS_H 12 #define _ASM_IRQFLAGS_H 13 14 #ifndef __ASSEMBLY__ 15 16 #include <linux/compiler.h> 17 #include <asm/hazards.h> 18 19 __asm__( 20 " .macro arch_local_irq_enable \n" 21 " .set push \n" 22 " .set reorder \n" 23 " .set noat \n" 24 #ifdef CONFIG_MIPS_MT_SMTC 25 " mfc0 $1, $2, 1 # SMTC - clear TCStatus.IXMT \n" 26 " ori $1, 0x400 \n" 27 " xori $1, 0x400 \n" 28 " mtc0 $1, $2, 1 \n" 29 #elif defined(CONFIG_CPU_MIPSR2) 30 " ei \n" 31 #else 32 " mfc0 $1,$12 \n" 33 " ori $1,0x1f \n" 34 " xori $1,0x1e \n" 35 " mtc0 $1,$12 \n" 36 #endif 37 " irq_enable_hazard \n" 38 " .set pop \n" 39 " .endm"); 40 41 extern void smtc_ipi_replay(void); 42 43 static inline void arch_local_irq_enable(void) 44 { 45 #ifdef CONFIG_MIPS_MT_SMTC 46 /* 47 * SMTC kernel needs to do a software replay of queued 48 * IPIs, at the cost of call overhead on each local_irq_enable() 49 */ 50 smtc_ipi_replay(); 51 #endif 52 __asm__ __volatile__( 53 "arch_local_irq_enable" 54 : /* no outputs */ 55 : /* no inputs */ 56 : "memory"); 57 } 58 59 60 /* 61 * For cli() we have to insert nops to make sure that the new value 62 * has actually arrived in the status register before the end of this 63 * macro. 64 * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs 65 * no nops at all. 66 */ 67 /* 68 * For TX49, operating only IE bit is not enough. 69 * 70 * If mfc0 $12 follows store and the mfc0 is last instruction of a 71 * page and fetching the next instruction causes TLB miss, the result 72 * of the mfc0 might wrongly contain EXL bit. 73 * 74 * ERT-TX49H2-027, ERT-TX49H3-012, ERT-TX49HL3-006, ERT-TX49H4-008 75 * 76 * Workaround: mask EXL bit of the result or place a nop before mfc0. 77 */ 78 __asm__( 79 " .macro arch_local_irq_disable\n" 80 " .set push \n" 81 " .set noat \n" 82 #ifdef CONFIG_MIPS_MT_SMTC 83 " mfc0 $1, $2, 1 \n" 84 " ori $1, 0x400 \n" 85 " .set noreorder \n" 86 " mtc0 $1, $2, 1 \n" 87 #elif defined(CONFIG_CPU_MIPSR2) 88 " di \n" 89 #else 90 " mfc0 $1,$12 \n" 91 " ori $1,0x1f \n" 92 " xori $1,0x1f \n" 93 " .set noreorder \n" 94 " mtc0 $1,$12 \n" 95 #endif 96 " irq_disable_hazard \n" 97 " .set pop \n" 98 " .endm \n"); 99 100 static inline void arch_local_irq_disable(void) 101 { 102 __asm__ __volatile__( 103 "arch_local_irq_disable" 104 : /* no outputs */ 105 : /* no inputs */ 106 : "memory"); 107 } 108 109 __asm__( 110 " .macro arch_local_save_flags flags \n" 111 " .set push \n" 112 " .set reorder \n" 113 #ifdef CONFIG_MIPS_MT_SMTC 114 " mfc0 \\flags, $2, 1 \n" 115 #else 116 " mfc0 \\flags, $12 \n" 117 #endif 118 " .set pop \n" 119 " .endm \n"); 120 121 static inline unsigned long arch_local_save_flags(void) 122 { 123 unsigned long flags; 124 asm volatile("arch_local_save_flags %0" : "=r" (flags)); 125 return flags; 126 } 127 128 __asm__( 129 " .macro arch_local_irq_save result \n" 130 " .set push \n" 131 " .set reorder \n" 132 " .set noat \n" 133 #ifdef CONFIG_MIPS_MT_SMTC 134 " mfc0 \\result, $2, 1 \n" 135 " ori $1, \\result, 0x400 \n" 136 " .set noreorder \n" 137 " mtc0 $1, $2, 1 \n" 138 " andi \\result, \\result, 0x400 \n" 139 #elif defined(CONFIG_CPU_MIPSR2) 140 " di \\result \n" 141 " andi \\result, 1 \n" 142 #else 143 " mfc0 \\result, $12 \n" 144 " ori $1, \\result, 0x1f \n" 145 " xori $1, 0x1f \n" 146 " .set noreorder \n" 147 " mtc0 $1, $12 \n" 148 #endif 149 " irq_disable_hazard \n" 150 " .set pop \n" 151 " .endm \n"); 152 153 static inline unsigned long arch_local_irq_save(void) 154 { 155 unsigned long flags; 156 asm volatile("arch_local_irq_save\t%0" 157 : "=r" (flags) 158 : /* no inputs */ 159 : "memory"); 160 return flags; 161 } 162 163 __asm__( 164 " .macro arch_local_irq_restore flags \n" 165 " .set push \n" 166 " .set noreorder \n" 167 " .set noat \n" 168 #ifdef CONFIG_MIPS_MT_SMTC 169 "mfc0 $1, $2, 1 \n" 170 "andi \\flags, 0x400 \n" 171 "ori $1, 0x400 \n" 172 "xori $1, 0x400 \n" 173 "or \\flags, $1 \n" 174 "mtc0 \\flags, $2, 1 \n" 175 #elif defined(CONFIG_CPU_MIPSR2) && defined(CONFIG_IRQ_CPU) 176 /* 177 * Slow, but doesn't suffer from a relatively unlikely race 178 * condition we're having since days 1. 179 */ 180 " beqz \\flags, 1f \n" 181 " di \n" 182 " ei \n" 183 "1: \n" 184 #elif defined(CONFIG_CPU_MIPSR2) 185 /* 186 * Fast, dangerous. Life is fun, life is good. 187 */ 188 " mfc0 $1, $12 \n" 189 " ins $1, \\flags, 0, 1 \n" 190 " mtc0 $1, $12 \n" 191 #else 192 " mfc0 $1, $12 \n" 193 " andi \\flags, 1 \n" 194 " ori $1, 0x1f \n" 195 " xori $1, 0x1f \n" 196 " or \\flags, $1 \n" 197 " mtc0 \\flags, $12 \n" 198 #endif 199 " irq_disable_hazard \n" 200 " .set pop \n" 201 " .endm \n"); 202 203 204 static inline void arch_local_irq_restore(unsigned long flags) 205 { 206 unsigned long __tmp1; 207 208 #ifdef CONFIG_MIPS_MT_SMTC 209 /* 210 * SMTC kernel needs to do a software replay of queued 211 * IPIs, at the cost of branch and call overhead on each 212 * local_irq_restore() 213 */ 214 if (unlikely(!(flags & 0x0400))) 215 smtc_ipi_replay(); 216 #endif 217 218 __asm__ __volatile__( 219 "arch_local_irq_restore\t%0" 220 : "=r" (__tmp1) 221 : "0" (flags) 222 : "memory"); 223 } 224 225 static inline void __arch_local_irq_restore(unsigned long flags) 226 { 227 unsigned long __tmp1; 228 229 __asm__ __volatile__( 230 "arch_local_irq_restore\t%0" 231 : "=r" (__tmp1) 232 : "0" (flags) 233 : "memory"); 234 } 235 236 static inline int arch_irqs_disabled_flags(unsigned long flags) 237 { 238 #ifdef CONFIG_MIPS_MT_SMTC 239 /* 240 * SMTC model uses TCStatus.IXMT to disable interrupts for a thread/CPU 241 */ 242 return flags & 0x400; 243 #else 244 return !(flags & 1); 245 #endif 246 } 247 248 #endif 249 250 /* 251 * Do the CPU's IRQ-state tracing from assembly code. 252 */ 253 #ifdef CONFIG_TRACE_IRQFLAGS 254 /* Reload some registers clobbered by trace_hardirqs_on */ 255 #ifdef CONFIG_64BIT 256 # define TRACE_IRQS_RELOAD_REGS \ 257 LONG_L $11, PT_R11(sp); \ 258 LONG_L $10, PT_R10(sp); \ 259 LONG_L $9, PT_R9(sp); \ 260 LONG_L $8, PT_R8(sp); \ 261 LONG_L $7, PT_R7(sp); \ 262 LONG_L $6, PT_R6(sp); \ 263 LONG_L $5, PT_R5(sp); \ 264 LONG_L $4, PT_R4(sp); \ 265 LONG_L $2, PT_R2(sp) 266 #else 267 # define TRACE_IRQS_RELOAD_REGS \ 268 LONG_L $7, PT_R7(sp); \ 269 LONG_L $6, PT_R6(sp); \ 270 LONG_L $5, PT_R5(sp); \ 271 LONG_L $4, PT_R4(sp); \ 272 LONG_L $2, PT_R2(sp) 273 #endif 274 # define TRACE_IRQS_ON \ 275 CLI; /* make sure trace_hardirqs_on() is called in kernel level */ \ 276 jal trace_hardirqs_on 277 # define TRACE_IRQS_ON_RELOAD \ 278 TRACE_IRQS_ON; \ 279 TRACE_IRQS_RELOAD_REGS 280 # define TRACE_IRQS_OFF \ 281 jal trace_hardirqs_off 282 #else 283 # define TRACE_IRQS_ON 284 # define TRACE_IRQS_ON_RELOAD 285 # define TRACE_IRQS_OFF 286 #endif 287 288 #endif /* _ASM_IRQFLAGS_H */ 289