Home | History | Annotate | Download | only in asm-mips
      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, 06 by Ralf Baechle
      7  * Copyright (C) 1996 by Paul M. Antoine
      8  * Copyright (C) 1999 Silicon Graphics
      9  * Kevin D. Kissell, kevink (at) mips.org and Carsten Langgaard, carstenl (at) mips.com
     10  * Copyright (C) 2000 MIPS Technologies, Inc.
     11  */
     12 #ifndef _ASM_SYSTEM_H
     13 #define _ASM_SYSTEM_H
     14 
     15 #include <linux/types.h>
     16 #include <linux/irqflags.h>
     17 
     18 #include <asm/addrspace.h>
     19 #include <asm/barrier.h>
     20 #include <asm/cmpxchg.h>
     21 #include <asm/cpu-features.h>
     22 #include <asm/dsp.h>
     23 #include <asm/war.h>
     24 
     25 
     26 /*
     27  * switch_to(n) should switch tasks to task nr n, first
     28  * checking that n isn't the current task, in which case it does nothing.
     29  */
     30 extern asmlinkage void *resume(void *last, void *next, void *next_ti);
     31 
     32 struct task_struct;
     33 
     34 #ifdef CONFIG_MIPS_MT_FPAFF
     35 
     36 /*
     37  * Handle the scheduler resume end of FPU affinity management.  We do this
     38  * inline to try to keep the overhead down. If we have been forced to run on
     39  * a "CPU" with an FPU because of a previous high level of FP computation,
     40  * but did not actually use the FPU during the most recent time-slice (CU1
     41  * isn't set), we undo the restriction on cpus_allowed.
     42  *
     43  * We're not calling set_cpus_allowed() here, because we have no need to
     44  * force prompt migration - we're already switching the current CPU to a
     45  * different thread.
     46  */
     47 
     48 #define __mips_mt_fpaff_switch_to(prev)					\
     49 do {									\
     50 	struct thread_info *__prev_ti = task_thread_info(prev);		\
     51 									\
     52 	if (cpu_has_fpu &&						\
     53 	    test_ti_thread_flag(__prev_ti, TIF_FPUBOUND) &&		\
     54 	    (!(KSTK_STATUS(prev) & ST0_CU1))) {				\
     55 		clear_ti_thread_flag(__prev_ti, TIF_FPUBOUND);		\
     56 		prev->cpus_allowed = prev->thread.user_cpus_allowed;	\
     57 	}								\
     58 	next->thread.emulated_fp = 0;					\
     59 } while(0)
     60 
     61 #else
     62 #define __mips_mt_fpaff_switch_to(prev) do { (void) (prev); } while (0)
     63 #endif
     64 
     65 #define switch_to(prev, next, last)					\
     66 do {									\
     67 	__mips_mt_fpaff_switch_to(prev);				\
     68 	if (cpu_has_dsp)						\
     69 		__save_dsp(prev);					\
     70 	(last) = resume(prev, next, task_thread_info(next));		\
     71 } while (0)
     72 
     73 #define finish_arch_switch(prev)					\
     74 do {									\
     75 	if (cpu_has_dsp)						\
     76 		__restore_dsp(current);					\
     77 	if (cpu_has_userlocal)						\
     78 		write_c0_userlocal(current_thread_info()->tp_value);	\
     79 } while (0)
     80 
     81 static inline unsigned long __xchg_u32(volatile int * m, unsigned int val)
     82 {
     83 	__u32 retval;
     84 
     85 	if (cpu_has_llsc && R10000_LLSC_WAR) {
     86 		unsigned long dummy;
     87 
     88 		__asm__ __volatile__(
     89 		"	.set	mips3					\n"
     90 		"1:	ll	%0, %3			# xchg_u32	\n"
     91 		"	.set	mips0					\n"
     92 		"	move	%2, %z4					\n"
     93 		"	.set	mips3					\n"
     94 		"	sc	%2, %1					\n"
     95 		"	beqzl	%2, 1b					\n"
     96 		"	.set	mips0					\n"
     97 		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
     98 		: "R" (*m), "Jr" (val)
     99 		: "memory");
    100 	} else if (cpu_has_llsc) {
    101 		unsigned long dummy;
    102 
    103 		__asm__ __volatile__(
    104 		"	.set	mips3					\n"
    105 		"1:	ll	%0, %3			# xchg_u32	\n"
    106 		"	.set	mips0					\n"
    107 		"	move	%2, %z4					\n"
    108 		"	.set	mips3					\n"
    109 		"	sc	%2, %1					\n"
    110 		"	beqz	%2, 2f					\n"
    111 		"	.subsection 2					\n"
    112 		"2:	b	1b					\n"
    113 		"	.previous					\n"
    114 		"	.set	mips0					\n"
    115 		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
    116 		: "R" (*m), "Jr" (val)
    117 		: "memory");
    118 	} else {
    119 		unsigned long flags;
    120 
    121 		raw_local_irq_save(flags);
    122 		retval = *m;
    123 		*m = val;
    124 		raw_local_irq_restore(flags);	/* implies memory barrier  */
    125 	}
    126 
    127 	smp_llsc_mb();
    128 
    129 	return retval;
    130 }
    131 
    132 #ifdef CONFIG_64BIT
    133 static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val)
    134 {
    135 	__u64 retval;
    136 
    137 	if (cpu_has_llsc && R10000_LLSC_WAR) {
    138 		unsigned long dummy;
    139 
    140 		__asm__ __volatile__(
    141 		"	.set	mips3					\n"
    142 		"1:	lld	%0, %3			# xchg_u64	\n"
    143 		"	move	%2, %z4					\n"
    144 		"	scd	%2, %1					\n"
    145 		"	beqzl	%2, 1b					\n"
    146 		"	.set	mips0					\n"
    147 		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
    148 		: "R" (*m), "Jr" (val)
    149 		: "memory");
    150 	} else if (cpu_has_llsc) {
    151 		unsigned long dummy;
    152 
    153 		__asm__ __volatile__(
    154 		"	.set	mips3					\n"
    155 		"1:	lld	%0, %3			# xchg_u64	\n"
    156 		"	move	%2, %z4					\n"
    157 		"	scd	%2, %1					\n"
    158 		"	beqz	%2, 2f					\n"
    159 		"	.subsection 2					\n"
    160 		"2:	b	1b					\n"
    161 		"	.previous					\n"
    162 		"	.set	mips0					\n"
    163 		: "=&r" (retval), "=m" (*m), "=&r" (dummy)
    164 		: "R" (*m), "Jr" (val)
    165 		: "memory");
    166 	} else {
    167 		unsigned long flags;
    168 
    169 		raw_local_irq_save(flags);
    170 		retval = *m;
    171 		*m = val;
    172 		raw_local_irq_restore(flags);	/* implies memory barrier  */
    173 	}
    174 
    175 	smp_llsc_mb();
    176 
    177 	return retval;
    178 }
    179 #else
    180 extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val);
    181 #define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels
    182 #endif
    183 
    184 /* This function doesn't exist, so you'll get a linker error
    185    if something tries to do an invalid xchg().  */
    186 extern void __xchg_called_with_bad_pointer(void);
    187 
    188 static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
    189 {
    190 	switch (size) {
    191 	case 4:
    192 		return __xchg_u32(ptr, x);
    193 	case 8:
    194 		return __xchg_u64(ptr, x);
    195 	}
    196 	__xchg_called_with_bad_pointer();
    197 	return x;
    198 }
    199 
    200 #define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
    201 
    202 extern void set_handler(unsigned long offset, void *addr, unsigned long len);
    203 extern void set_uncached_handler(unsigned long offset, void *addr, unsigned long len);
    204 
    205 typedef void (*vi_handler_t)(void);
    206 extern void *set_vi_handler(int n, vi_handler_t addr);
    207 
    208 extern void *set_except_vector(int n, void *addr);
    209 extern unsigned long ebase;
    210 extern void per_cpu_trap_init(void);
    211 
    212 /*
    213  * See include/asm-ia64/system.h; prevents deadlock on SMP
    214  * systems.
    215  */
    216 #define __ARCH_WANT_UNLOCKED_CTXSW
    217 
    218 extern unsigned long arch_align_stack(unsigned long sp);
    219 
    220 #endif /* _ASM_SYSTEM_H */
    221