File: /usr/src/linux/drivers/acpi/executer/exmutex.c
1
2 /******************************************************************************
3 *
4 * Module Name: exmutex - ASL Mutex Acquire/Release functions
5 * $Revision: 7 $
6 *
7 *****************************************************************************/
8
9 /*
10 * Copyright (C) 2000, 2001 R. Byron Moore
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27
28 #include "acpi.h"
29 #include "acinterp.h"
30 #include "acnamesp.h"
31 #include "achware.h"
32 #include "acevents.h"
33
34 #define _COMPONENT ACPI_EXECUTER
35 MODULE_NAME ("exmutex")
36
37
38 /*******************************************************************************
39 *
40 * FUNCTION: Acpi_ex_unlink_mutex
41 *
42 * PARAMETERS: *Obj_desc - The mutex to be unlinked
43 *
44 * RETURN: Status
45 *
46 * DESCRIPTION: Remove a mutex from the "Acquired_mutex" list
47 *
48 ******************************************************************************/
49
50 void
51 acpi_ex_unlink_mutex (
52 acpi_operand_object *obj_desc)
53 {
54
55 if (obj_desc->mutex.next) {
56 (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev;
57 }
58 if (obj_desc->mutex.prev) {
59 (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
60 }
61 }
62
63
64 /*******************************************************************************
65 *
66 * FUNCTION: Acpi_ex_link_mutex
67 *
68 * PARAMETERS: *Obj_desc - The mutex to be linked
69 * *List_head - head of the "Acquired_mutex" list
70 *
71 * RETURN: Status
72 *
73 * DESCRIPTION: Add a mutex to the "Acquired_mutex" list for this walk
74 *
75 ******************************************************************************/
76
77 void
78 acpi_ex_link_mutex (
79 acpi_operand_object *obj_desc,
80 acpi_operand_object *list_head)
81 {
82
83 /* This object will be the first object in the list */
84
85 obj_desc->mutex.prev = list_head;
86 obj_desc->mutex.next = list_head->mutex.next;
87
88 /* Update old first object to point back to this object */
89
90 if (list_head->mutex.next) {
91 (list_head->mutex.next)->mutex.prev = obj_desc;
92 }
93
94 /* Update list head */
95
96 list_head->mutex.next = obj_desc;
97 }
98
99
100 /*******************************************************************************
101 *
102 * FUNCTION: Acpi_ex_acquire_mutex
103 *
104 * PARAMETERS: *Time_desc - The 'time to delay' object descriptor
105 * *Obj_desc - The object descriptor for this op
106 *
107 * RETURN: Status
108 *
109 * DESCRIPTION: Acquire an AML mutex
110 *
111 ******************************************************************************/
112
113 acpi_status
114 acpi_ex_acquire_mutex (
115 acpi_operand_object *time_desc,
116 acpi_operand_object *obj_desc,
117 acpi_walk_state *walk_state)
118 {
119 acpi_status status;
120
121
122 FUNCTION_TRACE_PTR ("Ex_acquire_mutex", obj_desc);
123
124 if (!obj_desc) {
125 return_ACPI_STATUS (AE_BAD_PARAMETER);
126 }
127
128 /*
129 * Current Sync must be less than or equal to the sync level of the
130 * mutex. This mechanism provides some deadlock prevention
131 */
132 if (walk_state->current_sync_level > obj_desc->mutex.sync_level) {
133 return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
134 }
135
136 /*
137 * If the mutex is already owned by this thread,
138 * just increment the acquisition depth
139 */
140 if (obj_desc->mutex.owner == walk_state) {
141 obj_desc->mutex.acquisition_depth++;
142 return_ACPI_STATUS (AE_OK);
143 }
144
145 /* Acquire the mutex, wait if necessary */
146
147 status = acpi_ex_system_acquire_mutex (time_desc, obj_desc);
148 if (ACPI_FAILURE (status)) {
149 /* Includes failure from a timeout on Time_desc */
150
151 return_ACPI_STATUS (status);
152 }
153
154 /* Have the mutex, update mutex and walk info */
155
156 obj_desc->mutex.owner = walk_state;
157 obj_desc->mutex.acquisition_depth = 1;
158 walk_state->current_sync_level = obj_desc->mutex.sync_level;
159
160 /* Link the mutex to the walk state for force-unlock at method exit */
161
162 acpi_ex_link_mutex (obj_desc, (acpi_operand_object *)
163 &(walk_state->walk_list->acquired_mutex_list));
164
165 return_ACPI_STATUS (AE_OK);
166 }
167
168
169 /*******************************************************************************
170 *
171 * FUNCTION: Acpi_ex_release_mutex
172 *
173 * PARAMETERS: *Obj_desc - The object descriptor for this op
174 *
175 * RETURN: Status
176 *
177 * DESCRIPTION: Release a previously acquired Mutex.
178 *
179 ******************************************************************************/
180
181 acpi_status
182 acpi_ex_release_mutex (
183 acpi_operand_object *obj_desc,
184 acpi_walk_state *walk_state)
185 {
186 acpi_status status;
187
188
189 FUNCTION_TRACE ("Ex_release_mutex");
190
191
192 if (!obj_desc) {
193 return_ACPI_STATUS (AE_BAD_PARAMETER);
194 }
195
196 /* The mutex must have been previously acquired in order to release it */
197
198 if (!obj_desc->mutex.owner) {
199 return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
200 }
201
202 /* The Mutex is owned, but this thread must be the owner */
203
204 if (obj_desc->mutex.owner != walk_state) {
205 return_ACPI_STATUS (AE_AML_NOT_OWNER);
206 }
207
208 /*
209 * The sync level of the mutex must be less than or
210 * equal to the current sync level
211 */
212 if (obj_desc->mutex.sync_level > walk_state->current_sync_level) {
213 return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
214 }
215
216 /*
217 * Match multiple Acquires with multiple Releases
218 */
219 obj_desc->mutex.acquisition_depth--;
220 if (obj_desc->mutex.acquisition_depth != 0) {
221 /* Just decrement the depth and return */
222
223 return_ACPI_STATUS (AE_OK);
224 }
225
226
227 /* Release the mutex */
228
229 status = acpi_ex_system_release_mutex (obj_desc);
230
231 /* Update the mutex and walk state */
232
233 obj_desc->mutex.owner = NULL;
234 walk_state->current_sync_level = obj_desc->mutex.sync_level;
235
236 /* Unlink the mutex from the owner's list */
237
238 acpi_ex_unlink_mutex (obj_desc);
239
240 return_ACPI_STATUS (status);
241 }
242
243
244 /*******************************************************************************
245 *
246 * FUNCTION: Acpi_ex_release_all_mutexes
247 *
248 * PARAMETERS: *Mutex_list - Head of the mutex list
249 *
250 * RETURN: Status
251 *
252 * DESCRIPTION: Release all mutexes in the list
253 *
254 ******************************************************************************/
255
256 acpi_status
257 acpi_ex_release_all_mutexes (
258 acpi_operand_object *list_head)
259 {
260 acpi_operand_object *next = list_head->mutex.next;
261 acpi_operand_object *this;
262
263
264 FUNCTION_ENTRY ();
265
266
267 /*
268 * Traverse the list of owned mutexes, releasing each one.
269 */
270 while (next) {
271 this = next;
272 next = this->mutex.next;
273
274 /* Mark mutex un-owned */
275
276 this->mutex.owner = NULL;
277 this->mutex.prev = NULL;
278 this->mutex.next = NULL;
279 this->mutex.acquisition_depth = 0;
280
281 /* Release the mutex */
282
283 acpi_ex_system_release_mutex (this);
284 }
285
286 return (AE_OK);
287 }
288
289
290