1151937Sjkim/*******************************************************************************
2151937Sjkim *
3151937Sjkim * Module Name: utmutex - local mutex support
4151937Sjkim *
5151937Sjkim ******************************************************************************/
6151937Sjkim
7217365Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp.
9151937Sjkim * All rights reserved.
10151937Sjkim *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
25151937Sjkim *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
29151937Sjkim *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
43151937Sjkim
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46151937Sjkim
47151937Sjkim#define _COMPONENT          ACPI_UTILITIES
48151937Sjkim        ACPI_MODULE_NAME    ("utmutex")
49151937Sjkim
50151937Sjkim/* Local prototypes */
51151937Sjkim
52151937Sjkimstatic ACPI_STATUS
53151937SjkimAcpiUtCreateMutex (
54151937Sjkim    ACPI_MUTEX_HANDLE       MutexId);
55151937Sjkim
56202771Sjkimstatic void
57151937SjkimAcpiUtDeleteMutex (
58151937Sjkim    ACPI_MUTEX_HANDLE       MutexId);
59151937Sjkim
60151937Sjkim
61151937Sjkim/*******************************************************************************
62151937Sjkim *
63151937Sjkim * FUNCTION:    AcpiUtMutexInitialize
64151937Sjkim *
65151937Sjkim * PARAMETERS:  None.
66151937Sjkim *
67151937Sjkim * RETURN:      Status
68151937Sjkim *
69193267Sjkim * DESCRIPTION: Create the system mutex objects. This includes mutexes,
70193267Sjkim *              spin locks, and reader/writer locks.
71151937Sjkim *
72151937Sjkim ******************************************************************************/
73151937Sjkim
74151937SjkimACPI_STATUS
75151937SjkimAcpiUtMutexInitialize (
76151937Sjkim    void)
77151937Sjkim{
78151937Sjkim    UINT32                  i;
79151937Sjkim    ACPI_STATUS             Status;
80151937Sjkim
81151937Sjkim
82167802Sjkim    ACPI_FUNCTION_TRACE (UtMutexInitialize);
83151937Sjkim
84151937Sjkim
85193267Sjkim    /* Create each of the predefined mutex objects */
86193267Sjkim
87167802Sjkim    for (i = 0; i < ACPI_NUM_MUTEX; i++)
88151937Sjkim    {
89151937Sjkim        Status = AcpiUtCreateMutex (i);
90151937Sjkim        if (ACPI_FAILURE (Status))
91151937Sjkim        {
92151937Sjkim            return_ACPI_STATUS (Status);
93151937Sjkim        }
94151937Sjkim    }
95151937Sjkim
96249112Sjkim    /* Create the spinlocks for use at interrupt level or for speed */
97167802Sjkim
98151937Sjkim    Status = AcpiOsCreateLock (&AcpiGbl_GpeLock);
99167802Sjkim    if (ACPI_FAILURE (Status))
100167802Sjkim    {
101167802Sjkim        return_ACPI_STATUS (Status);
102167802Sjkim    }
103167802Sjkim
104167802Sjkim    Status = AcpiOsCreateLock (&AcpiGbl_HardwareLock);
105193267Sjkim    if (ACPI_FAILURE (Status))
106193267Sjkim    {
107193267Sjkim        return_ACPI_STATUS (Status);
108193267Sjkim    }
109193267Sjkim
110249112Sjkim    Status = AcpiOsCreateLock (&AcpiGbl_ReferenceCountLock);
111249112Sjkim    if (ACPI_FAILURE (Status))
112249112Sjkim    {
113249112Sjkim        return_ACPI_STATUS (Status);
114249112Sjkim    }
115249112Sjkim
116210976Sjkim    /* Mutex for _OSI support */
117249112Sjkim
118210976Sjkim    Status = AcpiOsCreateMutex (&AcpiGbl_OsiMutex);
119210976Sjkim    if (ACPI_FAILURE (Status))
120210976Sjkim    {
121210976Sjkim        return_ACPI_STATUS (Status);
122210976Sjkim    }
123210976Sjkim
124193267Sjkim    /* Create the reader/writer lock for namespace access */
125193267Sjkim
126193267Sjkim    Status = AcpiUtCreateRwLock (&AcpiGbl_NamespaceRwLock);
127151937Sjkim    return_ACPI_STATUS (Status);
128151937Sjkim}
129151937Sjkim
130151937Sjkim
131151937Sjkim/*******************************************************************************
132151937Sjkim *
133151937Sjkim * FUNCTION:    AcpiUtMutexTerminate
134151937Sjkim *
135151937Sjkim * PARAMETERS:  None.
136151937Sjkim *
137151937Sjkim * RETURN:      None.
138151937Sjkim *
139193267Sjkim * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
140193267Sjkim *              spin locks, and reader/writer locks.
141151937Sjkim *
142151937Sjkim ******************************************************************************/
143151937Sjkim
144151937Sjkimvoid
145151937SjkimAcpiUtMutexTerminate (
146151937Sjkim    void)
147151937Sjkim{
148151937Sjkim    UINT32                  i;
149151937Sjkim
150151937Sjkim
151167802Sjkim    ACPI_FUNCTION_TRACE (UtMutexTerminate);
152151937Sjkim
153151937Sjkim
154193267Sjkim    /* Delete each predefined mutex object */
155193267Sjkim
156167802Sjkim    for (i = 0; i < ACPI_NUM_MUTEX; i++)
157151937Sjkim    {
158202771Sjkim        AcpiUtDeleteMutex (i);
159151937Sjkim    }
160151937Sjkim
161210976Sjkim    AcpiOsDeleteMutex (AcpiGbl_OsiMutex);
162210976Sjkim
163167802Sjkim    /* Delete the spinlocks */
164167802Sjkim
165151937Sjkim    AcpiOsDeleteLock (AcpiGbl_GpeLock);
166167802Sjkim    AcpiOsDeleteLock (AcpiGbl_HardwareLock);
167249112Sjkim    AcpiOsDeleteLock (AcpiGbl_ReferenceCountLock);
168193267Sjkim
169193267Sjkim    /* Delete the reader/writer lock */
170193267Sjkim
171193267Sjkim    AcpiUtDeleteRwLock (&AcpiGbl_NamespaceRwLock);
172151937Sjkim    return_VOID;
173151937Sjkim}
174151937Sjkim
175151937Sjkim
176151937Sjkim/*******************************************************************************
177151937Sjkim *
178151937Sjkim * FUNCTION:    AcpiUtCreateMutex
179151937Sjkim *
180151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be created
181151937Sjkim *
182151937Sjkim * RETURN:      Status
183151937Sjkim *
184151937Sjkim * DESCRIPTION: Create a mutex object.
185151937Sjkim *
186151937Sjkim ******************************************************************************/
187151937Sjkim
188151937Sjkimstatic ACPI_STATUS
189151937SjkimAcpiUtCreateMutex (
190151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
191151937Sjkim{
192151937Sjkim    ACPI_STATUS             Status = AE_OK;
193151937Sjkim
194151937Sjkim
195167802Sjkim    ACPI_FUNCTION_TRACE_U32 (UtCreateMutex, MutexId);
196151937Sjkim
197151937Sjkim
198151937Sjkim    if (!AcpiGbl_MutexInfo[MutexId].Mutex)
199151937Sjkim    {
200167802Sjkim        Status = AcpiOsCreateMutex (&AcpiGbl_MutexInfo[MutexId].Mutex);
201151937Sjkim        AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
202151937Sjkim        AcpiGbl_MutexInfo[MutexId].UseCount = 0;
203151937Sjkim    }
204151937Sjkim
205151937Sjkim    return_ACPI_STATUS (Status);
206151937Sjkim}
207151937Sjkim
208151937Sjkim
209151937Sjkim/*******************************************************************************
210151937Sjkim *
211151937Sjkim * FUNCTION:    AcpiUtDeleteMutex
212151937Sjkim *
213151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be deleted
214151937Sjkim *
215151937Sjkim * RETURN:      Status
216151937Sjkim *
217151937Sjkim * DESCRIPTION: Delete a mutex object.
218151937Sjkim *
219151937Sjkim ******************************************************************************/
220151937Sjkim
221202771Sjkimstatic void
222151937SjkimAcpiUtDeleteMutex (
223151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
224151937Sjkim{
225151937Sjkim
226167802Sjkim    ACPI_FUNCTION_TRACE_U32 (UtDeleteMutex, MutexId);
227151937Sjkim
228151937Sjkim
229167802Sjkim    AcpiOsDeleteMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
230151937Sjkim
231151937Sjkim    AcpiGbl_MutexInfo[MutexId].Mutex = NULL;
232151937Sjkim    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
233241973Sjkim
234241973Sjkim    return_VOID;
235151937Sjkim}
236151937Sjkim
237151937Sjkim
238151937Sjkim/*******************************************************************************
239151937Sjkim *
240151937Sjkim * FUNCTION:    AcpiUtAcquireMutex
241151937Sjkim *
242151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be acquired
243151937Sjkim *
244151937Sjkim * RETURN:      Status
245151937Sjkim *
246151937Sjkim * DESCRIPTION: Acquire a mutex object.
247151937Sjkim *
248151937Sjkim ******************************************************************************/
249151937Sjkim
250151937SjkimACPI_STATUS
251151937SjkimAcpiUtAcquireMutex (
252151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
253151937Sjkim{
254151937Sjkim    ACPI_STATUS             Status;
255167802Sjkim    ACPI_THREAD_ID          ThisThreadId;
256151937Sjkim
257151937Sjkim
258167802Sjkim    ACPI_FUNCTION_NAME (UtAcquireMutex);
259151937Sjkim
260151937Sjkim
261167802Sjkim    if (MutexId > ACPI_MAX_MUTEX)
262151937Sjkim    {
263151937Sjkim        return (AE_BAD_PARAMETER);
264151937Sjkim    }
265151937Sjkim
266151937Sjkim    ThisThreadId = AcpiOsGetThreadId ();
267151937Sjkim
268151937Sjkim#ifdef ACPI_MUTEX_DEBUG
269151937Sjkim    {
270151937Sjkim        UINT32                  i;
271151937Sjkim        /*
272151937Sjkim         * Mutex debug code, for internal debugging only.
273151937Sjkim         *
274241973Sjkim         * Deadlock prevention. Check if this thread owns any mutexes of value
275241973Sjkim         * greater than or equal to this one. If so, the thread has violated
276241973Sjkim         * the mutex ordering rule. This indicates a coding error somewhere in
277151937Sjkim         * the ACPI subsystem code.
278151937Sjkim         */
279193267Sjkim        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
280151937Sjkim        {
281151937Sjkim            if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId)
282151937Sjkim            {
283151937Sjkim                if (i == MutexId)
284151937Sjkim                {
285167802Sjkim                    ACPI_ERROR ((AE_INFO,
286212761Sjkim                        "Mutex [%s] already acquired by this thread [%u]",
287193267Sjkim                        AcpiUtGetMutexName (MutexId),
288212761Sjkim                        (UINT32) ThisThreadId));
289151937Sjkim
290151937Sjkim                    return (AE_ALREADY_ACQUIRED);
291151937Sjkim                }
292151937Sjkim
293167802Sjkim                ACPI_ERROR ((AE_INFO,
294212761Sjkim                    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
295212761Sjkim                    (UINT32) ThisThreadId, AcpiUtGetMutexName (i),
296151937Sjkim                    AcpiUtGetMutexName (MutexId)));
297151937Sjkim
298151937Sjkim                return (AE_ACQUIRE_DEADLOCK);
299151937Sjkim            }
300151937Sjkim        }
301151937Sjkim    }
302151937Sjkim#endif
303151937Sjkim
304151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
305212761Sjkim        "Thread %u attempting to acquire Mutex [%s]\n",
306212761Sjkim        (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
307151937Sjkim
308167802Sjkim    Status = AcpiOsAcquireMutex (AcpiGbl_MutexInfo[MutexId].Mutex,
309167802Sjkim                ACPI_WAIT_FOREVER);
310151937Sjkim    if (ACPI_SUCCESS (Status))
311151937Sjkim    {
312212761Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u acquired Mutex [%s]\n",
313212761Sjkim            (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
314151937Sjkim
315151937Sjkim        AcpiGbl_MutexInfo[MutexId].UseCount++;
316151937Sjkim        AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId;
317151937Sjkim    }
318151937Sjkim    else
319151937Sjkim    {
320167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status,
321212761Sjkim            "Thread %u could not acquire Mutex [0x%X]",
322212761Sjkim            (UINT32) ThisThreadId, MutexId));
323151937Sjkim    }
324151937Sjkim
325151937Sjkim    return (Status);
326151937Sjkim}
327151937Sjkim
328151937Sjkim
329151937Sjkim/*******************************************************************************
330151937Sjkim *
331151937Sjkim * FUNCTION:    AcpiUtReleaseMutex
332151937Sjkim *
333151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be released
334151937Sjkim *
335151937Sjkim * RETURN:      Status
336151937Sjkim *
337151937Sjkim * DESCRIPTION: Release a mutex object.
338151937Sjkim *
339151937Sjkim ******************************************************************************/
340151937Sjkim
341151937SjkimACPI_STATUS
342151937SjkimAcpiUtReleaseMutex (
343151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
344151937Sjkim{
345167802Sjkim    ACPI_FUNCTION_NAME (UtReleaseMutex);
346151937Sjkim
347241973Sjkim
348212761Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
349228110Sjkim        (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId)));
350151937Sjkim
351167802Sjkim    if (MutexId > ACPI_MAX_MUTEX)
352151937Sjkim    {
353151937Sjkim        return (AE_BAD_PARAMETER);
354151937Sjkim    }
355151937Sjkim
356151937Sjkim    /*
357151937Sjkim     * Mutex must be acquired in order to release it!
358151937Sjkim     */
359151937Sjkim    if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED)
360151937Sjkim    {
361167802Sjkim        ACPI_ERROR ((AE_INFO,
362204773Sjkim            "Mutex [0x%X] is not acquired, cannot release", MutexId));
363151937Sjkim
364151937Sjkim        return (AE_NOT_ACQUIRED);
365151937Sjkim    }
366151937Sjkim
367151937Sjkim#ifdef ACPI_MUTEX_DEBUG
368151937Sjkim    {
369151937Sjkim        UINT32                  i;
370151937Sjkim        /*
371151937Sjkim         * Mutex debug code, for internal debugging only.
372151937Sjkim         *
373241973Sjkim         * Deadlock prevention. Check if this thread owns any mutexes of value
374241973Sjkim         * greater than this one. If so, the thread has violated the mutex
375241973Sjkim         * ordering rule. This indicates a coding error somewhere in
376151937Sjkim         * the ACPI subsystem code.
377151937Sjkim         */
378193267Sjkim        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
379151937Sjkim        {
380228110Sjkim            if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ())
381151937Sjkim            {
382151937Sjkim                if (i == MutexId)
383151937Sjkim                {
384151937Sjkim                    continue;
385151937Sjkim                }
386151937Sjkim
387167802Sjkim                ACPI_ERROR ((AE_INFO,
388167802Sjkim                    "Invalid release order: owns [%s], releasing [%s]",
389151937Sjkim                    AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId)));
390151937Sjkim
391151937Sjkim                return (AE_RELEASE_DEADLOCK);
392151937Sjkim            }
393151937Sjkim        }
394151937Sjkim    }
395151937Sjkim#endif
396151937Sjkim
397151937Sjkim    /* Mark unlocked FIRST */
398151937Sjkim
399151937Sjkim    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
400151937Sjkim
401167802Sjkim    AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
402167802Sjkim    return (AE_OK);
403151937Sjkim}
404