utmutex.c revision 241973
1/*******************************************************************************
2 *
3 * Module Name: utmutex - local mutex support
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2012, Intel Corp.
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
45#define __UTMUTEX_C__
46
47#include <contrib/dev/acpica/include/acpi.h>
48#include <contrib/dev/acpica/include/accommon.h>
49
50#define _COMPONENT          ACPI_UTILITIES
51        ACPI_MODULE_NAME    ("utmutex")
52
53/* Local prototypes */
54
55static ACPI_STATUS
56AcpiUtCreateMutex (
57    ACPI_MUTEX_HANDLE       MutexId);
58
59static void
60AcpiUtDeleteMutex (
61    ACPI_MUTEX_HANDLE       MutexId);
62
63
64/*******************************************************************************
65 *
66 * FUNCTION:    AcpiUtMutexInitialize
67 *
68 * PARAMETERS:  None.
69 *
70 * RETURN:      Status
71 *
72 * DESCRIPTION: Create the system mutex objects. This includes mutexes,
73 *              spin locks, and reader/writer locks.
74 *
75 ******************************************************************************/
76
77ACPI_STATUS
78AcpiUtMutexInitialize (
79    void)
80{
81    UINT32                  i;
82    ACPI_STATUS             Status;
83
84
85    ACPI_FUNCTION_TRACE (UtMutexInitialize);
86
87
88    /* Create each of the predefined mutex objects */
89
90    for (i = 0; i < ACPI_NUM_MUTEX; i++)
91    {
92        Status = AcpiUtCreateMutex (i);
93        if (ACPI_FAILURE (Status))
94        {
95            return_ACPI_STATUS (Status);
96        }
97    }
98
99    /* Create the spinlocks for use at interrupt level */
100
101    Status = AcpiOsCreateLock (&AcpiGbl_GpeLock);
102    if (ACPI_FAILURE (Status))
103    {
104        return_ACPI_STATUS (Status);
105    }
106
107    Status = AcpiOsCreateLock (&AcpiGbl_HardwareLock);
108    if (ACPI_FAILURE (Status))
109    {
110        return_ACPI_STATUS (Status);
111    }
112
113    /* Mutex for _OSI support */
114    Status = AcpiOsCreateMutex (&AcpiGbl_OsiMutex);
115    if (ACPI_FAILURE (Status))
116    {
117        return_ACPI_STATUS (Status);
118    }
119
120    /* Create the reader/writer lock for namespace access */
121
122    Status = AcpiUtCreateRwLock (&AcpiGbl_NamespaceRwLock);
123    return_ACPI_STATUS (Status);
124}
125
126
127/*******************************************************************************
128 *
129 * FUNCTION:    AcpiUtMutexTerminate
130 *
131 * PARAMETERS:  None.
132 *
133 * RETURN:      None.
134 *
135 * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
136 *              spin locks, and reader/writer locks.
137 *
138 ******************************************************************************/
139
140void
141AcpiUtMutexTerminate (
142    void)
143{
144    UINT32                  i;
145
146
147    ACPI_FUNCTION_TRACE (UtMutexTerminate);
148
149
150    /* Delete each predefined mutex object */
151
152    for (i = 0; i < ACPI_NUM_MUTEX; i++)
153    {
154        AcpiUtDeleteMutex (i);
155    }
156
157    AcpiOsDeleteMutex (AcpiGbl_OsiMutex);
158
159    /* Delete the spinlocks */
160
161    AcpiOsDeleteLock (AcpiGbl_GpeLock);
162    AcpiOsDeleteLock (AcpiGbl_HardwareLock);
163
164    /* Delete the reader/writer lock */
165
166    AcpiUtDeleteRwLock (&AcpiGbl_NamespaceRwLock);
167    return_VOID;
168}
169
170
171/*******************************************************************************
172 *
173 * FUNCTION:    AcpiUtCreateMutex
174 *
175 * PARAMETERS:  MutexID         - ID of the mutex to be created
176 *
177 * RETURN:      Status
178 *
179 * DESCRIPTION: Create a mutex object.
180 *
181 ******************************************************************************/
182
183static ACPI_STATUS
184AcpiUtCreateMutex (
185    ACPI_MUTEX_HANDLE       MutexId)
186{
187    ACPI_STATUS             Status = AE_OK;
188
189
190    ACPI_FUNCTION_TRACE_U32 (UtCreateMutex, MutexId);
191
192
193    if (!AcpiGbl_MutexInfo[MutexId].Mutex)
194    {
195        Status = AcpiOsCreateMutex (&AcpiGbl_MutexInfo[MutexId].Mutex);
196        AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
197        AcpiGbl_MutexInfo[MutexId].UseCount = 0;
198    }
199
200    return_ACPI_STATUS (Status);
201}
202
203
204/*******************************************************************************
205 *
206 * FUNCTION:    AcpiUtDeleteMutex
207 *
208 * PARAMETERS:  MutexID         - ID of the mutex to be deleted
209 *
210 * RETURN:      Status
211 *
212 * DESCRIPTION: Delete a mutex object.
213 *
214 ******************************************************************************/
215
216static void
217AcpiUtDeleteMutex (
218    ACPI_MUTEX_HANDLE       MutexId)
219{
220
221    ACPI_FUNCTION_TRACE_U32 (UtDeleteMutex, MutexId);
222
223
224    AcpiOsDeleteMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
225
226    AcpiGbl_MutexInfo[MutexId].Mutex = NULL;
227    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
228
229    return_VOID;
230}
231
232
233/*******************************************************************************
234 *
235 * FUNCTION:    AcpiUtAcquireMutex
236 *
237 * PARAMETERS:  MutexID         - ID of the mutex to be acquired
238 *
239 * RETURN:      Status
240 *
241 * DESCRIPTION: Acquire a mutex object.
242 *
243 ******************************************************************************/
244
245ACPI_STATUS
246AcpiUtAcquireMutex (
247    ACPI_MUTEX_HANDLE       MutexId)
248{
249    ACPI_STATUS             Status;
250    ACPI_THREAD_ID          ThisThreadId;
251
252
253    ACPI_FUNCTION_NAME (UtAcquireMutex);
254
255
256    if (MutexId > ACPI_MAX_MUTEX)
257    {
258        return (AE_BAD_PARAMETER);
259    }
260
261    ThisThreadId = AcpiOsGetThreadId ();
262
263#ifdef ACPI_MUTEX_DEBUG
264    {
265        UINT32                  i;
266        /*
267         * Mutex debug code, for internal debugging only.
268         *
269         * Deadlock prevention. Check if this thread owns any mutexes of value
270         * greater than or equal to this one. If so, the thread has violated
271         * the mutex ordering rule. This indicates a coding error somewhere in
272         * the ACPI subsystem code.
273         */
274        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
275        {
276            if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId)
277            {
278                if (i == MutexId)
279                {
280                    ACPI_ERROR ((AE_INFO,
281                        "Mutex [%s] already acquired by this thread [%u]",
282                        AcpiUtGetMutexName (MutexId),
283                        (UINT32) ThisThreadId));
284
285                    return (AE_ALREADY_ACQUIRED);
286                }
287
288                ACPI_ERROR ((AE_INFO,
289                    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
290                    (UINT32) ThisThreadId, AcpiUtGetMutexName (i),
291                    AcpiUtGetMutexName (MutexId)));
292
293                return (AE_ACQUIRE_DEADLOCK);
294            }
295        }
296    }
297#endif
298
299    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
300        "Thread %u attempting to acquire Mutex [%s]\n",
301        (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
302
303    Status = AcpiOsAcquireMutex (AcpiGbl_MutexInfo[MutexId].Mutex,
304                ACPI_WAIT_FOREVER);
305    if (ACPI_SUCCESS (Status))
306    {
307        ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u acquired Mutex [%s]\n",
308            (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
309
310        AcpiGbl_MutexInfo[MutexId].UseCount++;
311        AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId;
312    }
313    else
314    {
315        ACPI_EXCEPTION ((AE_INFO, Status,
316            "Thread %u could not acquire Mutex [0x%X]",
317            (UINT32) ThisThreadId, MutexId));
318    }
319
320    return (Status);
321}
322
323
324/*******************************************************************************
325 *
326 * FUNCTION:    AcpiUtReleaseMutex
327 *
328 * PARAMETERS:  MutexID         - ID of the mutex to be released
329 *
330 * RETURN:      Status
331 *
332 * DESCRIPTION: Release a mutex object.
333 *
334 ******************************************************************************/
335
336ACPI_STATUS
337AcpiUtReleaseMutex (
338    ACPI_MUTEX_HANDLE       MutexId)
339{
340    ACPI_FUNCTION_NAME (UtReleaseMutex);
341
342
343    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
344        (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId)));
345
346    if (MutexId > ACPI_MAX_MUTEX)
347    {
348        return (AE_BAD_PARAMETER);
349    }
350
351    /*
352     * Mutex must be acquired in order to release it!
353     */
354    if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED)
355    {
356        ACPI_ERROR ((AE_INFO,
357            "Mutex [0x%X] is not acquired, cannot release", MutexId));
358
359        return (AE_NOT_ACQUIRED);
360    }
361
362#ifdef ACPI_MUTEX_DEBUG
363    {
364        UINT32                  i;
365        /*
366         * Mutex debug code, for internal debugging only.
367         *
368         * Deadlock prevention. Check if this thread owns any mutexes of value
369         * greater than this one. If so, the thread has violated the mutex
370         * ordering rule. This indicates a coding error somewhere in
371         * the ACPI subsystem code.
372         */
373        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
374        {
375            if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ())
376            {
377                if (i == MutexId)
378                {
379                    continue;
380                }
381
382                ACPI_ERROR ((AE_INFO,
383                    "Invalid release order: owns [%s], releasing [%s]",
384                    AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId)));
385
386                return (AE_RELEASE_DEADLOCK);
387            }
388        }
389    }
390#endif
391
392    /* Mark unlocked FIRST */
393
394    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
395
396    AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
397    return (AE_OK);
398}
399