167760Smsmith/*-
267760Smsmith * Copyright (c) 2000 Michael Smith
367760Smsmith * Copyright (c) 2000 BSDi
4193750Sjkim * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org>
567760Smsmith * All rights reserved.
667760Smsmith *
767760Smsmith * Redistribution and use in source and binary forms, with or without
867760Smsmith * modification, are permitted provided that the following conditions
967760Smsmith * are met:
1067760Smsmith * 1. Redistributions of source code must retain the above copyright
1167760Smsmith *    notice, this list of conditions and the following disclaimer.
1267760Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1367760Smsmith *    notice, this list of conditions and the following disclaimer in the
1467760Smsmith *    documentation and/or other materials provided with the distribution.
1567760Smsmith *
1667760Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1767760Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1867760Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1967760Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2067760Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2167760Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2267760Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2367760Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2467760Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2567760Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2667760Smsmith * SUCH DAMAGE.
2767760Smsmith */
2867760Smsmith
2967760Smsmith/*
3067760Smsmith * 6.1 : Mutual Exclusion and Synchronisation
3167760Smsmith */
3267760Smsmith
33148318Snjl#include <sys/cdefs.h>
34148318Snjl__FBSDID("$FreeBSD$");
35148318Snjl
36193530Sjkim#include <contrib/dev/acpica/include/acpi.h>
37193530Sjkim#include <contrib/dev/acpica/include/accommon.h>
3867760Smsmith
39193750Sjkim#include <sys/condvar.h>
4067760Smsmith#include <sys/kernel.h>
41193750Sjkim#include <sys/lock.h>
42105278Sjhb#include <sys/malloc.h>
4367760Smsmith#include <sys/mutex.h>
4467760Smsmith
45193750Sjkim#define	_COMPONENT	ACPI_OS_SERVICES
4691128SmsmithACPI_MODULE_NAME("SYNCH")
4771876Smsmith
48227293Sedstatic MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
4967760Smsmith
50193750Sjkim/*
51193750Sjkim * Convert milliseconds to ticks.
52193750Sjkim */
53193750Sjkimstatic int
54193750Sjkimtimeout2hz(UINT16 Timeout)
55193750Sjkim{
56193750Sjkim	struct timeval		tv;
57105278Sjhb
58193750Sjkim	tv.tv_sec = (time_t)(Timeout / 1000);
59193750Sjkim	tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000;
60193750Sjkim
61193750Sjkim	return (tvtohz(&tv));
62193750Sjkim}
63193750Sjkim
6467760Smsmith/*
65193750Sjkim * ACPI_SEMAPHORE
6667760Smsmith */
67193750Sjkimstruct acpi_sema {
68193750Sjkim	struct mtx	as_lock;
69193750Sjkim	char		as_name[32];
70193750Sjkim	struct cv	as_cv;
71193750Sjkim	UINT32		as_maxunits;
72193750Sjkim	UINT32		as_units;
73193750Sjkim	int		as_waiters;
74193750Sjkim	int		as_reset;
7567760Smsmith};
7667760Smsmith
7767760SmsmithACPI_STATUS
78128227SnjlAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
79167915Sjkim    ACPI_SEMAPHORE *OutHandle)
8067760Smsmith{
81193750Sjkim	struct acpi_sema	*as;
8267760Smsmith
83193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
8471876Smsmith
85193750Sjkim	if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits)
86193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
8767760Smsmith
88193750Sjkim	if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
89193750Sjkim		return_ACPI_STATUS (AE_NO_MEMORY);
9067760Smsmith
91193750Sjkim	snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as);
92193750Sjkim	mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF);
93193750Sjkim	cv_init(&as->as_cv, as->as_name);
94193750Sjkim	as->as_maxunits = MaxUnits;
95193750Sjkim	as->as_units = InitialUnits;
9667760Smsmith
97193750Sjkim	*OutHandle = (ACPI_SEMAPHORE)as;
9871876Smsmith
99193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n",
100193750Sjkim	    as->as_name, MaxUnits, InitialUnits));
101128227Snjl
102193750Sjkim	return_ACPI_STATUS (AE_OK);
10367760Smsmith}
10467760Smsmith
10567760SmsmithACPI_STATUS
106167915SjkimAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
10767760Smsmith{
108193750Sjkim	struct acpi_sema	*as = (struct acpi_sema *)Handle;
10971876Smsmith
110193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
11171876Smsmith
112193750Sjkim	if (as == NULL)
113193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
114128227Snjl
115193750Sjkim	mtx_lock(&as->as_lock);
116193750Sjkim
117193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name));
118193750Sjkim
119193750Sjkim	if (as->as_waiters > 0) {
120193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
121193750Sjkim		    "reset %s, units %u, waiters %d\n",
122193750Sjkim		    as->as_name, as->as_units, as->as_waiters));
123193750Sjkim		as->as_reset = 1;
124193750Sjkim		cv_broadcast(&as->as_cv);
125193750Sjkim		while (as->as_waiters > 0) {
126193750Sjkim			if (mtx_sleep(&as->as_reset, &as->as_lock,
127193750Sjkim			    PCATCH, "acsrst", hz) == EINTR) {
128193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
129193750Sjkim				    "failed to reset %s, waiters %d\n",
130193750Sjkim				    as->as_name, as->as_waiters));
131193750Sjkim				mtx_unlock(&as->as_lock);
132193750Sjkim				return_ACPI_STATUS (AE_ERROR);
133193750Sjkim			}
134193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
135193750Sjkim			    "wait %s, units %u, waiters %d\n",
136193750Sjkim			    as->as_name, as->as_units, as->as_waiters));
137193750Sjkim		}
138193750Sjkim	}
139193750Sjkim
140193750Sjkim	mtx_unlock(&as->as_lock);
141193750Sjkim
142193750Sjkim	mtx_destroy(&as->as_lock);
143193750Sjkim	cv_destroy(&as->as_cv);
144193750Sjkim	free(as, M_ACPISEM);
145193750Sjkim
146193750Sjkim	return_ACPI_STATUS (AE_OK);
14767760Smsmith}
14867760Smsmith
149193750Sjkim#define	ACPISEM_AVAIL(s, u)	((s)->as_units >= (u))
150193750Sjkim
15167760SmsmithACPI_STATUS
152167915SjkimAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
15367760Smsmith{
154193750Sjkim	struct acpi_sema	*as = (struct acpi_sema *)Handle;
155193750Sjkim	int			error, prevtick, slptick, tmo;
156193750Sjkim	ACPI_STATUS		status = AE_OK;
15767760Smsmith
158193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
15971876Smsmith
160193750Sjkim	if (as == NULL || Units == 0)
161193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
16267760Smsmith
163193750Sjkim	mtx_lock(&as->as_lock);
16488420Siwasaki
165193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
166193750Sjkim	    "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n",
167193750Sjkim	    Units, as->as_name, as->as_units, as->as_waiters, Timeout));
16888420Siwasaki
169193750Sjkim	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) {
170193750Sjkim		mtx_unlock(&as->as_lock);
171193750Sjkim		return_ACPI_STATUS (AE_LIMIT);
172193750Sjkim	}
17388420Siwasaki
174193750Sjkim	switch (Timeout) {
175193750Sjkim	case ACPI_DO_NOT_WAIT:
176193750Sjkim		if (!ACPISEM_AVAIL(as, Units))
177193750Sjkim			status = AE_TIME;
178193750Sjkim		break;
179193750Sjkim	case ACPI_WAIT_FOREVER:
180193750Sjkim		while (!ACPISEM_AVAIL(as, Units)) {
181193750Sjkim			as->as_waiters++;
182193750Sjkim			error = cv_wait_sig(&as->as_cv, &as->as_lock);
183193750Sjkim			as->as_waiters--;
184193750Sjkim			if (error == EINTR || as->as_reset) {
185193750Sjkim				status = AE_ERROR;
186193750Sjkim				break;
187193750Sjkim			}
188193750Sjkim		}
189193750Sjkim		break;
190193750Sjkim	default:
191299977Sjhb		if (cold) {
192299977Sjhb			/*
193299977Sjhb			 * Just spin polling the semaphore once a
194299977Sjhb			 * millisecond.
195299977Sjhb			 */
196299977Sjhb			while (!ACPISEM_AVAIL(as, Units)) {
197299977Sjhb				if (Timeout == 0) {
198299977Sjhb					status = AE_TIME;
199299977Sjhb					break;
200299977Sjhb				}
201299977Sjhb				Timeout--;
202299977Sjhb				mtx_unlock(&as->as_lock);
203299977Sjhb				DELAY(1000);
204299977Sjhb				mtx_lock(&as->as_lock);
205299977Sjhb			}
206299977Sjhb			break;
207299977Sjhb		}
208193750Sjkim		tmo = timeout2hz(Timeout);
209193750Sjkim		while (!ACPISEM_AVAIL(as, Units)) {
210193750Sjkim			prevtick = ticks;
211193750Sjkim			as->as_waiters++;
212193750Sjkim			error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo);
213193750Sjkim			as->as_waiters--;
214193750Sjkim			if (error == EINTR || as->as_reset) {
215193750Sjkim				status = AE_ERROR;
216193750Sjkim				break;
217193750Sjkim			}
218193750Sjkim			if (ACPISEM_AVAIL(as, Units))
219193750Sjkim				break;
220193750Sjkim			slptick = ticks - prevtick;
221193750Sjkim			if (slptick >= tmo || slptick < 0) {
222193750Sjkim				status = AE_TIME;
223193750Sjkim				break;
224193750Sjkim			}
225193750Sjkim			tmo -= slptick;
226193750Sjkim		}
227193750Sjkim	}
228236424Sjkim	if (ACPI_SUCCESS(status))
229193750Sjkim		as->as_units -= Units;
23071876Smsmith
231193750Sjkim	mtx_unlock(&as->as_lock);
23288420Siwasaki
233193750Sjkim	return_ACPI_STATUS (status);
234193750Sjkim}
23588420Siwasaki
236193750SjkimACPI_STATUS
237193750SjkimAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
238193750Sjkim{
239193750Sjkim	struct acpi_sema	*as = (struct acpi_sema *)Handle;
240193750Sjkim	UINT32			i;
24188420Siwasaki
242193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
24388420Siwasaki
244193750Sjkim	if (as == NULL || Units == 0)
245193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
246193750Sjkim
247193750Sjkim	mtx_lock(&as->as_lock);
248193750Sjkim
24988420Siwasaki	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
250193750Sjkim	    "return %u units to %s, units %u, waiters %d\n",
251193750Sjkim	    Units, as->as_name, as->as_units, as->as_waiters));
25288420Siwasaki
253193750Sjkim	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT &&
254193750Sjkim	    (as->as_maxunits < Units ||
255193750Sjkim	    as->as_maxunits - Units < as->as_units)) {
256193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
257193750Sjkim		    "exceeded max units %u\n", as->as_maxunits));
258193750Sjkim		mtx_unlock(&as->as_lock);
259193750Sjkim		return_ACPI_STATUS (AE_LIMIT);
26088420Siwasaki	}
26188420Siwasaki
262193750Sjkim	as->as_units += Units;
263193750Sjkim	if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units))
264193750Sjkim		for (i = 0; i < Units; i++)
265193750Sjkim			cv_signal(&as->as_cv);
26688420Siwasaki
267193750Sjkim	mtx_unlock(&as->as_lock);
26888420Siwasaki
269193750Sjkim	return_ACPI_STATUS (AE_OK);
270193750Sjkim}
27188420Siwasaki
272193750Sjkim#undef ACPISEM_AVAIL
273193750Sjkim
274193750Sjkim/*
275193750Sjkim * ACPI_MUTEX
276193750Sjkim */
277193750Sjkimstruct acpi_mutex {
278193750Sjkim	struct mtx	am_lock;
279193750Sjkim	char		am_name[32];
280193750Sjkim	struct thread	*am_owner;
281193750Sjkim	int		am_nested;
282193750Sjkim	int		am_waiters;
283193750Sjkim	int		am_reset;
284193750Sjkim};
285193750Sjkim
286193750SjkimACPI_STATUS
287193750SjkimAcpiOsCreateMutex(ACPI_MUTEX *OutHandle)
288193750Sjkim{
289193750Sjkim	struct acpi_mutex	*am;
290193750Sjkim
291193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
292193750Sjkim
293193750Sjkim	if (OutHandle == NULL)
294193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
295193750Sjkim
296193750Sjkim	if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
297193750Sjkim		return_ACPI_STATUS (AE_NO_MEMORY);
298193750Sjkim
299193750Sjkim	snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am);
300193750Sjkim	mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF);
301193750Sjkim
302193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name));
303193750Sjkim
304193750Sjkim	*OutHandle = (ACPI_MUTEX)am;
305193750Sjkim
306193750Sjkim	return_ACPI_STATUS (AE_OK);
307193750Sjkim}
308193750Sjkim
309193750Sjkim#define	ACPIMTX_AVAIL(m)	((m)->am_owner == NULL)
310193750Sjkim#define	ACPIMTX_OWNED(m)	((m)->am_owner == curthread)
311193750Sjkim
312193750Sjkimvoid
313193750SjkimAcpiOsDeleteMutex(ACPI_MUTEX Handle)
314193750Sjkim{
315193750Sjkim	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
316193750Sjkim
317193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
318193750Sjkim
319193750Sjkim	if (am == NULL) {
320193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n"));
321193750Sjkim		return_VOID;
32267760Smsmith	}
32388420Siwasaki
324193750Sjkim	mtx_lock(&am->am_lock);
325193750Sjkim
326193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name));
327193750Sjkim
328193750Sjkim	if (am->am_waiters > 0) {
329193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
330193750Sjkim		    "reset %s, owner %p\n", am->am_name, am->am_owner));
331193750Sjkim		am->am_reset = 1;
332193750Sjkim		wakeup(am);
333193750Sjkim		while (am->am_waiters > 0) {
334193750Sjkim			if (mtx_sleep(&am->am_reset, &am->am_lock,
335193750Sjkim			    PCATCH, "acmrst", hz) == EINTR) {
336193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
337193750Sjkim				    "failed to reset %s, waiters %d\n",
338193750Sjkim				    am->am_name, am->am_waiters));
339193750Sjkim				mtx_unlock(&am->am_lock);
340193750Sjkim				return_VOID;
341193750Sjkim			}
342193750Sjkim			if (ACPIMTX_AVAIL(am))
343193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
344193750Sjkim				    "wait %s, waiters %d\n",
345193750Sjkim				    am->am_name, am->am_waiters));
346193750Sjkim			else
347193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
348193750Sjkim				    "wait %s, owner %p, waiters %d\n",
349193750Sjkim				    am->am_name, am->am_owner, am->am_waiters));
350193750Sjkim		}
35188420Siwasaki	}
35288420Siwasaki
353193750Sjkim	mtx_unlock(&am->am_lock);
35488420Siwasaki
355193750Sjkim	mtx_destroy(&am->am_lock);
356193750Sjkim	free(am, M_ACPISEM);
357193750Sjkim}
358193750Sjkim
359193750SjkimACPI_STATUS
360193750SjkimAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
361193750Sjkim{
362193750Sjkim	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
363193750Sjkim	int			error, prevtick, slptick, tmo;
364193750Sjkim	ACPI_STATUS		status = AE_OK;
365193750Sjkim
366193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
367193750Sjkim
368193750Sjkim	if (am == NULL)
369193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
370193750Sjkim
371193750Sjkim	mtx_lock(&am->am_lock);
372193750Sjkim
373193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name));
374193750Sjkim
375193750Sjkim	if (ACPIMTX_OWNED(am)) {
376193750Sjkim		am->am_nested++;
377193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
378193750Sjkim		    "acquire nested %s, depth %d\n",
379193750Sjkim		    am->am_name, am->am_nested));
380193750Sjkim		mtx_unlock(&am->am_lock);
381193750Sjkim		return_ACPI_STATUS (AE_OK);
38288420Siwasaki	}
38388420Siwasaki
384193750Sjkim	switch (Timeout) {
385193750Sjkim	case ACPI_DO_NOT_WAIT:
386193750Sjkim		if (!ACPIMTX_AVAIL(am))
387193750Sjkim			status = AE_TIME;
388193750Sjkim		break;
389193750Sjkim	case ACPI_WAIT_FOREVER:
390193750Sjkim		while (!ACPIMTX_AVAIL(am)) {
391193750Sjkim			am->am_waiters++;
392193750Sjkim			error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0);
393193750Sjkim			am->am_waiters--;
394193750Sjkim			if (error == EINTR || am->am_reset) {
395193750Sjkim				status = AE_ERROR;
396193750Sjkim				break;
397193750Sjkim			}
398193750Sjkim		}
399193750Sjkim		break;
400193750Sjkim	default:
401299977Sjhb		if (cold) {
402299977Sjhb			/*
403299977Sjhb			 * Just spin polling the mutex once a
404299977Sjhb			 * millisecond.
405299977Sjhb			 */
406299977Sjhb			while (!ACPIMTX_AVAIL(am)) {
407299977Sjhb				if (Timeout == 0) {
408299977Sjhb					status = AE_TIME;
409299977Sjhb					break;
410299977Sjhb				}
411299977Sjhb				Timeout--;
412299977Sjhb				mtx_unlock(&am->am_lock);
413299977Sjhb				DELAY(1000);
414299977Sjhb				mtx_lock(&am->am_lock);
415299977Sjhb			}
416299977Sjhb			break;
417299977Sjhb		}
418193750Sjkim		tmo = timeout2hz(Timeout);
419193750Sjkim		while (!ACPIMTX_AVAIL(am)) {
420193750Sjkim			prevtick = ticks;
421193750Sjkim			am->am_waiters++;
422193750Sjkim			error = mtx_sleep(am, &am->am_lock, PCATCH,
423193750Sjkim			    "acmtx", tmo);
424193750Sjkim			am->am_waiters--;
425193750Sjkim			if (error == EINTR || am->am_reset) {
426193750Sjkim				status = AE_ERROR;
427193750Sjkim				break;
428193750Sjkim			}
429193750Sjkim			if (ACPIMTX_AVAIL(am))
430193750Sjkim				break;
431193750Sjkim			slptick = ticks - prevtick;
432193750Sjkim			if (slptick >= tmo || slptick < 0) {
433193750Sjkim				status = AE_TIME;
434193750Sjkim				break;
435193750Sjkim			}
436193750Sjkim			tmo -= slptick;
437193750Sjkim		}
43888420Siwasaki	}
439236424Sjkim	if (ACPI_SUCCESS(status))
440193750Sjkim		am->am_owner = curthread;
44188420Siwasaki
442193750Sjkim	mtx_unlock(&am->am_lock);
44388420Siwasaki
444193750Sjkim	return_ACPI_STATUS (status);
44567760Smsmith}
44667760Smsmith
447193750Sjkimvoid
448193750SjkimAcpiOsReleaseMutex(ACPI_MUTEX Handle)
44967760Smsmith{
450193750Sjkim	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
45167760Smsmith
452193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
45371876Smsmith
454194639Sjkim	if (am == NULL) {
455193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
456193750Sjkim		    "cannot release null mutex\n"));
457194639Sjkim		return_VOID;
458194639Sjkim	}
45967760Smsmith
460193750Sjkim	mtx_lock(&am->am_lock);
46188420Siwasaki
462193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name));
46388420Siwasaki
464193750Sjkim	if (ACPIMTX_OWNED(am)) {
465193750Sjkim		if (am->am_nested > 0) {
466193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
467193750Sjkim			    "release nested %s, depth %d\n",
468193750Sjkim			    am->am_name, am->am_nested));
469193750Sjkim			am->am_nested--;
470193750Sjkim		} else
471193750Sjkim			am->am_owner = NULL;
472193750Sjkim	} else {
473193750Sjkim		if (ACPIMTX_AVAIL(am))
474193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
475193750Sjkim			    "release already available %s\n", am->am_name));
476193750Sjkim		else
477193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
478193750Sjkim			    "release unowned %s from %p, depth %d\n",
479193750Sjkim			    am->am_name, am->am_owner, am->am_nested));
480193750Sjkim	}
481193750Sjkim	if (am->am_waiters > 0 && ACPIMTX_AVAIL(am))
482193750Sjkim		wakeup_one(am);
483128227Snjl
484193750Sjkim	mtx_unlock(&am->am_lock);
48567760Smsmith}
486117530Snjl
487193750Sjkim#undef ACPIMTX_AVAIL
488193750Sjkim#undef ACPIMTX_OWNED
489193750Sjkim
490193750Sjkim/*
491193750Sjkim * ACPI_SPINLOCK
492193750Sjkim */
493167910Sjkimstruct acpi_spinlock {
494193750Sjkim	struct mtx	al_lock;
495193750Sjkim	char		al_name[32];
496193750Sjkim	int		al_nested;
497167908Snjl};
498167908Snjl
499117530SnjlACPI_STATUS
500193750SjkimAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
501117530Snjl{
502193750Sjkim	struct acpi_spinlock	*al;
503117530Snjl
504193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
505117530Snjl
506193750Sjkim	if (OutHandle == NULL)
507193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
508193750Sjkim
509193750Sjkim	if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
510193750Sjkim		return_ACPI_STATUS (AE_NO_MEMORY);
511193750Sjkim
512193750Sjkim#ifdef ACPI_DEBUG
513193750Sjkim	if (OutHandle == &AcpiGbl_GpeLock)
514193750Sjkim		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)");
515193750Sjkim	else if (OutHandle == &AcpiGbl_HardwareLock)
516193750Sjkim		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)");
517193750Sjkim	else
518193750Sjkim#endif
519193750Sjkim	snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al);
520193750Sjkim	mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN);
521193750Sjkim
522193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name));
523193750Sjkim
524193750Sjkim	*OutHandle = (ACPI_SPINLOCK)al;
525193750Sjkim
526193750Sjkim	return_ACPI_STATUS (AE_OK);
527117530Snjl}
528117530Snjl
529117530Snjlvoid
530193750SjkimAcpiOsDeleteLock(ACPI_SPINLOCK Handle)
531117530Snjl{
532193750Sjkim	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
533117530Snjl
534193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
535193750Sjkim
536193750Sjkim	if (al == NULL) {
537193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
538193750Sjkim		    "cannot delete null spinlock\n"));
539193750Sjkim		return_VOID;
540193750Sjkim	}
541193750Sjkim
542193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name));
543193750Sjkim
544193750Sjkim	mtx_destroy(&al->al_lock);
545193750Sjkim	free(al, M_ACPISEM);
546117530Snjl}
547117530Snjl
548193530SjkimACPI_CPU_FLAGS
549193750SjkimAcpiOsAcquireLock(ACPI_SPINLOCK Handle)
550117530Snjl{
551193750Sjkim	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
552117530Snjl
553193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
554193750Sjkim
555193750Sjkim	if (al == NULL) {
556193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
557193750Sjkim		    "cannot acquire null spinlock\n"));
558193750Sjkim		return (0);
559193750Sjkim	}
560193750Sjkim
561193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name));
562193750Sjkim
563193750Sjkim	if (mtx_owned(&al->al_lock)) {
564193750Sjkim		al->al_nested++;
565193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
566193750Sjkim		    "acquire nested %s, depth %d\n",
567193750Sjkim		    al->al_name, al->al_nested));
568193750Sjkim	} else
569193750Sjkim		mtx_lock_spin(&al->al_lock);
570193750Sjkim
571151948Sjkim	return (0);
572117530Snjl}
573117530Snjl
574117530Snjlvoid
575193750SjkimAcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
576117530Snjl{
577193750Sjkim	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
578117530Snjl
579193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
580193750Sjkim
581193750Sjkim	if (al == NULL) {
582193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
583193750Sjkim		    "cannot release null spinlock\n"));
584193750Sjkim		return_VOID;
585193750Sjkim	}
586193750Sjkim
587193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name));
588193750Sjkim
589193750Sjkim	if (mtx_owned(&al->al_lock)) {
590193750Sjkim		if (al->al_nested > 0) {
591193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
592193750Sjkim			    "release nested %s, depth %d\n",
593193750Sjkim			    al->al_name, al->al_nested));
594193750Sjkim			al->al_nested--;
595193750Sjkim		} else
596193750Sjkim			mtx_unlock_spin(&al->al_lock);
597193750Sjkim	} else
598193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
599193750Sjkim		    "cannot release unowned %s\n", al->al_name));
600117530Snjl}
601128979Snjl
602193750Sjkim/* Section 5.2.10.1: global lock acquire/release functions */
603128979Snjl
604128979Snjl/*
605128979Snjl * Acquire the global lock.  If busy, set the pending bit.  The caller
606128979Snjl * will wait for notification from the BIOS that the lock is available
607128979Snjl * and then attempt to acquire it again.
608128979Snjl */
609128979Snjlint
610254300Sjkimacpi_acquire_global_lock(volatile uint32_t *lock)
611128979Snjl{
612193750Sjkim	uint32_t	new, old;
613128979Snjl
614128979Snjl	do {
615128979Snjl		old = *lock;
616254300Sjkim		new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED;
617254300Sjkim		if ((old & ACPI_GLOCK_OWNED) != 0)
618254300Sjkim			new |= ACPI_GLOCK_PENDING;
619254300Sjkim	} while (atomic_cmpset_32(lock, old, new) == 0);
620128979Snjl
621254300Sjkim	return ((new & ACPI_GLOCK_PENDING) == 0);
622128979Snjl}
623128979Snjl
624128979Snjl/*
625128979Snjl * Release the global lock, returning whether there is a waiter pending.
626128979Snjl * If the BIOS set the pending bit, OSPM must notify the BIOS when it
627128979Snjl * releases the lock.
628128979Snjl */
629128979Snjlint
630254300Sjkimacpi_release_global_lock(volatile uint32_t *lock)
631128979Snjl{
632193750Sjkim	uint32_t	new, old;
633128979Snjl
634128979Snjl	do {
635128979Snjl		old = *lock;
636254300Sjkim		new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED);
637254300Sjkim	} while (atomic_cmpset_32(lock, old, new) == 0);
638128979Snjl
639254300Sjkim	return ((old & ACPI_GLOCK_PENDING) != 0);
640128979Snjl}
641