|  | /* | 
|  | * i386 semaphore implementation. | 
|  | * | 
|  | * (C) Copyright 1999 Linus Torvalds | 
|  | * | 
|  | * Portions Copyright 1999 Red Hat, Inc. | 
|  | * | 
|  | *	This program is free software; you can redistribute it and/or | 
|  | *	modify it under the terms of the GNU General Public License | 
|  | *	as published by the Free Software Foundation; either version | 
|  | *	2 of the License, or (at your option) any later version. | 
|  | * | 
|  | * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org> | 
|  | */ | 
|  |  | 
|  | #include <linux/linkage.h> | 
|  | #include <asm/rwlock.h> | 
|  | #include <asm/alternative-asm.h> | 
|  | #include <asm/frame.h> | 
|  | #include <asm/dwarf2.h> | 
|  |  | 
|  | /* | 
|  | * The semaphore operations have a special calling sequence that | 
|  | * allow us to do a simpler in-line version of them. These routines | 
|  | * need to convert that sequence back into the C sequence when | 
|  | * there is contention on the semaphore. | 
|  | * | 
|  | * %eax contains the semaphore pointer on entry. Save the C-clobbered | 
|  | * registers (%eax, %edx and %ecx) except %eax whish is either a return | 
|  | * value or just clobbered.. | 
|  | */ | 
|  | .section .sched.text, "ax" | 
|  |  | 
|  | /* | 
|  | * rw spinlock fallbacks | 
|  | */ | 
|  | #ifdef CONFIG_SMP | 
|  | ENTRY(__write_lock_failed) | 
|  | CFI_STARTPROC | 
|  | FRAME | 
|  | 2: 	LOCK_PREFIX | 
|  | addl	$ RW_LOCK_BIAS,(%eax) | 
|  | 1:	rep; nop | 
|  | cmpl	$ RW_LOCK_BIAS,(%eax) | 
|  | jne	1b | 
|  | LOCK_PREFIX | 
|  | subl	$ RW_LOCK_BIAS,(%eax) | 
|  | jnz	2b | 
|  | ENDFRAME | 
|  | ret | 
|  | CFI_ENDPROC | 
|  | ENDPROC(__write_lock_failed) | 
|  |  | 
|  | ENTRY(__read_lock_failed) | 
|  | CFI_STARTPROC | 
|  | FRAME | 
|  | 2: 	LOCK_PREFIX | 
|  | incl	(%eax) | 
|  | 1:	rep; nop | 
|  | cmpl	$1,(%eax) | 
|  | js	1b | 
|  | LOCK_PREFIX | 
|  | decl	(%eax) | 
|  | js	2b | 
|  | ENDFRAME | 
|  | ret | 
|  | CFI_ENDPROC | 
|  | ENDPROC(__read_lock_failed) | 
|  |  | 
|  | #endif | 
|  |  | 
|  | #ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM | 
|  |  | 
|  | /* Fix up special calling conventions */ | 
|  | ENTRY(call_rwsem_down_read_failed) | 
|  | CFI_STARTPROC | 
|  | pushl_cfi %ecx | 
|  | CFI_REL_OFFSET ecx,0 | 
|  | pushl_cfi %edx | 
|  | CFI_REL_OFFSET edx,0 | 
|  | call rwsem_down_read_failed | 
|  | popl_cfi %edx | 
|  | popl_cfi %ecx | 
|  | ret | 
|  | CFI_ENDPROC | 
|  | ENDPROC(call_rwsem_down_read_failed) | 
|  |  | 
|  | ENTRY(call_rwsem_down_write_failed) | 
|  | CFI_STARTPROC | 
|  | pushl_cfi %ecx | 
|  | CFI_REL_OFFSET ecx,0 | 
|  | calll rwsem_down_write_failed | 
|  | popl_cfi %ecx | 
|  | ret | 
|  | CFI_ENDPROC | 
|  | ENDPROC(call_rwsem_down_write_failed) | 
|  |  | 
|  | ENTRY(call_rwsem_wake) | 
|  | CFI_STARTPROC | 
|  | decw %dx    /* do nothing if still outstanding active readers */ | 
|  | jnz 1f | 
|  | pushl_cfi %ecx | 
|  | CFI_REL_OFFSET ecx,0 | 
|  | call rwsem_wake | 
|  | popl_cfi %ecx | 
|  | 1:	ret | 
|  | CFI_ENDPROC | 
|  | ENDPROC(call_rwsem_wake) | 
|  |  | 
|  | /* Fix up special calling conventions */ | 
|  | ENTRY(call_rwsem_downgrade_wake) | 
|  | CFI_STARTPROC | 
|  | pushl_cfi %ecx | 
|  | CFI_REL_OFFSET ecx,0 | 
|  | pushl_cfi %edx | 
|  | CFI_REL_OFFSET edx,0 | 
|  | call rwsem_downgrade_wake | 
|  | popl_cfi %edx | 
|  | popl_cfi %ecx | 
|  | ret | 
|  | CFI_ENDPROC | 
|  | ENDPROC(call_rwsem_downgrade_wake) | 
|  |  | 
|  | #endif |