]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sys/dev/acpica/Osd/OsdSynch.c
MFC r363988:
[FreeBSD/stable/9.git] / sys / dev / acpica / Osd / OsdSynch.c
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 (status == AE_OK)
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 (status == AE_OK)
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 #define GL_BIT_PENDING  0x01
604 #define GL_BIT_OWNED    0x02
605
606 /*
607  * Acquire the global lock.  If busy, set the pending bit.  The caller
608  * will wait for notification from the BIOS that the lock is available
609  * and then attempt to acquire it again.
610  */
611 int
612 acpi_acquire_global_lock(uint32_t *lock)
613 {
614         uint32_t        new, old;
615
616         do {
617                 old = *lock;
618                 new = (old & ~GL_BIT_PENDING) | GL_BIT_OWNED;
619                 if ((old & GL_BIT_OWNED) != 0)
620                         new |= GL_BIT_PENDING;
621         } while (atomic_cmpset_acq_int(lock, old, new) == 0);
622
623         return ((new & GL_BIT_PENDING) == 0);
624 }
625
626 /*
627  * Release the global lock, returning whether there is a waiter pending.
628  * If the BIOS set the pending bit, OSPM must notify the BIOS when it
629  * releases the lock.
630  */
631 int
632 acpi_release_global_lock(uint32_t *lock)
633 {
634         uint32_t        new, old;
635
636         do {
637                 old = *lock;
638                 new = old & ~(GL_BIT_PENDING | GL_BIT_OWNED);
639         } while (atomic_cmpset_rel_int(lock, old, new) == 0);
640
641         return ((old & GL_BIT_PENDING) != 0);
642 }