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:
191193750Sjkim		tmo = timeout2hz(Timeout);
192193750Sjkim		while (!ACPISEM_AVAIL(as, Units)) {
193193750Sjkim			prevtick = ticks;
194193750Sjkim			as->as_waiters++;
195193750Sjkim			error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo);
196193750Sjkim			as->as_waiters--;
197193750Sjkim			if (error == EINTR || as->as_reset) {
198193750Sjkim				status = AE_ERROR;
199193750Sjkim				break;
200193750Sjkim			}
201193750Sjkim			if (ACPISEM_AVAIL(as, Units))
202193750Sjkim				break;
203193750Sjkim			slptick = ticks - prevtick;
204193750Sjkim			if (slptick >= tmo || slptick < 0) {
205193750Sjkim				status = AE_TIME;
206193750Sjkim				break;
207193750Sjkim			}
208193750Sjkim			tmo -= slptick;
209193750Sjkim		}
210193750Sjkim	}
211236424Sjkim	if (ACPI_SUCCESS(status))
212193750Sjkim		as->as_units -= Units;
21371876Smsmith
214193750Sjkim	mtx_unlock(&as->as_lock);
21588420Siwasaki
216193750Sjkim	return_ACPI_STATUS (status);
217193750Sjkim}
21888420Siwasaki
219193750SjkimACPI_STATUS
220193750SjkimAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
221193750Sjkim{
222193750Sjkim	struct acpi_sema	*as = (struct acpi_sema *)Handle;
223193750Sjkim	UINT32			i;
22488420Siwasaki
225193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
22688420Siwasaki
227193750Sjkim	if (as == NULL || Units == 0)
228193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
229193750Sjkim
230193750Sjkim	mtx_lock(&as->as_lock);
231193750Sjkim
23288420Siwasaki	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
233193750Sjkim	    "return %u units to %s, units %u, waiters %d\n",
234193750Sjkim	    Units, as->as_name, as->as_units, as->as_waiters));
23588420Siwasaki
236193750Sjkim	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT &&
237193750Sjkim	    (as->as_maxunits < Units ||
238193750Sjkim	    as->as_maxunits - Units < as->as_units)) {
239193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
240193750Sjkim		    "exceeded max units %u\n", as->as_maxunits));
241193750Sjkim		mtx_unlock(&as->as_lock);
242193750Sjkim		return_ACPI_STATUS (AE_LIMIT);
24388420Siwasaki	}
24488420Siwasaki
245193750Sjkim	as->as_units += Units;
246193750Sjkim	if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units))
247193750Sjkim		for (i = 0; i < Units; i++)
248193750Sjkim			cv_signal(&as->as_cv);
24988420Siwasaki
250193750Sjkim	mtx_unlock(&as->as_lock);
25188420Siwasaki
252193750Sjkim	return_ACPI_STATUS (AE_OK);
253193750Sjkim}
25488420Siwasaki
255193750Sjkim#undef ACPISEM_AVAIL
256193750Sjkim
257193750Sjkim/*
258193750Sjkim * ACPI_MUTEX
259193750Sjkim */
260193750Sjkimstruct acpi_mutex {
261193750Sjkim	struct mtx	am_lock;
262193750Sjkim	char		am_name[32];
263193750Sjkim	struct thread	*am_owner;
264193750Sjkim	int		am_nested;
265193750Sjkim	int		am_waiters;
266193750Sjkim	int		am_reset;
267193750Sjkim};
268193750Sjkim
269193750SjkimACPI_STATUS
270193750SjkimAcpiOsCreateMutex(ACPI_MUTEX *OutHandle)
271193750Sjkim{
272193750Sjkim	struct acpi_mutex	*am;
273193750Sjkim
274193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
275193750Sjkim
276193750Sjkim	if (OutHandle == NULL)
277193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
278193750Sjkim
279193750Sjkim	if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
280193750Sjkim		return_ACPI_STATUS (AE_NO_MEMORY);
281193750Sjkim
282193750Sjkim	snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am);
283193750Sjkim	mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF);
284193750Sjkim
285193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name));
286193750Sjkim
287193750Sjkim	*OutHandle = (ACPI_MUTEX)am;
288193750Sjkim
289193750Sjkim	return_ACPI_STATUS (AE_OK);
290193750Sjkim}
291193750Sjkim
292193750Sjkim#define	ACPIMTX_AVAIL(m)	((m)->am_owner == NULL)
293193750Sjkim#define	ACPIMTX_OWNED(m)	((m)->am_owner == curthread)
294193750Sjkim
295193750Sjkimvoid
296193750SjkimAcpiOsDeleteMutex(ACPI_MUTEX Handle)
297193750Sjkim{
298193750Sjkim	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
299193750Sjkim
300193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
301193750Sjkim
302193750Sjkim	if (am == NULL) {
303193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n"));
304193750Sjkim		return_VOID;
30567760Smsmith	}
30688420Siwasaki
307193750Sjkim	mtx_lock(&am->am_lock);
308193750Sjkim
309193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name));
310193750Sjkim
311193750Sjkim	if (am->am_waiters > 0) {
312193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
313193750Sjkim		    "reset %s, owner %p\n", am->am_name, am->am_owner));
314193750Sjkim		am->am_reset = 1;
315193750Sjkim		wakeup(am);
316193750Sjkim		while (am->am_waiters > 0) {
317193750Sjkim			if (mtx_sleep(&am->am_reset, &am->am_lock,
318193750Sjkim			    PCATCH, "acmrst", hz) == EINTR) {
319193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
320193750Sjkim				    "failed to reset %s, waiters %d\n",
321193750Sjkim				    am->am_name, am->am_waiters));
322193750Sjkim				mtx_unlock(&am->am_lock);
323193750Sjkim				return_VOID;
324193750Sjkim			}
325193750Sjkim			if (ACPIMTX_AVAIL(am))
326193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
327193750Sjkim				    "wait %s, waiters %d\n",
328193750Sjkim				    am->am_name, am->am_waiters));
329193750Sjkim			else
330193750Sjkim				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
331193750Sjkim				    "wait %s, owner %p, waiters %d\n",
332193750Sjkim				    am->am_name, am->am_owner, am->am_waiters));
333193750Sjkim		}
33488420Siwasaki	}
33588420Siwasaki
336193750Sjkim	mtx_unlock(&am->am_lock);
33788420Siwasaki
338193750Sjkim	mtx_destroy(&am->am_lock);
339193750Sjkim	free(am, M_ACPISEM);
340193750Sjkim}
341193750Sjkim
342193750SjkimACPI_STATUS
343193750SjkimAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
344193750Sjkim{
345193750Sjkim	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
346193750Sjkim	int			error, prevtick, slptick, tmo;
347193750Sjkim	ACPI_STATUS		status = AE_OK;
348193750Sjkim
349193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
350193750Sjkim
351193750Sjkim	if (am == NULL)
352193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
353193750Sjkim
354193750Sjkim	mtx_lock(&am->am_lock);
355193750Sjkim
356193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name));
357193750Sjkim
358193750Sjkim	if (ACPIMTX_OWNED(am)) {
359193750Sjkim		am->am_nested++;
360193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
361193750Sjkim		    "acquire nested %s, depth %d\n",
362193750Sjkim		    am->am_name, am->am_nested));
363193750Sjkim		mtx_unlock(&am->am_lock);
364193750Sjkim		return_ACPI_STATUS (AE_OK);
36588420Siwasaki	}
36688420Siwasaki
367193750Sjkim	switch (Timeout) {
368193750Sjkim	case ACPI_DO_NOT_WAIT:
369193750Sjkim		if (!ACPIMTX_AVAIL(am))
370193750Sjkim			status = AE_TIME;
371193750Sjkim		break;
372193750Sjkim	case ACPI_WAIT_FOREVER:
373193750Sjkim		while (!ACPIMTX_AVAIL(am)) {
374193750Sjkim			am->am_waiters++;
375193750Sjkim			error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0);
376193750Sjkim			am->am_waiters--;
377193750Sjkim			if (error == EINTR || am->am_reset) {
378193750Sjkim				status = AE_ERROR;
379193750Sjkim				break;
380193750Sjkim			}
381193750Sjkim		}
382193750Sjkim		break;
383193750Sjkim	default:
384193750Sjkim		tmo = timeout2hz(Timeout);
385193750Sjkim		while (!ACPIMTX_AVAIL(am)) {
386193750Sjkim			prevtick = ticks;
387193750Sjkim			am->am_waiters++;
388193750Sjkim			error = mtx_sleep(am, &am->am_lock, PCATCH,
389193750Sjkim			    "acmtx", tmo);
390193750Sjkim			am->am_waiters--;
391193750Sjkim			if (error == EINTR || am->am_reset) {
392193750Sjkim				status = AE_ERROR;
393193750Sjkim				break;
394193750Sjkim			}
395193750Sjkim			if (ACPIMTX_AVAIL(am))
396193750Sjkim				break;
397193750Sjkim			slptick = ticks - prevtick;
398193750Sjkim			if (slptick >= tmo || slptick < 0) {
399193750Sjkim				status = AE_TIME;
400193750Sjkim				break;
401193750Sjkim			}
402193750Sjkim			tmo -= slptick;
403193750Sjkim		}
40488420Siwasaki	}
405236424Sjkim	if (ACPI_SUCCESS(status))
406193750Sjkim		am->am_owner = curthread;
40788420Siwasaki
408193750Sjkim	mtx_unlock(&am->am_lock);
40988420Siwasaki
410193750Sjkim	return_ACPI_STATUS (status);
41167760Smsmith}
41267760Smsmith
413193750Sjkimvoid
414193750SjkimAcpiOsReleaseMutex(ACPI_MUTEX Handle)
41567760Smsmith{
416193750Sjkim	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
41767760Smsmith
418193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
41971876Smsmith
420194639Sjkim	if (am == NULL) {
421193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
422193750Sjkim		    "cannot release null mutex\n"));
423194639Sjkim		return_VOID;
424194639Sjkim	}
42567760Smsmith
426193750Sjkim	mtx_lock(&am->am_lock);
42788420Siwasaki
428193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name));
42988420Siwasaki
430193750Sjkim	if (ACPIMTX_OWNED(am)) {
431193750Sjkim		if (am->am_nested > 0) {
432193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
433193750Sjkim			    "release nested %s, depth %d\n",
434193750Sjkim			    am->am_name, am->am_nested));
435193750Sjkim			am->am_nested--;
436193750Sjkim		} else
437193750Sjkim			am->am_owner = NULL;
438193750Sjkim	} else {
439193750Sjkim		if (ACPIMTX_AVAIL(am))
440193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
441193750Sjkim			    "release already available %s\n", am->am_name));
442193750Sjkim		else
443193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
444193750Sjkim			    "release unowned %s from %p, depth %d\n",
445193750Sjkim			    am->am_name, am->am_owner, am->am_nested));
446193750Sjkim	}
447193750Sjkim	if (am->am_waiters > 0 && ACPIMTX_AVAIL(am))
448193750Sjkim		wakeup_one(am);
449128227Snjl
450193750Sjkim	mtx_unlock(&am->am_lock);
45167760Smsmith}
452117530Snjl
453193750Sjkim#undef ACPIMTX_AVAIL
454193750Sjkim#undef ACPIMTX_OWNED
455193750Sjkim
456193750Sjkim/*
457193750Sjkim * ACPI_SPINLOCK
458193750Sjkim */
459167910Sjkimstruct acpi_spinlock {
460193750Sjkim	struct mtx	al_lock;
461193750Sjkim	char		al_name[32];
462193750Sjkim	int		al_nested;
463167908Snjl};
464167908Snjl
465117530SnjlACPI_STATUS
466193750SjkimAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
467117530Snjl{
468193750Sjkim	struct acpi_spinlock	*al;
469117530Snjl
470193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
471117530Snjl
472193750Sjkim	if (OutHandle == NULL)
473193750Sjkim		return_ACPI_STATUS (AE_BAD_PARAMETER);
474193750Sjkim
475193750Sjkim	if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
476193750Sjkim		return_ACPI_STATUS (AE_NO_MEMORY);
477193750Sjkim
478193750Sjkim#ifdef ACPI_DEBUG
479193750Sjkim	if (OutHandle == &AcpiGbl_GpeLock)
480193750Sjkim		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)");
481193750Sjkim	else if (OutHandle == &AcpiGbl_HardwareLock)
482193750Sjkim		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)");
483193750Sjkim	else
484193750Sjkim#endif
485193750Sjkim	snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al);
486193750Sjkim	mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN);
487193750Sjkim
488193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name));
489193750Sjkim
490193750Sjkim	*OutHandle = (ACPI_SPINLOCK)al;
491193750Sjkim
492193750Sjkim	return_ACPI_STATUS (AE_OK);
493117530Snjl}
494117530Snjl
495117530Snjlvoid
496193750SjkimAcpiOsDeleteLock(ACPI_SPINLOCK Handle)
497117530Snjl{
498193750Sjkim	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
499117530Snjl
500193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
501193750Sjkim
502193750Sjkim	if (al == NULL) {
503193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
504193750Sjkim		    "cannot delete null spinlock\n"));
505193750Sjkim		return_VOID;
506193750Sjkim	}
507193750Sjkim
508193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name));
509193750Sjkim
510193750Sjkim	mtx_destroy(&al->al_lock);
511193750Sjkim	free(al, M_ACPISEM);
512117530Snjl}
513117530Snjl
514193530SjkimACPI_CPU_FLAGS
515193750SjkimAcpiOsAcquireLock(ACPI_SPINLOCK Handle)
516117530Snjl{
517193750Sjkim	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
518117530Snjl
519193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
520193750Sjkim
521193750Sjkim	if (al == NULL) {
522193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
523193750Sjkim		    "cannot acquire null spinlock\n"));
524193750Sjkim		return (0);
525193750Sjkim	}
526193750Sjkim
527193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name));
528193750Sjkim
529193750Sjkim	if (mtx_owned(&al->al_lock)) {
530193750Sjkim		al->al_nested++;
531193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
532193750Sjkim		    "acquire nested %s, depth %d\n",
533193750Sjkim		    al->al_name, al->al_nested));
534193750Sjkim	} else
535193750Sjkim		mtx_lock_spin(&al->al_lock);
536193750Sjkim
537151948Sjkim	return (0);
538117530Snjl}
539117530Snjl
540117530Snjlvoid
541193750SjkimAcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
542117530Snjl{
543193750Sjkim	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
544117530Snjl
545193750Sjkim	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
546193750Sjkim
547193750Sjkim	if (al == NULL) {
548193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
549193750Sjkim		    "cannot release null spinlock\n"));
550193750Sjkim		return_VOID;
551193750Sjkim	}
552193750Sjkim
553193750Sjkim	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name));
554193750Sjkim
555193750Sjkim	if (mtx_owned(&al->al_lock)) {
556193750Sjkim		if (al->al_nested > 0) {
557193750Sjkim			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
558193750Sjkim			    "release nested %s, depth %d\n",
559193750Sjkim			    al->al_name, al->al_nested));
560193750Sjkim			al->al_nested--;
561193750Sjkim		} else
562193750Sjkim			mtx_unlock_spin(&al->al_lock);
563193750Sjkim	} else
564193750Sjkim		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
565193750Sjkim		    "cannot release unowned %s\n", al->al_name));
566117530Snjl}
567128979Snjl
568193750Sjkim/* Section 5.2.10.1: global lock acquire/release functions */
569128979Snjl
570128979Snjl/*
571128979Snjl * Acquire the global lock.  If busy, set the pending bit.  The caller
572128979Snjl * will wait for notification from the BIOS that the lock is available
573128979Snjl * and then attempt to acquire it again.
574128979Snjl */
575128979Snjlint
576254300Sjkimacpi_acquire_global_lock(volatile uint32_t *lock)
577128979Snjl{
578193750Sjkim	uint32_t	new, old;
579128979Snjl
580128979Snjl	do {
581128979Snjl		old = *lock;
582254300Sjkim		new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED;
583254300Sjkim		if ((old & ACPI_GLOCK_OWNED) != 0)
584254300Sjkim			new |= ACPI_GLOCK_PENDING;
585254300Sjkim	} while (atomic_cmpset_32(lock, old, new) == 0);
586128979Snjl
587254300Sjkim	return ((new & ACPI_GLOCK_PENDING) == 0);
588128979Snjl}
589128979Snjl
590128979Snjl/*
591128979Snjl * Release the global lock, returning whether there is a waiter pending.
592128979Snjl * If the BIOS set the pending bit, OSPM must notify the BIOS when it
593128979Snjl * releases the lock.
594128979Snjl */
595128979Snjlint
596254300Sjkimacpi_release_global_lock(volatile uint32_t *lock)
597128979Snjl{
598193750Sjkim	uint32_t	new, old;
599128979Snjl
600128979Snjl	do {
601128979Snjl		old = *lock;
602254300Sjkim		new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED);
603254300Sjkim	} while (atomic_cmpset_32(lock, old, new) == 0);
604128979Snjl
605254300Sjkim	return ((old & ACPI_GLOCK_PENDING) != 0);
606128979Snjl}
607