167760Smsmith/*- 267760Smsmith * Copyright (c) 2000 Michael Smith 367760Smsmith * Copyright (c) 2000 BSDi 4193750Sjkim * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org> 567760Smsmith * All rights reserved. 667760Smsmith * 767760Smsmith * Redistribution and use in source and binary forms, with or without 867760Smsmith * modification, are permitted provided that the following conditions 967760Smsmith * are met: 1067760Smsmith * 1. Redistributions of source code must retain the above copyright 1167760Smsmith * notice, this list of conditions and the following disclaimer. 1267760Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1367760Smsmith * notice, this list of conditions and the following disclaimer in the 1467760Smsmith * documentation and/or other materials provided with the distribution. 1567760Smsmith * 1667760Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1767760Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1867760Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1967760Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2067760Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2167760Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2267760Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2367760Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2467760Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2567760Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2667760Smsmith * SUCH DAMAGE. 2767760Smsmith */ 2867760Smsmith 2967760Smsmith/* 3067760Smsmith * 6.1 : Mutual Exclusion and Synchronisation 3167760Smsmith */ 3267760Smsmith 33148318Snjl#include <sys/cdefs.h> 34148318Snjl__FBSDID("$FreeBSD$"); 35148318Snjl 36193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 37193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 3867760Smsmith 39193750Sjkim#include <sys/condvar.h> 4067760Smsmith#include <sys/kernel.h> 41193750Sjkim#include <sys/lock.h> 42105278Sjhb#include <sys/malloc.h> 4367760Smsmith#include <sys/mutex.h> 4467760Smsmith 45193750Sjkim#define _COMPONENT ACPI_OS_SERVICES 4691128SmsmithACPI_MODULE_NAME("SYNCH") 4771876Smsmith 48227293Sedstatic MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore"); 4967760Smsmith 50193750Sjkim/* 51193750Sjkim * Convert milliseconds to ticks. 52193750Sjkim */ 53193750Sjkimstatic int 54193750Sjkimtimeout2hz(UINT16 Timeout) 55193750Sjkim{ 56193750Sjkim struct timeval tv; 57105278Sjhb 58193750Sjkim tv.tv_sec = (time_t)(Timeout / 1000); 59193750Sjkim tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000; 60193750Sjkim 61193750Sjkim return (tvtohz(&tv)); 62193750Sjkim} 63193750Sjkim 6467760Smsmith/* 65193750Sjkim * ACPI_SEMAPHORE 6667760Smsmith */ 67193750Sjkimstruct acpi_sema { 68193750Sjkim struct mtx as_lock; 69193750Sjkim char as_name[32]; 70193750Sjkim struct cv as_cv; 71193750Sjkim UINT32 as_maxunits; 72193750Sjkim UINT32 as_units; 73193750Sjkim int as_waiters; 74193750Sjkim int as_reset; 7567760Smsmith}; 7667760Smsmith 7767760SmsmithACPI_STATUS 78128227SnjlAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 79167915Sjkim ACPI_SEMAPHORE *OutHandle) 8067760Smsmith{ 81193750Sjkim struct acpi_sema *as; 8267760Smsmith 83193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 8471876Smsmith 85193750Sjkim if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits) 86193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 8767760Smsmith 88193750Sjkim if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 89193750Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 9067760Smsmith 91193750Sjkim snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as); 92193750Sjkim mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF); 93193750Sjkim cv_init(&as->as_cv, as->as_name); 94193750Sjkim as->as_maxunits = MaxUnits; 95193750Sjkim as->as_units = InitialUnits; 9667760Smsmith 97193750Sjkim *OutHandle = (ACPI_SEMAPHORE)as; 9871876Smsmith 99193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n", 100193750Sjkim as->as_name, MaxUnits, InitialUnits)); 101128227Snjl 102193750Sjkim return_ACPI_STATUS (AE_OK); 10367760Smsmith} 10467760Smsmith 10567760SmsmithACPI_STATUS 106167915SjkimAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle) 10767760Smsmith{ 108193750Sjkim struct acpi_sema *as = (struct acpi_sema *)Handle; 10971876Smsmith 110193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 11171876Smsmith 112193750Sjkim if (as == NULL) 113193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 114128227Snjl 115193750Sjkim mtx_lock(&as->as_lock); 116193750Sjkim 117193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name)); 118193750Sjkim 119193750Sjkim if (as->as_waiters > 0) { 120193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 121193750Sjkim "reset %s, units %u, waiters %d\n", 122193750Sjkim as->as_name, as->as_units, as->as_waiters)); 123193750Sjkim as->as_reset = 1; 124193750Sjkim cv_broadcast(&as->as_cv); 125193750Sjkim while (as->as_waiters > 0) { 126193750Sjkim if (mtx_sleep(&as->as_reset, &as->as_lock, 127193750Sjkim PCATCH, "acsrst", hz) == EINTR) { 128193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 129193750Sjkim "failed to reset %s, waiters %d\n", 130193750Sjkim as->as_name, as->as_waiters)); 131193750Sjkim mtx_unlock(&as->as_lock); 132193750Sjkim return_ACPI_STATUS (AE_ERROR); 133193750Sjkim } 134193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 135193750Sjkim "wait %s, units %u, waiters %d\n", 136193750Sjkim as->as_name, as->as_units, as->as_waiters)); 137193750Sjkim } 138193750Sjkim } 139193750Sjkim 140193750Sjkim mtx_unlock(&as->as_lock); 141193750Sjkim 142193750Sjkim mtx_destroy(&as->as_lock); 143193750Sjkim cv_destroy(&as->as_cv); 144193750Sjkim free(as, M_ACPISEM); 145193750Sjkim 146193750Sjkim return_ACPI_STATUS (AE_OK); 14767760Smsmith} 14867760Smsmith 149193750Sjkim#define ACPISEM_AVAIL(s, u) ((s)->as_units >= (u)) 150193750Sjkim 15167760SmsmithACPI_STATUS 152167915SjkimAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 15367760Smsmith{ 154193750Sjkim struct acpi_sema *as = (struct acpi_sema *)Handle; 155193750Sjkim int error, prevtick, slptick, tmo; 156193750Sjkim ACPI_STATUS status = AE_OK; 15767760Smsmith 158193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 15971876Smsmith 160193750Sjkim if (as == NULL || Units == 0) 161193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 16267760Smsmith 163193750Sjkim mtx_lock(&as->as_lock); 16488420Siwasaki 165193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 166193750Sjkim "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n", 167193750Sjkim Units, as->as_name, as->as_units, as->as_waiters, Timeout)); 16888420Siwasaki 169193750Sjkim if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) { 170193750Sjkim mtx_unlock(&as->as_lock); 171193750Sjkim return_ACPI_STATUS (AE_LIMIT); 172193750Sjkim } 17388420Siwasaki 174193750Sjkim switch (Timeout) { 175193750Sjkim case ACPI_DO_NOT_WAIT: 176193750Sjkim if (!ACPISEM_AVAIL(as, Units)) 177193750Sjkim status = AE_TIME; 178193750Sjkim break; 179193750Sjkim case ACPI_WAIT_FOREVER: 180193750Sjkim while (!ACPISEM_AVAIL(as, Units)) { 181193750Sjkim as->as_waiters++; 182193750Sjkim error = cv_wait_sig(&as->as_cv, &as->as_lock); 183193750Sjkim as->as_waiters--; 184193750Sjkim if (error == EINTR || as->as_reset) { 185193750Sjkim status = AE_ERROR; 186193750Sjkim break; 187193750Sjkim } 188193750Sjkim } 189193750Sjkim break; 190193750Sjkim default: 191299977Sjhb if (cold) { 192299977Sjhb /* 193299977Sjhb * Just spin polling the semaphore once a 194299977Sjhb * millisecond. 195299977Sjhb */ 196299977Sjhb while (!ACPISEM_AVAIL(as, Units)) { 197299977Sjhb if (Timeout == 0) { 198299977Sjhb status = AE_TIME; 199299977Sjhb break; 200299977Sjhb } 201299977Sjhb Timeout--; 202299977Sjhb mtx_unlock(&as->as_lock); 203299977Sjhb DELAY(1000); 204299977Sjhb mtx_lock(&as->as_lock); 205299977Sjhb } 206299977Sjhb break; 207299977Sjhb } 208193750Sjkim tmo = timeout2hz(Timeout); 209193750Sjkim while (!ACPISEM_AVAIL(as, Units)) { 210193750Sjkim prevtick = ticks; 211193750Sjkim as->as_waiters++; 212193750Sjkim error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo); 213193750Sjkim as->as_waiters--; 214193750Sjkim if (error == EINTR || as->as_reset) { 215193750Sjkim status = AE_ERROR; 216193750Sjkim break; 217193750Sjkim } 218193750Sjkim if (ACPISEM_AVAIL(as, Units)) 219193750Sjkim break; 220193750Sjkim slptick = ticks - prevtick; 221193750Sjkim if (slptick >= tmo || slptick < 0) { 222193750Sjkim status = AE_TIME; 223193750Sjkim break; 224193750Sjkim } 225193750Sjkim tmo -= slptick; 226193750Sjkim } 227193750Sjkim } 228236424Sjkim if (ACPI_SUCCESS(status)) 229193750Sjkim as->as_units -= Units; 23071876Smsmith 231193750Sjkim mtx_unlock(&as->as_lock); 23288420Siwasaki 233193750Sjkim return_ACPI_STATUS (status); 234193750Sjkim} 23588420Siwasaki 236193750SjkimACPI_STATUS 237193750SjkimAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units) 238193750Sjkim{ 239193750Sjkim struct acpi_sema *as = (struct acpi_sema *)Handle; 240193750Sjkim UINT32 i; 24188420Siwasaki 242193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 24388420Siwasaki 244193750Sjkim if (as == NULL || Units == 0) 245193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 246193750Sjkim 247193750Sjkim mtx_lock(&as->as_lock); 248193750Sjkim 24988420Siwasaki ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 250193750Sjkim "return %u units to %s, units %u, waiters %d\n", 251193750Sjkim Units, as->as_name, as->as_units, as->as_waiters)); 25288420Siwasaki 253193750Sjkim if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && 254193750Sjkim (as->as_maxunits < Units || 255193750Sjkim as->as_maxunits - Units < as->as_units)) { 256193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 257193750Sjkim "exceeded max units %u\n", as->as_maxunits)); 258193750Sjkim mtx_unlock(&as->as_lock); 259193750Sjkim return_ACPI_STATUS (AE_LIMIT); 26088420Siwasaki } 26188420Siwasaki 262193750Sjkim as->as_units += Units; 263193750Sjkim if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units)) 264193750Sjkim for (i = 0; i < Units; i++) 265193750Sjkim cv_signal(&as->as_cv); 26688420Siwasaki 267193750Sjkim mtx_unlock(&as->as_lock); 26888420Siwasaki 269193750Sjkim return_ACPI_STATUS (AE_OK); 270193750Sjkim} 27188420Siwasaki 272193750Sjkim#undef ACPISEM_AVAIL 273193750Sjkim 274193750Sjkim/* 275193750Sjkim * ACPI_MUTEX 276193750Sjkim */ 277193750Sjkimstruct acpi_mutex { 278193750Sjkim struct mtx am_lock; 279193750Sjkim char am_name[32]; 280193750Sjkim struct thread *am_owner; 281193750Sjkim int am_nested; 282193750Sjkim int am_waiters; 283193750Sjkim int am_reset; 284193750Sjkim}; 285193750Sjkim 286193750SjkimACPI_STATUS 287193750SjkimAcpiOsCreateMutex(ACPI_MUTEX *OutHandle) 288193750Sjkim{ 289193750Sjkim struct acpi_mutex *am; 290193750Sjkim 291193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 292193750Sjkim 293193750Sjkim if (OutHandle == NULL) 294193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 295193750Sjkim 296193750Sjkim if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 297193750Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 298193750Sjkim 299193750Sjkim snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am); 300193750Sjkim mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF); 301193750Sjkim 302193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name)); 303193750Sjkim 304193750Sjkim *OutHandle = (ACPI_MUTEX)am; 305193750Sjkim 306193750Sjkim return_ACPI_STATUS (AE_OK); 307193750Sjkim} 308193750Sjkim 309193750Sjkim#define ACPIMTX_AVAIL(m) ((m)->am_owner == NULL) 310193750Sjkim#define ACPIMTX_OWNED(m) ((m)->am_owner == curthread) 311193750Sjkim 312193750Sjkimvoid 313193750SjkimAcpiOsDeleteMutex(ACPI_MUTEX Handle) 314193750Sjkim{ 315193750Sjkim struct acpi_mutex *am = (struct acpi_mutex *)Handle; 316193750Sjkim 317193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 318193750Sjkim 319193750Sjkim if (am == NULL) { 320193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n")); 321193750Sjkim return_VOID; 32267760Smsmith } 32388420Siwasaki 324193750Sjkim mtx_lock(&am->am_lock); 325193750Sjkim 326193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name)); 327193750Sjkim 328193750Sjkim if (am->am_waiters > 0) { 329193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 330193750Sjkim "reset %s, owner %p\n", am->am_name, am->am_owner)); 331193750Sjkim am->am_reset = 1; 332193750Sjkim wakeup(am); 333193750Sjkim while (am->am_waiters > 0) { 334193750Sjkim if (mtx_sleep(&am->am_reset, &am->am_lock, 335193750Sjkim PCATCH, "acmrst", hz) == EINTR) { 336193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 337193750Sjkim "failed to reset %s, waiters %d\n", 338193750Sjkim am->am_name, am->am_waiters)); 339193750Sjkim mtx_unlock(&am->am_lock); 340193750Sjkim return_VOID; 341193750Sjkim } 342193750Sjkim if (ACPIMTX_AVAIL(am)) 343193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 344193750Sjkim "wait %s, waiters %d\n", 345193750Sjkim am->am_name, am->am_waiters)); 346193750Sjkim else 347193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 348193750Sjkim "wait %s, owner %p, waiters %d\n", 349193750Sjkim am->am_name, am->am_owner, am->am_waiters)); 350193750Sjkim } 35188420Siwasaki } 35288420Siwasaki 353193750Sjkim mtx_unlock(&am->am_lock); 35488420Siwasaki 355193750Sjkim mtx_destroy(&am->am_lock); 356193750Sjkim free(am, M_ACPISEM); 357193750Sjkim} 358193750Sjkim 359193750SjkimACPI_STATUS 360193750SjkimAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout) 361193750Sjkim{ 362193750Sjkim struct acpi_mutex *am = (struct acpi_mutex *)Handle; 363193750Sjkim int error, prevtick, slptick, tmo; 364193750Sjkim ACPI_STATUS status = AE_OK; 365193750Sjkim 366193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 367193750Sjkim 368193750Sjkim if (am == NULL) 369193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 370193750Sjkim 371193750Sjkim mtx_lock(&am->am_lock); 372193750Sjkim 373193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name)); 374193750Sjkim 375193750Sjkim if (ACPIMTX_OWNED(am)) { 376193750Sjkim am->am_nested++; 377193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 378193750Sjkim "acquire nested %s, depth %d\n", 379193750Sjkim am->am_name, am->am_nested)); 380193750Sjkim mtx_unlock(&am->am_lock); 381193750Sjkim return_ACPI_STATUS (AE_OK); 38288420Siwasaki } 38388420Siwasaki 384193750Sjkim switch (Timeout) { 385193750Sjkim case ACPI_DO_NOT_WAIT: 386193750Sjkim if (!ACPIMTX_AVAIL(am)) 387193750Sjkim status = AE_TIME; 388193750Sjkim break; 389193750Sjkim case ACPI_WAIT_FOREVER: 390193750Sjkim while (!ACPIMTX_AVAIL(am)) { 391193750Sjkim am->am_waiters++; 392193750Sjkim error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0); 393193750Sjkim am->am_waiters--; 394193750Sjkim if (error == EINTR || am->am_reset) { 395193750Sjkim status = AE_ERROR; 396193750Sjkim break; 397193750Sjkim } 398193750Sjkim } 399193750Sjkim break; 400193750Sjkim default: 401299977Sjhb if (cold) { 402299977Sjhb /* 403299977Sjhb * Just spin polling the mutex once a 404299977Sjhb * millisecond. 405299977Sjhb */ 406299977Sjhb while (!ACPIMTX_AVAIL(am)) { 407299977Sjhb if (Timeout == 0) { 408299977Sjhb status = AE_TIME; 409299977Sjhb break; 410299977Sjhb } 411299977Sjhb Timeout--; 412299977Sjhb mtx_unlock(&am->am_lock); 413299977Sjhb DELAY(1000); 414299977Sjhb mtx_lock(&am->am_lock); 415299977Sjhb } 416299977Sjhb break; 417299977Sjhb } 418193750Sjkim tmo = timeout2hz(Timeout); 419193750Sjkim while (!ACPIMTX_AVAIL(am)) { 420193750Sjkim prevtick = ticks; 421193750Sjkim am->am_waiters++; 422193750Sjkim error = mtx_sleep(am, &am->am_lock, PCATCH, 423193750Sjkim "acmtx", tmo); 424193750Sjkim am->am_waiters--; 425193750Sjkim if (error == EINTR || am->am_reset) { 426193750Sjkim status = AE_ERROR; 427193750Sjkim break; 428193750Sjkim } 429193750Sjkim if (ACPIMTX_AVAIL(am)) 430193750Sjkim break; 431193750Sjkim slptick = ticks - prevtick; 432193750Sjkim if (slptick >= tmo || slptick < 0) { 433193750Sjkim status = AE_TIME; 434193750Sjkim break; 435193750Sjkim } 436193750Sjkim tmo -= slptick; 437193750Sjkim } 43888420Siwasaki } 439236424Sjkim if (ACPI_SUCCESS(status)) 440193750Sjkim am->am_owner = curthread; 44188420Siwasaki 442193750Sjkim mtx_unlock(&am->am_lock); 44388420Siwasaki 444193750Sjkim return_ACPI_STATUS (status); 44567760Smsmith} 44667760Smsmith 447193750Sjkimvoid 448193750SjkimAcpiOsReleaseMutex(ACPI_MUTEX Handle) 44967760Smsmith{ 450193750Sjkim struct acpi_mutex *am = (struct acpi_mutex *)Handle; 45167760Smsmith 452193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 45371876Smsmith 454194639Sjkim if (am == NULL) { 455193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 456193750Sjkim "cannot release null mutex\n")); 457194639Sjkim return_VOID; 458194639Sjkim } 45967760Smsmith 460193750Sjkim mtx_lock(&am->am_lock); 46188420Siwasaki 462193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name)); 46388420Siwasaki 464193750Sjkim if (ACPIMTX_OWNED(am)) { 465193750Sjkim if (am->am_nested > 0) { 466193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 467193750Sjkim "release nested %s, depth %d\n", 468193750Sjkim am->am_name, am->am_nested)); 469193750Sjkim am->am_nested--; 470193750Sjkim } else 471193750Sjkim am->am_owner = NULL; 472193750Sjkim } else { 473193750Sjkim if (ACPIMTX_AVAIL(am)) 474193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 475193750Sjkim "release already available %s\n", am->am_name)); 476193750Sjkim else 477193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 478193750Sjkim "release unowned %s from %p, depth %d\n", 479193750Sjkim am->am_name, am->am_owner, am->am_nested)); 480193750Sjkim } 481193750Sjkim if (am->am_waiters > 0 && ACPIMTX_AVAIL(am)) 482193750Sjkim wakeup_one(am); 483128227Snjl 484193750Sjkim mtx_unlock(&am->am_lock); 48567760Smsmith} 486117530Snjl 487193750Sjkim#undef ACPIMTX_AVAIL 488193750Sjkim#undef ACPIMTX_OWNED 489193750Sjkim 490193750Sjkim/* 491193750Sjkim * ACPI_SPINLOCK 492193750Sjkim */ 493167910Sjkimstruct acpi_spinlock { 494193750Sjkim struct mtx al_lock; 495193750Sjkim char al_name[32]; 496193750Sjkim int al_nested; 497167908Snjl}; 498167908Snjl 499117530SnjlACPI_STATUS 500193750SjkimAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle) 501117530Snjl{ 502193750Sjkim struct acpi_spinlock *al; 503117530Snjl 504193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 505117530Snjl 506193750Sjkim if (OutHandle == NULL) 507193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 508193750Sjkim 509193750Sjkim if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 510193750Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 511193750Sjkim 512193750Sjkim#ifdef ACPI_DEBUG 513193750Sjkim if (OutHandle == &AcpiGbl_GpeLock) 514193750Sjkim snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)"); 515193750Sjkim else if (OutHandle == &AcpiGbl_HardwareLock) 516193750Sjkim snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)"); 517193750Sjkim else 518193750Sjkim#endif 519193750Sjkim snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al); 520193750Sjkim mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN); 521193750Sjkim 522193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name)); 523193750Sjkim 524193750Sjkim *OutHandle = (ACPI_SPINLOCK)al; 525193750Sjkim 526193750Sjkim return_ACPI_STATUS (AE_OK); 527117530Snjl} 528117530Snjl 529117530Snjlvoid 530193750SjkimAcpiOsDeleteLock(ACPI_SPINLOCK Handle) 531117530Snjl{ 532193750Sjkim struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 533117530Snjl 534193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 535193750Sjkim 536193750Sjkim if (al == NULL) { 537193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 538193750Sjkim "cannot delete null spinlock\n")); 539193750Sjkim return_VOID; 540193750Sjkim } 541193750Sjkim 542193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name)); 543193750Sjkim 544193750Sjkim mtx_destroy(&al->al_lock); 545193750Sjkim free(al, M_ACPISEM); 546117530Snjl} 547117530Snjl 548193530SjkimACPI_CPU_FLAGS 549193750SjkimAcpiOsAcquireLock(ACPI_SPINLOCK Handle) 550117530Snjl{ 551193750Sjkim struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 552117530Snjl 553193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 554193750Sjkim 555193750Sjkim if (al == NULL) { 556193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 557193750Sjkim "cannot acquire null spinlock\n")); 558193750Sjkim return (0); 559193750Sjkim } 560193750Sjkim 561193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name)); 562193750Sjkim 563193750Sjkim if (mtx_owned(&al->al_lock)) { 564193750Sjkim al->al_nested++; 565193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 566193750Sjkim "acquire nested %s, depth %d\n", 567193750Sjkim al->al_name, al->al_nested)); 568193750Sjkim } else 569193750Sjkim mtx_lock_spin(&al->al_lock); 570193750Sjkim 571151948Sjkim return (0); 572117530Snjl} 573117530Snjl 574117530Snjlvoid 575193750SjkimAcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) 576117530Snjl{ 577193750Sjkim struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 578117530Snjl 579193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 580193750Sjkim 581193750Sjkim if (al == NULL) { 582193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 583193750Sjkim "cannot release null spinlock\n")); 584193750Sjkim return_VOID; 585193750Sjkim } 586193750Sjkim 587193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name)); 588193750Sjkim 589193750Sjkim if (mtx_owned(&al->al_lock)) { 590193750Sjkim if (al->al_nested > 0) { 591193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 592193750Sjkim "release nested %s, depth %d\n", 593193750Sjkim al->al_name, al->al_nested)); 594193750Sjkim al->al_nested--; 595193750Sjkim } else 596193750Sjkim mtx_unlock_spin(&al->al_lock); 597193750Sjkim } else 598193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 599193750Sjkim "cannot release unowned %s\n", al->al_name)); 600117530Snjl} 601128979Snjl 602193750Sjkim/* Section 5.2.10.1: global lock acquire/release functions */ 603128979Snjl 604128979Snjl/* 605128979Snjl * Acquire the global lock. If busy, set the pending bit. The caller 606128979Snjl * will wait for notification from the BIOS that the lock is available 607128979Snjl * and then attempt to acquire it again. 608128979Snjl */ 609128979Snjlint 610254300Sjkimacpi_acquire_global_lock(volatile uint32_t *lock) 611128979Snjl{ 612193750Sjkim uint32_t new, old; 613128979Snjl 614128979Snjl do { 615128979Snjl old = *lock; 616254300Sjkim new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED; 617254300Sjkim if ((old & ACPI_GLOCK_OWNED) != 0) 618254300Sjkim new |= ACPI_GLOCK_PENDING; 619254300Sjkim } while (atomic_cmpset_32(lock, old, new) == 0); 620128979Snjl 621254300Sjkim return ((new & ACPI_GLOCK_PENDING) == 0); 622128979Snjl} 623128979Snjl 624128979Snjl/* 625128979Snjl * Release the global lock, returning whether there is a waiter pending. 626128979Snjl * If the BIOS set the pending bit, OSPM must notify the BIOS when it 627128979Snjl * releases the lock. 628128979Snjl */ 629128979Snjlint 630254300Sjkimacpi_release_global_lock(volatile uint32_t *lock) 631128979Snjl{ 632193750Sjkim uint32_t new, old; 633128979Snjl 634128979Snjl do { 635128979Snjl old = *lock; 636254300Sjkim new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED); 637254300Sjkim } while (atomic_cmpset_32(lock, old, new) == 0); 638128979Snjl 639254300Sjkim return ((old & ACPI_GLOCK_PENDING) != 0); 640128979Snjl} 641