OsdSynch.c revision 225736
1177633Sdfr/*- 2177633Sdfr * Copyright (c) 2000 Michael Smith 3177633Sdfr * Copyright (c) 2000 BSDi 4177633Sdfr * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org> 5177633Sdfr * All rights reserved. 6177633Sdfr * 7177633Sdfr * Redistribution and use in source and binary forms, with or without 8177633Sdfr * modification, are permitted provided that the following conditions 9177633Sdfr * are met: 10177633Sdfr * 1. Redistributions of source code must retain the above copyright 11177633Sdfr * notice, this list of conditions and the following disclaimer. 12177633Sdfr * 2. Redistributions in binary form must reproduce the above copyright 13177633Sdfr * notice, this list of conditions and the following disclaimer in the 14177633Sdfr * documentation and/or other materials provided with the distribution. 15177633Sdfr * 16177633Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17177633Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18177633Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19177633Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20177633Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21177633Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22177633Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23177633Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24177633Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25177633Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26177633Sdfr * SUCH DAMAGE. 27177633Sdfr */ 28177633Sdfr 29177633Sdfr/* 30177633Sdfr * 6.1 : Mutual Exclusion and Synchronisation 31177633Sdfr */ 32177633Sdfr 33177633Sdfr#include <sys/cdefs.h> 34177633Sdfr__FBSDID("$FreeBSD: stable/9/sys/dev/acpica/Osd/OsdSynch.c 194639 2009-06-22 17:46:55Z jkim $"); 35177633Sdfr 36177633Sdfr#include <contrib/dev/acpica/include/acpi.h> 37177633Sdfr#include <contrib/dev/acpica/include/accommon.h> 38177633Sdfr 39177633Sdfr#include <sys/condvar.h> 40177633Sdfr#include <sys/kernel.h> 41177633Sdfr#include <sys/lock.h> 42177633Sdfr#include <sys/malloc.h> 43177633Sdfr#include <sys/mutex.h> 44177633Sdfr 45177633Sdfr#define _COMPONENT ACPI_OS_SERVICES 46177633SdfrACPI_MODULE_NAME("SYNCH") 47177633Sdfr 48177633SdfrMALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore"); 49177633Sdfr 50177633Sdfr/* 51177633Sdfr * Convert milliseconds to ticks. 52177633Sdfr */ 53180025Sdfrstatic int 54180025Sdfrtimeout2hz(UINT16 Timeout) 55177633Sdfr{ 56177633Sdfr struct timeval tv; 57180064Sdfr 58180743Sdfr tv.tv_sec = (time_t)(Timeout / 1000); 59180025Sdfr tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000; 60177633Sdfr 61177633Sdfr return (tvtohz(&tv)); 62177633Sdfr} 63177633Sdfr 64177633Sdfr/* 65177633Sdfr * ACPI_SEMAPHORE 66177685Sdfr */ 67177633Sdfrstruct acpi_sema { 68177633Sdfr struct mtx as_lock; 69177633Sdfr char as_name[32]; 70177633Sdfr struct cv as_cv; 71177633Sdfr UINT32 as_maxunits; 72177633Sdfr UINT32 as_units; 73177633Sdfr int as_waiters; 74177633Sdfr int as_reset; 75177633Sdfr}; 76177633Sdfr 77177633SdfrACPI_STATUS 78177633SdfrAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 79177633Sdfr ACPI_SEMAPHORE *OutHandle) 80177633Sdfr{ 81177633Sdfr struct acpi_sema *as; 82177633Sdfr 83177633Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 84177633Sdfr 85177633Sdfr if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits) 86177633Sdfr return_ACPI_STATUS (AE_BAD_PARAMETER); 87177633Sdfr 88180025Sdfr if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 89180025Sdfr return_ACPI_STATUS (AE_NO_MEMORY); 90180743Sdfr 91180025Sdfr snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as); 92177633Sdfr mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF); 93177633Sdfr cv_init(&as->as_cv, as->as_name); 94177633Sdfr as->as_maxunits = MaxUnits; 95177633Sdfr as->as_units = InitialUnits; 96177633Sdfr 97180025Sdfr *OutHandle = (ACPI_SEMAPHORE)as; 98177633Sdfr 99180025Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n", 100177633Sdfr as->as_name, MaxUnits, InitialUnits)); 101177633Sdfr 102180025Sdfr return_ACPI_STATUS (AE_OK); 103180025Sdfr} 104180025Sdfr 105180025SdfrACPI_STATUS 106180025SdfrAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle) 107180025Sdfr{ 108180025Sdfr struct acpi_sema *as = (struct acpi_sema *)Handle; 109180025Sdfr 110180025Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 111180025Sdfr 112180025Sdfr if (as == NULL) 113180025Sdfr return_ACPI_STATUS (AE_BAD_PARAMETER); 114180025Sdfr 115180025Sdfr mtx_lock(&as->as_lock); 116180025Sdfr 117180025Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name)); 118180025Sdfr 119180025Sdfr if (as->as_waiters > 0) { 120180025Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 121177633Sdfr "reset %s, units %u, waiters %d\n", 122177633Sdfr as->as_name, as->as_units, as->as_waiters)); 123177633Sdfr as->as_reset = 1; 124177633Sdfr cv_broadcast(&as->as_cv); 125177633Sdfr while (as->as_waiters > 0) { 126177633Sdfr if (mtx_sleep(&as->as_reset, &as->as_lock, 127177633Sdfr PCATCH, "acsrst", hz) == EINTR) { 128180025Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 129177633Sdfr "failed to reset %s, waiters %d\n", 130177633Sdfr as->as_name, as->as_waiters)); 131177633Sdfr mtx_unlock(&as->as_lock); 132177633Sdfr return_ACPI_STATUS (AE_ERROR); 133180025Sdfr } 134177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 135177633Sdfr "wait %s, units %u, waiters %d\n", 136177633Sdfr as->as_name, as->as_units, as->as_waiters)); 137177633Sdfr } 138180025Sdfr } 139180025Sdfr 140180025Sdfr mtx_unlock(&as->as_lock); 141180025Sdfr 142180025Sdfr mtx_destroy(&as->as_lock); 143180025Sdfr cv_destroy(&as->as_cv); 144180025Sdfr free(as, M_ACPISEM); 145180025Sdfr 146180025Sdfr return_ACPI_STATUS (AE_OK); 147180025Sdfr} 148180025Sdfr 149180025Sdfr#define ACPISEM_AVAIL(s, u) ((s)->as_units >= (u)) 150180025Sdfr 151180025SdfrACPI_STATUS 152177633SdfrAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 153180025Sdfr{ 154180025Sdfr struct acpi_sema *as = (struct acpi_sema *)Handle; 155180025Sdfr int error, prevtick, slptick, tmo; 156180025Sdfr ACPI_STATUS status = AE_OK; 157180025Sdfr 158180025Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 159180025Sdfr 160180025Sdfr if (as == NULL || Units == 0) 161180743Sdfr return_ACPI_STATUS (AE_BAD_PARAMETER); 162180025Sdfr 163180025Sdfr mtx_lock(&as->as_lock); 164180025Sdfr 165180025Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 166180025Sdfr "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n", 167180025Sdfr Units, as->as_name, as->as_units, as->as_waiters, Timeout)); 168180025Sdfr 169180025Sdfr if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) { 170180025Sdfr mtx_unlock(&as->as_lock); 171180025Sdfr return_ACPI_STATUS (AE_LIMIT); 172180025Sdfr } 173180743Sdfr 174180025Sdfr switch (Timeout) { 175180025Sdfr case ACPI_DO_NOT_WAIT: 176180025Sdfr if (!ACPISEM_AVAIL(as, Units)) 177180743Sdfr status = AE_TIME; 178180743Sdfr break; 179180025Sdfr case ACPI_WAIT_FOREVER: 180177633Sdfr while (!ACPISEM_AVAIL(as, Units)) { 181177633Sdfr as->as_waiters++; 182177633Sdfr error = cv_wait_sig(&as->as_cv, &as->as_lock); 183177633Sdfr as->as_waiters--; 184177633Sdfr if (error == EINTR || as->as_reset) { 185177633Sdfr status = AE_ERROR; 186177633Sdfr break; 187177633Sdfr } 188180743Sdfr } 189180025Sdfr break; 190177633Sdfr default: 191177633Sdfr tmo = timeout2hz(Timeout); 192180025Sdfr while (!ACPISEM_AVAIL(as, Units)) { 193177633Sdfr prevtick = ticks; 194177633Sdfr as->as_waiters++; 195177633Sdfr error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo); 196177633Sdfr as->as_waiters--; 197177633Sdfr if (error == EINTR || as->as_reset) { 198177633Sdfr status = AE_ERROR; 199177633Sdfr break; 200177633Sdfr } 201177633Sdfr if (ACPISEM_AVAIL(as, Units)) 202177633Sdfr break; 203177633Sdfr slptick = ticks - prevtick; 204177633Sdfr if (slptick >= tmo || slptick < 0) { 205177633Sdfr status = AE_TIME; 206177633Sdfr break; 207177633Sdfr } 208177633Sdfr tmo -= slptick; 209177633Sdfr } 210177633Sdfr } 211177633Sdfr if (status == AE_OK) 212177633Sdfr as->as_units -= Units; 213177633Sdfr 214180025Sdfr mtx_unlock(&as->as_lock); 215180743Sdfr 216180743Sdfr return_ACPI_STATUS (status); 217180743Sdfr} 218180743Sdfr 219180743SdfrACPI_STATUS 220180743SdfrAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units) 221180743Sdfr{ 222180743Sdfr struct acpi_sema *as = (struct acpi_sema *)Handle; 223180743Sdfr UINT32 i; 224180743Sdfr 225180743Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 226177633Sdfr 227180743Sdfr if (as == NULL || Units == 0) 228180743Sdfr return_ACPI_STATUS (AE_BAD_PARAMETER); 229180743Sdfr 230180743Sdfr mtx_lock(&as->as_lock); 231180743Sdfr 232180743Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 233180743Sdfr "return %u units to %s, units %u, waiters %d\n", 234180743Sdfr Units, as->as_name, as->as_units, as->as_waiters)); 235177633Sdfr 236177633Sdfr if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && 237177633Sdfr (as->as_maxunits < Units || 238177633Sdfr as->as_maxunits - Units < as->as_units)) { 239177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 240177633Sdfr "exceeded max units %u\n", as->as_maxunits)); 241177633Sdfr mtx_unlock(&as->as_lock); 242177633Sdfr return_ACPI_STATUS (AE_LIMIT); 243177633Sdfr } 244177633Sdfr 245177633Sdfr as->as_units += Units; 246177633Sdfr if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units)) 247177633Sdfr for (i = 0; i < Units; i++) 248177633Sdfr cv_signal(&as->as_cv); 249177633Sdfr 250177633Sdfr mtx_unlock(&as->as_lock); 251177633Sdfr 252177633Sdfr return_ACPI_STATUS (AE_OK); 253177633Sdfr} 254177633Sdfr 255177633Sdfr#undef ACPISEM_AVAIL 256177633Sdfr 257177633Sdfr/* 258177633Sdfr * ACPI_MUTEX 259177633Sdfr */ 260177633Sdfrstruct acpi_mutex { 261177633Sdfr struct mtx am_lock; 262177633Sdfr char am_name[32]; 263177633Sdfr struct thread *am_owner; 264177633Sdfr int am_nested; 265177633Sdfr int am_waiters; 266177633Sdfr int am_reset; 267177633Sdfr}; 268177633Sdfr 269177633SdfrACPI_STATUS 270177633SdfrAcpiOsCreateMutex(ACPI_MUTEX *OutHandle) 271177633Sdfr{ 272177633Sdfr struct acpi_mutex *am; 273177633Sdfr 274177633Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 275177633Sdfr 276177633Sdfr if (OutHandle == NULL) 277177633Sdfr return_ACPI_STATUS (AE_BAD_PARAMETER); 278177633Sdfr 279177633Sdfr if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 280177633Sdfr return_ACPI_STATUS (AE_NO_MEMORY); 281177633Sdfr 282177633Sdfr snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am); 283177633Sdfr mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF); 284177633Sdfr 285177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name)); 286177633Sdfr 287177633Sdfr *OutHandle = (ACPI_MUTEX)am; 288177633Sdfr 289177633Sdfr return_ACPI_STATUS (AE_OK); 290177633Sdfr} 291177633Sdfr 292177633Sdfr#define ACPIMTX_AVAIL(m) ((m)->am_owner == NULL) 293177633Sdfr#define ACPIMTX_OWNED(m) ((m)->am_owner == curthread) 294177633Sdfr 295177633Sdfrvoid 296177633SdfrAcpiOsDeleteMutex(ACPI_MUTEX Handle) 297177633Sdfr{ 298177633Sdfr struct acpi_mutex *am = (struct acpi_mutex *)Handle; 299177633Sdfr 300177633Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 301177633Sdfr 302177633Sdfr if (am == NULL) { 303177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n")); 304177633Sdfr return_VOID; 305177633Sdfr } 306177633Sdfr 307177633Sdfr mtx_lock(&am->am_lock); 308177633Sdfr 309177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name)); 310177633Sdfr 311177633Sdfr if (am->am_waiters > 0) { 312177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 313177633Sdfr "reset %s, owner %p\n", am->am_name, am->am_owner)); 314177633Sdfr am->am_reset = 1; 315177633Sdfr wakeup(am); 316177633Sdfr while (am->am_waiters > 0) { 317177633Sdfr if (mtx_sleep(&am->am_reset, &am->am_lock, 318177633Sdfr PCATCH, "acmrst", hz) == EINTR) { 319177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 320177633Sdfr "failed to reset %s, waiters %d\n", 321177633Sdfr am->am_name, am->am_waiters)); 322177633Sdfr mtx_unlock(&am->am_lock); 323177633Sdfr return_VOID; 324177633Sdfr } 325177633Sdfr if (ACPIMTX_AVAIL(am)) 326177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 327177633Sdfr "wait %s, waiters %d\n", 328177633Sdfr am->am_name, am->am_waiters)); 329177633Sdfr else 330177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 331180025Sdfr "wait %s, owner %p, waiters %d\n", 332180743Sdfr am->am_name, am->am_owner, am->am_waiters)); 333180025Sdfr } 334180025Sdfr } 335177633Sdfr 336177633Sdfr mtx_unlock(&am->am_lock); 337177633Sdfr 338177633Sdfr mtx_destroy(&am->am_lock); 339177633Sdfr free(am, M_ACPISEM); 340177633Sdfr} 341177633Sdfr 342177633SdfrACPI_STATUS 343177633SdfrAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout) 344177633Sdfr{ 345177633Sdfr struct acpi_mutex *am = (struct acpi_mutex *)Handle; 346177633Sdfr int error, prevtick, slptick, tmo; 347177633Sdfr ACPI_STATUS status = AE_OK; 348177633Sdfr 349177633Sdfr ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 350177633Sdfr 351177633Sdfr if (am == NULL) 352177633Sdfr return_ACPI_STATUS (AE_BAD_PARAMETER); 353177633Sdfr 354177633Sdfr mtx_lock(&am->am_lock); 355177633Sdfr 356177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name)); 357177633Sdfr 358177633Sdfr if (ACPIMTX_OWNED(am)) { 359177633Sdfr am->am_nested++; 360177633Sdfr ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 361177633Sdfr "acquire nested %s, depth %d\n", 362177633Sdfr am->am_name, am->am_nested)); 363177633Sdfr mtx_unlock(&am->am_lock); 364177633Sdfr return_ACPI_STATUS (AE_OK); 365177633Sdfr } 366177633Sdfr 367177633Sdfr switch (Timeout) { 368 case ACPI_DO_NOT_WAIT: 369 if (!ACPIMTX_AVAIL(am)) 370 status = AE_TIME; 371 break; 372 case ACPI_WAIT_FOREVER: 373 while (!ACPIMTX_AVAIL(am)) { 374 am->am_waiters++; 375 error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0); 376 am->am_waiters--; 377 if (error == EINTR || am->am_reset) { 378 status = AE_ERROR; 379 break; 380 } 381 } 382 break; 383 default: 384 tmo = timeout2hz(Timeout); 385 while (!ACPIMTX_AVAIL(am)) { 386 prevtick = ticks; 387 am->am_waiters++; 388 error = mtx_sleep(am, &am->am_lock, PCATCH, 389 "acmtx", tmo); 390 am->am_waiters--; 391 if (error == EINTR || am->am_reset) { 392 status = AE_ERROR; 393 break; 394 } 395 if (ACPIMTX_AVAIL(am)) 396 break; 397 slptick = ticks - prevtick; 398 if (slptick >= tmo || slptick < 0) { 399 status = AE_TIME; 400 break; 401 } 402 tmo -= slptick; 403 } 404 } 405 if (status == AE_OK) 406 am->am_owner = curthread; 407 408 mtx_unlock(&am->am_lock); 409 410 return_ACPI_STATUS (status); 411} 412 413void 414AcpiOsReleaseMutex(ACPI_MUTEX Handle) 415{ 416 struct acpi_mutex *am = (struct acpi_mutex *)Handle; 417 418 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 419 420 if (am == NULL) { 421 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 422 "cannot release null mutex\n")); 423 return_VOID; 424 } 425 426 mtx_lock(&am->am_lock); 427 428 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name)); 429 430 if (ACPIMTX_OWNED(am)) { 431 if (am->am_nested > 0) { 432 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 433 "release nested %s, depth %d\n", 434 am->am_name, am->am_nested)); 435 am->am_nested--; 436 } else 437 am->am_owner = NULL; 438 } else { 439 if (ACPIMTX_AVAIL(am)) 440 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 441 "release already available %s\n", am->am_name)); 442 else 443 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 444 "release unowned %s from %p, depth %d\n", 445 am->am_name, am->am_owner, am->am_nested)); 446 } 447 if (am->am_waiters > 0 && ACPIMTX_AVAIL(am)) 448 wakeup_one(am); 449 450 mtx_unlock(&am->am_lock); 451} 452 453#undef ACPIMTX_AVAIL 454#undef ACPIMTX_OWNED 455 456/* 457 * ACPI_SPINLOCK 458 */ 459struct acpi_spinlock { 460 struct mtx al_lock; 461 char al_name[32]; 462 int al_nested; 463}; 464 465ACPI_STATUS 466AcpiOsCreateLock(ACPI_SPINLOCK *OutHandle) 467{ 468 struct acpi_spinlock *al; 469 470 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 471 472 if (OutHandle == NULL) 473 return_ACPI_STATUS (AE_BAD_PARAMETER); 474 475 if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 476 return_ACPI_STATUS (AE_NO_MEMORY); 477 478#ifdef ACPI_DEBUG 479 if (OutHandle == &AcpiGbl_GpeLock) 480 snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)"); 481 else if (OutHandle == &AcpiGbl_HardwareLock) 482 snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)"); 483 else 484#endif 485 snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al); 486 mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN); 487 488 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name)); 489 490 *OutHandle = (ACPI_SPINLOCK)al; 491 492 return_ACPI_STATUS (AE_OK); 493} 494 495void 496AcpiOsDeleteLock(ACPI_SPINLOCK Handle) 497{ 498 struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 499 500 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 501 502 if (al == NULL) { 503 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 504 "cannot delete null spinlock\n")); 505 return_VOID; 506 } 507 508 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name)); 509 510 mtx_destroy(&al->al_lock); 511 free(al, M_ACPISEM); 512} 513 514ACPI_CPU_FLAGS 515AcpiOsAcquireLock(ACPI_SPINLOCK Handle) 516{ 517 struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 518 519 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 520 521 if (al == NULL) { 522 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 523 "cannot acquire null spinlock\n")); 524 return (0); 525 } 526 527 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name)); 528 529 if (mtx_owned(&al->al_lock)) { 530 al->al_nested++; 531 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 532 "acquire nested %s, depth %d\n", 533 al->al_name, al->al_nested)); 534 } else 535 mtx_lock_spin(&al->al_lock); 536 537 return (0); 538} 539 540void 541AcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) 542{ 543 struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 544 545 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 546 547 if (al == NULL) { 548 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 549 "cannot release null spinlock\n")); 550 return_VOID; 551 } 552 553 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name)); 554 555 if (mtx_owned(&al->al_lock)) { 556 if (al->al_nested > 0) { 557 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 558 "release nested %s, depth %d\n", 559 al->al_name, al->al_nested)); 560 al->al_nested--; 561 } else 562 mtx_unlock_spin(&al->al_lock); 563 } else 564 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 565 "cannot release unowned %s\n", al->al_name)); 566} 567 568/* Section 5.2.10.1: global lock acquire/release functions */ 569#define GL_ACQUIRED (-1) 570#define GL_BUSY 0 571#define GL_BIT_PENDING 0x01 572#define GL_BIT_OWNED 0x02 573#define GL_BIT_MASK (GL_BIT_PENDING | GL_BIT_OWNED) 574 575/* 576 * Acquire the global lock. If busy, set the pending bit. The caller 577 * will wait for notification from the BIOS that the lock is available 578 * and then attempt to acquire it again. 579 */ 580int 581acpi_acquire_global_lock(uint32_t *lock) 582{ 583 uint32_t new, old; 584 585 do { 586 old = *lock; 587 new = ((old & ~GL_BIT_MASK) | GL_BIT_OWNED) | 588 ((old >> 1) & GL_BIT_PENDING); 589 } while (atomic_cmpset_acq_int(lock, old, new) == 0); 590 591 return ((new < GL_BIT_MASK) ? GL_ACQUIRED : GL_BUSY); 592} 593 594/* 595 * Release the global lock, returning whether there is a waiter pending. 596 * If the BIOS set the pending bit, OSPM must notify the BIOS when it 597 * releases the lock. 598 */ 599int 600acpi_release_global_lock(uint32_t *lock) 601{ 602 uint32_t new, old; 603 604 do { 605 old = *lock; 606 new = old & ~GL_BIT_MASK; 607 } while (atomic_cmpset_rel_int(lock, old, new) == 0); 608 609 return (old & GL_BIT_PENDING); 610} 611