OsdSynch.c revision 193750
1123120Simp/*- 2123120Simp * Copyright (c) 2000 Michael Smith 3123120Simp * Copyright (c) 2000 BSDi 4123120Simp * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org> 5123120Simp * All rights reserved. 6123120Simp * 7123120Simp * Redistribution and use in source and binary forms, with or without 8123120Simp * modification, are permitted provided that the following conditions 9123120Simp * are met: 10123120Simp * 1. Redistributions of source code must retain the above copyright 11123120Simp * notice, this list of conditions and the following disclaimer. 12123120Simp * 2. Redistributions in binary form must reproduce the above copyright 13123120Simp * notice, this list of conditions and the following disclaimer in the 14123120Simp * documentation and/or other materials provided with the distribution. 15123120Simp * 16123120Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17123120Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18123120Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19123120Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20123120Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21123120Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22123120Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23123120Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24123120Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25123120Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26123120Simp * SUCH DAMAGE. 27123120Simp */ 28123120Simp 29123120Simp/* 30123120Simp * 6.1 : Mutual Exclusion and Synchronisation 31123120Simp */ 32123120Simp 33123120Simp#include <sys/cdefs.h> 34123120Simp__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSynch.c 193750 2009-06-08 20:07:16Z jkim $"); 35123120Simp 36123120Simp#include <contrib/dev/acpica/include/acpi.h> 37123120Simp#include <contrib/dev/acpica/include/accommon.h> 38123120Simp 39123120Simp#include <sys/condvar.h> 40123120Simp#include <sys/kernel.h> 41123120Simp#include <sys/lock.h> 42123120Simp#include <sys/malloc.h> 43123120Simp#include <sys/mutex.h> 44123120Simp 45123120Simp#define _COMPONENT ACPI_OS_SERVICES 46123120SimpACPI_MODULE_NAME("SYNCH") 47123120Simp 48123120SimpMALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore"); 49123120Simp 50123120Simp/* 51123120Simp * Convert milliseconds to ticks. 52123120Simp */ 53123120Simpstatic int 54123120Simptimeout2hz(UINT16 Timeout) 55123120Simp{ 56123120Simp struct timeval tv; 57123120Simp 58123120Simp tv.tv_sec = (time_t)(Timeout / 1000); 59123120Simp tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000; 60123120Simp 61123120Simp return (tvtohz(&tv)); 62123120Simp} 63123120Simp 64123120Simp/* 65123120Simp * ACPI_SEMAPHORE 66123120Simp */ 67123120Simpstruct acpi_sema { 68123120Simp struct mtx as_lock; 69123120Simp char as_name[32]; 70123120Simp struct cv as_cv; 71123120Simp UINT32 as_maxunits; 72123120Simp UINT32 as_units; 73123120Simp int as_waiters; 74123120Simp int as_reset; 75123120Simp}; 76123120Simp 77123120SimpACPI_STATUS 78123120SimpAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 79123120Simp ACPI_SEMAPHORE *OutHandle) 80123120Simp{ 81123120Simp struct acpi_sema *as; 82123120Simp 83123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 84123120Simp 85123120Simp if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits) 86123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 87123120Simp 88123120Simp if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 89123120Simp return_ACPI_STATUS (AE_NO_MEMORY); 90123120Simp 91123120Simp snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as); 92123120Simp mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF); 93123120Simp cv_init(&as->as_cv, as->as_name); 94123120Simp as->as_maxunits = MaxUnits; 95123120Simp as->as_units = InitialUnits; 96123120Simp 97123120Simp *OutHandle = (ACPI_SEMAPHORE)as; 98123120Simp 99123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n", 100123120Simp as->as_name, MaxUnits, InitialUnits)); 101123120Simp 102123120Simp return_ACPI_STATUS (AE_OK); 103123120Simp} 104123120Simp 105123120SimpACPI_STATUS 106123120SimpAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle) 107123120Simp{ 108123120Simp struct acpi_sema *as = (struct acpi_sema *)Handle; 109123120Simp 110123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 111123120Simp 112123120Simp if (as == NULL) 113123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 114123120Simp 115123120Simp mtx_lock(&as->as_lock); 116123120Simp 117123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name)); 118123120Simp 119123120Simp if (as->as_waiters > 0) { 120123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 121123120Simp "reset %s, units %u, waiters %d\n", 122123120Simp as->as_name, as->as_units, as->as_waiters)); 123123120Simp as->as_reset = 1; 124123120Simp cv_broadcast(&as->as_cv); 125123120Simp while (as->as_waiters > 0) { 126123120Simp if (mtx_sleep(&as->as_reset, &as->as_lock, 127123120Simp PCATCH, "acsrst", hz) == EINTR) { 128123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 129123120Simp "failed to reset %s, waiters %d\n", 130123120Simp as->as_name, as->as_waiters)); 131123120Simp mtx_unlock(&as->as_lock); 132123120Simp return_ACPI_STATUS (AE_ERROR); 133123120Simp } 134123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 135123120Simp "wait %s, units %u, waiters %d\n", 136123120Simp as->as_name, as->as_units, as->as_waiters)); 137123120Simp } 138123120Simp } 139123120Simp 140123120Simp mtx_unlock(&as->as_lock); 141123120Simp 142123120Simp mtx_destroy(&as->as_lock); 143123120Simp cv_destroy(&as->as_cv); 144123120Simp free(as, M_ACPISEM); 145123120Simp 146123120Simp return_ACPI_STATUS (AE_OK); 147123120Simp} 148123120Simp 149123120Simp#define ACPISEM_AVAIL(s, u) ((s)->as_units >= (u)) 150123120Simp 151123120SimpACPI_STATUS 152123120SimpAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 153123120Simp{ 154123120Simp struct acpi_sema *as = (struct acpi_sema *)Handle; 155123120Simp int error, prevtick, slptick, tmo; 156123120Simp ACPI_STATUS status = AE_OK; 157123120Simp 158123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 159123120Simp 160123120Simp if (as == NULL || Units == 0) 161123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 162123120Simp 163123120Simp mtx_lock(&as->as_lock); 164123120Simp 165123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 166123120Simp "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n", 167123120Simp Units, as->as_name, as->as_units, as->as_waiters, Timeout)); 168123120Simp 169123120Simp if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) { 170123120Simp mtx_unlock(&as->as_lock); 171123120Simp return_ACPI_STATUS (AE_LIMIT); 172123120Simp } 173123120Simp 174123120Simp switch (Timeout) { 175123120Simp case ACPI_DO_NOT_WAIT: 176123120Simp if (!ACPISEM_AVAIL(as, Units)) 177123120Simp status = AE_TIME; 178123120Simp break; 179123120Simp case ACPI_WAIT_FOREVER: 180123120Simp while (!ACPISEM_AVAIL(as, Units)) { 181123120Simp as->as_waiters++; 182123120Simp error = cv_wait_sig(&as->as_cv, &as->as_lock); 183123120Simp as->as_waiters--; 184123120Simp if (error == EINTR || as->as_reset) { 185123120Simp status = AE_ERROR; 186123120Simp break; 187123120Simp } 188123120Simp if (ACPISEM_AVAIL(as, Units)) 189123120Simp break; 190123120Simp } 191123120Simp break; 192123120Simp default: 193123120Simp tmo = timeout2hz(Timeout); 194123120Simp while (!ACPISEM_AVAIL(as, Units)) { 195123120Simp prevtick = ticks; 196123120Simp as->as_waiters++; 197123120Simp error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo); 198123120Simp as->as_waiters--; 199123120Simp if (error == EINTR || as->as_reset) { 200123120Simp status = AE_ERROR; 201123120Simp break; 202123120Simp } 203123120Simp if (ACPISEM_AVAIL(as, Units)) 204123120Simp break; 205123120Simp slptick = ticks - prevtick; 206123120Simp if (slptick >= tmo || slptick < 0) { 207123120Simp status = AE_TIME; 208123120Simp break; 209123120Simp } 210123120Simp tmo -= slptick; 211123120Simp } 212123120Simp } 213123120Simp if (status == AE_OK) 214123120Simp as->as_units -= Units; 215123120Simp 216123120Simp mtx_unlock(&as->as_lock); 217123120Simp 218123120Simp return_ACPI_STATUS (status); 219123120Simp} 220123120Simp 221123120SimpACPI_STATUS 222123120SimpAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units) 223123120Simp{ 224123120Simp struct acpi_sema *as = (struct acpi_sema *)Handle; 225123120Simp UINT32 i; 226123120Simp 227123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 228123120Simp 229123120Simp if (as == NULL || Units == 0) 230123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 231123120Simp 232123120Simp mtx_lock(&as->as_lock); 233123120Simp 234123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 235123120Simp "return %u units to %s, units %u, waiters %d\n", 236123120Simp Units, as->as_name, as->as_units, as->as_waiters)); 237123120Simp 238123120Simp if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && 239123120Simp (as->as_maxunits < Units || 240123120Simp as->as_maxunits - Units < as->as_units)) { 241123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 242123120Simp "exceeded max units %u\n", as->as_maxunits)); 243123120Simp mtx_unlock(&as->as_lock); 244123120Simp return_ACPI_STATUS (AE_LIMIT); 245123120Simp } 246123120Simp 247123120Simp as->as_units += Units; 248123120Simp if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units)) 249123120Simp for (i = 0; i < Units; i++) 250123120Simp cv_signal(&as->as_cv); 251123120Simp 252123120Simp mtx_unlock(&as->as_lock); 253123120Simp 254123120Simp return_ACPI_STATUS (AE_OK); 255123120Simp} 256123120Simp 257123120Simp#undef ACPISEM_AVAIL 258123120Simp 259123120Simp/* 260123120Simp * ACPI_MUTEX 261123120Simp */ 262123120Simpstruct acpi_mutex { 263123120Simp struct mtx am_lock; 264123120Simp char am_name[32]; 265123120Simp struct thread *am_owner; 266123120Simp int am_nested; 267123120Simp int am_waiters; 268123120Simp int am_reset; 269123120Simp}; 270123120Simp 271123120SimpACPI_STATUS 272123120SimpAcpiOsCreateMutex(ACPI_MUTEX *OutHandle) 273123120Simp{ 274123120Simp struct acpi_mutex *am; 275123120Simp 276123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 277123120Simp 278123120Simp if (OutHandle == NULL) 279123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 280123120Simp 281123120Simp if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 282123120Simp return_ACPI_STATUS (AE_NO_MEMORY); 283123120Simp 284123120Simp snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am); 285123120Simp mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF); 286123120Simp 287123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name)); 288123120Simp 289123120Simp *OutHandle = (ACPI_MUTEX)am; 290123120Simp 291123120Simp return_ACPI_STATUS (AE_OK); 292123120Simp} 293123120Simp 294123120Simp#define ACPIMTX_AVAIL(m) ((m)->am_owner == NULL) 295123120Simp#define ACPIMTX_OWNED(m) ((m)->am_owner == curthread) 296123120Simp 297123120Simpvoid 298123120SimpAcpiOsDeleteMutex(ACPI_MUTEX Handle) 299123120Simp{ 300123120Simp struct acpi_mutex *am = (struct acpi_mutex *)Handle; 301123120Simp 302123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 303123120Simp 304123120Simp if (am == NULL) { 305123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n")); 306123120Simp return_VOID; 307123120Simp } 308123120Simp 309123120Simp mtx_lock(&am->am_lock); 310123120Simp 311123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name)); 312123120Simp 313123120Simp if (am->am_waiters > 0) { 314123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 315123120Simp "reset %s, owner %p\n", am->am_name, am->am_owner)); 316123120Simp am->am_reset = 1; 317123120Simp wakeup(am); 318123120Simp while (am->am_waiters > 0) { 319123120Simp if (mtx_sleep(&am->am_reset, &am->am_lock, 320123120Simp PCATCH, "acmrst", hz) == EINTR) { 321123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 322123120Simp "failed to reset %s, waiters %d\n", 323123120Simp am->am_name, am->am_waiters)); 324123120Simp mtx_unlock(&am->am_lock); 325123120Simp return_VOID; 326123120Simp } 327123120Simp if (ACPIMTX_AVAIL(am)) 328123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 329123120Simp "wait %s, waiters %d\n", 330123120Simp am->am_name, am->am_waiters)); 331123120Simp else 332123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 333123120Simp "wait %s, owner %p, waiters %d\n", 334123120Simp am->am_name, am->am_owner, am->am_waiters)); 335123120Simp } 336123120Simp } 337123120Simp 338123120Simp mtx_unlock(&am->am_lock); 339123120Simp 340123120Simp mtx_destroy(&am->am_lock); 341123120Simp free(am, M_ACPISEM); 342123120Simp} 343123120Simp 344123120SimpACPI_STATUS 345123120SimpAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout) 346123120Simp{ 347123120Simp struct acpi_mutex *am = (struct acpi_mutex *)Handle; 348123120Simp int error, prevtick, slptick, tmo; 349123120Simp ACPI_STATUS status = AE_OK; 350123120Simp 351123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 352123120Simp 353123120Simp if (am == NULL) 354123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 355123120Simp 356123120Simp mtx_lock(&am->am_lock); 357123120Simp 358123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name)); 359123120Simp 360123120Simp if (ACPIMTX_OWNED(am)) { 361123120Simp am->am_nested++; 362123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 363123120Simp "acquire nested %s, depth %d\n", 364123120Simp am->am_name, am->am_nested)); 365123120Simp mtx_unlock(&am->am_lock); 366123120Simp return_ACPI_STATUS (AE_OK); 367123120Simp } 368123120Simp 369123120Simp switch (Timeout) { 370123120Simp case ACPI_DO_NOT_WAIT: 371123120Simp if (!ACPIMTX_AVAIL(am)) 372123120Simp status = AE_TIME; 373123120Simp break; 374123120Simp case ACPI_WAIT_FOREVER: 375123120Simp while (!ACPIMTX_AVAIL(am)) { 376123120Simp am->am_waiters++; 377123120Simp error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0); 378123120Simp am->am_waiters--; 379123120Simp if (error == EINTR || am->am_reset) { 380123120Simp status = AE_ERROR; 381123120Simp break; 382123120Simp } 383123120Simp if (ACPIMTX_AVAIL(am)) 384123120Simp break; 385123120Simp } 386123120Simp break; 387123120Simp default: 388123120Simp tmo = timeout2hz(Timeout); 389123120Simp while (!ACPIMTX_AVAIL(am)) { 390123120Simp prevtick = ticks; 391123120Simp am->am_waiters++; 392123120Simp error = mtx_sleep(am, &am->am_lock, PCATCH, 393123120Simp "acmtx", tmo); 394123120Simp am->am_waiters--; 395123120Simp if (error == EINTR || am->am_reset) { 396123120Simp status = AE_ERROR; 397123120Simp break; 398123120Simp } 399123120Simp if (ACPIMTX_AVAIL(am)) 400123120Simp break; 401123120Simp slptick = ticks - prevtick; 402123120Simp if (slptick >= tmo || slptick < 0) { 403123120Simp status = AE_TIME; 404123120Simp break; 405123120Simp } 406123120Simp tmo -= slptick; 407123120Simp } 408123120Simp } 409123120Simp if (status == AE_OK) 410123120Simp am->am_owner = curthread; 411123120Simp 412123120Simp mtx_unlock(&am->am_lock); 413123120Simp 414123120Simp return_ACPI_STATUS (status); 415123120Simp} 416123120Simp 417123120Simpvoid 418123120SimpAcpiOsReleaseMutex(ACPI_MUTEX Handle) 419123120Simp{ 420123120Simp struct acpi_mutex *am = (struct acpi_mutex *)Handle; 421123120Simp 422123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 423123120Simp 424123120Simp if (am == NULL) 425123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 426123120Simp "cannot release null mutex\n")); 427123120Simp 428123120Simp mtx_lock(&am->am_lock); 429123120Simp 430123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name)); 431123120Simp 432123120Simp if (ACPIMTX_OWNED(am)) { 433123120Simp if (am->am_nested > 0) { 434123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 435123120Simp "release nested %s, depth %d\n", 436123120Simp am->am_name, am->am_nested)); 437123120Simp am->am_nested--; 438123120Simp } else 439123120Simp am->am_owner = NULL; 440123120Simp } else { 441123120Simp if (ACPIMTX_AVAIL(am)) 442123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 443123120Simp "release already available %s\n", am->am_name)); 444123120Simp else 445123120Simp ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 446123120Simp "release unowned %s from %p, depth %d\n", 447123120Simp am->am_name, am->am_owner, am->am_nested)); 448123120Simp } 449123120Simp if (am->am_waiters > 0 && ACPIMTX_AVAIL(am)) 450123120Simp wakeup_one(am); 451123120Simp 452123120Simp mtx_unlock(&am->am_lock); 453123120Simp} 454123120Simp 455123120Simp#undef ACPIMTX_AVAIL 456123120Simp#undef ACPIMTX_OWNED 457123120Simp 458123120Simp/* 459123120Simp * ACPI_SPINLOCK 460123120Simp */ 461123120Simpstruct acpi_spinlock { 462123120Simp struct mtx al_lock; 463123120Simp char al_name[32]; 464123120Simp int al_nested; 465123120Simp}; 466123120Simp 467123120SimpACPI_STATUS 468123120SimpAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle) 469123120Simp{ 470123120Simp struct acpi_spinlock *al; 471123120Simp 472123120Simp ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 473123120Simp 474123120Simp if (OutHandle == NULL) 475123120Simp return_ACPI_STATUS (AE_BAD_PARAMETER); 476123120Simp 477123120Simp if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 478123120Simp return_ACPI_STATUS (AE_NO_MEMORY); 479123120Simp 480123120Simp#ifdef ACPI_DEBUG 481123120Simp if (OutHandle == &AcpiGbl_GpeLock) 482123120Simp snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)"); 483123120Simp else if (OutHandle == &AcpiGbl_HardwareLock) 484123120Simp snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)"); 485123120Simp else 486123120Simp#endif 487123120Simp snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al); 488 mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN); 489 490 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name)); 491 492 *OutHandle = (ACPI_SPINLOCK)al; 493 494 return_ACPI_STATUS (AE_OK); 495} 496 497void 498AcpiOsDeleteLock(ACPI_SPINLOCK Handle) 499{ 500 struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 501 502 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 503 504 if (al == NULL) { 505 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 506 "cannot delete null spinlock\n")); 507 return_VOID; 508 } 509 510 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name)); 511 512 mtx_destroy(&al->al_lock); 513 free(al, M_ACPISEM); 514} 515 516ACPI_CPU_FLAGS 517AcpiOsAcquireLock(ACPI_SPINLOCK Handle) 518{ 519 struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 520 521 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 522 523 if (al == NULL) { 524 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 525 "cannot acquire null spinlock\n")); 526 return (0); 527 } 528 529 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name)); 530 531 if (mtx_owned(&al->al_lock)) { 532 al->al_nested++; 533 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 534 "acquire nested %s, depth %d\n", 535 al->al_name, al->al_nested)); 536 } else 537 mtx_lock_spin(&al->al_lock); 538 539 return (0); 540} 541 542void 543AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) 544{ 545 struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 546 547 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 548 549 if (al == NULL) { 550 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 551 "cannot release null spinlock\n")); 552 return_VOID; 553 } 554 555 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name)); 556 557 if (mtx_owned(&al->al_lock)) { 558 if (al->al_nested > 0) { 559 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 560 "release nested %s, depth %d\n", 561 al->al_name, al->al_nested)); 562 al->al_nested--; 563 } else 564 mtx_unlock_spin(&al->al_lock); 565 } else 566 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 567 "cannot release unowned %s\n", al->al_name)); 568} 569 570/* Section 5.2.10.1: global lock acquire/release functions */ 571#define GL_ACQUIRED (-1) 572#define GL_BUSY 0 573#define GL_BIT_PENDING 0x01 574#define GL_BIT_OWNED 0x02 575#define GL_BIT_MASK (GL_BIT_PENDING | GL_BIT_OWNED) 576 577/* 578 * Acquire the global lock. If busy, set the pending bit. The caller 579 * will wait for notification from the BIOS that the lock is available 580 * and then attempt to acquire it again. 581 */ 582int 583acpi_acquire_global_lock(uint32_t *lock) 584{ 585 uint32_t new, old; 586 587 do { 588 old = *lock; 589 new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) | 590 ((old >> 1) & GL_BIT_PENDING); 591 } while (atomic_cmpset_acq_int(lock, old, new) == 0); 592 593 return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY); 594} 595 596/* 597 * Release the global lock, returning whether there is a waiter pending. 598 * If the BIOS set the pending bit, OSPM must notify the BIOS when it 599 * releases the lock. 600 */ 601int 602acpi_release_global_lock(uint32_t *lock) 603{ 604 uint32_t new, old; 605 606 do { 607 old = *lock; 608 new = old & ~GL_BIT_MASK; 609 } while (atomic_cmpset_rel_int(lock, old, new) == 0); 610 611 return (old & GL_BIT_PENDING); 612} 613