OsdSynch.c revision 167915
1252190Srpaulo/*-
2252190Srpaulo * Copyright (c) 2000 Michael Smith
3252190Srpaulo * Copyright (c) 2000 BSDi
4252190Srpaulo * All rights reserved.
5252190Srpaulo *
6252190Srpaulo * Redistribution and use in source and binary forms, with or without
7252190Srpaulo * modification, are permitted provided that the following conditions
8252190Srpaulo * are met:
9252190Srpaulo * 1. Redistributions of source code must retain the above copyright
10252190Srpaulo *    notice, this list of conditions and the following disclaimer.
11252190Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
12252190Srpaulo *    notice, this list of conditions and the following disclaimer in the
13252190Srpaulo *    documentation and/or other materials provided with the distribution.
14252190Srpaulo *
15252190Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16252190Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17252190Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18252190Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19252190Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20252190Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21252190Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22252190Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23252190Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24252190Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25252190Srpaulo * SUCH DAMAGE.
26252190Srpaulo */
27252190Srpaulo
28252190Srpaulo/*
29252190Srpaulo * 6.1 : Mutual Exclusion and Synchronisation
30252190Srpaulo */
31252190Srpaulo
32252190Srpaulo#include <sys/cdefs.h>
33252190Srpaulo__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSynch.c 167915 2007-03-26 21:56:35Z jkim $");
34252190Srpaulo
35252190Srpaulo#include <contrib/dev/acpica/acpi.h>
36252190Srpaulo
37252190Srpaulo#include "opt_acpi.h"
38252190Srpaulo#include <sys/kernel.h>
39252190Srpaulo#include <sys/malloc.h>
40252190Srpaulo#include <sys/sysctl.h>
41252190Srpaulo#include <sys/lock.h>
42252190Srpaulo#include <sys/mutex.h>
43252190Srpaulo
44252190Srpaulo#define _COMPONENT	ACPI_OS_SERVICES
45252190SrpauloACPI_MODULE_NAME("SYNCH")
46252190Srpaulo
47252190SrpauloMALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
48252190Srpaulo
49252190Srpaulo#define AS_LOCK(as)	mtx_lock(&(as)->as_mtx)
50252190Srpaulo#define AS_UNLOCK(as)	mtx_unlock(&(as)->as_mtx)
51252190Srpaulo
52252190Srpaulo/*
53252190Srpaulo * Simple counting semaphore implemented using a mutex.  (Subsequently used
54252190Srpaulo * in the OSI code to implement a mutex.  Go figure.)
55252190Srpaulo */
56252190Srpaulostruct acpi_semaphore {
57252190Srpaulo    struct mtx	as_mtx;
58252190Srpaulo    UINT32	as_units;
59252190Srpaulo    UINT32	as_maxunits;
60252190Srpaulo    UINT32	as_pendings;
61252190Srpaulo    UINT32	as_resetting;
62252190Srpaulo    UINT32	as_timeouts;
63252190Srpaulo};
64252190Srpaulo
65252190Srpaulo/* Default number of maximum pending threads. */
66252190Srpaulo#ifndef ACPI_NO_SEMAPHORES
67252190Srpaulo#ifndef ACPI_SEMAPHORES_MAX_PENDING
68252190Srpaulo#define ACPI_SEMAPHORES_MAX_PENDING	4
69252190Srpaulo#endif
70252190Srpaulo
71252190Srpaulostatic int	acpi_semaphore_debug = 0;
72252190SrpauloTUNABLE_INT("debug.acpi_semaphore_debug", &acpi_semaphore_debug);
73252190SrpauloSYSCTL_DECL(_debug_acpi);
74252190SrpauloSYSCTL_INT(_debug_acpi, OID_AUTO, semaphore_debug, CTLFLAG_RW,
75252190Srpaulo	   &acpi_semaphore_debug, 0, "Enable ACPI semaphore debug messages");
76252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */
77252190Srpaulo
78252190SrpauloACPI_STATUS
79252190SrpauloAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
80252190Srpaulo    ACPI_SEMAPHORE *OutHandle)
81252190Srpaulo{
82252190Srpaulo#ifndef ACPI_NO_SEMAPHORES
83252190Srpaulo    struct acpi_semaphore	*as;
84252190Srpaulo
85252190Srpaulo    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
86252190Srpaulo
87252190Srpaulo    if (OutHandle == NULL)
88252190Srpaulo	return_ACPI_STATUS (AE_BAD_PARAMETER);
89252190Srpaulo    if (InitialUnits > MaxUnits)
90252190Srpaulo	return_ACPI_STATUS (AE_BAD_PARAMETER);
91252190Srpaulo
92252190Srpaulo    if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
93252190Srpaulo	return_ACPI_STATUS (AE_NO_MEMORY);
94252190Srpaulo
95252190Srpaulo    mtx_init(&as->as_mtx, "ACPI semaphore", NULL, MTX_DEF);
96252190Srpaulo    as->as_units = InitialUnits;
97252190Srpaulo    as->as_maxunits = MaxUnits;
98252190Srpaulo    as->as_pendings = as->as_resetting = as->as_timeouts = 0;
99252190Srpaulo
100252190Srpaulo    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
101252190Srpaulo	"created semaphore %p max %d, initial %d\n",
102252190Srpaulo	as, InitialUnits, MaxUnits));
103252190Srpaulo
104252190Srpaulo    *OutHandle = (ACPI_HANDLE)as;
105252190Srpaulo#else
106252190Srpaulo    *OutHandle = (ACPI_HANDLE)OutHandle;
107252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */
108252190Srpaulo
109252190Srpaulo    return_ACPI_STATUS (AE_OK);
110252190Srpaulo}
111252190Srpaulo
112252190SrpauloACPI_STATUS
113252190SrpauloAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
114252190Srpaulo{
115252190Srpaulo#ifndef ACPI_NO_SEMAPHORES
116252190Srpaulo    struct acpi_semaphore *as = (struct acpi_semaphore *)Handle;
117252190Srpaulo
118252190Srpaulo    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
119252190Srpaulo
120252190Srpaulo    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed semaphore %p\n", as));
121252190Srpaulo    mtx_destroy(&as->as_mtx);
122252190Srpaulo    free(Handle, M_ACPISEM);
123252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */
124252190Srpaulo
125252190Srpaulo    return_ACPI_STATUS (AE_OK);
126252190Srpaulo}
127252190Srpaulo
128252190Srpaulo/*
129252190Srpaulo * This implementation has a bug, in that it has to stall for the entire
130252190Srpaulo * timeout before it will return AE_TIME.  A better implementation would
131252190Srpaulo * use getmicrotime() to correctly adjust the timeout after being woken up.
132252190Srpaulo */
133252190SrpauloACPI_STATUS
134252190SrpauloAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
135252190Srpaulo{
136252190Srpaulo#ifndef ACPI_NO_SEMAPHORES
137252190Srpaulo    ACPI_STATUS			result;
138252190Srpaulo    struct acpi_semaphore	*as = (struct acpi_semaphore *)Handle;
139252190Srpaulo    int				rv, tmo;
140252190Srpaulo    struct timeval		timeouttv, currenttv, timelefttv;
141252190Srpaulo
142252190Srpaulo    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
143252190Srpaulo
144252190Srpaulo    if (as == NULL)
145252190Srpaulo	return_ACPI_STATUS (AE_BAD_PARAMETER);
146252190Srpaulo
147252190Srpaulo    if (cold)
148252190Srpaulo	return_ACPI_STATUS (AE_OK);
149252190Srpaulo
150252190Srpaulo#if 0
151252190Srpaulo    if (as->as_units < Units && as->as_timeouts > 10) {
152252190Srpaulo	printf("%s: semaphore %p too many timeouts, resetting\n", __func__, as);
153252190Srpaulo	AS_LOCK(as);
154252190Srpaulo	as->as_units = as->as_maxunits;
155252190Srpaulo	if (as->as_pendings)
156252190Srpaulo	    as->as_resetting = 1;
157252190Srpaulo	as->as_timeouts = 0;
158252190Srpaulo	wakeup(as);
159252190Srpaulo	AS_UNLOCK(as);
160252190Srpaulo	return_ACPI_STATUS (AE_TIME);
161252190Srpaulo    }
162252190Srpaulo
163252190Srpaulo    if (as->as_resetting)
164252190Srpaulo	return_ACPI_STATUS (AE_TIME);
165252190Srpaulo#endif
166252190Srpaulo
167252190Srpaulo    /* a timeout of ACPI_WAIT_FOREVER means "forever" */
168252190Srpaulo    if (Timeout == ACPI_WAIT_FOREVER) {
169252190Srpaulo	tmo = 0;
170252190Srpaulo	timeouttv.tv_sec = ((0xffff/1000) + 1);	/* cf. ACPI spec */
171252190Srpaulo	timeouttv.tv_usec = 0;
172252190Srpaulo    } else {
173252190Srpaulo	/* compute timeout using microseconds per tick */
174252190Srpaulo	tmo = (Timeout * 1000) / (1000000 / hz);
175252190Srpaulo	if (tmo <= 0)
176252190Srpaulo	    tmo = 1;
177252190Srpaulo	timeouttv.tv_sec  = Timeout / 1000;
178252190Srpaulo	timeouttv.tv_usec = (Timeout % 1000) * 1000;
179252190Srpaulo    }
180252190Srpaulo
181252190Srpaulo    /* calculate timeout value in timeval */
182252190Srpaulo    getmicrotime(&currenttv);
183252190Srpaulo    timevaladd(&timeouttv, &currenttv);
184252190Srpaulo
185252190Srpaulo    AS_LOCK(as);
186252190Srpaulo    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
187252190Srpaulo	"get %d units from semaphore %p (has %d), timeout %d\n",
188252190Srpaulo	Units, as, as->as_units, Timeout));
189252190Srpaulo    for (;;) {
190252190Srpaulo	if (as->as_maxunits == ACPI_NO_UNIT_LIMIT) {
191252190Srpaulo	    result = AE_OK;
192252190Srpaulo	    break;
193252190Srpaulo	}
194252190Srpaulo	if (as->as_units >= Units) {
195252190Srpaulo	    as->as_units -= Units;
196252190Srpaulo	    result = AE_OK;
197252190Srpaulo	    break;
198252190Srpaulo	}
199252190Srpaulo
200252190Srpaulo	/* limit number of pending threads */
201252190Srpaulo	if (as->as_pendings >= ACPI_SEMAPHORES_MAX_PENDING) {
202252190Srpaulo	    result = AE_TIME;
203252190Srpaulo	    break;
204252190Srpaulo	}
205252190Srpaulo
206252190Srpaulo	/* if timeout values of zero is specified, return immediately */
207252190Srpaulo	if (Timeout == 0) {
208252190Srpaulo	    result = AE_TIME;
209252190Srpaulo	    break;
210252190Srpaulo	}
211252190Srpaulo
212252190Srpaulo	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
213252190Srpaulo	    "semaphore blocked, calling msleep(%p, %p, %d, \"acsem\", %d)\n",
214252190Srpaulo	    as, &as->as_mtx, PCATCH, tmo));
215252190Srpaulo
216252190Srpaulo	as->as_pendings++;
217252190Srpaulo
218252190Srpaulo	if (acpi_semaphore_debug) {
219252190Srpaulo	    printf("%s: Sleep %d, pending %d, semaphore %p, thread %d\n",
220252190Srpaulo		__func__, Timeout, as->as_pendings, as, AcpiOsGetThreadId());
221252190Srpaulo	}
222252190Srpaulo
223252190Srpaulo	rv = msleep(as, &as->as_mtx, PCATCH, "acsem", tmo);
224252190Srpaulo
225252190Srpaulo	as->as_pendings--;
226252190Srpaulo
227252190Srpaulo#if 0
228252190Srpaulo	if (as->as_resetting) {
229252190Srpaulo	    /* semaphore reset, return immediately */
230252190Srpaulo	    if (as->as_pendings == 0) {
231252190Srpaulo		as->as_resetting = 0;
232252190Srpaulo	    }
233252190Srpaulo	    result = AE_TIME;
234252190Srpaulo	    break;
235252190Srpaulo	}
236252190Srpaulo#endif
237252190Srpaulo
238252190Srpaulo	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "msleep(%d) returned %d\n", tmo, rv));
239252190Srpaulo	if (rv == EWOULDBLOCK) {
240252190Srpaulo	    result = AE_TIME;
241252190Srpaulo	    break;
242252190Srpaulo	}
243252190Srpaulo
244252190Srpaulo	/* check if we already awaited enough */
245252190Srpaulo	timelefttv = timeouttv;
246252190Srpaulo	getmicrotime(&currenttv);
247252190Srpaulo	timevalsub(&timelefttv, &currenttv);
248252190Srpaulo	if (timelefttv.tv_sec < 0) {
249252190Srpaulo	    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "await semaphore %p timeout\n",
250252190Srpaulo		as));
251252190Srpaulo	    result = AE_TIME;
252252190Srpaulo	    break;
253252190Srpaulo	}
254252190Srpaulo
255252190Srpaulo	/* adjust timeout for the next sleep */
256252190Srpaulo	tmo = (timelefttv.tv_sec * 1000000 + timelefttv.tv_usec) /
257252190Srpaulo	    (1000000 / hz);
258252190Srpaulo	if (tmo <= 0)
259252190Srpaulo	    tmo = 1;
260252190Srpaulo
261252190Srpaulo	if (acpi_semaphore_debug) {
262252190Srpaulo	    printf("%s: Wakeup timeleft(%jd, %lu), tmo %u, sem %p, thread %d\n",
263252190Srpaulo		__func__, (intmax_t)timelefttv.tv_sec, timelefttv.tv_usec, tmo, as,
264252190Srpaulo		AcpiOsGetThreadId());
265252190Srpaulo	}
266252190Srpaulo    }
267252190Srpaulo
268252190Srpaulo    if (acpi_semaphore_debug) {
269252190Srpaulo	if (result == AE_TIME && Timeout > 0) {
270252190Srpaulo	    printf("%s: Timeout %d, pending %d, semaphore %p\n",
271252190Srpaulo		__func__, Timeout, as->as_pendings, as);
272252190Srpaulo	}
273252190Srpaulo	if (result == AE_OK && (as->as_timeouts > 0 || as->as_pendings > 0)) {
274252190Srpaulo	    printf("%s: Acquire %d, units %d, pending %d, sem %p, thread %d\n",
275252190Srpaulo		__func__, Units, as->as_units, as->as_pendings, as,
276252190Srpaulo		AcpiOsGetThreadId());
277252190Srpaulo	}
278252190Srpaulo    }
279252190Srpaulo
280252190Srpaulo    if (result == AE_TIME)
281252190Srpaulo	as->as_timeouts++;
282252190Srpaulo    else
283252190Srpaulo	as->as_timeouts = 0;
284252190Srpaulo
285252190Srpaulo    AS_UNLOCK(as);
286252190Srpaulo    return_ACPI_STATUS (result);
287252190Srpaulo#else
288252190Srpaulo    return_ACPI_STATUS (AE_OK);
289252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */
290252190Srpaulo}
291252190Srpaulo
292252190SrpauloACPI_STATUS
293252190SrpauloAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
294252190Srpaulo{
295252190Srpaulo#ifndef ACPI_NO_SEMAPHORES
296252190Srpaulo    struct acpi_semaphore	*as = (struct acpi_semaphore *)Handle;
297252190Srpaulo
298252190Srpaulo    ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
299252190Srpaulo
300252190Srpaulo    if (as == NULL)
301252190Srpaulo	return_ACPI_STATUS(AE_BAD_PARAMETER);
302252190Srpaulo
303252190Srpaulo    AS_LOCK(as);
304252190Srpaulo    ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
305252190Srpaulo	"return %d units to semaphore %p (has %d)\n",
306252190Srpaulo	Units, as, as->as_units));
307252190Srpaulo    if (as->as_maxunits != ACPI_NO_UNIT_LIMIT) {
308252190Srpaulo	as->as_units += Units;
309252190Srpaulo	if (as->as_units > as->as_maxunits)
310252190Srpaulo	    as->as_units = as->as_maxunits;
311252190Srpaulo    }
312252190Srpaulo
313252190Srpaulo    if (acpi_semaphore_debug && (as->as_timeouts > 0 || as->as_pendings > 0)) {
314252190Srpaulo	printf("%s: Release %d, units %d, pending %d, semaphore %p, thread %d\n",
315252190Srpaulo	    __func__, Units, as->as_units, as->as_pendings, as, AcpiOsGetThreadId());
316252190Srpaulo    }
317252190Srpaulo
318252190Srpaulo    wakeup(as);
319252190Srpaulo    AS_UNLOCK(as);
320252190Srpaulo#endif /* !ACPI_NO_SEMAPHORES */
321252190Srpaulo
322252190Srpaulo    return_ACPI_STATUS (AE_OK);
323252190Srpaulo}
324252190Srpaulo
325252190Srpaulo/* Combined mutex + mutex name storage since the latter must persist. */
326252190Srpaulostruct acpi_spinlock {
327252190Srpaulo    struct mtx	lock;
328252190Srpaulo    char	name[32];
329252190Srpaulo};
330252190Srpaulo
331252190SrpauloACPI_STATUS
332252190SrpauloAcpiOsCreateLock (ACPI_SPINLOCK *OutHandle)
333252190Srpaulo{
334252190Srpaulo    struct acpi_spinlock *h;
335252190Srpaulo
336252190Srpaulo    if (OutHandle == NULL)
337252190Srpaulo	return (AE_BAD_PARAMETER);
338252190Srpaulo    h = malloc(sizeof(struct acpi_spinlock), M_ACPISEM, M_NOWAIT | M_ZERO);
339252190Srpaulo    if (h == NULL)
340252190Srpaulo	return (AE_NO_MEMORY);
341252190Srpaulo
342252190Srpaulo    /* Build a unique name based on the address of the handle. */
343252190Srpaulo    if (OutHandle == &AcpiGbl_GpeLock)
344252190Srpaulo	snprintf(h->name, sizeof(h->name), "acpi subsystem GPE lock");
345252190Srpaulo    if (OutHandle == &AcpiGbl_HardwareLock)
346252190Srpaulo	snprintf(h->name, sizeof(h->name), "acpi subsystem HW lock");
347252190Srpaulo    else
348252190Srpaulo	snprintf(h->name, sizeof(h->name), "acpi subsys %p", OutHandle);
349252190Srpaulo    mtx_init(&h->lock, h->name, NULL, MTX_DEF);
350252190Srpaulo    *OutHandle = (ACPI_SPINLOCK)h;
351252190Srpaulo    return (AE_OK);
352252190Srpaulo}
353252190Srpaulo
354252190Srpaulovoid
355252190SrpauloAcpiOsDeleteLock (ACPI_SPINLOCK Handle)
356252190Srpaulo{
357252190Srpaulo    struct acpi_spinlock *h = (struct acpi_spinlock *)Handle;
358252190Srpaulo
359252190Srpaulo    if (Handle == NULL)
360252190Srpaulo        return;
361252190Srpaulo    mtx_destroy(&h->lock);
362252190Srpaulo    free(h, M_ACPISEM);
363252190Srpaulo}
364252190Srpaulo
365252190Srpaulo/*
366252190Srpaulo * The Flags parameter seems to state whether or not caller is an ISR
367252190Srpaulo * (and thus can't block) but since we have ithreads, we don't worry
368252190Srpaulo * about potentially blocking.
369252190Srpaulo */
370252190SrpauloACPI_NATIVE_UINT
371252190SrpauloAcpiOsAcquireLock (ACPI_SPINLOCK Handle)
372252190Srpaulo{
373252190Srpaulo    struct acpi_spinlock *h = (struct acpi_spinlock *)Handle;
374252190Srpaulo
375252190Srpaulo    if (Handle == NULL)
376252190Srpaulo	return (0);
377252190Srpaulo    mtx_lock(&h->lock);
378252190Srpaulo    return (0);
379252190Srpaulo}
380252190Srpaulo
381252190Srpaulovoid
382252190SrpauloAcpiOsReleaseLock (ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
383252190Srpaulo{
384252190Srpaulo    struct acpi_spinlock *h = (struct acpi_spinlock *)Handle;
385252190Srpaulo
386252190Srpaulo    if (Handle == NULL)
387252190Srpaulo	return;
388252190Srpaulo    mtx_unlock(&h->lock);
389252190Srpaulo}
390252190Srpaulo
391252190Srpaulo/* Section 5.2.9.1:  global lock acquire/release functions */
392252190Srpaulo#define GL_ACQUIRED	(-1)
393252190Srpaulo#define GL_BUSY		0
394252190Srpaulo#define GL_BIT_PENDING	0x1
395252190Srpaulo#define GL_BIT_OWNED	0x2
396252190Srpaulo#define GL_BIT_MASK	(GL_BIT_PENDING | GL_BIT_OWNED)
397252190Srpaulo
398252190Srpaulo/*
399252190Srpaulo * Acquire the global lock.  If busy, set the pending bit.  The caller
400252190Srpaulo * will wait for notification from the BIOS that the lock is available
401252190Srpaulo * and then attempt to acquire it again.
402252190Srpaulo */
403252190Srpauloint
404252190Srpauloacpi_acquire_global_lock(uint32_t *lock)
405252190Srpaulo{
406252190Srpaulo	uint32_t new, old;
407252190Srpaulo
408252190Srpaulo	do {
409252190Srpaulo		old = *lock;
410252190Srpaulo		new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) |
411252190Srpaulo			((old >> 1) & GL_BIT_PENDING);
412252190Srpaulo	} while (atomic_cmpset_acq_int(lock, old, new) == 0);
413252190Srpaulo
414252190Srpaulo	return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY);
415252190Srpaulo}
416252190Srpaulo
417252190Srpaulo/*
418252190Srpaulo * Release the global lock, returning whether there is a waiter pending.
419252190Srpaulo * If the BIOS set the pending bit, OSPM must notify the BIOS when it
420252190Srpaulo * releases the lock.
421252190Srpaulo */
422252190Srpauloint
423252190Srpauloacpi_release_global_lock(uint32_t *lock)
424252190Srpaulo{
425252190Srpaulo	uint32_t new, old;
426252190Srpaulo
427252190Srpaulo	do {
428252190Srpaulo		old = *lock;
429252190Srpaulo		new = old & ~GL_BIT_MASK;
430252190Srpaulo	} while (atomic_cmpset_rel_int(lock, old, new) == 0);
431252190Srpaulo
432252190Srpaulo	return (old & GL_BIT_PENDING);
433252190Srpaulo}
434252190Srpaulo