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