utmutex.c revision 229989
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
230
231/*******************************************************************************
232 *
233 * FUNCTION:    AcpiUtAcquireMutex
234 *
235 * PARAMETERS:  MutexID         - ID of the mutex to be acquired
236 *
237 * RETURN:      Status
238 *
239 * DESCRIPTION: Acquire a mutex object.
240 *
241 ******************************************************************************/
242
243ACPI_STATUS
244AcpiUtAcquireMutex (
245    ACPI_MUTEX_HANDLE       MutexId)
246{
247    ACPI_STATUS             Status;
248    ACPI_THREAD_ID          ThisThreadId;
249
250
251    ACPI_FUNCTION_NAME (UtAcquireMutex);
252
253
254    if (MutexId > ACPI_MAX_MUTEX)
255    {
256        return (AE_BAD_PARAMETER);
257    }
258
259    ThisThreadId = AcpiOsGetThreadId ();
260
261#ifdef ACPI_MUTEX_DEBUG
262    {
263        UINT32                  i;
264        /*
265         * Mutex debug code, for internal debugging only.
266         *
267         * Deadlock prevention.  Check if this thread owns any mutexes of value
268         * greater than or equal to this one.  If so, the thread has violated
269         * the mutex ordering rule.  This indicates a coding error somewhere in
270         * the ACPI subsystem code.
271         */
272        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
273        {
274            if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId)
275            {
276                if (i == MutexId)
277                {
278                    ACPI_ERROR ((AE_INFO,
279                        "Mutex [%s] already acquired by this thread [%u]",
280                        AcpiUtGetMutexName (MutexId),
281                        (UINT32) ThisThreadId));
282
283                    return (AE_ALREADY_ACQUIRED);
284                }
285
286                ACPI_ERROR ((AE_INFO,
287                    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
288                    (UINT32) ThisThreadId, AcpiUtGetMutexName (i),
289                    AcpiUtGetMutexName (MutexId)));
290
291                return (AE_ACQUIRE_DEADLOCK);
292            }
293        }
294    }
295#endif
296
297    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
298        "Thread %u attempting to acquire Mutex [%s]\n",
299        (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
300
301    Status = AcpiOsAcquireMutex (AcpiGbl_MutexInfo[MutexId].Mutex,
302                ACPI_WAIT_FOREVER);
303    if (ACPI_SUCCESS (Status))
304    {
305        ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u acquired Mutex [%s]\n",
306            (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
307
308        AcpiGbl_MutexInfo[MutexId].UseCount++;
309        AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId;
310    }
311    else
312    {
313        ACPI_EXCEPTION ((AE_INFO, Status,
314            "Thread %u could not acquire Mutex [0x%X]",
315            (UINT32) ThisThreadId, MutexId));
316    }
317
318    return (Status);
319}
320
321
322/*******************************************************************************
323 *
324 * FUNCTION:    AcpiUtReleaseMutex
325 *
326 * PARAMETERS:  MutexID         - ID of the mutex to be released
327 *
328 * RETURN:      Status
329 *
330 * DESCRIPTION: Release a mutex object.
331 *
332 ******************************************************************************/
333
334ACPI_STATUS
335AcpiUtReleaseMutex (
336    ACPI_MUTEX_HANDLE       MutexId)
337{
338    ACPI_FUNCTION_NAME (UtReleaseMutex);
339
340    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
341        (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId)));
342
343    if (MutexId > ACPI_MAX_MUTEX)
344    {
345        return (AE_BAD_PARAMETER);
346    }
347
348    /*
349     * Mutex must be acquired in order to release it!
350     */
351    if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED)
352    {
353        ACPI_ERROR ((AE_INFO,
354            "Mutex [0x%X] is not acquired, cannot release", MutexId));
355
356        return (AE_NOT_ACQUIRED);
357    }
358
359#ifdef ACPI_MUTEX_DEBUG
360    {
361        UINT32                  i;
362        /*
363         * Mutex debug code, for internal debugging only.
364         *
365         * Deadlock prevention.  Check if this thread owns any mutexes of value
366         * greater than this one.  If so, the thread has violated the mutex
367         * ordering rule.  This indicates a coding error somewhere in
368         * the ACPI subsystem code.
369         */
370        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
371        {
372            if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ())
373            {
374                if (i == MutexId)
375                {
376                    continue;
377                }
378
379                ACPI_ERROR ((AE_INFO,
380                    "Invalid release order: owns [%s], releasing [%s]",
381                    AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId)));
382
383                return (AE_RELEASE_DEADLOCK);
384            }
385        }
386    }
387#endif
388
389    /* Mark unlocked FIRST */
390
391    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
392
393    AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
394    return (AE_OK);
395}
396
397
398