Merge tag 'jg-20061012-00' of git://electric-eye.fr.zoreil.com/home/romieu/linux...
[linux-2.6] / arch / i386 / lib / semaphore.S
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.i>
19 #include <asm/frame.i>
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
33 ENTRY(__down_failed)
34         CFI_STARTPROC
35         FRAME
36         pushl %edx
37         CFI_ADJUST_CFA_OFFSET 4
38         CFI_REL_OFFSET edx,0
39         pushl %ecx
40         CFI_ADJUST_CFA_OFFSET 4
41         CFI_REL_OFFSET ecx,0
42         call __down
43         popl %ecx
44         CFI_ADJUST_CFA_OFFSET -4
45         CFI_RESTORE ecx
46         popl %edx
47         CFI_ADJUST_CFA_OFFSET -4
48         CFI_RESTORE edx
49         ENDFRAME
50         ret
51         CFI_ENDPROC
52         END(__down_failed)
53
54 ENTRY(__down_failed_interruptible)
55         CFI_STARTPROC
56         FRAME
57         pushl %edx
58         CFI_ADJUST_CFA_OFFSET 4
59         CFI_REL_OFFSET edx,0
60         pushl %ecx
61         CFI_ADJUST_CFA_OFFSET 4
62         CFI_REL_OFFSET ecx,0
63         call __down_interruptible
64         popl %ecx
65         CFI_ADJUST_CFA_OFFSET -4
66         CFI_RESTORE ecx
67         popl %edx
68         CFI_ADJUST_CFA_OFFSET -4
69         CFI_RESTORE edx
70         ENDFRAME
71         ret
72         CFI_ENDPROC
73         END(__down_failed_interruptible)
74
75 ENTRY(__down_failed_trylock)
76         CFI_STARTPROC
77         FRAME
78         pushl %edx
79         CFI_ADJUST_CFA_OFFSET 4
80         CFI_REL_OFFSET edx,0
81         pushl %ecx
82         CFI_ADJUST_CFA_OFFSET 4
83         CFI_REL_OFFSET ecx,0
84         call __down_trylock
85         popl %ecx
86         CFI_ADJUST_CFA_OFFSET -4
87         CFI_RESTORE ecx
88         popl %edx
89         CFI_ADJUST_CFA_OFFSET -4
90         CFI_RESTORE edx
91         ENDFRAME
92         ret
93         CFI_ENDPROC
94         END(__down_failed_trylock)
95
96 ENTRY(__up_wakeup)
97         CFI_STARTPROC
98         FRAME
99         pushl %edx
100         CFI_ADJUST_CFA_OFFSET 4
101         CFI_REL_OFFSET edx,0
102         pushl %ecx
103         CFI_ADJUST_CFA_OFFSET 4
104         CFI_REL_OFFSET ecx,0
105         call __up
106         popl %ecx
107         CFI_ADJUST_CFA_OFFSET -4
108         CFI_RESTORE ecx
109         popl %edx
110         CFI_ADJUST_CFA_OFFSET -4
111         CFI_RESTORE edx
112         ENDFRAME
113         ret
114         CFI_ENDPROC
115         END(__up_wakeup)
116
117 /*
118  * rw spinlock fallbacks
119  */
120 #ifdef CONFIG_SMP
121 ENTRY(__write_lock_failed)
122         CFI_STARTPROC simple
123         FRAME
124 2:      LOCK_PREFIX
125         addl    $ RW_LOCK_BIAS,(%eax)
126 1:      rep; nop
127         cmpl    $ RW_LOCK_BIAS,(%eax)
128         jne     1b
129         LOCK_PREFIX
130         subl    $ RW_LOCK_BIAS,(%eax)
131         jnz     2b
132         ENDFRAME
133         ret
134         CFI_ENDPROC
135         END(__write_lock_failed)
136
137 ENTRY(__read_lock_failed)
138         CFI_STARTPROC
139         FRAME
140 2:      LOCK_PREFIX
141         incl    (%eax)
142 1:      rep; nop
143         cmpl    $1,(%eax)
144         js      1b
145         LOCK_PREFIX
146         decl    (%eax)
147         js      2b
148         ENDFRAME
149         ret
150         CFI_ENDPROC
151         END(__read_lock_failed)
152
153 #endif
154
155 #ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
156
157 /* Fix up special calling conventions */
158 ENTRY(call_rwsem_down_read_failed)
159         CFI_STARTPROC
160         push %ecx
161         CFI_ADJUST_CFA_OFFSET 4
162         CFI_REL_OFFSET ecx,0
163         push %edx
164         CFI_ADJUST_CFA_OFFSET 4
165         CFI_REL_OFFSET edx,0
166         call rwsem_down_read_failed
167         pop %edx
168         CFI_ADJUST_CFA_OFFSET -4
169         pop %ecx
170         CFI_ADJUST_CFA_OFFSET -4
171         ret
172         CFI_ENDPROC
173         END(call_rwsem_down_read_failed)
174
175 ENTRY(call_rwsem_down_write_failed)
176         CFI_STARTPROC
177         push %ecx
178         CFI_ADJUST_CFA_OFFSET 4
179         CFI_REL_OFFSET ecx,0
180         calll rwsem_down_write_failed
181         pop %ecx
182         CFI_ADJUST_CFA_OFFSET -4
183         ret
184         CFI_ENDPROC
185         END(call_rwsem_down_write_failed)
186
187 ENTRY(call_rwsem_wake)
188         CFI_STARTPROC
189         decw %dx    /* do nothing if still outstanding active readers */
190         jnz 1f
191         push %ecx
192         CFI_ADJUST_CFA_OFFSET 4
193         CFI_REL_OFFSET ecx,0
194         call rwsem_wake
195         pop %ecx
196         CFI_ADJUST_CFA_OFFSET -4
197 1:      ret
198         CFI_ENDPROC
199         END(call_rwsem_wake)
200
201 /* Fix up special calling conventions */
202 ENTRY(call_rwsem_downgrade_wake)
203         CFI_STARTPROC
204         push %ecx
205         CFI_ADJUST_CFA_OFFSET 4
206         CFI_REL_OFFSET ecx,0
207         push %edx
208         CFI_ADJUST_CFA_OFFSET 4
209         CFI_REL_OFFSET edx,0
210         call rwsem_downgrade_wake
211         pop %edx
212         CFI_ADJUST_CFA_OFFSET -4
213         pop %ecx
214         CFI_ADJUST_CFA_OFFSET -4
215         ret
216         CFI_ENDPROC
217         END(call_rwsem_downgrade_wake)
218
219 #endif