1/*******************************************************************************
2 *
3 * Module Name: utmutex - local mutex support
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2007, R. Byron Moore
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <acpi/acpi.h>
45
46#define _COMPONENT          ACPI_UTILITIES
47ACPI_MODULE_NAME("utmutex")
48
49/* Local prototypes */
50static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id);
51
52static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id);
53
54/*******************************************************************************
55 *
56 * FUNCTION:    acpi_ut_mutex_initialize
57 *
58 * PARAMETERS:  None.
59 *
60 * RETURN:      Status
61 *
62 * DESCRIPTION: Create the system mutex objects.
63 *
64 ******************************************************************************/
65
66acpi_status acpi_ut_mutex_initialize(void)
67{
68	u32 i;
69	acpi_status status;
70
71	ACPI_FUNCTION_TRACE(ut_mutex_initialize);
72
73	/*
74	 * Create each of the predefined mutex objects
75	 */
76	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
77		status = acpi_ut_create_mutex(i);
78		if (ACPI_FAILURE(status)) {
79			return_ACPI_STATUS(status);
80		}
81	}
82
83	/* Create the spinlocks for use at interrupt level */
84
85	spin_lock_init(acpi_gbl_gpe_lock);
86	spin_lock_init(acpi_gbl_hardware_lock);
87
88	return_ACPI_STATUS(status);
89}
90
91/*******************************************************************************
92 *
93 * FUNCTION:    acpi_ut_mutex_terminate
94 *
95 * PARAMETERS:  None.
96 *
97 * RETURN:      None.
98 *
99 * DESCRIPTION: Delete all of the system mutex objects.
100 *
101 ******************************************************************************/
102
103void acpi_ut_mutex_terminate(void)
104{
105	u32 i;
106
107	ACPI_FUNCTION_TRACE(ut_mutex_terminate);
108
109	/*
110	 * Delete each predefined mutex object
111	 */
112	for (i = 0; i < ACPI_NUM_MUTEX; i++) {
113		(void)acpi_ut_delete_mutex(i);
114	}
115
116	/* Delete the spinlocks */
117
118	acpi_os_delete_lock(acpi_gbl_gpe_lock);
119	acpi_os_delete_lock(acpi_gbl_hardware_lock);
120	return_VOID;
121}
122
123/*******************************************************************************
124 *
125 * FUNCTION:    acpi_ut_create_mutex
126 *
127 * PARAMETERS:  mutex_iD        - ID of the mutex to be created
128 *
129 * RETURN:      Status
130 *
131 * DESCRIPTION: Create a mutex object.
132 *
133 ******************************************************************************/
134
135static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
136{
137	acpi_status status = AE_OK;
138
139	ACPI_FUNCTION_TRACE_U32(ut_create_mutex, mutex_id);
140
141	if (mutex_id > ACPI_MAX_MUTEX) {
142		return_ACPI_STATUS(AE_BAD_PARAMETER);
143	}
144
145	if (!acpi_gbl_mutex_info[mutex_id].mutex) {
146		status =
147		    acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex);
148		acpi_gbl_mutex_info[mutex_id].thread_id =
149		    ACPI_MUTEX_NOT_ACQUIRED;
150		acpi_gbl_mutex_info[mutex_id].use_count = 0;
151	}
152
153	return_ACPI_STATUS(status);
154}
155
156/*******************************************************************************
157 *
158 * FUNCTION:    acpi_ut_delete_mutex
159 *
160 * PARAMETERS:  mutex_iD        - ID of the mutex to be deleted
161 *
162 * RETURN:      Status
163 *
164 * DESCRIPTION: Delete a mutex object.
165 *
166 ******************************************************************************/
167
168static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
169{
170
171	ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
172
173	if (mutex_id > ACPI_MAX_MUTEX) {
174		return_ACPI_STATUS(AE_BAD_PARAMETER);
175	}
176
177	acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
178
179	acpi_gbl_mutex_info[mutex_id].mutex = NULL;
180	acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
181
182	return_ACPI_STATUS(AE_OK);
183}
184
185/*******************************************************************************
186 *
187 * FUNCTION:    acpi_ut_acquire_mutex
188 *
189 * PARAMETERS:  mutex_iD        - ID of the mutex to be acquired
190 *
191 * RETURN:      Status
192 *
193 * DESCRIPTION: Acquire a mutex object.
194 *
195 ******************************************************************************/
196
197acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
198{
199	acpi_status status;
200	acpi_thread_id this_thread_id;
201
202	ACPI_FUNCTION_NAME(ut_acquire_mutex);
203
204	if (mutex_id > ACPI_MAX_MUTEX) {
205		return (AE_BAD_PARAMETER);
206	}
207
208	this_thread_id = acpi_os_get_thread_id();
209
210#ifdef ACPI_MUTEX_DEBUG
211	{
212		u32 i;
213		/*
214		 * Mutex debug code, for internal debugging only.
215		 *
216		 * Deadlock prevention.  Check if this thread owns any mutexes of value
217		 * greater than or equal to this one.  If so, the thread has violated
218		 * the mutex ordering rule.  This indicates a coding error somewhere in
219		 * the ACPI subsystem code.
220		 */
221		for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) {
222			if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
223				if (i == mutex_id) {
224					ACPI_ERROR((AE_INFO,
225						    "Mutex [%s] already acquired by this thread [%X]",
226						    acpi_ut_get_mutex_name
227						    (mutex_id),
228						    this_thread_id));
229
230					return (AE_ALREADY_ACQUIRED);
231				}
232
233				ACPI_ERROR((AE_INFO,
234					    "Invalid acquire order: Thread %X owns [%s], wants [%s]",
235					    this_thread_id,
236					    acpi_ut_get_mutex_name(i),
237					    acpi_ut_get_mutex_name(mutex_id)));
238
239				return (AE_ACQUIRE_DEADLOCK);
240			}
241		}
242	}
243#endif
244
245	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
246			  "Thread %lX attempting to acquire Mutex [%s]\n",
247			  (unsigned long)this_thread_id,
248			  acpi_ut_get_mutex_name(mutex_id)));
249
250	status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
251				       ACPI_WAIT_FOREVER);
252	if (ACPI_SUCCESS(status)) {
253		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
254				  "Thread %lX acquired Mutex [%s]\n",
255				  (unsigned long)this_thread_id,
256				  acpi_ut_get_mutex_name(mutex_id)));
257
258		acpi_gbl_mutex_info[mutex_id].use_count++;
259		acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id;
260	} else {
261		ACPI_EXCEPTION((AE_INFO, status,
262				"Thread %lX could not acquire Mutex [%X]",
263				(unsigned long)this_thread_id, mutex_id));
264	}
265
266	return (status);
267}
268
269/*******************************************************************************
270 *
271 * FUNCTION:    acpi_ut_release_mutex
272 *
273 * PARAMETERS:  mutex_iD        - ID of the mutex to be released
274 *
275 * RETURN:      Status
276 *
277 * DESCRIPTION: Release a mutex object.
278 *
279 ******************************************************************************/
280
281acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
282{
283	acpi_thread_id this_thread_id;
284
285	ACPI_FUNCTION_NAME(ut_release_mutex);
286
287	this_thread_id = acpi_os_get_thread_id();
288	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
289			  "Thread %lX releasing Mutex [%s]\n",
290			  (unsigned long)this_thread_id,
291			  acpi_ut_get_mutex_name(mutex_id)));
292
293	if (mutex_id > ACPI_MAX_MUTEX) {
294		return (AE_BAD_PARAMETER);
295	}
296
297	/*
298	 * Mutex must be acquired in order to release it!
299	 */
300	if (acpi_gbl_mutex_info[mutex_id].thread_id == ACPI_MUTEX_NOT_ACQUIRED) {
301		ACPI_ERROR((AE_INFO,
302			    "Mutex [%X] is not acquired, cannot release",
303			    mutex_id));
304
305		return (AE_NOT_ACQUIRED);
306	}
307#ifdef ACPI_MUTEX_DEBUG
308	{
309		u32 i;
310		/*
311		 * Mutex debug code, for internal debugging only.
312		 *
313		 * Deadlock prevention.  Check if this thread owns any mutexes of value
314		 * greater than this one.  If so, the thread has violated the mutex
315		 * ordering rule.  This indicates a coding error somewhere in
316		 * the ACPI subsystem code.
317		 */
318		for (i = mutex_id; i < ACPI_MAX_MUTEX; i++) {
319			if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) {
320				if (i == mutex_id) {
321					continue;
322				}
323
324				ACPI_ERROR((AE_INFO,
325					    "Invalid release order: owns [%s], releasing [%s]",
326					    acpi_ut_get_mutex_name(i),
327					    acpi_ut_get_mutex_name(mutex_id)));
328
329				return (AE_RELEASE_DEADLOCK);
330			}
331		}
332	}
333#endif
334
335	/* Mark unlocked FIRST */
336
337	acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
338
339	acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
340	return (AE_OK);
341}
342