xref: /freebsd/sys/dev/acpica/Osd/OsdSynch.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * 6.1 : Mutual Exclusion and Synchronisation
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include <contrib/dev/acpica/include/acpi.h>
37 #include <contrib/dev/acpica/include/accommon.h>
38 
39 #include <sys/condvar.h>
40 #include <sys/kernel.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mutex.h>
44 
45 #define	_COMPONENT	ACPI_OS_SERVICES
46 ACPI_MODULE_NAME("SYNCH")
47 
48 static MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
49 
50 /*
51  * Convert milliseconds to ticks.
52  */
53 static int
54 timeout2hz(UINT16 Timeout)
55 {
56 	struct timeval		tv;
57 
58 	tv.tv_sec = (time_t)(Timeout / 1000);
59 	tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000;
60 
61 	return (tvtohz(&tv));
62 }
63 
64 /*
65  * ACPI_SEMAPHORE
66  */
67 struct acpi_sema {
68 	struct mtx	as_lock;
69 	char		as_name[32];
70 	struct cv	as_cv;
71 	UINT32		as_maxunits;
72 	UINT32		as_units;
73 	int		as_waiters;
74 	int		as_reset;
75 };
76 
77 ACPI_STATUS
78 AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits,
79     ACPI_SEMAPHORE *OutHandle)
80 {
81 	struct acpi_sema	*as;
82 
83 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
84 
85 	if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits)
86 		return_ACPI_STATUS (AE_BAD_PARAMETER);
87 
88 	if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
89 		return_ACPI_STATUS (AE_NO_MEMORY);
90 
91 	snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as);
92 	mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF);
93 	cv_init(&as->as_cv, as->as_name);
94 	as->as_maxunits = MaxUnits;
95 	as->as_units = InitialUnits;
96 
97 	*OutHandle = (ACPI_SEMAPHORE)as;
98 
99 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n",
100 	    as->as_name, MaxUnits, InitialUnits));
101 
102 	return_ACPI_STATUS (AE_OK);
103 }
104 
105 ACPI_STATUS
106 AcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle)
107 {
108 	struct acpi_sema	*as = (struct acpi_sema *)Handle;
109 
110 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
111 
112 	if (as == NULL)
113 		return_ACPI_STATUS (AE_BAD_PARAMETER);
114 
115 	mtx_lock(&as->as_lock);
116 
117 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name));
118 
119 	if (as->as_waiters > 0) {
120 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
121 		    "reset %s, units %u, waiters %d\n",
122 		    as->as_name, as->as_units, as->as_waiters));
123 		as->as_reset = 1;
124 		cv_broadcast(&as->as_cv);
125 		while (as->as_waiters > 0) {
126 			if (mtx_sleep(&as->as_reset, &as->as_lock,
127 			    PCATCH, "acsrst", hz) == EINTR) {
128 				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
129 				    "failed to reset %s, waiters %d\n",
130 				    as->as_name, as->as_waiters));
131 				mtx_unlock(&as->as_lock);
132 				return_ACPI_STATUS (AE_ERROR);
133 			}
134 			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
135 			    "wait %s, units %u, waiters %d\n",
136 			    as->as_name, as->as_units, as->as_waiters));
137 		}
138 	}
139 
140 	mtx_unlock(&as->as_lock);
141 
142 	mtx_destroy(&as->as_lock);
143 	cv_destroy(&as->as_cv);
144 	free(as, M_ACPISEM);
145 
146 	return_ACPI_STATUS (AE_OK);
147 }
148 
149 #define	ACPISEM_AVAIL(s, u)	((s)->as_units >= (u))
150 
151 ACPI_STATUS
152 AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout)
153 {
154 	struct acpi_sema	*as = (struct acpi_sema *)Handle;
155 	int			error, prevtick, slptick, tmo;
156 	ACPI_STATUS		status = AE_OK;
157 
158 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
159 
160 	if (as == NULL || Units == 0)
161 		return_ACPI_STATUS (AE_BAD_PARAMETER);
162 
163 	mtx_lock(&as->as_lock);
164 
165 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
166 	    "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n",
167 	    Units, as->as_name, as->as_units, as->as_waiters, Timeout));
168 
169 	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) {
170 		mtx_unlock(&as->as_lock);
171 		return_ACPI_STATUS (AE_LIMIT);
172 	}
173 
174 	switch (Timeout) {
175 	case ACPI_DO_NOT_WAIT:
176 		if (!ACPISEM_AVAIL(as, Units))
177 			status = AE_TIME;
178 		break;
179 	case ACPI_WAIT_FOREVER:
180 		while (!ACPISEM_AVAIL(as, Units)) {
181 			as->as_waiters++;
182 			error = cv_wait_sig(&as->as_cv, &as->as_lock);
183 			as->as_waiters--;
184 			if (error == EINTR || as->as_reset) {
185 				status = AE_ERROR;
186 				break;
187 			}
188 		}
189 		break;
190 	default:
191 		if (cold) {
192 			/*
193 			 * Just spin polling the semaphore once a
194 			 * millisecond.
195 			 */
196 			while (!ACPISEM_AVAIL(as, Units)) {
197 				if (Timeout == 0) {
198 					status = AE_TIME;
199 					break;
200 				}
201 				Timeout--;
202 				mtx_unlock(&as->as_lock);
203 				DELAY(1000);
204 				mtx_lock(&as->as_lock);
205 			}
206 			break;
207 		}
208 		tmo = timeout2hz(Timeout);
209 		while (!ACPISEM_AVAIL(as, Units)) {
210 			prevtick = ticks;
211 			as->as_waiters++;
212 			error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo);
213 			as->as_waiters--;
214 			if (error == EINTR || as->as_reset) {
215 				status = AE_ERROR;
216 				break;
217 			}
218 			if (ACPISEM_AVAIL(as, Units))
219 				break;
220 			slptick = ticks - prevtick;
221 			if (slptick >= tmo || slptick < 0) {
222 				status = AE_TIME;
223 				break;
224 			}
225 			tmo -= slptick;
226 		}
227 	}
228 	if (ACPI_SUCCESS(status))
229 		as->as_units -= Units;
230 
231 	mtx_unlock(&as->as_lock);
232 
233 	return_ACPI_STATUS (status);
234 }
235 
236 ACPI_STATUS
237 AcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units)
238 {
239 	struct acpi_sema	*as = (struct acpi_sema *)Handle;
240 	UINT32			i;
241 
242 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
243 
244 	if (as == NULL || Units == 0)
245 		return_ACPI_STATUS (AE_BAD_PARAMETER);
246 
247 	mtx_lock(&as->as_lock);
248 
249 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
250 	    "return %u units to %s, units %u, waiters %d\n",
251 	    Units, as->as_name, as->as_units, as->as_waiters));
252 
253 	if (as->as_maxunits != ACPI_NO_UNIT_LIMIT &&
254 	    (as->as_maxunits < Units ||
255 	    as->as_maxunits - Units < as->as_units)) {
256 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
257 		    "exceeded max units %u\n", as->as_maxunits));
258 		mtx_unlock(&as->as_lock);
259 		return_ACPI_STATUS (AE_LIMIT);
260 	}
261 
262 	as->as_units += Units;
263 	if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units))
264 		for (i = 0; i < Units; i++)
265 			cv_signal(&as->as_cv);
266 
267 	mtx_unlock(&as->as_lock);
268 
269 	return_ACPI_STATUS (AE_OK);
270 }
271 
272 #undef ACPISEM_AVAIL
273 
274 /*
275  * ACPI_MUTEX
276  */
277 struct acpi_mutex {
278 	struct mtx	am_lock;
279 	char		am_name[32];
280 	struct thread	*am_owner;
281 	int		am_nested;
282 	int		am_waiters;
283 	int		am_reset;
284 };
285 
286 ACPI_STATUS
287 AcpiOsCreateMutex(ACPI_MUTEX *OutHandle)
288 {
289 	struct acpi_mutex	*am;
290 
291 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
292 
293 	if (OutHandle == NULL)
294 		return_ACPI_STATUS (AE_BAD_PARAMETER);
295 
296 	if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
297 		return_ACPI_STATUS (AE_NO_MEMORY);
298 
299 	snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am);
300 	mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF);
301 
302 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name));
303 
304 	*OutHandle = (ACPI_MUTEX)am;
305 
306 	return_ACPI_STATUS (AE_OK);
307 }
308 
309 #define	ACPIMTX_AVAIL(m)	((m)->am_owner == NULL)
310 #define	ACPIMTX_OWNED(m)	((m)->am_owner == curthread)
311 
312 void
313 AcpiOsDeleteMutex(ACPI_MUTEX Handle)
314 {
315 	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
316 
317 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
318 
319 	if (am == NULL) {
320 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n"));
321 		return_VOID;
322 	}
323 
324 	mtx_lock(&am->am_lock);
325 
326 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name));
327 
328 	if (am->am_waiters > 0) {
329 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
330 		    "reset %s, owner %p\n", am->am_name, am->am_owner));
331 		am->am_reset = 1;
332 		wakeup(am);
333 		while (am->am_waiters > 0) {
334 			if (mtx_sleep(&am->am_reset, &am->am_lock,
335 			    PCATCH, "acmrst", hz) == EINTR) {
336 				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
337 				    "failed to reset %s, waiters %d\n",
338 				    am->am_name, am->am_waiters));
339 				mtx_unlock(&am->am_lock);
340 				return_VOID;
341 			}
342 			if (ACPIMTX_AVAIL(am))
343 				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
344 				    "wait %s, waiters %d\n",
345 				    am->am_name, am->am_waiters));
346 			else
347 				ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
348 				    "wait %s, owner %p, waiters %d\n",
349 				    am->am_name, am->am_owner, am->am_waiters));
350 		}
351 	}
352 
353 	mtx_unlock(&am->am_lock);
354 
355 	mtx_destroy(&am->am_lock);
356 	free(am, M_ACPISEM);
357 }
358 
359 ACPI_STATUS
360 AcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout)
361 {
362 	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
363 	int			error, prevtick, slptick, tmo;
364 	ACPI_STATUS		status = AE_OK;
365 
366 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
367 
368 	if (am == NULL)
369 		return_ACPI_STATUS (AE_BAD_PARAMETER);
370 
371 	mtx_lock(&am->am_lock);
372 
373 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name));
374 
375 	if (ACPIMTX_OWNED(am)) {
376 		am->am_nested++;
377 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
378 		    "acquire nested %s, depth %d\n",
379 		    am->am_name, am->am_nested));
380 		mtx_unlock(&am->am_lock);
381 		return_ACPI_STATUS (AE_OK);
382 	}
383 
384 	switch (Timeout) {
385 	case ACPI_DO_NOT_WAIT:
386 		if (!ACPIMTX_AVAIL(am))
387 			status = AE_TIME;
388 		break;
389 	case ACPI_WAIT_FOREVER:
390 		while (!ACPIMTX_AVAIL(am)) {
391 			am->am_waiters++;
392 			error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0);
393 			am->am_waiters--;
394 			if (error == EINTR || am->am_reset) {
395 				status = AE_ERROR;
396 				break;
397 			}
398 		}
399 		break;
400 	default:
401 		if (cold) {
402 			/*
403 			 * Just spin polling the mutex once a
404 			 * millisecond.
405 			 */
406 			while (!ACPIMTX_AVAIL(am)) {
407 				if (Timeout == 0) {
408 					status = AE_TIME;
409 					break;
410 				}
411 				Timeout--;
412 				mtx_unlock(&am->am_lock);
413 				DELAY(1000);
414 				mtx_lock(&am->am_lock);
415 			}
416 			break;
417 		}
418 		tmo = timeout2hz(Timeout);
419 		while (!ACPIMTX_AVAIL(am)) {
420 			prevtick = ticks;
421 			am->am_waiters++;
422 			error = mtx_sleep(am, &am->am_lock, PCATCH,
423 			    "acmtx", tmo);
424 			am->am_waiters--;
425 			if (error == EINTR || am->am_reset) {
426 				status = AE_ERROR;
427 				break;
428 			}
429 			if (ACPIMTX_AVAIL(am))
430 				break;
431 			slptick = ticks - prevtick;
432 			if (slptick >= tmo || slptick < 0) {
433 				status = AE_TIME;
434 				break;
435 			}
436 			tmo -= slptick;
437 		}
438 	}
439 	if (ACPI_SUCCESS(status))
440 		am->am_owner = curthread;
441 
442 	mtx_unlock(&am->am_lock);
443 
444 	return_ACPI_STATUS (status);
445 }
446 
447 void
448 AcpiOsReleaseMutex(ACPI_MUTEX Handle)
449 {
450 	struct acpi_mutex	*am = (struct acpi_mutex *)Handle;
451 
452 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
453 
454 	if (am == NULL) {
455 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
456 		    "cannot release null mutex\n"));
457 		return_VOID;
458 	}
459 
460 	mtx_lock(&am->am_lock);
461 
462 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name));
463 
464 	if (ACPIMTX_OWNED(am)) {
465 		if (am->am_nested > 0) {
466 			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
467 			    "release nested %s, depth %d\n",
468 			    am->am_name, am->am_nested));
469 			am->am_nested--;
470 		} else
471 			am->am_owner = NULL;
472 	} else {
473 		if (ACPIMTX_AVAIL(am))
474 			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
475 			    "release already available %s\n", am->am_name));
476 		else
477 			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
478 			    "release unowned %s from %p, depth %d\n",
479 			    am->am_name, am->am_owner, am->am_nested));
480 	}
481 	if (am->am_waiters > 0 && ACPIMTX_AVAIL(am))
482 		wakeup_one(am);
483 
484 	mtx_unlock(&am->am_lock);
485 }
486 
487 #undef ACPIMTX_AVAIL
488 #undef ACPIMTX_OWNED
489 
490 /*
491  * ACPI_SPINLOCK
492  */
493 struct acpi_spinlock {
494 	struct mtx	al_lock;
495 	char		al_name[32];
496 	int		al_nested;
497 };
498 
499 ACPI_STATUS
500 AcpiOsCreateLock(ACPI_SPINLOCK *OutHandle)
501 {
502 	struct acpi_spinlock	*al;
503 
504 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
505 
506 	if (OutHandle == NULL)
507 		return_ACPI_STATUS (AE_BAD_PARAMETER);
508 
509 	if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL)
510 		return_ACPI_STATUS (AE_NO_MEMORY);
511 
512 #ifdef ACPI_DEBUG
513 	if (OutHandle == &AcpiGbl_GpeLock)
514 		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)");
515 	else if (OutHandle == &AcpiGbl_HardwareLock)
516 		snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)");
517 	else
518 #endif
519 	snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al);
520 	mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN);
521 
522 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name));
523 
524 	*OutHandle = (ACPI_SPINLOCK)al;
525 
526 	return_ACPI_STATUS (AE_OK);
527 }
528 
529 void
530 AcpiOsDeleteLock(ACPI_SPINLOCK Handle)
531 {
532 	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
533 
534 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
535 
536 	if (al == NULL) {
537 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
538 		    "cannot delete null spinlock\n"));
539 		return_VOID;
540 	}
541 
542 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name));
543 
544 	mtx_destroy(&al->al_lock);
545 	free(al, M_ACPISEM);
546 }
547 
548 ACPI_CPU_FLAGS
549 AcpiOsAcquireLock(ACPI_SPINLOCK Handle)
550 {
551 	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
552 
553 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
554 
555 	if (al == NULL) {
556 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
557 		    "cannot acquire null spinlock\n"));
558 		return (0);
559 	}
560 
561 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name));
562 
563 	if (mtx_owned(&al->al_lock)) {
564 		al->al_nested++;
565 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
566 		    "acquire nested %s, depth %d\n",
567 		    al->al_name, al->al_nested));
568 	} else
569 		mtx_lock_spin(&al->al_lock);
570 
571 	return (0);
572 }
573 
574 void
575 AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags)
576 {
577 	struct acpi_spinlock	*al = (struct acpi_spinlock *)Handle;
578 
579 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
580 
581 	if (al == NULL) {
582 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
583 		    "cannot release null spinlock\n"));
584 		return_VOID;
585 	}
586 
587 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name));
588 
589 	if (mtx_owned(&al->al_lock)) {
590 		if (al->al_nested > 0) {
591 			ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
592 			    "release nested %s, depth %d\n",
593 			    al->al_name, al->al_nested));
594 			al->al_nested--;
595 		} else
596 			mtx_unlock_spin(&al->al_lock);
597 	} else
598 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
599 		    "cannot release unowned %s\n", al->al_name));
600 }
601 
602 /* Section 5.2.10.1: global lock acquire/release functions */
603 
604 /*
605  * Acquire the global lock.  If busy, set the pending bit.  The caller
606  * will wait for notification from the BIOS that the lock is available
607  * and then attempt to acquire it again.
608  */
609 int
610 acpi_acquire_global_lock(volatile uint32_t *lock)
611 {
612 	uint32_t	new, old;
613 
614 	do {
615 		old = *lock;
616 		new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED;
617 		if ((old & ACPI_GLOCK_OWNED) != 0)
618 			new |= ACPI_GLOCK_PENDING;
619 	} while (atomic_cmpset_32(lock, old, new) == 0);
620 
621 	return ((new & ACPI_GLOCK_PENDING) == 0);
622 }
623 
624 /*
625  * Release the global lock, returning whether there is a waiter pending.
626  * If the BIOS set the pending bit, OSPM must notify the BIOS when it
627  * releases the lock.
628  */
629 int
630 acpi_release_global_lock(volatile uint32_t *lock)
631 {
632 	uint32_t	new, old;
633 
634 	do {
635 		old = *lock;
636 		new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED);
637 	} while (atomic_cmpset_32(lock, old, new) == 0);
638 
639 	return ((old & ACPI_GLOCK_PENDING) != 0);
640 }
641