| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 | * | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 6 | * Copyright (C) 1994, 95, 96, 97, 98, 99, 2003, 06 by Ralf Baechle | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | * Copyright (C) 1996 by Paul M. Antoine | 
|  | 8 | * Copyright (C) 1999 Silicon Graphics | 
|  | 9 | * Kevin D. Kissell, kevink@mips.org and Carsten Langgaard, carstenl@mips.com | 
|  | 10 | * Copyright (C) 2000 MIPS Technologies, Inc. | 
|  | 11 | */ | 
|  | 12 | #ifndef _ASM_SYSTEM_H | 
|  | 13 | #define _ASM_SYSTEM_H | 
|  | 14 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <linux/types.h> | 
| Ralf Baechle | 192ef36 | 2006-07-07 14:07:18 +0100 | [diff] [blame] | 16 | #include <linux/irqflags.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 17 |  | 
|  | 18 | #include <asm/addrspace.h> | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 19 | #include <asm/barrier.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 | #include <asm/cpu-features.h> | 
| Ralf Baechle | e50c0a8 | 2005-05-31 11:49:19 +0000 | [diff] [blame] | 21 | #include <asm/dsp.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | #include <asm/war.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 23 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 | /* | 
|  | 26 | * switch_to(n) should switch tasks to task nr n, first | 
|  | 27 | * checking that n isn't the current task, in which case it does nothing. | 
|  | 28 | */ | 
|  | 29 | extern asmlinkage void *resume(void *last, void *next, void *next_ti); | 
|  | 30 |  | 
|  | 31 | struct task_struct; | 
|  | 32 |  | 
| Ralf Baechle | f088fc8 | 2006-04-05 09:45:47 +0100 | [diff] [blame] | 33 | #ifdef CONFIG_MIPS_MT_FPAFF | 
|  | 34 |  | 
|  | 35 | /* | 
|  | 36 | * Handle the scheduler resume end of FPU affinity management.  We do this | 
|  | 37 | * inline to try to keep the overhead down. If we have been forced to run on | 
|  | 38 | * a "CPU" with an FPU because of a previous high level of FP computation, | 
|  | 39 | * but did not actually use the FPU during the most recent time-slice (CU1 | 
|  | 40 | * isn't set), we undo the restriction on cpus_allowed. | 
|  | 41 | * | 
|  | 42 | * We're not calling set_cpus_allowed() here, because we have no need to | 
|  | 43 | * force prompt migration - we're already switching the current CPU to a | 
|  | 44 | * different thread. | 
|  | 45 | */ | 
|  | 46 |  | 
|  | 47 | #define switch_to(prev,next,last)					\ | 
|  | 48 | do {									\ | 
|  | 49 | if (cpu_has_fpu &&						\ | 
|  | 50 | (prev->thread.mflags & MF_FPUBOUND) &&			\ | 
|  | 51 | (!(KSTK_STATUS(prev) & ST0_CU1))) {			\ | 
|  | 52 | prev->thread.mflags &= ~MF_FPUBOUND;			\ | 
|  | 53 | prev->cpus_allowed = prev->thread.user_cpus_allowed;	\ | 
|  | 54 | }								\ | 
|  | 55 | if (cpu_has_dsp)						\ | 
|  | 56 | __save_dsp(prev);					\ | 
|  | 57 | next->thread.emulated_fp = 0;					\ | 
|  | 58 | (last) = resume(prev, next, next->thread_info);			\ | 
|  | 59 | if (cpu_has_dsp)						\ | 
|  | 60 | __restore_dsp(current);					\ | 
|  | 61 | } while(0) | 
|  | 62 |  | 
|  | 63 | #else | 
| Ralf Baechle | e50c0a8 | 2005-05-31 11:49:19 +0000 | [diff] [blame] | 64 | #define switch_to(prev,next,last)					\ | 
|  | 65 | do {									\ | 
|  | 66 | if (cpu_has_dsp)						\ | 
|  | 67 | __save_dsp(prev);					\ | 
| Al Viro | 40bc9c6 | 2006-01-12 01:06:07 -0800 | [diff] [blame] | 68 | (last) = resume(prev, next, task_thread_info(next));		\ | 
| Ralf Baechle | e50c0a8 | 2005-05-31 11:49:19 +0000 | [diff] [blame] | 69 | if (cpu_has_dsp)						\ | 
|  | 70 | __restore_dsp(current);					\ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 | } while(0) | 
| Ralf Baechle | f088fc8 | 2006-04-05 09:45:47 +0100 | [diff] [blame] | 72 | #endif | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 |  | 
| Ingo Molnar | 4dc7a0b | 2006-01-12 01:05:27 -0800 | [diff] [blame] | 74 | /* | 
|  | 75 | * On SMP systems, when the scheduler does migration-cost autodetection, | 
|  | 76 | * it needs a way to flush as much of the CPU's caches as possible. | 
|  | 77 | * | 
|  | 78 | * TODO: fill this in! | 
|  | 79 | */ | 
|  | 80 | static inline void sched_cacheflush(void) | 
|  | 81 | { | 
|  | 82 | } | 
|  | 83 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) | 
|  | 85 | { | 
|  | 86 | __u32 retval; | 
|  | 87 |  | 
|  | 88 | if (cpu_has_llsc && R10000_LLSC_WAR) { | 
|  | 89 | unsigned long dummy; | 
|  | 90 |  | 
|  | 91 | __asm__ __volatile__( | 
| Maciej W. Rozycki | c4559f6 | 2005-06-23 15:57:15 +0000 | [diff] [blame] | 92 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 | "1:	ll	%0, %3			# xchg_u32	\n" | 
| Ralf Baechle | 7222424 | 2005-06-29 13:35:19 +0000 | [diff] [blame] | 94 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | "	move	%2, %z4					\n" | 
| Ralf Baechle | 7222424 | 2005-06-29 13:35:19 +0000 | [diff] [blame] | 96 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | "	sc	%2, %1					\n" | 
|  | 98 | "	beqzl	%2, 1b					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 99 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | 
|  | 101 | : "R" (*m), "Jr" (val) | 
|  | 102 | : "memory"); | 
|  | 103 | } else if (cpu_has_llsc) { | 
|  | 104 | unsigned long dummy; | 
|  | 105 |  | 
|  | 106 | __asm__ __volatile__( | 
| Maciej W. Rozycki | c4559f6 | 2005-06-23 15:57:15 +0000 | [diff] [blame] | 107 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | "1:	ll	%0, %3			# xchg_u32	\n" | 
| Ralf Baechle | 7222424 | 2005-06-29 13:35:19 +0000 | [diff] [blame] | 109 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | "	move	%2, %z4					\n" | 
| Ralf Baechle | 7222424 | 2005-06-29 13:35:19 +0000 | [diff] [blame] | 111 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 112 | "	sc	%2, %1					\n" | 
| Ralf Baechle | f65e4fa | 2006-09-28 01:45:21 +0100 | [diff] [blame] | 113 | "	beqz	%2, 2f					\n" | 
|  | 114 | "	.subsection 2					\n" | 
|  | 115 | "2:	b	1b					\n" | 
|  | 116 | "	.previous					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 117 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 118 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | 
|  | 119 | : "R" (*m), "Jr" (val) | 
|  | 120 | : "memory"); | 
|  | 121 | } else { | 
|  | 122 | unsigned long flags; | 
|  | 123 |  | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 124 | raw_local_irq_save(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | retval = *m; | 
|  | 126 | *m = val; | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 127 | raw_local_irq_restore(flags);	/* implies memory barrier  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 128 | } | 
|  | 129 |  | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 130 | smp_mb(); | 
|  | 131 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | return retval; | 
|  | 133 | } | 
|  | 134 |  | 
| Ralf Baechle | 875d43e | 2005-09-03 15:56:16 -0700 | [diff] [blame] | 135 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 136 | static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) | 
|  | 137 | { | 
|  | 138 | __u64 retval; | 
|  | 139 |  | 
|  | 140 | if (cpu_has_llsc && R10000_LLSC_WAR) { | 
|  | 141 | unsigned long dummy; | 
|  | 142 |  | 
|  | 143 | __asm__ __volatile__( | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 144 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 145 | "1:	lld	%0, %3			# xchg_u64	\n" | 
|  | 146 | "	move	%2, %z4					\n" | 
|  | 147 | "	scd	%2, %1					\n" | 
|  | 148 | "	beqzl	%2, 1b					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 149 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | 
|  | 151 | : "R" (*m), "Jr" (val) | 
|  | 152 | : "memory"); | 
|  | 153 | } else if (cpu_has_llsc) { | 
|  | 154 | unsigned long dummy; | 
|  | 155 |  | 
|  | 156 | __asm__ __volatile__( | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 157 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 158 | "1:	lld	%0, %3			# xchg_u64	\n" | 
|  | 159 | "	move	%2, %z4					\n" | 
|  | 160 | "	scd	%2, %1					\n" | 
| Ralf Baechle | f65e4fa | 2006-09-28 01:45:21 +0100 | [diff] [blame] | 161 | "	beqz	%2, 2f					\n" | 
|  | 162 | "	.subsection 2					\n" | 
|  | 163 | "2:	b	1b					\n" | 
|  | 164 | "	.previous					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 165 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 166 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | 
|  | 167 | : "R" (*m), "Jr" (val) | 
|  | 168 | : "memory"); | 
|  | 169 | } else { | 
|  | 170 | unsigned long flags; | 
|  | 171 |  | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 172 | raw_local_irq_save(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 173 | retval = *m; | 
|  | 174 | *m = val; | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 175 | raw_local_irq_restore(flags);	/* implies memory barrier  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 176 | } | 
|  | 177 |  | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 178 | smp_mb(); | 
|  | 179 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 | return retval; | 
|  | 181 | } | 
|  | 182 | #else | 
|  | 183 | extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val); | 
|  | 184 | #define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels | 
|  | 185 | #endif | 
|  | 186 |  | 
|  | 187 | /* This function doesn't exist, so you'll get a linker error | 
|  | 188 | if something tries to do an invalid xchg().  */ | 
|  | 189 | extern void __xchg_called_with_bad_pointer(void); | 
|  | 190 |  | 
|  | 191 | static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) | 
|  | 192 | { | 
|  | 193 | switch (size) { | 
| Ralf Baechle | 0cea043 | 2006-03-03 09:42:05 +0000 | [diff] [blame] | 194 | case 4: | 
|  | 195 | return __xchg_u32(ptr, x); | 
|  | 196 | case 8: | 
|  | 197 | return __xchg_u64(ptr, x); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 198 | } | 
|  | 199 | __xchg_called_with_bad_pointer(); | 
|  | 200 | return x; | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | 
|  | 204 | #define tas(ptr) (xchg((ptr),1)) | 
|  | 205 |  | 
|  | 206 | #define __HAVE_ARCH_CMPXCHG 1 | 
|  | 207 |  | 
|  | 208 | static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old, | 
|  | 209 | unsigned long new) | 
|  | 210 | { | 
|  | 211 | __u32 retval; | 
|  | 212 |  | 
|  | 213 | if (cpu_has_llsc && R10000_LLSC_WAR) { | 
|  | 214 | __asm__ __volatile__( | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 215 | "	.set	push					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 216 | "	.set	noat					\n" | 
| Maciej W. Rozycki | c4559f6 | 2005-06-23 15:57:15 +0000 | [diff] [blame] | 217 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 218 | "1:	ll	%0, %2			# __cmpxchg_u32	\n" | 
|  | 219 | "	bne	%0, %z3, 2f				\n" | 
| Ralf Baechle | f99d302 | 2005-08-25 16:22:09 +0000 | [diff] [blame] | 220 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | "	move	$1, %z4					\n" | 
| Ralf Baechle | f99d302 | 2005-08-25 16:22:09 +0000 | [diff] [blame] | 222 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 223 | "	sc	$1, %1					\n" | 
|  | 224 | "	beqzl	$1, 1b					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 225 | "2:							\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 226 | "	.set	pop					\n" | 
| Ralf Baechle | 3e6cb2d | 2006-02-21 18:32:14 +0000 | [diff] [blame] | 227 | : "=&r" (retval), "=R" (*m) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 228 | : "R" (*m), "Jr" (old), "Jr" (new) | 
|  | 229 | : "memory"); | 
|  | 230 | } else if (cpu_has_llsc) { | 
|  | 231 | __asm__ __volatile__( | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 232 | "	.set	push					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 233 | "	.set	noat					\n" | 
| Maciej W. Rozycki | c4559f6 | 2005-06-23 15:57:15 +0000 | [diff] [blame] | 234 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | "1:	ll	%0, %2			# __cmpxchg_u32	\n" | 
|  | 236 | "	bne	%0, %z3, 2f				\n" | 
| Ralf Baechle | f99d302 | 2005-08-25 16:22:09 +0000 | [diff] [blame] | 237 | "	.set	mips0					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 238 | "	move	$1, %z4					\n" | 
| Ralf Baechle | f99d302 | 2005-08-25 16:22:09 +0000 | [diff] [blame] | 239 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 240 | "	sc	$1, %1					\n" | 
| Ralf Baechle | f65e4fa | 2006-09-28 01:45:21 +0100 | [diff] [blame] | 241 | "	beqz	$1, 3f					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 242 | "2:							\n" | 
| Ralf Baechle | f65e4fa | 2006-09-28 01:45:21 +0100 | [diff] [blame] | 243 | "	.subsection 2					\n" | 
|  | 244 | "3:	b	1b					\n" | 
|  | 245 | "	.previous					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 246 | "	.set	pop					\n" | 
| Ralf Baechle | 3e6cb2d | 2006-02-21 18:32:14 +0000 | [diff] [blame] | 247 | : "=&r" (retval), "=R" (*m) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 248 | : "R" (*m), "Jr" (old), "Jr" (new) | 
|  | 249 | : "memory"); | 
|  | 250 | } else { | 
|  | 251 | unsigned long flags; | 
|  | 252 |  | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 253 | raw_local_irq_save(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 254 | retval = *m; | 
|  | 255 | if (retval == old) | 
|  | 256 | *m = new; | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 257 | raw_local_irq_restore(flags);	/* implies memory barrier  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 258 | } | 
|  | 259 |  | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 260 | smp_mb(); | 
|  | 261 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 262 | return retval; | 
|  | 263 | } | 
|  | 264 |  | 
| Ralf Baechle | 875d43e | 2005-09-03 15:56:16 -0700 | [diff] [blame] | 265 | #ifdef CONFIG_64BIT | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 | static inline unsigned long __cmpxchg_u64(volatile int * m, unsigned long old, | 
|  | 267 | unsigned long new) | 
|  | 268 | { | 
|  | 269 | __u64 retval; | 
|  | 270 |  | 
| Ralf Baechle | 904880e | 2006-10-13 11:32:50 +0100 | [diff] [blame] | 271 | if (cpu_has_llsc && R10000_LLSC_WAR) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 272 | __asm__ __volatile__( | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 273 | "	.set	push					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 274 | "	.set	noat					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 275 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 276 | "1:	lld	%0, %2			# __cmpxchg_u64	\n" | 
|  | 277 | "	bne	%0, %z3, 2f				\n" | 
|  | 278 | "	move	$1, %z4					\n" | 
|  | 279 | "	scd	$1, %1					\n" | 
|  | 280 | "	beqzl	$1, 1b					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 281 | "2:							\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 282 | "	.set	pop					\n" | 
| Ralf Baechle | 3e6cb2d | 2006-02-21 18:32:14 +0000 | [diff] [blame] | 283 | : "=&r" (retval), "=R" (*m) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 284 | : "R" (*m), "Jr" (old), "Jr" (new) | 
|  | 285 | : "memory"); | 
|  | 286 | } else if (cpu_has_llsc) { | 
|  | 287 | __asm__ __volatile__( | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 288 | "	.set	push					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 289 | "	.set	noat					\n" | 
| Maciej W. Rozycki | c4559f6 | 2005-06-23 15:57:15 +0000 | [diff] [blame] | 290 | "	.set	mips3					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 291 | "1:	lld	%0, %2			# __cmpxchg_u64	\n" | 
|  | 292 | "	bne	%0, %z3, 2f				\n" | 
|  | 293 | "	move	$1, %z4					\n" | 
|  | 294 | "	scd	$1, %1					\n" | 
| Ralf Baechle | f65e4fa | 2006-09-28 01:45:21 +0100 | [diff] [blame] | 295 | "	beqz	$1, 3f					\n" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | "2:							\n" | 
| Ralf Baechle | f65e4fa | 2006-09-28 01:45:21 +0100 | [diff] [blame] | 297 | "	.subsection 2					\n" | 
|  | 298 | "3:	b	1b					\n" | 
|  | 299 | "	.previous					\n" | 
| Maciej W. Rozycki | aac8aa7 | 2005-06-14 17:35:03 +0000 | [diff] [blame] | 300 | "	.set	pop					\n" | 
| Ralf Baechle | 3e6cb2d | 2006-02-21 18:32:14 +0000 | [diff] [blame] | 301 | : "=&r" (retval), "=R" (*m) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 | : "R" (*m), "Jr" (old), "Jr" (new) | 
|  | 303 | : "memory"); | 
|  | 304 | } else { | 
|  | 305 | unsigned long flags; | 
|  | 306 |  | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 307 | raw_local_irq_save(flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 308 | retval = *m; | 
|  | 309 | if (retval == old) | 
|  | 310 | *m = new; | 
| Ralf Baechle | 49edd09 | 2007-03-16 16:10:36 +0000 | [diff] [blame] | 311 | raw_local_irq_restore(flags);	/* implies memory barrier  */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 312 | } | 
|  | 313 |  | 
| Ralf Baechle | 0004a9d | 2006-10-31 03:45:07 +0000 | [diff] [blame] | 314 | smp_mb(); | 
|  | 315 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 | return retval; | 
|  | 317 | } | 
|  | 318 | #else | 
|  | 319 | extern unsigned long __cmpxchg_u64_unsupported_on_32bit_kernels( | 
|  | 320 | volatile int * m, unsigned long old, unsigned long new); | 
|  | 321 | #define __cmpxchg_u64 __cmpxchg_u64_unsupported_on_32bit_kernels | 
|  | 322 | #endif | 
|  | 323 |  | 
|  | 324 | /* This function doesn't exist, so you'll get a linker error | 
|  | 325 | if something tries to do an invalid cmpxchg().  */ | 
|  | 326 | extern void __cmpxchg_called_with_bad_pointer(void); | 
|  | 327 |  | 
|  | 328 | static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, | 
|  | 329 | unsigned long new, int size) | 
|  | 330 | { | 
|  | 331 | switch (size) { | 
|  | 332 | case 4: | 
|  | 333 | return __cmpxchg_u32(ptr, old, new); | 
|  | 334 | case 8: | 
|  | 335 | return __cmpxchg_u64(ptr, old, new); | 
|  | 336 | } | 
|  | 337 | __cmpxchg_called_with_bad_pointer(); | 
|  | 338 | return old; | 
|  | 339 | } | 
|  | 340 |  | 
|  | 341 | #define cmpxchg(ptr,old,new) ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(old), (unsigned long)(new),sizeof(*(ptr)))) | 
|  | 342 |  | 
| Ralf Baechle | e01402b | 2005-07-14 15:57:16 +0000 | [diff] [blame] | 343 | extern void set_handler (unsigned long offset, void *addr, unsigned long len); | 
|  | 344 | extern void set_uncached_handler (unsigned long offset, void *addr, unsigned long len); | 
|  | 345 | extern void *set_vi_handler (int n, void *addr); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 346 | extern void *set_except_vector(int n, void *addr); | 
| Ralf Baechle | 91b05e6 | 2006-03-29 18:53:00 +0100 | [diff] [blame] | 347 | extern unsigned long ebase; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 348 | extern void per_cpu_trap_init(void); | 
|  | 349 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 350 | extern int stop_a_enabled; | 
|  | 351 |  | 
|  | 352 | /* | 
| Nick Piggin | 4866cde | 2005-06-25 14:57:23 -0700 | [diff] [blame] | 353 | * See include/asm-ia64/system.h; prevents deadlock on SMP | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 354 | * systems. | 
|  | 355 | */ | 
| Nick Piggin | 4866cde | 2005-06-25 14:57:23 -0700 | [diff] [blame] | 356 | #define __ARCH_WANT_UNLOCKED_CTXSW | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 357 |  | 
|  | 358 | #define arch_align_stack(x) (x) | 
|  | 359 |  | 
|  | 360 | #endif /* _ASM_SYSTEM_H */ |