1/*
2 * i386 semaphore implementation.
3 *
4 * (C) Copyright 1999 Linus Torvalds
5 *
6 * Portions Copyright 1999 Red Hat, Inc.
7 *
8 *	This program is free software; you can redistribute it and/or
9 *	modify it under the terms of the GNU General Public License
10 *	as published by the Free Software Foundation; either version
11 *	2 of the License, or (at your option) any later version.
12 *
13 * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
14 */
15
16#include <linux/linkage.h>
17#include <asm/rwlock.h>
18#include <asm/alternative-asm.h>
19#include <asm/frame.h>
20#include <asm/dwarf2.h>
21
22/*
23 * The semaphore operations have a special calling sequence that
24 * allow us to do a simpler in-line version of them. These routines
25 * need to convert that sequence back into the C sequence when
26 * there is contention on the semaphore.
27 *
28 * %eax contains the semaphore pointer on entry. Save the C-clobbered
29 * registers (%eax, %edx and %ecx) except %eax whish is either a return
30 * value or just clobbered..
31 */
32	.section .sched.text, "ax"
33
34/*
35 * rw spinlock fallbacks
36 */
37#ifdef CONFIG_SMP
38ENTRY(__write_lock_failed)
39	CFI_STARTPROC
40	FRAME
412: 	LOCK_PREFIX
42	addl	$ RW_LOCK_BIAS,(%eax)
431:	rep; nop
44	cmpl	$ RW_LOCK_BIAS,(%eax)
45	jne	1b
46	LOCK_PREFIX
47	subl	$ RW_LOCK_BIAS,(%eax)
48	jnz	2b
49	ENDFRAME
50	ret
51	CFI_ENDPROC
52	ENDPROC(__write_lock_failed)
53
54ENTRY(__read_lock_failed)
55	CFI_STARTPROC
56	FRAME
572: 	LOCK_PREFIX
58	incl	(%eax)
591:	rep; nop
60	cmpl	$1,(%eax)
61	js	1b
62	LOCK_PREFIX
63	decl	(%eax)
64	js	2b
65	ENDFRAME
66	ret
67	CFI_ENDPROC
68	ENDPROC(__read_lock_failed)
69
70#endif
71
72#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
73
74/* Fix up special calling conventions */
75ENTRY(call_rwsem_down_read_failed)
76	CFI_STARTPROC
77	pushl_cfi %ecx
78	CFI_REL_OFFSET ecx,0
79	pushl_cfi %edx
80	CFI_REL_OFFSET edx,0
81	call rwsem_down_read_failed
82	popl_cfi %edx
83	popl_cfi %ecx
84	ret
85	CFI_ENDPROC
86	ENDPROC(call_rwsem_down_read_failed)
87
88ENTRY(call_rwsem_down_write_failed)
89	CFI_STARTPROC
90	pushl_cfi %ecx
91	CFI_REL_OFFSET ecx,0
92	calll rwsem_down_write_failed
93	popl_cfi %ecx
94	ret
95	CFI_ENDPROC
96	ENDPROC(call_rwsem_down_write_failed)
97
98ENTRY(call_rwsem_wake)
99	CFI_STARTPROC
100	decw %dx    /* do nothing if still outstanding active readers */
101	jnz 1f
102	pushl_cfi %ecx
103	CFI_REL_OFFSET ecx,0
104	call rwsem_wake
105	popl_cfi %ecx
1061:	ret
107	CFI_ENDPROC
108	ENDPROC(call_rwsem_wake)
109
110/* Fix up special calling conventions */
111ENTRY(call_rwsem_downgrade_wake)
112	CFI_STARTPROC
113	pushl_cfi %ecx
114	CFI_REL_OFFSET ecx,0
115	pushl_cfi %edx
116	CFI_REL_OFFSET edx,0
117	call rwsem_downgrade_wake
118	popl_cfi %edx
119	popl_cfi %ecx
120	ret
121	CFI_ENDPROC
122	ENDPROC(call_rwsem_downgrade_wake)
123
124#endif
125