diff options
Diffstat (limited to 'arch/x86/lib')
| -rw-r--r-- | arch/x86/lib/Makefile | 1 | ||||
| -rw-r--r-- | arch/x86/lib/atomic64_32.c | 230 | ||||
| -rw-r--r-- | arch/x86/lib/clear_page_64.S | 5 | ||||
| -rw-r--r-- | arch/x86/lib/copy_user_64.S | 1 | ||||
| -rw-r--r-- | arch/x86/lib/msr.c | 26 | ||||
| -rw-r--r-- | arch/x86/lib/usercopy_32.c | 2 | 
6 files changed, 245 insertions, 20 deletions
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index f9d35632666..07c31899c9c 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -10,6 +10,7 @@ lib-y += usercopy_$(BITS).o getuser.o putuser.o  lib-y += memcpy_$(BITS).o  ifeq ($(CONFIG_X86_32),y) +        obj-y += atomic64_32.o          lib-y += checksum_32.o          lib-y += strstr_32.o          lib-y += semaphore_32.o string_32.o diff --git a/arch/x86/lib/atomic64_32.c b/arch/x86/lib/atomic64_32.c new file mode 100644 index 00000000000..824fa0be55a --- /dev/null +++ b/arch/x86/lib/atomic64_32.c @@ -0,0 +1,230 @@ +#include <linux/compiler.h> +#include <linux/module.h> +#include <linux/types.h> + +#include <asm/processor.h> +#include <asm/cmpxchg.h> +#include <asm/atomic.h> + +static noinline u64 cmpxchg8b(u64 *ptr, u64 old, u64 new) +{ +	u32 low = new; +	u32 high = new >> 32; + +	asm volatile( +		LOCK_PREFIX "cmpxchg8b %1\n" +		     : "+A" (old), "+m" (*ptr) +		     :  "b" (low),  "c" (high) +		     ); +	return old; +} + +u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val) +{ +	return cmpxchg8b(&ptr->counter, old_val, new_val); +} +EXPORT_SYMBOL(atomic64_cmpxchg); + +/** + * atomic64_xchg - xchg atomic64 variable + * @ptr:      pointer to type atomic64_t + * @new_val:  value to assign + * + * Atomically xchgs the value of @ptr to @new_val and returns + * the old value. + */ +u64 atomic64_xchg(atomic64_t *ptr, u64 new_val) +{ +	/* +	 * Try first with a (possibly incorrect) assumption about +	 * what we have there. We'll do two loops most likely, +	 * but we'll get an ownership MESI transaction straight away +	 * instead of a read transaction followed by a +	 * flush-for-ownership transaction: +	 */ +	u64 old_val, real_val = 0; + +	do { +		old_val = real_val; + +		real_val = atomic64_cmpxchg(ptr, old_val, new_val); + +	} while (real_val != old_val); + +	return old_val; +} +EXPORT_SYMBOL(atomic64_xchg); + +/** + * atomic64_set - set atomic64 variable + * @ptr:      pointer to type atomic64_t + * @new_val:  value to assign + * + * Atomically sets the value of @ptr to @new_val. + */ +void atomic64_set(atomic64_t *ptr, u64 new_val) +{ +	atomic64_xchg(ptr, new_val); +} +EXPORT_SYMBOL(atomic64_set); + +/** +EXPORT_SYMBOL(atomic64_read); + * atomic64_add_return - add and return + * @delta: integer value to add + * @ptr:   pointer to type atomic64_t + * + * Atomically adds @delta to @ptr and returns @delta + *@ptr + */ +noinline u64 atomic64_add_return(u64 delta, atomic64_t *ptr) +{ +	/* +	 * Try first with a (possibly incorrect) assumption about +	 * what we have there. We'll do two loops most likely, +	 * but we'll get an ownership MESI transaction straight away +	 * instead of a read transaction followed by a +	 * flush-for-ownership transaction: +	 */ +	u64 old_val, new_val, real_val = 0; + +	do { +		old_val = real_val; +		new_val = old_val + delta; + +		real_val = atomic64_cmpxchg(ptr, old_val, new_val); + +	} while (real_val != old_val); + +	return new_val; +} +EXPORT_SYMBOL(atomic64_add_return); + +u64 atomic64_sub_return(u64 delta, atomic64_t *ptr) +{ +	return atomic64_add_return(-delta, ptr); +} +EXPORT_SYMBOL(atomic64_sub_return); + +u64 atomic64_inc_return(atomic64_t *ptr) +{ +	return atomic64_add_return(1, ptr); +} +EXPORT_SYMBOL(atomic64_inc_return); + +u64 atomic64_dec_return(atomic64_t *ptr) +{ +	return atomic64_sub_return(1, ptr); +} +EXPORT_SYMBOL(atomic64_dec_return); + +/** + * atomic64_add - add integer to atomic64 variable + * @delta: integer value to add + * @ptr:   pointer to type atomic64_t + * + * Atomically adds @delta to @ptr. + */ +void atomic64_add(u64 delta, atomic64_t *ptr) +{ +	atomic64_add_return(delta, ptr); +} +EXPORT_SYMBOL(atomic64_add); + +/** + * atomic64_sub - subtract the atomic64 variable + * @delta: integer value to subtract + * @ptr:   pointer to type atomic64_t + * + * Atomically subtracts @delta from @ptr. + */ +void atomic64_sub(u64 delta, atomic64_t *ptr) +{ +	atomic64_add(-delta, ptr); +} +EXPORT_SYMBOL(atomic64_sub); + +/** + * atomic64_sub_and_test - subtract value from variable and test result + * @delta: integer value to subtract + * @ptr:   pointer to type atomic64_t + * + * Atomically subtracts @delta from @ptr and returns + * true if the result is zero, or false for all + * other cases. + */ +int atomic64_sub_and_test(u64 delta, atomic64_t *ptr) +{ +	u64 new_val = atomic64_sub_return(delta, ptr); + +	return new_val == 0; +} +EXPORT_SYMBOL(atomic64_sub_and_test); + +/** + * atomic64_inc - increment atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically increments @ptr by 1. + */ +void atomic64_inc(atomic64_t *ptr) +{ +	atomic64_add(1, ptr); +} +EXPORT_SYMBOL(atomic64_inc); + +/** + * atomic64_dec - decrement atomic64 variable + * @ptr: pointer to type atomic64_t + * + * Atomically decrements @ptr by 1. + */ +void atomic64_dec(atomic64_t *ptr) +{ +	atomic64_sub(1, ptr); +} +EXPORT_SYMBOL(atomic64_dec); + +/** + * atomic64_dec_and_test - decrement and test + * @ptr: pointer to type atomic64_t + * + * Atomically decrements @ptr by 1 and + * returns true if the result is 0, or false for all other + * cases. + */ +int atomic64_dec_and_test(atomic64_t *ptr) +{ +	return atomic64_sub_and_test(1, ptr); +} +EXPORT_SYMBOL(atomic64_dec_and_test); + +/** + * atomic64_inc_and_test - increment and test + * @ptr: pointer to type atomic64_t + * + * Atomically increments @ptr by 1 + * and returns true if the result is zero, or false for all + * other cases. + */ +int atomic64_inc_and_test(atomic64_t *ptr) +{ +	return atomic64_sub_and_test(-1, ptr); +} +EXPORT_SYMBOL(atomic64_inc_and_test); + +/** + * atomic64_add_negative - add and test if negative + * @delta: integer value to add + * @ptr:   pointer to type atomic64_t + * + * Atomically adds @delta to @ptr and returns true + * if the result is negative, or false when + * result is greater than or equal to zero. + */ +int atomic64_add_negative(u64 delta, atomic64_t *ptr) +{ +	s64 new_val = atomic64_add_return(delta, ptr); + +	return new_val < 0; +} +EXPORT_SYMBOL(atomic64_add_negative); diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S index 9a10a78bb4a..ebeafcce04a 100644 --- a/arch/x86/lib/clear_page_64.S +++ b/arch/x86/lib/clear_page_64.S @@ -5,15 +5,14 @@   * Zero a page. 	   * rdi	page   */			 -	ALIGN -clear_page_c: +ENTRY(clear_page_c)  	CFI_STARTPROC  	movl $4096/8,%ecx  	xorl %eax,%eax  	rep stosq  	ret  	CFI_ENDPROC -ENDPROC(clear_page) +ENDPROC(clear_page_c)  ENTRY(clear_page)  	CFI_STARTPROC diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S index f118c110af3..6ba0f7bb85e 100644 --- a/arch/x86/lib/copy_user_64.S +++ b/arch/x86/lib/copy_user_64.S @@ -75,6 +75,7 @@ ENTRY(copy_to_user)  	jae bad_to_user  	ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string  	CFI_ENDPROC +ENDPROC(copy_to_user)  /* Standard copy_from_user with segment limit checking */  ENTRY(copy_from_user) diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c index 1440b9c0547..caa24aca811 100644 --- a/arch/x86/lib/msr.c +++ b/arch/x86/lib/msr.c @@ -89,16 +89,13 @@ void rdmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)  	rv.msrs	  = msrs;  	rv.msr_no = msr_no; -	preempt_disable(); -	/* -	 * FIXME: handle the CPU we're executing on separately for now until -	 * smp_call_function_many has been fixed to not skip it. -	 */ -	this_cpu = raw_smp_processor_id(); -	smp_call_function_single(this_cpu, __rdmsr_on_cpu, &rv, 1); +	this_cpu = get_cpu(); + +	if (cpumask_test_cpu(this_cpu, mask)) +		__rdmsr_on_cpu(&rv);  	smp_call_function_many(mask, __rdmsr_on_cpu, &rv, 1); -	preempt_enable(); +	put_cpu();  }  EXPORT_SYMBOL(rdmsr_on_cpus); @@ -121,16 +118,13 @@ void wrmsr_on_cpus(const cpumask_t *mask, u32 msr_no, struct msr *msrs)  	rv.msrs   = msrs;  	rv.msr_no = msr_no; -	preempt_disable(); -	/* -	 * FIXME: handle the CPU we're executing on separately for now until -	 * smp_call_function_many has been fixed to not skip it. -	 */ -	this_cpu = raw_smp_processor_id(); -	smp_call_function_single(this_cpu, __wrmsr_on_cpu, &rv, 1); +	this_cpu = get_cpu(); + +	if (cpumask_test_cpu(this_cpu, mask)) +		__wrmsr_on_cpu(&rv);  	smp_call_function_many(mask, __wrmsr_on_cpu, &rv, 1); -	preempt_enable(); +	put_cpu();  }  EXPORT_SYMBOL(wrmsr_on_cpus); diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 7c8ca91bb9e..1f118d462ac 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -751,7 +751,7 @@ survive:  			if (retval == -ENOMEM && is_global_init(current)) {  				up_read(¤t->mm->mmap_sem); -				congestion_wait(WRITE, HZ/50); +				congestion_wait(BLK_RW_ASYNC, HZ/50);  				goto survive;  			}  |