Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v3.1-rc3 288 lines 6.8 kB view raw
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 41extern void smtc_ipi_replay(void); 42 43static 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 100static 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 121static 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 153static 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 204static 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 225static 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 236static 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 */