utmutex.c revision 306536
1178170Simp/*******************************************************************************
2178170Simp *
3178170Simp * Module Name: utmutex - local mutex support
4178170Simp *
5178170Simp ******************************************************************************/
6178170Simp
7241933Simp/*
8241933Simp * Copyright (C) 2000 - 2016, Intel Corp.
9241933Simp * All rights reserved.
10241933Simp *
11241933Simp * Redistribution and use in source and binary forms, with or without
12241933Simp * modification, are permitted provided that the following conditions
13241933Simp * are met:
14241933Simp * 1. Redistributions of source code must retain the above copyright
15241933Simp *    notice, this list of conditions, and the following disclaimer,
16241933Simp *    without modification.
17241933Simp * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18241933Simp *    substantially similar to the "NO WARRANTY" disclaimer below
19241933Simp *    ("Disclaimer") and any redistribution must be conditioned upon
20241933Simp *    including a substantially similar Disclaimer requirement for further
21242066Simp *    binary redistribution.
22241933Simp * 3. Neither the names of the above-listed copyright holders nor the names
23241933Simp *    of any contributors may be used to endorse or promote products derived
24241933Simp *    from this software without specific prior written permission.
25241933Simp *
26241933Simp * Alternatively, this software may be distributed under the terms of the
27241933Simp * GNU General Public License ("GPL") version 2 as published by the Free
28241933Simp * Software Foundation.
29241933Simp *
30241933Simp * NO WARRANTY
31241933Simp * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32292556Sian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33241933Simp * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34241933Simp * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35241933Simp * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36241933Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37242162Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38251524Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39251524Sed * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40241933Simp * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41255367Sjchandra * POSSIBILITY OF SUCH DAMAGES.
42241933Simp */
43241933Simp
44241933Simp#include <contrib/dev/acpica/include/acpi.h>
45241933Simp#include <contrib/dev/acpica/include/accommon.h>
46241933Simp
47241933Simp#define _COMPONENT          ACPI_UTILITIES
48241933Simp        ACPI_MODULE_NAME    ("utmutex")
49178170Simp
50241933Simp/* Local prototypes */
51241933Simp
52241933Simpstatic ACPI_STATUS
53289701SianAcpiUtCreateMutex (
54241933Simp    ACPI_MUTEX_HANDLE       MutexId);
55269577Sglebius
56178170Simpstatic void
57241933SimpAcpiUtDeleteMutex (
58241933Simp    ACPI_MUTEX_HANDLE       MutexId);
59289765Scem
60241933Simp
61241933Simp/*******************************************************************************
62261891Savg *
63241933Simp * FUNCTION:    AcpiUtMutexInitialize
64255290Sglebius *
65242064Simp * PARAMETERS:  None.
66284587Sadrian *
67284587Sadrian * RETURN:      Status
68241933Simp *
69241936Simp * DESCRIPTION: Create the system mutex objects. This includes mutexes,
70241933Simp *              spin locks, and reader/writer locks.
71241933Simp *
72241933Simp ******************************************************************************/
73241936Simp
74241936SimpACPI_STATUS
75241936SimpAcpiUtMutexInitialize (
76241936Simp    void)
77241936Simp{
78241936Simp    UINT32                  i;
79241936Simp    ACPI_STATUS             Status;
80241953Simp
81241953Simp
82250840Smarcel    ACPI_FUNCTION_TRACE (UtMutexInitialize);
83241954Simp
84241954Simp
85315514Sae    /* Create each of the predefined mutex objects */
86315514Sae
87315514Sae    for (i = 0; i < ACPI_NUM_MUTEX; i++)
88315514Sae    {
89241964Simp        Status = AcpiUtCreateMutex (i);
90242204Simp        if (ACPI_FAILURE (Status))
91241964Simp        {
92241986Simp            return_ACPI_STATUS (Status);
93242204Simp        }
94242004Simp    }
95243178Sadrian
96281098Sadrian    /* Create the spinlocks for use at interrupt level or for speed */
97297392Szbb
98297392Szbb    Status = AcpiOsCreateLock (&AcpiGbl_GpeLock);
99297392Szbb    if (ACPI_FAILURE (Status))
100299118Sbr    {
101299118Sbr        return_ACPI_STATUS (Status);
102299118Sbr    }
103299118Sbr
104299118Sbr    Status = AcpiOsCreateLock (&AcpiGbl_HardwareLock);
105299118Sbr    if (ACPI_FAILURE (Status))
106    {
107        return_ACPI_STATUS (Status);
108    }
109
110    Status = AcpiOsCreateLock (&AcpiGbl_ReferenceCountLock);
111    if (ACPI_FAILURE (Status))
112    {
113        return_ACPI_STATUS (Status);
114    }
115
116    /* Mutex for _OSI support */
117
118    Status = AcpiOsCreateMutex (&AcpiGbl_OsiMutex);
119    if (ACPI_FAILURE (Status))
120    {
121        return_ACPI_STATUS (Status);
122    }
123
124    /* Create the reader/writer lock for namespace access */
125
126    Status = AcpiUtCreateRwLock (&AcpiGbl_NamespaceRwLock);
127    if (ACPI_FAILURE (Status))
128    {
129        return_ACPI_STATUS (Status);
130    }
131
132#ifdef ACPI_DEBUGGER
133
134    /* Debugger Support */
135
136    Status = AcpiOsCreateMutex (&AcpiGbl_DbCommandReady);
137    if (ACPI_FAILURE (Status))
138    {
139        return_ACPI_STATUS (Status);
140    }
141
142    Status = AcpiOsCreateMutex (&AcpiGbl_DbCommandComplete);
143#endif
144
145    return_ACPI_STATUS (Status);
146}
147
148
149/*******************************************************************************
150 *
151 * FUNCTION:    AcpiUtMutexTerminate
152 *
153 * PARAMETERS:  None.
154 *
155 * RETURN:      None.
156 *
157 * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
158 *              spin locks, and reader/writer locks.
159 *
160 ******************************************************************************/
161
162void
163AcpiUtMutexTerminate (
164    void)
165{
166    UINT32                  i;
167
168
169    ACPI_FUNCTION_TRACE (UtMutexTerminate);
170
171
172    /* Delete each predefined mutex object */
173
174    for (i = 0; i < ACPI_NUM_MUTEX; i++)
175    {
176        AcpiUtDeleteMutex (i);
177    }
178
179    AcpiOsDeleteMutex (AcpiGbl_OsiMutex);
180
181    /* Delete the spinlocks */
182
183    AcpiOsDeleteLock (AcpiGbl_GpeLock);
184    AcpiOsDeleteLock (AcpiGbl_HardwareLock);
185    AcpiOsDeleteLock (AcpiGbl_ReferenceCountLock);
186
187    /* Delete the reader/writer lock */
188
189    AcpiUtDeleteRwLock (&AcpiGbl_NamespaceRwLock);
190
191#ifdef ACPI_DEBUGGER
192    AcpiOsDeleteMutex (AcpiGbl_DbCommandReady);
193    AcpiOsDeleteMutex (AcpiGbl_DbCommandComplete);
194#endif
195
196    return_VOID;
197}
198
199
200/*******************************************************************************
201 *
202 * FUNCTION:    AcpiUtCreateMutex
203 *
204 * PARAMETERS:  MutexID         - ID of the mutex to be created
205 *
206 * RETURN:      Status
207 *
208 * DESCRIPTION: Create a mutex object.
209 *
210 ******************************************************************************/
211
212static ACPI_STATUS
213AcpiUtCreateMutex (
214    ACPI_MUTEX_HANDLE       MutexId)
215{
216    ACPI_STATUS             Status = AE_OK;
217
218
219    ACPI_FUNCTION_TRACE_U32 (UtCreateMutex, MutexId);
220
221
222    if (!AcpiGbl_MutexInfo[MutexId].Mutex)
223    {
224        Status = AcpiOsCreateMutex (&AcpiGbl_MutexInfo[MutexId].Mutex);
225        AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
226        AcpiGbl_MutexInfo[MutexId].UseCount = 0;
227    }
228
229    return_ACPI_STATUS (Status);
230}
231
232
233/*******************************************************************************
234 *
235 * FUNCTION:    AcpiUtDeleteMutex
236 *
237 * PARAMETERS:  MutexID         - ID of the mutex to be deleted
238 *
239 * RETURN:      Status
240 *
241 * DESCRIPTION: Delete a mutex object.
242 *
243 ******************************************************************************/
244
245static void
246AcpiUtDeleteMutex (
247    ACPI_MUTEX_HANDLE       MutexId)
248{
249
250    ACPI_FUNCTION_TRACE_U32 (UtDeleteMutex, MutexId);
251
252
253    AcpiOsDeleteMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
254
255    AcpiGbl_MutexInfo[MutexId].Mutex = NULL;
256    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
257
258    return_VOID;
259}
260
261
262/*******************************************************************************
263 *
264 * FUNCTION:    AcpiUtAcquireMutex
265 *
266 * PARAMETERS:  MutexID         - ID of the mutex to be acquired
267 *
268 * RETURN:      Status
269 *
270 * DESCRIPTION: Acquire a mutex object.
271 *
272 ******************************************************************************/
273
274ACPI_STATUS
275AcpiUtAcquireMutex (
276    ACPI_MUTEX_HANDLE       MutexId)
277{
278    ACPI_STATUS             Status;
279    ACPI_THREAD_ID          ThisThreadId;
280
281
282    ACPI_FUNCTION_NAME (UtAcquireMutex);
283
284
285    if (MutexId > ACPI_MAX_MUTEX)
286    {
287        return (AE_BAD_PARAMETER);
288    }
289
290    ThisThreadId = AcpiOsGetThreadId ();
291
292#ifdef ACPI_MUTEX_DEBUG
293    {
294        UINT32                  i;
295        /*
296         * Mutex debug code, for internal debugging only.
297         *
298         * Deadlock prevention. Check if this thread owns any mutexes of value
299         * greater than or equal to this one. If so, the thread has violated
300         * the mutex ordering rule. This indicates a coding error somewhere in
301         * the ACPI subsystem code.
302         */
303        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
304        {
305            if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId)
306            {
307                if (i == MutexId)
308                {
309                    ACPI_ERROR ((AE_INFO,
310                        "Mutex [%s] already acquired by this thread [%u]",
311                        AcpiUtGetMutexName (MutexId),
312                        (UINT32) ThisThreadId));
313
314                    return (AE_ALREADY_ACQUIRED);
315                }
316
317                ACPI_ERROR ((AE_INFO,
318                    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
319                    (UINT32) ThisThreadId, AcpiUtGetMutexName (i),
320                    AcpiUtGetMutexName (MutexId)));
321
322                return (AE_ACQUIRE_DEADLOCK);
323            }
324        }
325    }
326#endif
327
328    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
329        "Thread %u attempting to acquire Mutex [%s]\n",
330        (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
331
332    Status = AcpiOsAcquireMutex (
333        AcpiGbl_MutexInfo[MutexId].Mutex, ACPI_WAIT_FOREVER);
334    if (ACPI_SUCCESS (Status))
335    {
336        ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
337            "Thread %u acquired Mutex [%s]\n",
338            (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
339
340        AcpiGbl_MutexInfo[MutexId].UseCount++;
341        AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId;
342    }
343    else
344    {
345        ACPI_EXCEPTION ((AE_INFO, Status,
346            "Thread %u could not acquire Mutex [0x%X]",
347            (UINT32) ThisThreadId, MutexId));
348    }
349
350    return (Status);
351}
352
353
354/*******************************************************************************
355 *
356 * FUNCTION:    AcpiUtReleaseMutex
357 *
358 * PARAMETERS:  MutexID         - ID of the mutex to be released
359 *
360 * RETURN:      Status
361 *
362 * DESCRIPTION: Release a mutex object.
363 *
364 ******************************************************************************/
365
366ACPI_STATUS
367AcpiUtReleaseMutex (
368    ACPI_MUTEX_HANDLE       MutexId)
369{
370    ACPI_FUNCTION_NAME (UtReleaseMutex);
371
372
373    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
374        (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId)));
375
376    if (MutexId > ACPI_MAX_MUTEX)
377    {
378        return (AE_BAD_PARAMETER);
379    }
380
381    /*
382     * Mutex must be acquired in order to release it!
383     */
384    if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED)
385    {
386        ACPI_ERROR ((AE_INFO,
387            "Mutex [0x%X] is not acquired, cannot release", MutexId));
388
389        return (AE_NOT_ACQUIRED);
390    }
391
392#ifdef ACPI_MUTEX_DEBUG
393    {
394        UINT32                  i;
395        /*
396         * Mutex debug code, for internal debugging only.
397         *
398         * Deadlock prevention. Check if this thread owns any mutexes of value
399         * greater than this one. If so, the thread has violated the mutex
400         * ordering rule. This indicates a coding error somewhere in
401         * the ACPI subsystem code.
402         */
403        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
404        {
405            if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ())
406            {
407                if (i == MutexId)
408                {
409                    continue;
410                }
411
412                ACPI_ERROR ((AE_INFO,
413                    "Invalid release order: owns [%s], releasing [%s]",
414                    AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId)));
415
416                return (AE_RELEASE_DEADLOCK);
417            }
418        }
419    }
420#endif
421
422    /* Mark unlocked FIRST */
423
424    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
425
426    AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
427    return (AE_OK);
428}
429