OsdSynch.c revision 193750
1123120Simp/*-
2123120Simp * Copyright (c) 2000 Michael Smith
3123120Simp * Copyright (c) 2000 BSDi
4123120Simp * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org>
5123120Simp * All rights reserved.
6123120Simp *
7123120Simp * Redistribution and use in source and binary forms, with or without
8123120Simp * modification, are permitted provided that the following conditions
9123120Simp * are met:
10123120Simp * 1. Redistributions of source code must retain the above copyright
11123120Simp *    notice, this list of conditions and the following disclaimer.
12123120Simp * 2. Redistributions in binary form must reproduce the above copyright
13123120Simp *    notice, this list of conditions and the following disclaimer in the
14123120Simp *    documentation and/or other materials provided with the distribution.
15123120Simp *
16123120Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17123120Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18123120Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19123120Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20123120Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21123120Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22123120Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23123120Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24123120Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25123120Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26123120Simp * SUCH DAMAGE.
27123120Simp */
28123120Simp
29123120Simp/*
30123120Simp * 6.1 : Mutual Exclusion and Synchronisation
31123120Simp */
32123120Simp
33123120Simp#include <sys/cdefs.h>
34123120Simp__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSynch.c 193750 2009-06-08 20:07:16Z jkim $");
35123120Simp
36123120Simp#include <contrib/dev/acpica/include/acpi.h>
37123120Simp#include <contrib/dev/acpica/include/accommon.h>
38123120Simp
39123120Simp#include <sys/condvar.h>
40123120Simp#include <sys/kernel.h>
41123120Simp#include <sys/lock.h>
42123120Simp#include <sys/malloc.h>
43123120Simp#include <sys/mutex.h>
44123120Simp
45123120Simp#define	_COMPONENT	ACPI_OS_SERVICES
46123120SimpACPI_MODULE_NAME("SYNCH")
47123120Simp
48123120SimpMALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
49123120Simp
50123120Simp/*
51123120Simp * Convert milliseconds to ticks.
52123120Simp */
53123120Simpstatic int
54123120Simptimeout2hz(UINT16 Timeout)
55123120Simp{
56123120Simp	struct timeval		tv;
57123120Simp
58123120Simp	tv.tv_sec = (time_t)(Timeout / 1000);
59123120Simp	tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000;
60123120Simp
61123120Simp	return (tvtohz(&tv));
62123120Simp}
63123120Simp
64123120Simp/*
65123120Simp * ACPI_SEMAPHORE
66123120Simp */
67123120Simpstruct acpi_sema {
68123120Simp	struct mtx	as_lock;
69123120Simp	char		as_name[32];
70123120Simp	struct cv	as_cv;
71123120Simp	UINT32		as_maxunits;
72123120Simp	UINT32		as_units;
73123120Simp	int		as_waiters;
74123120Simp	int		as_reset;
75123120Simp};
76123120Simp
77123120SimpACPI_STATUS
78123120SimpAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
79123120Simp    ACPI_SEMAPHORE *OutHandle)
80123120Simp{
81123120Simp	struct acpi_sema	*as;
82123120Simp
83123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
84123120Simp
85123120Simp	if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits)
86123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
87123120Simp
88123120Simp	if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
89123120Simp		return_ACPI_STATUS (AE_NO_MEMORY);
90123120Simp
91123120Simp	snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as);
92123120Simp	mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF);
93123120Simp	cv_init(&as->as_cv, as->as_name);
94123120Simp	as->as_maxunits = MaxUnits;
95123120Simp	as->as_units = InitialUnits;
96123120Simp
97123120Simp	*OutHandle = (ACPI_SEMAPHORE)as;
98123120Simp
99123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n",
100123120Simp	    as->as_name, MaxUnits, InitialUnits));
101123120Simp
102123120Simp	return_ACPI_STATUS (AE_OK);
103123120Simp}
104123120Simp
105123120SimpACPI_STATUS
106123120SimpAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
107123120Simp{
108123120Simp	struct acpi_sema	*as = (struct acpi_sema *)Handle;
109123120Simp
110123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
111123120Simp
112123120Simp	if (as == NULL)
113123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
114123120Simp
115123120Simp	mtx_lock(&as->as_lock);
116123120Simp
117123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name));
118123120Simp
119123120Simp	if (as->as_waiters > 0) {
120123120Simp		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
121123120Simp		    "reset %s, units %u, waiters %d\n",
122123120Simp		    as->as_name, as->as_units, as->as_waiters));
123123120Simp		as->as_reset = 1;
124123120Simp		cv_broadcast(&as->as_cv);
125123120Simp		while (as->as_waiters > 0) {
126123120Simp			if (mtx_sleep(&as->as_reset, &as->as_lock,
127123120Simp			    PCATCH, "acsrst", hz) == EINTR) {
128123120Simp				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
129123120Simp				    "failed to reset %s, waiters %d\n",
130123120Simp				    as->as_name, as->as_waiters));
131123120Simp				mtx_unlock(&as->as_lock);
132123120Simp				return_ACPI_STATUS (AE_ERROR);
133123120Simp			}
134123120Simp			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
135123120Simp			    "wait %s, units %u, waiters %d\n",
136123120Simp			    as->as_name, as->as_units, as->as_waiters));
137123120Simp		}
138123120Simp	}
139123120Simp
140123120Simp	mtx_unlock(&as->as_lock);
141123120Simp
142123120Simp	mtx_destroy(&as->as_lock);
143123120Simp	cv_destroy(&as->as_cv);
144123120Simp	free(as, M_ACPISEM);
145123120Simp
146123120Simp	return_ACPI_STATUS (AE_OK);
147123120Simp}
148123120Simp
149123120Simp#define	ACPISEM_AVAIL(s, u)	((s)->as_units >= (u))
150123120Simp
151123120SimpACPI_STATUS
152123120SimpAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
153123120Simp{
154123120Simp	struct acpi_sema	*as = (struct acpi_sema *)Handle;
155123120Simp	int			error, prevtick, slptick, tmo;
156123120Simp	ACPI_STATUS		status = AE_OK;
157123120Simp
158123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
159123120Simp
160123120Simp	if (as == NULL || Units == 0)
161123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
162123120Simp
163123120Simp	mtx_lock(&as->as_lock);
164123120Simp
165123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
166123120Simp	    "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n",
167123120Simp	    Units, as->as_name, as->as_units, as->as_waiters, Timeout));
168123120Simp
169123120Simp	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) {
170123120Simp		mtx_unlock(&as->as_lock);
171123120Simp		return_ACPI_STATUS (AE_LIMIT);
172123120Simp	}
173123120Simp
174123120Simp	switch (Timeout) {
175123120Simp	case ACPI_DO_NOT_WAIT:
176123120Simp		if (!ACPISEM_AVAIL(as, Units))
177123120Simp			status = AE_TIME;
178123120Simp		break;
179123120Simp	case ACPI_WAIT_FOREVER:
180123120Simp		while (!ACPISEM_AVAIL(as, Units)) {
181123120Simp			as->as_waiters++;
182123120Simp			error = cv_wait_sig(&as->as_cv, &as->as_lock);
183123120Simp			as->as_waiters--;
184123120Simp			if (error == EINTR || as->as_reset) {
185123120Simp				status = AE_ERROR;
186123120Simp				break;
187123120Simp			}
188123120Simp			if (ACPISEM_AVAIL(as, Units))
189123120Simp				break;
190123120Simp		}
191123120Simp		break;
192123120Simp	default:
193123120Simp		tmo = timeout2hz(Timeout);
194123120Simp		while (!ACPISEM_AVAIL(as, Units)) {
195123120Simp			prevtick = ticks;
196123120Simp			as->as_waiters++;
197123120Simp			error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo);
198123120Simp			as->as_waiters--;
199123120Simp			if (error == EINTR || as->as_reset) {
200123120Simp				status = AE_ERROR;
201123120Simp				break;
202123120Simp			}
203123120Simp			if (ACPISEM_AVAIL(as, Units))
204123120Simp				break;
205123120Simp			slptick = ticks - prevtick;
206123120Simp			if (slptick >= tmo || slptick < 0) {
207123120Simp				status = AE_TIME;
208123120Simp				break;
209123120Simp			}
210123120Simp			tmo -= slptick;
211123120Simp		}
212123120Simp	}
213123120Simp	if (status == AE_OK)
214123120Simp		as->as_units -= Units;
215123120Simp
216123120Simp	mtx_unlock(&as->as_lock);
217123120Simp
218123120Simp	return_ACPI_STATUS (status);
219123120Simp}
220123120Simp
221123120SimpACPI_STATUS
222123120SimpAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
223123120Simp{
224123120Simp	struct acpi_sema	*as = (struct acpi_sema *)Handle;
225123120Simp	UINT32			i;
226123120Simp
227123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
228123120Simp
229123120Simp	if (as == NULL || Units == 0)
230123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
231123120Simp
232123120Simp	mtx_lock(&as->as_lock);
233123120Simp
234123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
235123120Simp	    "return %u units to %s, units %u, waiters %d\n",
236123120Simp	    Units, as->as_name, as->as_units, as->as_waiters));
237123120Simp
238123120Simp	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT &&
239123120Simp	    (as->as_maxunits < Units ||
240123120Simp	    as->as_maxunits - Units < as->as_units)) {
241123120Simp		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
242123120Simp		    "exceeded max units %u\n", as->as_maxunits));
243123120Simp		mtx_unlock(&as->as_lock);
244123120Simp		return_ACPI_STATUS (AE_LIMIT);
245123120Simp	}
246123120Simp
247123120Simp	as->as_units += Units;
248123120Simp	if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units))
249123120Simp		for (i = 0; i < Units; i++)
250123120Simp			cv_signal(&as->as_cv);
251123120Simp
252123120Simp	mtx_unlock(&as->as_lock);
253123120Simp
254123120Simp	return_ACPI_STATUS (AE_OK);
255123120Simp}
256123120Simp
257123120Simp#undef ACPISEM_AVAIL
258123120Simp
259123120Simp/*
260123120Simp * ACPI_MUTEX
261123120Simp */
262123120Simpstruct acpi_mutex {
263123120Simp	struct mtx	am_lock;
264123120Simp	char		am_name[32];
265123120Simp	struct thread	*am_owner;
266123120Simp	int		am_nested;
267123120Simp	int		am_waiters;
268123120Simp	int		am_reset;
269123120Simp};
270123120Simp
271123120SimpACPI_STATUS
272123120SimpAcpiOsCreateMutex(ACPI_MUTEX *OutHandle)
273123120Simp{
274123120Simp	struct acpi_mutex	*am;
275123120Simp
276123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
277123120Simp
278123120Simp	if (OutHandle == NULL)
279123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
280123120Simp
281123120Simp	if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
282123120Simp		return_ACPI_STATUS (AE_NO_MEMORY);
283123120Simp
284123120Simp	snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am);
285123120Simp	mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF);
286123120Simp
287123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name));
288123120Simp
289123120Simp	*OutHandle = (ACPI_MUTEX)am;
290123120Simp
291123120Simp	return_ACPI_STATUS (AE_OK);
292123120Simp}
293123120Simp
294123120Simp#define	ACPIMTX_AVAIL(m)	((m)->am_owner == NULL)
295123120Simp#define	ACPIMTX_OWNED(m)	((m)->am_owner == curthread)
296123120Simp
297123120Simpvoid
298123120SimpAcpiOsDeleteMutex(ACPI_MUTEX Handle)
299123120Simp{
300123120Simp	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
301123120Simp
302123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
303123120Simp
304123120Simp	if (am == NULL) {
305123120Simp		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n"));
306123120Simp		return_VOID;
307123120Simp	}
308123120Simp
309123120Simp	mtx_lock(&am->am_lock);
310123120Simp
311123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name));
312123120Simp
313123120Simp	if (am->am_waiters > 0) {
314123120Simp		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
315123120Simp		    "reset %s, owner %p\n", am->am_name, am->am_owner));
316123120Simp		am->am_reset = 1;
317123120Simp		wakeup(am);
318123120Simp		while (am->am_waiters > 0) {
319123120Simp			if (mtx_sleep(&am->am_reset, &am->am_lock,
320123120Simp			    PCATCH, "acmrst", hz) == EINTR) {
321123120Simp				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
322123120Simp				    "failed to reset %s, waiters %d\n",
323123120Simp				    am->am_name, am->am_waiters));
324123120Simp				mtx_unlock(&am->am_lock);
325123120Simp				return_VOID;
326123120Simp			}
327123120Simp			if (ACPIMTX_AVAIL(am))
328123120Simp				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
329123120Simp				    "wait %s, waiters %d\n",
330123120Simp				    am->am_name, am->am_waiters));
331123120Simp			else
332123120Simp				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
333123120Simp				    "wait %s, owner %p, waiters %d\n",
334123120Simp				    am->am_name, am->am_owner, am->am_waiters));
335123120Simp		}
336123120Simp	}
337123120Simp
338123120Simp	mtx_unlock(&am->am_lock);
339123120Simp
340123120Simp	mtx_destroy(&am->am_lock);
341123120Simp	free(am, M_ACPISEM);
342123120Simp}
343123120Simp
344123120SimpACPI_STATUS
345123120SimpAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
346123120Simp{
347123120Simp	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
348123120Simp	int			error, prevtick, slptick, tmo;
349123120Simp	ACPI_STATUS		status = AE_OK;
350123120Simp
351123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
352123120Simp
353123120Simp	if (am == NULL)
354123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
355123120Simp
356123120Simp	mtx_lock(&am->am_lock);
357123120Simp
358123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name));
359123120Simp
360123120Simp	if (ACPIMTX_OWNED(am)) {
361123120Simp		am->am_nested++;
362123120Simp		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
363123120Simp		    "acquire nested %s, depth %d\n",
364123120Simp		    am->am_name, am->am_nested));
365123120Simp		mtx_unlock(&am->am_lock);
366123120Simp		return_ACPI_STATUS (AE_OK);
367123120Simp	}
368123120Simp
369123120Simp	switch (Timeout) {
370123120Simp	case ACPI_DO_NOT_WAIT:
371123120Simp		if (!ACPIMTX_AVAIL(am))
372123120Simp			status = AE_TIME;
373123120Simp		break;
374123120Simp	case ACPI_WAIT_FOREVER:
375123120Simp		while (!ACPIMTX_AVAIL(am)) {
376123120Simp			am->am_waiters++;
377123120Simp			error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0);
378123120Simp			am->am_waiters--;
379123120Simp			if (error == EINTR || am->am_reset) {
380123120Simp				status = AE_ERROR;
381123120Simp				break;
382123120Simp			}
383123120Simp			if (ACPIMTX_AVAIL(am))
384123120Simp				break;
385123120Simp		}
386123120Simp		break;
387123120Simp	default:
388123120Simp		tmo = timeout2hz(Timeout);
389123120Simp		while (!ACPIMTX_AVAIL(am)) {
390123120Simp			prevtick = ticks;
391123120Simp			am->am_waiters++;
392123120Simp			error = mtx_sleep(am, &am->am_lock, PCATCH,
393123120Simp			    "acmtx", tmo);
394123120Simp			am->am_waiters--;
395123120Simp			if (error == EINTR || am->am_reset) {
396123120Simp				status = AE_ERROR;
397123120Simp				break;
398123120Simp			}
399123120Simp			if (ACPIMTX_AVAIL(am))
400123120Simp				break;
401123120Simp			slptick = ticks - prevtick;
402123120Simp			if (slptick >= tmo || slptick < 0) {
403123120Simp				status = AE_TIME;
404123120Simp				break;
405123120Simp			}
406123120Simp			tmo -= slptick;
407123120Simp		}
408123120Simp	}
409123120Simp	if (status == AE_OK)
410123120Simp		am->am_owner = curthread;
411123120Simp
412123120Simp	mtx_unlock(&am->am_lock);
413123120Simp
414123120Simp	return_ACPI_STATUS (status);
415123120Simp}
416123120Simp
417123120Simpvoid
418123120SimpAcpiOsReleaseMutex(ACPI_MUTEX Handle)
419123120Simp{
420123120Simp	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
421123120Simp
422123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
423123120Simp
424123120Simp	if (am == NULL)
425123120Simp		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
426123120Simp		    "cannot release null mutex\n"));
427123120Simp
428123120Simp	mtx_lock(&am->am_lock);
429123120Simp
430123120Simp	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name));
431123120Simp
432123120Simp	if (ACPIMTX_OWNED(am)) {
433123120Simp		if (am->am_nested > 0) {
434123120Simp			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
435123120Simp			    "release nested %s, depth %d\n",
436123120Simp			    am->am_name, am->am_nested));
437123120Simp			am->am_nested--;
438123120Simp		} else
439123120Simp			am->am_owner = NULL;
440123120Simp	} else {
441123120Simp		if (ACPIMTX_AVAIL(am))
442123120Simp			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
443123120Simp			    "release already available %s\n", am->am_name));
444123120Simp		else
445123120Simp			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
446123120Simp			    "release unowned %s from %p, depth %d\n",
447123120Simp			    am->am_name, am->am_owner, am->am_nested));
448123120Simp	}
449123120Simp	if (am->am_waiters > 0 && ACPIMTX_AVAIL(am))
450123120Simp		wakeup_one(am);
451123120Simp
452123120Simp	mtx_unlock(&am->am_lock);
453123120Simp}
454123120Simp
455123120Simp#undef ACPIMTX_AVAIL
456123120Simp#undef ACPIMTX_OWNED
457123120Simp
458123120Simp/*
459123120Simp * ACPI_SPINLOCK
460123120Simp */
461123120Simpstruct acpi_spinlock {
462123120Simp	struct mtx	al_lock;
463123120Simp	char		al_name[32];
464123120Simp	int		al_nested;
465123120Simp};
466123120Simp
467123120SimpACPI_STATUS
468123120SimpAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
469123120Simp{
470123120Simp	struct acpi_spinlock	*al;
471123120Simp
472123120Simp	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
473123120Simp
474123120Simp	if (OutHandle == NULL)
475123120Simp		return_ACPI_STATUS (AE_BAD_PARAMETER);
476123120Simp
477123120Simp	if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
478123120Simp		return_ACPI_STATUS (AE_NO_MEMORY);
479123120Simp
480123120Simp#ifdef ACPI_DEBUG
481123120Simp	if (OutHandle == &AcpiGbl_GpeLock)
482123120Simp		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)");
483123120Simp	else if (OutHandle == &AcpiGbl_HardwareLock)
484123120Simp		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)");
485123120Simp	else
486123120Simp#endif
487123120Simp	snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al);
488	mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN);
489
490	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name));
491
492	*OutHandle = (ACPI_SPINLOCK)al;
493
494	return_ACPI_STATUS (AE_OK);
495}
496
497void
498AcpiOsDeleteLock(ACPI_SPINLOCK Handle)
499{
500	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
501
502	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
503
504	if (al == NULL) {
505		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
506		    "cannot delete null spinlock\n"));
507		return_VOID;
508	}
509
510	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name));
511
512	mtx_destroy(&al->al_lock);
513	free(al, M_ACPISEM);
514}
515
516ACPI_CPU_FLAGS
517AcpiOsAcquireLock(ACPI_SPINLOCK Handle)
518{
519	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
520
521	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
522
523	if (al == NULL) {
524		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
525		    "cannot acquire null spinlock\n"));
526		return (0);
527	}
528
529	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name));
530
531	if (mtx_owned(&al->al_lock)) {
532		al->al_nested++;
533		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
534		    "acquire nested %s, depth %d\n",
535		    al->al_name, al->al_nested));
536	} else
537		mtx_lock_spin(&al->al_lock);
538
539	return (0);
540}
541
542void
543AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
544{
545	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
546
547	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
548
549	if (al == NULL) {
550		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
551		    "cannot release null spinlock\n"));
552		return_VOID;
553	}
554
555	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name));
556
557	if (mtx_owned(&al->al_lock)) {
558		if (al->al_nested > 0) {
559			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
560			    "release nested %s, depth %d\n",
561			    al->al_name, al->al_nested));
562			al->al_nested--;
563		} else
564			mtx_unlock_spin(&al->al_lock);
565	} else
566		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
567		    "cannot release unowned %s\n", al->al_name));
568}
569
570/* Section 5.2.10.1: global lock acquire/release functions */
571#define	GL_ACQUIRED	(-1)
572#define	GL_BUSY		0
573#define	GL_BIT_PENDING	0x01
574#define	GL_BIT_OWNED	0x02
575#define	GL_BIT_MASK	(GL_BIT_PENDING | GL_BIT_OWNED)
576
577/*
578 * Acquire the global lock.  If busy, set the pending bit.  The caller
579 * will wait for notification from the BIOS that the lock is available
580 * and then attempt to acquire it again.
581 */
582int
583acpi_acquire_global_lock(uint32_t *lock)
584{
585	uint32_t	new, old;
586
587	do {
588		old = *lock;
589		new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) |
590			((old >> 1) & GL_BIT_PENDING);
591	} while (atomic_cmpset_acq_int(lock, old, new) == 0);
592
593	return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY);
594}
595
596/*
597 * Release the global lock, returning whether there is a waiter pending.
598 * If the BIOS set the pending bit, OSPM must notify the BIOS when it
599 * releases the lock.
600 */
601int
602acpi_release_global_lock(uint32_t *lock)
603{
604	uint32_t	new, old;
605
606	do {
607		old = *lock;
608		new = old & ~GL_BIT_MASK;
609	} while (atomic_cmpset_rel_int(lock, old, new) == 0);
610
611	return (old & GL_BIT_PENDING);
612}
613