OsdSynch.c revision 254300
1203288Srnoland/*-
2203288Srnoland * Copyright (c) 2000 Michael Smith
3203288Srnoland * Copyright (c) 2000 BSDi
4203288Srnoland * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org>
5203288Srnoland * All rights reserved.
6203288Srnoland *
7203288Srnoland * Redistribution and use in source and binary forms, with or without
8203288Srnoland * modification, are permitted provided that the following conditions
9203288Srnoland * are met:
10203288Srnoland * 1. Redistributions of source code must retain the above copyright
11203288Srnoland *    notice, this list of conditions and the following disclaimer.
12203288Srnoland * 2. Redistributions in binary form must reproduce the above copyright
13203288Srnoland *    notice, this list of conditions and the following disclaimer in the
14203288Srnoland *    documentation and/or other materials provided with the distribution.
15203288Srnoland *
16203288Srnoland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17203288Srnoland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18203288Srnoland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19203288Srnoland * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20203288Srnoland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21203288Srnoland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22203288Srnoland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23203288Srnoland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24203288Srnoland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25203288Srnoland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26203288Srnoland * SUCH DAMAGE.
27203288Srnoland */
28203288Srnoland
29203288Srnoland/*
30203288Srnoland * 6.1 : Mutual Exclusion and Synchronisation
31203288Srnoland */
32203288Srnoland
33203288Srnoland#include <sys/cdefs.h>
34203288Srnoland__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSynch.c 254300 2013-08-13 21:34:03Z jkim $");
35203288Srnoland
36203288Srnoland#include <contrib/dev/acpica/include/acpi.h>
37203288Srnoland#include <contrib/dev/acpica/include/accommon.h>
38203288Srnoland
39203288Srnoland#include <sys/condvar.h>
40203288Srnoland#include <sys/kernel.h>
41203288Srnoland#include <sys/lock.h>
42203288Srnoland#include <sys/malloc.h>
43203288Srnoland#include <sys/mutex.h>
44203288Srnoland
45203288Srnoland#define	_COMPONENT	ACPI_OS_SERVICES
46203288SrnolandACPI_MODULE_NAME("SYNCH")
47203288Srnoland
48203288Srnolandstatic MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
49203288Srnoland
50203288Srnoland/*
51203288Srnoland * Convert milliseconds to ticks.
52203288Srnoland */
53203288Srnolandstatic int
54203288Srnolandtimeout2hz(UINT16 Timeout)
55203288Srnoland{
56203288Srnoland	struct timeval		tv;
57203288Srnoland
58203288Srnoland	tv.tv_sec = (time_t)(Timeout / 1000);
59203288Srnoland	tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000;
60203288Srnoland
61203288Srnoland	return (tvtohz(&tv));
62203288Srnoland}
63203288Srnoland
64203288Srnoland/*
65203288Srnoland * ACPI_SEMAPHORE
66203288Srnoland */
67203288Srnolandstruct acpi_sema {
68203288Srnoland	struct mtx	as_lock;
69203288Srnoland	char		as_name[32];
70203288Srnoland	struct cv	as_cv;
71203288Srnoland	UINT32		as_maxunits;
72203288Srnoland	UINT32		as_units;
73203288Srnoland	int		as_waiters;
74203288Srnoland	int		as_reset;
75203288Srnoland};
76203288Srnoland
77203288SrnolandACPI_STATUS
78203288SrnolandAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
79203288Srnoland    ACPI_SEMAPHORE *OutHandle)
80203288Srnoland{
81203288Srnoland	struct acpi_sema	*as;
82203288Srnoland
83203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
84203288Srnoland
85203288Srnoland	if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits)
86203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
87203288Srnoland
88203288Srnoland	if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
89203288Srnoland		return_ACPI_STATUS (AE_NO_MEMORY);
90203288Srnoland
91203288Srnoland	snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as);
92203288Srnoland	mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF);
93203288Srnoland	cv_init(&as->as_cv, as->as_name);
94203288Srnoland	as->as_maxunits = MaxUnits;
95203288Srnoland	as->as_units = InitialUnits;
96203288Srnoland
97203288Srnoland	*OutHandle = (ACPI_SEMAPHORE)as;
98203288Srnoland
99203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n",
100203288Srnoland	    as->as_name, MaxUnits, InitialUnits));
101203288Srnoland
102203288Srnoland	return_ACPI_STATUS (AE_OK);
103203288Srnoland}
104203288Srnoland
105203288SrnolandACPI_STATUS
106203288SrnolandAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
107203288Srnoland{
108203288Srnoland	struct acpi_sema	*as = (struct acpi_sema *)Handle;
109203288Srnoland
110203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
111203288Srnoland
112203288Srnoland	if (as == NULL)
113203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
114203288Srnoland
115203288Srnoland	mtx_lock(&as->as_lock);
116203288Srnoland
117203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name));
118203288Srnoland
119203288Srnoland	if (as->as_waiters > 0) {
120203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
121203288Srnoland		    "reset %s, units %u, waiters %d\n",
122203288Srnoland		    as->as_name, as->as_units, as->as_waiters));
123203288Srnoland		as->as_reset = 1;
124203288Srnoland		cv_broadcast(&as->as_cv);
125203288Srnoland		while (as->as_waiters > 0) {
126203288Srnoland			if (mtx_sleep(&as->as_reset, &as->as_lock,
127203288Srnoland			    PCATCH, "acsrst", hz) == EINTR) {
128203288Srnoland				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
129203288Srnoland				    "failed to reset %s, waiters %d\n",
130203288Srnoland				    as->as_name, as->as_waiters));
131203288Srnoland				mtx_unlock(&as->as_lock);
132203288Srnoland				return_ACPI_STATUS (AE_ERROR);
133203288Srnoland			}
134203288Srnoland			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
135203288Srnoland			    "wait %s, units %u, waiters %d\n",
136203288Srnoland			    as->as_name, as->as_units, as->as_waiters));
137203288Srnoland		}
138203288Srnoland	}
139203288Srnoland
140203288Srnoland	mtx_unlock(&as->as_lock);
141203288Srnoland
142203288Srnoland	mtx_destroy(&as->as_lock);
143203288Srnoland	cv_destroy(&as->as_cv);
144203288Srnoland	free(as, M_ACPISEM);
145203288Srnoland
146203288Srnoland	return_ACPI_STATUS (AE_OK);
147203288Srnoland}
148203288Srnoland
149203288Srnoland#define	ACPISEM_AVAIL(s, u)	((s)->as_units >= (u))
150203288Srnoland
151203288SrnolandACPI_STATUS
152203288SrnolandAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
153203288Srnoland{
154203288Srnoland	struct acpi_sema	*as = (struct acpi_sema *)Handle;
155203288Srnoland	int			error, prevtick, slptick, tmo;
156203288Srnoland	ACPI_STATUS		status = AE_OK;
157203288Srnoland
158203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
159203288Srnoland
160203288Srnoland	if (as == NULL || Units == 0)
161203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
162203288Srnoland
163203288Srnoland	mtx_lock(&as->as_lock);
164203288Srnoland
165203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
166203288Srnoland	    "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n",
167203288Srnoland	    Units, as->as_name, as->as_units, as->as_waiters, Timeout));
168203288Srnoland
169203288Srnoland	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) {
170203288Srnoland		mtx_unlock(&as->as_lock);
171203288Srnoland		return_ACPI_STATUS (AE_LIMIT);
172203288Srnoland	}
173203288Srnoland
174203288Srnoland	switch (Timeout) {
175203288Srnoland	case ACPI_DO_NOT_WAIT:
176203288Srnoland		if (!ACPISEM_AVAIL(as, Units))
177203288Srnoland			status = AE_TIME;
178203288Srnoland		break;
179203288Srnoland	case ACPI_WAIT_FOREVER:
180216699Salc		while (!ACPISEM_AVAIL(as, Units)) {
181216699Salc			as->as_waiters++;
182216699Salc			error = cv_wait_sig(&as->as_cv, &as->as_lock);
183216699Salc			as->as_waiters--;
184203288Srnoland			if (error == EINTR || as->as_reset) {
185203288Srnoland				status = AE_ERROR;
186203288Srnoland				break;
187203288Srnoland			}
188203288Srnoland		}
189203288Srnoland		break;
190203288Srnoland	default:
191203288Srnoland		tmo = timeout2hz(Timeout);
192203288Srnoland		while (!ACPISEM_AVAIL(as, Units)) {
193203288Srnoland			prevtick = ticks;
194203288Srnoland			as->as_waiters++;
195203288Srnoland			error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo);
196203288Srnoland			as->as_waiters--;
197203288Srnoland			if (error == EINTR || as->as_reset) {
198203288Srnoland				status = AE_ERROR;
199203288Srnoland				break;
200203288Srnoland			}
201203288Srnoland			if (ACPISEM_AVAIL(as, Units))
202203288Srnoland				break;
203203288Srnoland			slptick = ticks - prevtick;
204203288Srnoland			if (slptick >= tmo || slptick < 0) {
205203288Srnoland				status = AE_TIME;
206203288Srnoland				break;
207203288Srnoland			}
208203288Srnoland			tmo -= slptick;
209203288Srnoland		}
210203288Srnoland	}
211203288Srnoland	if (ACPI_SUCCESS(status))
212203288Srnoland		as->as_units -= Units;
213203288Srnoland
214203288Srnoland	mtx_unlock(&as->as_lock);
215203288Srnoland
216203288Srnoland	return_ACPI_STATUS (status);
217203288Srnoland}
218203288Srnoland
219203288SrnolandACPI_STATUS
220203288SrnolandAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
221203288Srnoland{
222203288Srnoland	struct acpi_sema	*as = (struct acpi_sema *)Handle;
223203288Srnoland	UINT32			i;
224203288Srnoland
225203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
226203288Srnoland
227203288Srnoland	if (as == NULL || Units == 0)
228203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
229203288Srnoland
230203288Srnoland	mtx_lock(&as->as_lock);
231203288Srnoland
232216699Salc	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
233203288Srnoland	    "return %u units to %s, units %u, waiters %d\n",
234203288Srnoland	    Units, as->as_name, as->as_units, as->as_waiters));
235216699Salc
236216699Salc	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT &&
237216699Salc	    (as->as_maxunits < Units ||
238216699Salc	    as->as_maxunits - Units < as->as_units)) {
239216699Salc		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
240216699Salc		    "exceeded max units %u\n", as->as_maxunits));
241216699Salc		mtx_unlock(&as->as_lock);
242216699Salc		return_ACPI_STATUS (AE_LIMIT);
243216699Salc	}
244207410Skmacy
245203288Srnoland	as->as_units += Units;
246203288Srnoland	if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units))
247207410Skmacy		for (i = 0; i < Units; i++)
248203288Srnoland			cv_signal(&as->as_cv);
249203288Srnoland
250203288Srnoland	mtx_unlock(&as->as_lock);
251203288Srnoland
252203288Srnoland	return_ACPI_STATUS (AE_OK);
253203288Srnoland}
254203288Srnoland
255203288Srnoland#undef ACPISEM_AVAIL
256203288Srnoland
257203288Srnoland/*
258203288Srnoland * ACPI_MUTEX
259203288Srnoland */
260203288Srnolandstruct acpi_mutex {
261203288Srnoland	struct mtx	am_lock;
262203288Srnoland	char		am_name[32];
263203288Srnoland	struct thread	*am_owner;
264203288Srnoland	int		am_nested;
265203288Srnoland	int		am_waiters;
266203288Srnoland	int		am_reset;
267203288Srnoland};
268203288Srnoland
269203288SrnolandACPI_STATUS
270203288SrnolandAcpiOsCreateMutex(ACPI_MUTEX *OutHandle)
271203288Srnoland{
272203288Srnoland	struct acpi_mutex	*am;
273203288Srnoland
274203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
275203288Srnoland
276203288Srnoland	if (OutHandle == NULL)
277203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
278203288Srnoland
279203288Srnoland	if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
280203288Srnoland		return_ACPI_STATUS (AE_NO_MEMORY);
281203288Srnoland
282203288Srnoland	snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am);
283203288Srnoland	mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF);
284203288Srnoland
285203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name));
286203288Srnoland
287203288Srnoland	*OutHandle = (ACPI_MUTEX)am;
288203288Srnoland
289203288Srnoland	return_ACPI_STATUS (AE_OK);
290203288Srnoland}
291203288Srnoland
292203288Srnoland#define	ACPIMTX_AVAIL(m)	((m)->am_owner == NULL)
293203288Srnoland#define	ACPIMTX_OWNED(m)	((m)->am_owner == curthread)
294203288Srnoland
295203288Srnolandvoid
296203288SrnolandAcpiOsDeleteMutex(ACPI_MUTEX Handle)
297203288Srnoland{
298203288Srnoland	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
299203288Srnoland
300203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
301203288Srnoland
302203288Srnoland	if (am == NULL) {
303203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n"));
304203288Srnoland		return_VOID;
305203288Srnoland	}
306203288Srnoland
307203288Srnoland	mtx_lock(&am->am_lock);
308203288Srnoland
309203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name));
310203288Srnoland
311203288Srnoland	if (am->am_waiters > 0) {
312203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
313203288Srnoland		    "reset %s, owner %p\n", am->am_name, am->am_owner));
314203288Srnoland		am->am_reset = 1;
315203288Srnoland		wakeup(am);
316203288Srnoland		while (am->am_waiters > 0) {
317203288Srnoland			if (mtx_sleep(&am->am_reset, &am->am_lock,
318203288Srnoland			    PCATCH, "acmrst", hz) == EINTR) {
319203288Srnoland				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
320203288Srnoland				    "failed to reset %s, waiters %d\n",
321203288Srnoland				    am->am_name, am->am_waiters));
322203288Srnoland				mtx_unlock(&am->am_lock);
323203288Srnoland				return_VOID;
324203288Srnoland			}
325203288Srnoland			if (ACPIMTX_AVAIL(am))
326203288Srnoland				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
327203288Srnoland				    "wait %s, waiters %d\n",
328203288Srnoland				    am->am_name, am->am_waiters));
329203288Srnoland			else
330203288Srnoland				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
331203288Srnoland				    "wait %s, owner %p, waiters %d\n",
332203288Srnoland				    am->am_name, am->am_owner, am->am_waiters));
333203288Srnoland		}
334203288Srnoland	}
335203288Srnoland
336203288Srnoland	mtx_unlock(&am->am_lock);
337203288Srnoland
338203288Srnoland	mtx_destroy(&am->am_lock);
339203288Srnoland	free(am, M_ACPISEM);
340203288Srnoland}
341203288Srnoland
342203288SrnolandACPI_STATUS
343203288SrnolandAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
344203288Srnoland{
345203288Srnoland	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
346203288Srnoland	int			error, prevtick, slptick, tmo;
347203288Srnoland	ACPI_STATUS		status = AE_OK;
348203288Srnoland
349203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
350203288Srnoland
351203288Srnoland	if (am == NULL)
352203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
353203288Srnoland
354203288Srnoland	mtx_lock(&am->am_lock);
355203288Srnoland
356203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name));
357203288Srnoland
358203288Srnoland	if (ACPIMTX_OWNED(am)) {
359203288Srnoland		am->am_nested++;
360203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
361203288Srnoland		    "acquire nested %s, depth %d\n",
362203288Srnoland		    am->am_name, am->am_nested));
363203288Srnoland		mtx_unlock(&am->am_lock);
364203288Srnoland		return_ACPI_STATUS (AE_OK);
365203288Srnoland	}
366203288Srnoland
367203288Srnoland	switch (Timeout) {
368203288Srnoland	case ACPI_DO_NOT_WAIT:
369203288Srnoland		if (!ACPIMTX_AVAIL(am))
370203288Srnoland			status = AE_TIME;
371203288Srnoland		break;
372203288Srnoland	case ACPI_WAIT_FOREVER:
373203288Srnoland		while (!ACPIMTX_AVAIL(am)) {
374203288Srnoland			am->am_waiters++;
375203288Srnoland			error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0);
376203288Srnoland			am->am_waiters--;
377203288Srnoland			if (error == EINTR || am->am_reset) {
378203288Srnoland				status = AE_ERROR;
379203288Srnoland				break;
380203288Srnoland			}
381203288Srnoland		}
382203288Srnoland		break;
383203288Srnoland	default:
384203288Srnoland		tmo = timeout2hz(Timeout);
385203288Srnoland		while (!ACPIMTX_AVAIL(am)) {
386203288Srnoland			prevtick = ticks;
387203288Srnoland			am->am_waiters++;
388203288Srnoland			error = mtx_sleep(am, &am->am_lock, PCATCH,
389203288Srnoland			    "acmtx", tmo);
390203288Srnoland			am->am_waiters--;
391203288Srnoland			if (error == EINTR || am->am_reset) {
392203288Srnoland				status = AE_ERROR;
393203288Srnoland				break;
394203288Srnoland			}
395203288Srnoland			if (ACPIMTX_AVAIL(am))
396203288Srnoland				break;
397203288Srnoland			slptick = ticks - prevtick;
398203288Srnoland			if (slptick >= tmo || slptick < 0) {
399203288Srnoland				status = AE_TIME;
400203288Srnoland				break;
401203288Srnoland			}
402203288Srnoland			tmo -= slptick;
403203288Srnoland		}
404203288Srnoland	}
405203288Srnoland	if (ACPI_SUCCESS(status))
406203288Srnoland		am->am_owner = curthread;
407203288Srnoland
408203288Srnoland	mtx_unlock(&am->am_lock);
409203288Srnoland
410203288Srnoland	return_ACPI_STATUS (status);
411203288Srnoland}
412203288Srnoland
413203288Srnolandvoid
414203288SrnolandAcpiOsReleaseMutex(ACPI_MUTEX Handle)
415203288Srnoland{
416203288Srnoland	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
417203288Srnoland
418203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
419203288Srnoland
420203288Srnoland	if (am == NULL) {
421203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
422203288Srnoland		    "cannot release null mutex\n"));
423203288Srnoland		return_VOID;
424203288Srnoland	}
425203288Srnoland
426203288Srnoland	mtx_lock(&am->am_lock);
427203288Srnoland
428203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name));
429203288Srnoland
430203288Srnoland	if (ACPIMTX_OWNED(am)) {
431203288Srnoland		if (am->am_nested > 0) {
432203288Srnoland			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
433203288Srnoland			    "release nested %s, depth %d\n",
434203288Srnoland			    am->am_name, am->am_nested));
435203288Srnoland			am->am_nested--;
436203288Srnoland		} else
437203288Srnoland			am->am_owner = NULL;
438203288Srnoland	} else {
439203288Srnoland		if (ACPIMTX_AVAIL(am))
440203288Srnoland			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
441203288Srnoland			    "release already available %s\n", am->am_name));
442203288Srnoland		else
443203288Srnoland			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
444203288Srnoland			    "release unowned %s from %p, depth %d\n",
445203288Srnoland			    am->am_name, am->am_owner, am->am_nested));
446203288Srnoland	}
447203288Srnoland	if (am->am_waiters > 0 && ACPIMTX_AVAIL(am))
448203288Srnoland		wakeup_one(am);
449203288Srnoland
450203288Srnoland	mtx_unlock(&am->am_lock);
451203288Srnoland}
452203288Srnoland
453203288Srnoland#undef ACPIMTX_AVAIL
454203288Srnoland#undef ACPIMTX_OWNED
455203288Srnoland
456203288Srnoland/*
457203288Srnoland * ACPI_SPINLOCK
458203288Srnoland */
459203288Srnolandstruct acpi_spinlock {
460203288Srnoland	struct mtx	al_lock;
461203288Srnoland	char		al_name[32];
462203288Srnoland	int		al_nested;
463203288Srnoland};
464203288Srnoland
465203288SrnolandACPI_STATUS
466203288SrnolandAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
467203288Srnoland{
468203288Srnoland	struct acpi_spinlock	*al;
469203288Srnoland
470203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
471203288Srnoland
472203288Srnoland	if (OutHandle == NULL)
473203288Srnoland		return_ACPI_STATUS (AE_BAD_PARAMETER);
474203288Srnoland
475203288Srnoland	if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
476203288Srnoland		return_ACPI_STATUS (AE_NO_MEMORY);
477203288Srnoland
478203288Srnoland#ifdef ACPI_DEBUG
479203288Srnoland	if (OutHandle == &AcpiGbl_GpeLock)
480203288Srnoland		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)");
481203288Srnoland	else if (OutHandle == &AcpiGbl_HardwareLock)
482203288Srnoland		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)");
483203288Srnoland	else
484203288Srnoland#endif
485203288Srnoland	snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al);
486203288Srnoland	mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN);
487203288Srnoland
488203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name));
489203288Srnoland
490203288Srnoland	*OutHandle = (ACPI_SPINLOCK)al;
491203288Srnoland
492203288Srnoland	return_ACPI_STATUS (AE_OK);
493203288Srnoland}
494203288Srnoland
495203288Srnolandvoid
496203288SrnolandAcpiOsDeleteLock(ACPI_SPINLOCK Handle)
497203288Srnoland{
498203288Srnoland	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
499203288Srnoland
500203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
501203288Srnoland
502203288Srnoland	if (al == NULL) {
503203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
504203288Srnoland		    "cannot delete null spinlock\n"));
505203288Srnoland		return_VOID;
506203288Srnoland	}
507203288Srnoland
508203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name));
509203288Srnoland
510203288Srnoland	mtx_destroy(&al->al_lock);
511203288Srnoland	free(al, M_ACPISEM);
512203288Srnoland}
513203288Srnoland
514203288SrnolandACPI_CPU_FLAGS
515203288SrnolandAcpiOsAcquireLock(ACPI_SPINLOCK Handle)
516203288Srnoland{
517203288Srnoland	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
518203288Srnoland
519203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
520203288Srnoland
521203288Srnoland	if (al == NULL) {
522203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
523203288Srnoland		    "cannot acquire null spinlock\n"));
524203288Srnoland		return (0);
525203288Srnoland	}
526203288Srnoland
527203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name));
528203288Srnoland
529203288Srnoland	if (mtx_owned(&al->al_lock)) {
530203288Srnoland		al->al_nested++;
531203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
532203288Srnoland		    "acquire nested %s, depth %d\n",
533203288Srnoland		    al->al_name, al->al_nested));
534203288Srnoland	} else
535203288Srnoland		mtx_lock_spin(&al->al_lock);
536203288Srnoland
537203288Srnoland	return (0);
538203288Srnoland}
539203288Srnoland
540203288Srnolandvoid
541203288SrnolandAcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
542203288Srnoland{
543203288Srnoland	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
544203288Srnoland
545203288Srnoland	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
546203288Srnoland
547203288Srnoland	if (al == NULL) {
548203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
549203288Srnoland		    "cannot release null spinlock\n"));
550203288Srnoland		return_VOID;
551203288Srnoland	}
552203288Srnoland
553203288Srnoland	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name));
554203288Srnoland
555203288Srnoland	if (mtx_owned(&al->al_lock)) {
556203288Srnoland		if (al->al_nested > 0) {
557203288Srnoland			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
558203288Srnoland			    "release nested %s, depth %d\n",
559203288Srnoland			    al->al_name, al->al_nested));
560203288Srnoland			al->al_nested--;
561203288Srnoland		} else
562203288Srnoland			mtx_unlock_spin(&al->al_lock);
563203288Srnoland	} else
564203288Srnoland		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
565203288Srnoland		    "cannot release unowned %s\n", al->al_name));
566203288Srnoland}
567203288Srnoland
568203288Srnoland/* Section 5.2.10.1: global lock acquire/release functions */
569203288Srnoland
570203288Srnoland/*
571203288Srnoland * Acquire the global lock.  If busy, set the pending bit.  The caller
572203288Srnoland * will wait for notification from the BIOS that the lock is available
573203288Srnoland * and then attempt to acquire it again.
574203288Srnoland */
575203288Srnolandint
576203288Srnolandacpi_acquire_global_lock(volatile uint32_t *lock)
577203288Srnoland{
578203288Srnoland	uint32_t	new, old;
579203288Srnoland
580203288Srnoland	do {
581203288Srnoland		old = *lock;
582203288Srnoland		new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED;
583203288Srnoland		if ((old & ACPI_GLOCK_OWNED) != 0)
584203288Srnoland			new |= ACPI_GLOCK_PENDING;
585203288Srnoland	} while (atomic_cmpset_32(lock, old, new) == 0);
586203288Srnoland
587203288Srnoland	return ((new & ACPI_GLOCK_PENDING) == 0);
588203288Srnoland}
589203288Srnoland
590203288Srnoland/*
591203288Srnoland * Release the global lock, returning whether there is a waiter pending.
592203288Srnoland * If the BIOS set the pending bit, OSPM must notify the BIOS when it
593203288Srnoland * releases the lock.
594203288Srnoland */
595203288Srnolandint
596203288Srnolandacpi_release_global_lock(volatile uint32_t *lock)
597203288Srnoland{
598203288Srnoland	uint32_t	new, old;
599203288Srnoland
600203288Srnoland	do {
601203288Srnoland		old = *lock;
602203288Srnoland		new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED);
603203288Srnoland	} while (atomic_cmpset_32(lock, old, new) == 0);
604203288Srnoland
605203288Srnoland	return ((old & ACPI_GLOCK_PENDING) != 0);
606203288Srnoland}
607203288Srnoland