1151937Sjkim/*******************************************************************************
2151937Sjkim *
3151937Sjkim * Module Name: utmutex - local mutex support
4151937Sjkim *
5151937Sjkim ******************************************************************************/
6151937Sjkim
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, 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);
127306536Sjkim    if (ACPI_FAILURE (Status))
128306536Sjkim    {
129306536Sjkim        return_ACPI_STATUS (Status);
130306536Sjkim    }
131306536Sjkim
132306536Sjkim#ifdef ACPI_DEBUGGER
133306536Sjkim
134306536Sjkim    /* Debugger Support */
135306536Sjkim
136306536Sjkim    Status = AcpiOsCreateMutex (&AcpiGbl_DbCommandReady);
137306536Sjkim    if (ACPI_FAILURE (Status))
138306536Sjkim    {
139306536Sjkim        return_ACPI_STATUS (Status);
140306536Sjkim    }
141306536Sjkim
142306536Sjkim    Status = AcpiOsCreateMutex (&AcpiGbl_DbCommandComplete);
143306536Sjkim#endif
144306536Sjkim
145151937Sjkim    return_ACPI_STATUS (Status);
146151937Sjkim}
147151937Sjkim
148151937Sjkim
149151937Sjkim/*******************************************************************************
150151937Sjkim *
151151937Sjkim * FUNCTION:    AcpiUtMutexTerminate
152151937Sjkim *
153151937Sjkim * PARAMETERS:  None.
154151937Sjkim *
155151937Sjkim * RETURN:      None.
156151937Sjkim *
157193267Sjkim * DESCRIPTION: Delete all of the system mutex objects. This includes mutexes,
158193267Sjkim *              spin locks, and reader/writer locks.
159151937Sjkim *
160151937Sjkim ******************************************************************************/
161151937Sjkim
162151937Sjkimvoid
163151937SjkimAcpiUtMutexTerminate (
164151937Sjkim    void)
165151937Sjkim{
166151937Sjkim    UINT32                  i;
167151937Sjkim
168151937Sjkim
169167802Sjkim    ACPI_FUNCTION_TRACE (UtMutexTerminate);
170151937Sjkim
171151937Sjkim
172193267Sjkim    /* Delete each predefined mutex object */
173193267Sjkim
174167802Sjkim    for (i = 0; i < ACPI_NUM_MUTEX; i++)
175151937Sjkim    {
176202771Sjkim        AcpiUtDeleteMutex (i);
177151937Sjkim    }
178151937Sjkim
179210976Sjkim    AcpiOsDeleteMutex (AcpiGbl_OsiMutex);
180210976Sjkim
181167802Sjkim    /* Delete the spinlocks */
182167802Sjkim
183151937Sjkim    AcpiOsDeleteLock (AcpiGbl_GpeLock);
184167802Sjkim    AcpiOsDeleteLock (AcpiGbl_HardwareLock);
185249112Sjkim    AcpiOsDeleteLock (AcpiGbl_ReferenceCountLock);
186193267Sjkim
187193267Sjkim    /* Delete the reader/writer lock */
188193267Sjkim
189193267Sjkim    AcpiUtDeleteRwLock (&AcpiGbl_NamespaceRwLock);
190306536Sjkim
191306536Sjkim#ifdef ACPI_DEBUGGER
192306536Sjkim    AcpiOsDeleteMutex (AcpiGbl_DbCommandReady);
193306536Sjkim    AcpiOsDeleteMutex (AcpiGbl_DbCommandComplete);
194306536Sjkim#endif
195306536Sjkim
196151937Sjkim    return_VOID;
197151937Sjkim}
198151937Sjkim
199151937Sjkim
200151937Sjkim/*******************************************************************************
201151937Sjkim *
202151937Sjkim * FUNCTION:    AcpiUtCreateMutex
203151937Sjkim *
204151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be created
205151937Sjkim *
206151937Sjkim * RETURN:      Status
207151937Sjkim *
208151937Sjkim * DESCRIPTION: Create a mutex object.
209151937Sjkim *
210151937Sjkim ******************************************************************************/
211151937Sjkim
212151937Sjkimstatic ACPI_STATUS
213151937SjkimAcpiUtCreateMutex (
214151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
215151937Sjkim{
216151937Sjkim    ACPI_STATUS             Status = AE_OK;
217151937Sjkim
218151937Sjkim
219167802Sjkim    ACPI_FUNCTION_TRACE_U32 (UtCreateMutex, MutexId);
220151937Sjkim
221151937Sjkim
222151937Sjkim    if (!AcpiGbl_MutexInfo[MutexId].Mutex)
223151937Sjkim    {
224167802Sjkim        Status = AcpiOsCreateMutex (&AcpiGbl_MutexInfo[MutexId].Mutex);
225151937Sjkim        AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
226151937Sjkim        AcpiGbl_MutexInfo[MutexId].UseCount = 0;
227151937Sjkim    }
228151937Sjkim
229151937Sjkim    return_ACPI_STATUS (Status);
230151937Sjkim}
231151937Sjkim
232151937Sjkim
233151937Sjkim/*******************************************************************************
234151937Sjkim *
235151937Sjkim * FUNCTION:    AcpiUtDeleteMutex
236151937Sjkim *
237151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be deleted
238151937Sjkim *
239151937Sjkim * RETURN:      Status
240151937Sjkim *
241151937Sjkim * DESCRIPTION: Delete a mutex object.
242151937Sjkim *
243151937Sjkim ******************************************************************************/
244151937Sjkim
245202771Sjkimstatic void
246151937SjkimAcpiUtDeleteMutex (
247151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
248151937Sjkim{
249151937Sjkim
250167802Sjkim    ACPI_FUNCTION_TRACE_U32 (UtDeleteMutex, MutexId);
251151937Sjkim
252151937Sjkim
253167802Sjkim    AcpiOsDeleteMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
254151937Sjkim
255151937Sjkim    AcpiGbl_MutexInfo[MutexId].Mutex = NULL;
256151937Sjkim    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
257241973Sjkim
258241973Sjkim    return_VOID;
259151937Sjkim}
260151937Sjkim
261151937Sjkim
262151937Sjkim/*******************************************************************************
263151937Sjkim *
264151937Sjkim * FUNCTION:    AcpiUtAcquireMutex
265151937Sjkim *
266151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be acquired
267151937Sjkim *
268151937Sjkim * RETURN:      Status
269151937Sjkim *
270151937Sjkim * DESCRIPTION: Acquire a mutex object.
271151937Sjkim *
272151937Sjkim ******************************************************************************/
273151937Sjkim
274151937SjkimACPI_STATUS
275151937SjkimAcpiUtAcquireMutex (
276151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
277151937Sjkim{
278151937Sjkim    ACPI_STATUS             Status;
279167802Sjkim    ACPI_THREAD_ID          ThisThreadId;
280151937Sjkim
281151937Sjkim
282167802Sjkim    ACPI_FUNCTION_NAME (UtAcquireMutex);
283151937Sjkim
284151937Sjkim
285167802Sjkim    if (MutexId > ACPI_MAX_MUTEX)
286151937Sjkim    {
287151937Sjkim        return (AE_BAD_PARAMETER);
288151937Sjkim    }
289151937Sjkim
290151937Sjkim    ThisThreadId = AcpiOsGetThreadId ();
291151937Sjkim
292151937Sjkim#ifdef ACPI_MUTEX_DEBUG
293151937Sjkim    {
294151937Sjkim        UINT32                  i;
295151937Sjkim        /*
296151937Sjkim         * Mutex debug code, for internal debugging only.
297151937Sjkim         *
298241973Sjkim         * Deadlock prevention. Check if this thread owns any mutexes of value
299241973Sjkim         * greater than or equal to this one. If so, the thread has violated
300241973Sjkim         * the mutex ordering rule. This indicates a coding error somewhere in
301151937Sjkim         * the ACPI subsystem code.
302151937Sjkim         */
303193267Sjkim        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
304151937Sjkim        {
305151937Sjkim            if (AcpiGbl_MutexInfo[i].ThreadId == ThisThreadId)
306151937Sjkim            {
307151937Sjkim                if (i == MutexId)
308151937Sjkim                {
309167802Sjkim                    ACPI_ERROR ((AE_INFO,
310212761Sjkim                        "Mutex [%s] already acquired by this thread [%u]",
311193267Sjkim                        AcpiUtGetMutexName (MutexId),
312212761Sjkim                        (UINT32) ThisThreadId));
313151937Sjkim
314151937Sjkim                    return (AE_ALREADY_ACQUIRED);
315151937Sjkim                }
316151937Sjkim
317167802Sjkim                ACPI_ERROR ((AE_INFO,
318212761Sjkim                    "Invalid acquire order: Thread %u owns [%s], wants [%s]",
319212761Sjkim                    (UINT32) ThisThreadId, AcpiUtGetMutexName (i),
320151937Sjkim                    AcpiUtGetMutexName (MutexId)));
321151937Sjkim
322151937Sjkim                return (AE_ACQUIRE_DEADLOCK);
323151937Sjkim            }
324151937Sjkim        }
325151937Sjkim    }
326151937Sjkim#endif
327151937Sjkim
328151937Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
329212761Sjkim        "Thread %u attempting to acquire Mutex [%s]\n",
330212761Sjkim        (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
331151937Sjkim
332306536Sjkim    Status = AcpiOsAcquireMutex (
333306536Sjkim        AcpiGbl_MutexInfo[MutexId].Mutex, ACPI_WAIT_FOREVER);
334151937Sjkim    if (ACPI_SUCCESS (Status))
335151937Sjkim    {
336306536Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
337306536Sjkim            "Thread %u acquired Mutex [%s]\n",
338212761Sjkim            (UINT32) ThisThreadId, AcpiUtGetMutexName (MutexId)));
339151937Sjkim
340151937Sjkim        AcpiGbl_MutexInfo[MutexId].UseCount++;
341151937Sjkim        AcpiGbl_MutexInfo[MutexId].ThreadId = ThisThreadId;
342151937Sjkim    }
343151937Sjkim    else
344151937Sjkim    {
345167802Sjkim        ACPI_EXCEPTION ((AE_INFO, Status,
346212761Sjkim            "Thread %u could not acquire Mutex [0x%X]",
347212761Sjkim            (UINT32) ThisThreadId, MutexId));
348151937Sjkim    }
349151937Sjkim
350151937Sjkim    return (Status);
351151937Sjkim}
352151937Sjkim
353151937Sjkim
354151937Sjkim/*******************************************************************************
355151937Sjkim *
356151937Sjkim * FUNCTION:    AcpiUtReleaseMutex
357151937Sjkim *
358151937Sjkim * PARAMETERS:  MutexID         - ID of the mutex to be released
359151937Sjkim *
360151937Sjkim * RETURN:      Status
361151937Sjkim *
362151937Sjkim * DESCRIPTION: Release a mutex object.
363151937Sjkim *
364151937Sjkim ******************************************************************************/
365151937Sjkim
366151937SjkimACPI_STATUS
367151937SjkimAcpiUtReleaseMutex (
368151937Sjkim    ACPI_MUTEX_HANDLE       MutexId)
369151937Sjkim{
370167802Sjkim    ACPI_FUNCTION_NAME (UtReleaseMutex);
371151937Sjkim
372241973Sjkim
373212761Sjkim    ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n",
374228110Sjkim        (UINT32) AcpiOsGetThreadId (), AcpiUtGetMutexName (MutexId)));
375151937Sjkim
376167802Sjkim    if (MutexId > ACPI_MAX_MUTEX)
377151937Sjkim    {
378151937Sjkim        return (AE_BAD_PARAMETER);
379151937Sjkim    }
380151937Sjkim
381151937Sjkim    /*
382151937Sjkim     * Mutex must be acquired in order to release it!
383151937Sjkim     */
384151937Sjkim    if (AcpiGbl_MutexInfo[MutexId].ThreadId == ACPI_MUTEX_NOT_ACQUIRED)
385151937Sjkim    {
386167802Sjkim        ACPI_ERROR ((AE_INFO,
387204773Sjkim            "Mutex [0x%X] is not acquired, cannot release", MutexId));
388151937Sjkim
389151937Sjkim        return (AE_NOT_ACQUIRED);
390151937Sjkim    }
391151937Sjkim
392151937Sjkim#ifdef ACPI_MUTEX_DEBUG
393151937Sjkim    {
394151937Sjkim        UINT32                  i;
395151937Sjkim        /*
396151937Sjkim         * Mutex debug code, for internal debugging only.
397151937Sjkim         *
398241973Sjkim         * Deadlock prevention. Check if this thread owns any mutexes of value
399241973Sjkim         * greater than this one. If so, the thread has violated the mutex
400241973Sjkim         * ordering rule. This indicates a coding error somewhere in
401151937Sjkim         * the ACPI subsystem code.
402151937Sjkim         */
403193267Sjkim        for (i = MutexId; i < ACPI_NUM_MUTEX; i++)
404151937Sjkim        {
405228110Sjkim            if (AcpiGbl_MutexInfo[i].ThreadId == AcpiOsGetThreadId ())
406151937Sjkim            {
407151937Sjkim                if (i == MutexId)
408151937Sjkim                {
409151937Sjkim                    continue;
410151937Sjkim                }
411151937Sjkim
412167802Sjkim                ACPI_ERROR ((AE_INFO,
413167802Sjkim                    "Invalid release order: owns [%s], releasing [%s]",
414151937Sjkim                    AcpiUtGetMutexName (i), AcpiUtGetMutexName (MutexId)));
415151937Sjkim
416151937Sjkim                return (AE_RELEASE_DEADLOCK);
417151937Sjkim            }
418151937Sjkim        }
419151937Sjkim    }
420151937Sjkim#endif
421151937Sjkim
422151937Sjkim    /* Mark unlocked FIRST */
423151937Sjkim
424151937Sjkim    AcpiGbl_MutexInfo[MutexId].ThreadId = ACPI_MUTEX_NOT_ACQUIRED;
425151937Sjkim
426167802Sjkim    AcpiOsReleaseMutex (AcpiGbl_MutexInfo[MutexId].Mutex);
427167802Sjkim    return (AE_OK);
428151937Sjkim}
429