]> err.no Git - linux-2.6/blob - drivers/acpi/executer/exmutex.c
NTFS: 2.1.24 release and some minor final fixes.
[linux-2.6] / drivers / acpi / executer / exmutex.c
1
2 /******************************************************************************
3  *
4  * Module Name: exmutex - ASL Mutex Acquire/Release functions
5  *
6  *****************************************************************************/
7
8 /*
9  * Copyright (C) 2000 - 2005, R. Byron Moore
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44
45
46 #include <acpi/acpi.h>
47 #include <acpi/acinterp.h>
48
49 #define _COMPONENT          ACPI_EXECUTER
50          ACPI_MODULE_NAME    ("exmutex")
51
52 /* Local prototypes */
53
54 static void
55 acpi_ex_link_mutex (
56         union acpi_operand_object       *obj_desc,
57         struct acpi_thread_state        *thread);
58
59
60 /*******************************************************************************
61  *
62  * FUNCTION:    acpi_ex_unlink_mutex
63  *
64  * PARAMETERS:  obj_desc            - The mutex to be unlinked
65  *
66  * RETURN:      None
67  *
68  * DESCRIPTION: Remove a mutex from the "acquired_mutex" list
69  *
70  ******************************************************************************/
71
72 void
73 acpi_ex_unlink_mutex (
74         union acpi_operand_object       *obj_desc)
75 {
76         struct acpi_thread_state        *thread = obj_desc->mutex.owner_thread;
77
78
79         if (!thread) {
80                 return;
81         }
82
83         /* Doubly linked list */
84
85         if (obj_desc->mutex.next) {
86                 (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev;
87         }
88
89         if (obj_desc->mutex.prev) {
90                 (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
91         }
92         else {
93                 thread->acquired_mutex_list = obj_desc->mutex.next;
94         }
95 }
96
97
98 /*******************************************************************************
99  *
100  * FUNCTION:    acpi_ex_link_mutex
101  *
102  * PARAMETERS:  obj_desc        - The mutex to be linked
103  *              Thread          - Current executing thread object
104  *
105  * RETURN:      None
106  *
107  * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk
108  *
109  ******************************************************************************/
110
111 static void
112 acpi_ex_link_mutex (
113         union acpi_operand_object       *obj_desc,
114         struct acpi_thread_state        *thread)
115 {
116         union acpi_operand_object       *list_head;
117
118
119         list_head = thread->acquired_mutex_list;
120
121         /* This object will be the first object in the list */
122
123         obj_desc->mutex.prev = NULL;
124         obj_desc->mutex.next = list_head;
125
126         /* Update old first object to point back to this object */
127
128         if (list_head) {
129                 list_head->mutex.prev = obj_desc;
130         }
131
132         /* Update list head */
133
134         thread->acquired_mutex_list = obj_desc;
135 }
136
137
138 /*******************************************************************************
139  *
140  * FUNCTION:    acpi_ex_acquire_mutex
141  *
142  * PARAMETERS:  time_desc           - Timeout integer
143  *              obj_desc            - Mutex object
144  *              walk_state          - Current method execution state
145  *
146  * RETURN:      Status
147  *
148  * DESCRIPTION: Acquire an AML mutex
149  *
150  ******************************************************************************/
151
152 acpi_status
153 acpi_ex_acquire_mutex (
154         union acpi_operand_object       *time_desc,
155         union acpi_operand_object       *obj_desc,
156         struct acpi_walk_state          *walk_state)
157 {
158         acpi_status                     status;
159
160
161         ACPI_FUNCTION_TRACE_PTR ("ex_acquire_mutex", obj_desc);
162
163
164         if (!obj_desc) {
165                 return_ACPI_STATUS (AE_BAD_PARAMETER);
166         }
167
168         /* Sanity check -- we must have a valid thread ID */
169
170         if (!walk_state->thread) {
171                 ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n",
172                         acpi_ut_get_node_name (obj_desc->mutex.node)));
173                 return_ACPI_STATUS (AE_AML_INTERNAL);
174         }
175
176         /*
177          * Current Sync must be less than or equal to the sync level of the
178          * mutex.  This mechanism provides some deadlock prevention
179          */
180         if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
181                 ACPI_REPORT_ERROR ((
182                         "Cannot acquire Mutex [%4.4s], incorrect sync_level\n",
183                         acpi_ut_get_node_name (obj_desc->mutex.node)));
184                 return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
185         }
186
187         /* Support for multiple acquires by the owning thread */
188
189         if (obj_desc->mutex.owner_thread) {
190                 /* Special case for Global Lock, allow all threads */
191
192                 if ((obj_desc->mutex.owner_thread->thread_id ==
193                                 walk_state->thread->thread_id)      ||
194                         (obj_desc->mutex.semaphore ==
195                                 acpi_gbl_global_lock_semaphore)) {
196                         /*
197                          * The mutex is already owned by this thread,
198                          * just increment the acquisition depth
199                          */
200                         obj_desc->mutex.acquisition_depth++;
201                         return_ACPI_STATUS (AE_OK);
202                 }
203         }
204
205         /* Acquire the mutex, wait if necessary */
206
207         status = acpi_ex_system_acquire_mutex (time_desc, obj_desc);
208         if (ACPI_FAILURE (status)) {
209                 /* Includes failure from a timeout on time_desc */
210
211                 return_ACPI_STATUS (status);
212         }
213
214         /* Have the mutex: update mutex and walk info and save the sync_level */
215
216         obj_desc->mutex.owner_thread     = walk_state->thread;
217         obj_desc->mutex.acquisition_depth = 1;
218         obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level;
219
220         walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
221
222         /* Link the mutex to the current thread for force-unlock at method exit */
223
224         acpi_ex_link_mutex (obj_desc, walk_state->thread);
225
226         return_ACPI_STATUS (AE_OK);
227 }
228
229
230 /*******************************************************************************
231  *
232  * FUNCTION:    acpi_ex_release_mutex
233  *
234  * PARAMETERS:  obj_desc            - The object descriptor for this op
235  *              walk_state          - Current method execution state
236  *
237  * RETURN:      Status
238  *
239  * DESCRIPTION: Release a previously acquired Mutex.
240  *
241  ******************************************************************************/
242
243 acpi_status
244 acpi_ex_release_mutex (
245         union acpi_operand_object       *obj_desc,
246         struct acpi_walk_state          *walk_state)
247 {
248         acpi_status                     status;
249
250
251         ACPI_FUNCTION_TRACE ("ex_release_mutex");
252
253
254         if (!obj_desc) {
255                 return_ACPI_STATUS (AE_BAD_PARAMETER);
256         }
257
258         /* The mutex must have been previously acquired in order to release it */
259
260         if (!obj_desc->mutex.owner_thread) {
261                 ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], not acquired\n",
262                                 acpi_ut_get_node_name (obj_desc->mutex.node)));
263                 return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
264         }
265
266         /* Sanity check -- we must have a valid thread ID */
267
268         if (!walk_state->thread) {
269                 ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], null thread info\n",
270                                 acpi_ut_get_node_name (obj_desc->mutex.node)));
271                 return_ACPI_STATUS (AE_AML_INTERNAL);
272         }
273
274         /*
275          * The Mutex is owned, but this thread must be the owner.
276          * Special case for Global Lock, any thread can release
277          */
278         if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) &&
279                 (obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) {
280                 ACPI_REPORT_ERROR ((
281                         "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n",
282                         walk_state->thread->thread_id,
283                         acpi_ut_get_node_name (obj_desc->mutex.node),
284                         obj_desc->mutex.owner_thread->thread_id));
285                 return_ACPI_STATUS (AE_AML_NOT_OWNER);
286         }
287
288         /*
289          * The sync level of the mutex must be less than or
290          * equal to the current sync level
291          */
292         if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
293                 ACPI_REPORT_ERROR ((
294                         "Cannot release Mutex [%4.4s], incorrect sync_level\n",
295                         acpi_ut_get_node_name (obj_desc->mutex.node)));
296                 return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
297         }
298
299         /* Match multiple Acquires with multiple Releases */
300
301         obj_desc->mutex.acquisition_depth--;
302         if (obj_desc->mutex.acquisition_depth != 0) {
303                 /* Just decrement the depth and return */
304
305                 return_ACPI_STATUS (AE_OK);
306         }
307
308         /* Unlink the mutex from the owner's list */
309
310         acpi_ex_unlink_mutex (obj_desc);
311
312         /* Release the mutex */
313
314         status = acpi_ex_system_release_mutex (obj_desc);
315
316         /* Update the mutex and walk state, restore sync_level before acquire */
317
318         obj_desc->mutex.owner_thread = NULL;
319         walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level;
320
321         return_ACPI_STATUS (status);
322 }
323
324
325 /*******************************************************************************
326  *
327  * FUNCTION:    acpi_ex_release_all_mutexes
328  *
329  * PARAMETERS:  Thread          - Current executing thread object
330  *
331  * RETURN:      Status
332  *
333  * DESCRIPTION: Release all mutexes held by this thread
334  *
335  ******************************************************************************/
336
337 void
338 acpi_ex_release_all_mutexes (
339         struct acpi_thread_state        *thread)
340 {
341         union acpi_operand_object       *next = thread->acquired_mutex_list;
342         union acpi_operand_object       *this;
343         acpi_status                     status;
344
345
346         ACPI_FUNCTION_ENTRY ();
347
348
349         /* Traverse the list of owned mutexes, releasing each one */
350
351         while (next) {
352                 this = next;
353                 next = this->mutex.next;
354
355                 this->mutex.acquisition_depth = 1;
356                 this->mutex.prev             = NULL;
357                 this->mutex.next             = NULL;
358
359                  /* Release the mutex */
360
361                 status = acpi_ex_system_release_mutex (this);
362                 if (ACPI_FAILURE (status)) {
363                         continue;
364                 }
365
366                 /* Mark mutex unowned */
367
368                 this->mutex.owner_thread = NULL;
369
370                 /* Update Thread sync_level (Last mutex is the important one) */
371
372                 thread->current_sync_level = this->mutex.original_sync_level;
373         }
374 }
375
376