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: 191193750Sjkim tmo = timeout2hz(Timeout); 192193750Sjkim while (!ACPISEM_AVAIL(as, Units)) { 193193750Sjkim prevtick = ticks; 194193750Sjkim as->as_waiters++; 195193750Sjkim error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo); 196193750Sjkim as->as_waiters--; 197193750Sjkim if (error == EINTR || as->as_reset) { 198193750Sjkim status = AE_ERROR; 199193750Sjkim break; 200193750Sjkim } 201193750Sjkim if (ACPISEM_AVAIL(as, Units)) 202193750Sjkim break; 203193750Sjkim slptick = ticks - prevtick; 204193750Sjkim if (slptick >= tmo || slptick < 0) { 205193750Sjkim status = AE_TIME; 206193750Sjkim break; 207193750Sjkim } 208193750Sjkim tmo -= slptick; 209193750Sjkim } 210193750Sjkim } 211236424Sjkim if (ACPI_SUCCESS(status)) 212193750Sjkim as->as_units -= Units; 21371876Smsmith 214193750Sjkim mtx_unlock(&as->as_lock); 21588420Siwasaki 216193750Sjkim return_ACPI_STATUS (status); 217193750Sjkim} 21888420Siwasaki 219193750SjkimACPI_STATUS 220193750SjkimAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units) 221193750Sjkim{ 222193750Sjkim struct acpi_sema *as = (struct acpi_sema *)Handle; 223193750Sjkim UINT32 i; 22488420Siwasaki 225193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 22688420Siwasaki 227193750Sjkim if (as == NULL || Units == 0) 228193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 229193750Sjkim 230193750Sjkim mtx_lock(&as->as_lock); 231193750Sjkim 23288420Siwasaki ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 233193750Sjkim "return %u units to %s, units %u, waiters %d\n", 234193750Sjkim Units, as->as_name, as->as_units, as->as_waiters)); 23588420Siwasaki 236193750Sjkim if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && 237193750Sjkim (as->as_maxunits < Units || 238193750Sjkim as->as_maxunits - Units < as->as_units)) { 239193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 240193750Sjkim "exceeded max units %u\n", as->as_maxunits)); 241193750Sjkim mtx_unlock(&as->as_lock); 242193750Sjkim return_ACPI_STATUS (AE_LIMIT); 24388420Siwasaki } 24488420Siwasaki 245193750Sjkim as->as_units += Units; 246193750Sjkim if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units)) 247193750Sjkim for (i = 0; i < Units; i++) 248193750Sjkim cv_signal(&as->as_cv); 24988420Siwasaki 250193750Sjkim mtx_unlock(&as->as_lock); 25188420Siwasaki 252193750Sjkim return_ACPI_STATUS (AE_OK); 253193750Sjkim} 25488420Siwasaki 255193750Sjkim#undef ACPISEM_AVAIL 256193750Sjkim 257193750Sjkim/* 258193750Sjkim * ACPI_MUTEX 259193750Sjkim */ 260193750Sjkimstruct acpi_mutex { 261193750Sjkim struct mtx am_lock; 262193750Sjkim char am_name[32]; 263193750Sjkim struct thread *am_owner; 264193750Sjkim int am_nested; 265193750Sjkim int am_waiters; 266193750Sjkim int am_reset; 267193750Sjkim}; 268193750Sjkim 269193750SjkimACPI_STATUS 270193750SjkimAcpiOsCreateMutex(ACPI_MUTEX *OutHandle) 271193750Sjkim{ 272193750Sjkim struct acpi_mutex *am; 273193750Sjkim 274193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 275193750Sjkim 276193750Sjkim if (OutHandle == NULL) 277193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 278193750Sjkim 279193750Sjkim if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 280193750Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 281193750Sjkim 282193750Sjkim snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am); 283193750Sjkim mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF); 284193750Sjkim 285193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name)); 286193750Sjkim 287193750Sjkim *OutHandle = (ACPI_MUTEX)am; 288193750Sjkim 289193750Sjkim return_ACPI_STATUS (AE_OK); 290193750Sjkim} 291193750Sjkim 292193750Sjkim#define ACPIMTX_AVAIL(m) ((m)->am_owner == NULL) 293193750Sjkim#define ACPIMTX_OWNED(m) ((m)->am_owner == curthread) 294193750Sjkim 295193750Sjkimvoid 296193750SjkimAcpiOsDeleteMutex(ACPI_MUTEX Handle) 297193750Sjkim{ 298193750Sjkim struct acpi_mutex *am = (struct acpi_mutex *)Handle; 299193750Sjkim 300193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 301193750Sjkim 302193750Sjkim if (am == NULL) { 303193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n")); 304193750Sjkim return_VOID; 30567760Smsmith } 30688420Siwasaki 307193750Sjkim mtx_lock(&am->am_lock); 308193750Sjkim 309193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name)); 310193750Sjkim 311193750Sjkim if (am->am_waiters > 0) { 312193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 313193750Sjkim "reset %s, owner %p\n", am->am_name, am->am_owner)); 314193750Sjkim am->am_reset = 1; 315193750Sjkim wakeup(am); 316193750Sjkim while (am->am_waiters > 0) { 317193750Sjkim if (mtx_sleep(&am->am_reset, &am->am_lock, 318193750Sjkim PCATCH, "acmrst", hz) == EINTR) { 319193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 320193750Sjkim "failed to reset %s, waiters %d\n", 321193750Sjkim am->am_name, am->am_waiters)); 322193750Sjkim mtx_unlock(&am->am_lock); 323193750Sjkim return_VOID; 324193750Sjkim } 325193750Sjkim if (ACPIMTX_AVAIL(am)) 326193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 327193750Sjkim "wait %s, waiters %d\n", 328193750Sjkim am->am_name, am->am_waiters)); 329193750Sjkim else 330193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 331193750Sjkim "wait %s, owner %p, waiters %d\n", 332193750Sjkim am->am_name, am->am_owner, am->am_waiters)); 333193750Sjkim } 33488420Siwasaki } 33588420Siwasaki 336193750Sjkim mtx_unlock(&am->am_lock); 33788420Siwasaki 338193750Sjkim mtx_destroy(&am->am_lock); 339193750Sjkim free(am, M_ACPISEM); 340193750Sjkim} 341193750Sjkim 342193750SjkimACPI_STATUS 343193750SjkimAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout) 344193750Sjkim{ 345193750Sjkim struct acpi_mutex *am = (struct acpi_mutex *)Handle; 346193750Sjkim int error, prevtick, slptick, tmo; 347193750Sjkim ACPI_STATUS status = AE_OK; 348193750Sjkim 349193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 350193750Sjkim 351193750Sjkim if (am == NULL) 352193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 353193750Sjkim 354193750Sjkim mtx_lock(&am->am_lock); 355193750Sjkim 356193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name)); 357193750Sjkim 358193750Sjkim if (ACPIMTX_OWNED(am)) { 359193750Sjkim am->am_nested++; 360193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 361193750Sjkim "acquire nested %s, depth %d\n", 362193750Sjkim am->am_name, am->am_nested)); 363193750Sjkim mtx_unlock(&am->am_lock); 364193750Sjkim return_ACPI_STATUS (AE_OK); 36588420Siwasaki } 36688420Siwasaki 367193750Sjkim switch (Timeout) { 368193750Sjkim case ACPI_DO_NOT_WAIT: 369193750Sjkim if (!ACPIMTX_AVAIL(am)) 370193750Sjkim status = AE_TIME; 371193750Sjkim break; 372193750Sjkim case ACPI_WAIT_FOREVER: 373193750Sjkim while (!ACPIMTX_AVAIL(am)) { 374193750Sjkim am->am_waiters++; 375193750Sjkim error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0); 376193750Sjkim am->am_waiters--; 377193750Sjkim if (error == EINTR || am->am_reset) { 378193750Sjkim status = AE_ERROR; 379193750Sjkim break; 380193750Sjkim } 381193750Sjkim } 382193750Sjkim break; 383193750Sjkim default: 384193750Sjkim tmo = timeout2hz(Timeout); 385193750Sjkim while (!ACPIMTX_AVAIL(am)) { 386193750Sjkim prevtick = ticks; 387193750Sjkim am->am_waiters++; 388193750Sjkim error = mtx_sleep(am, &am->am_lock, PCATCH, 389193750Sjkim "acmtx", tmo); 390193750Sjkim am->am_waiters--; 391193750Sjkim if (error == EINTR || am->am_reset) { 392193750Sjkim status = AE_ERROR; 393193750Sjkim break; 394193750Sjkim } 395193750Sjkim if (ACPIMTX_AVAIL(am)) 396193750Sjkim break; 397193750Sjkim slptick = ticks - prevtick; 398193750Sjkim if (slptick >= tmo || slptick < 0) { 399193750Sjkim status = AE_TIME; 400193750Sjkim break; 401193750Sjkim } 402193750Sjkim tmo -= slptick; 403193750Sjkim } 40488420Siwasaki } 405236424Sjkim if (ACPI_SUCCESS(status)) 406193750Sjkim am->am_owner = curthread; 40788420Siwasaki 408193750Sjkim mtx_unlock(&am->am_lock); 40988420Siwasaki 410193750Sjkim return_ACPI_STATUS (status); 41167760Smsmith} 41267760Smsmith 413193750Sjkimvoid 414193750SjkimAcpiOsReleaseMutex(ACPI_MUTEX Handle) 41567760Smsmith{ 416193750Sjkim struct acpi_mutex *am = (struct acpi_mutex *)Handle; 41767760Smsmith 418193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 41971876Smsmith 420194639Sjkim if (am == NULL) { 421193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 422193750Sjkim "cannot release null mutex\n")); 423194639Sjkim return_VOID; 424194639Sjkim } 42567760Smsmith 426193750Sjkim mtx_lock(&am->am_lock); 42788420Siwasaki 428193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name)); 42988420Siwasaki 430193750Sjkim if (ACPIMTX_OWNED(am)) { 431193750Sjkim if (am->am_nested > 0) { 432193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 433193750Sjkim "release nested %s, depth %d\n", 434193750Sjkim am->am_name, am->am_nested)); 435193750Sjkim am->am_nested--; 436193750Sjkim } else 437193750Sjkim am->am_owner = NULL; 438193750Sjkim } else { 439193750Sjkim if (ACPIMTX_AVAIL(am)) 440193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 441193750Sjkim "release already available %s\n", am->am_name)); 442193750Sjkim else 443193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 444193750Sjkim "release unowned %s from %p, depth %d\n", 445193750Sjkim am->am_name, am->am_owner, am->am_nested)); 446193750Sjkim } 447193750Sjkim if (am->am_waiters > 0 && ACPIMTX_AVAIL(am)) 448193750Sjkim wakeup_one(am); 449128227Snjl 450193750Sjkim mtx_unlock(&am->am_lock); 45167760Smsmith} 452117530Snjl 453193750Sjkim#undef ACPIMTX_AVAIL 454193750Sjkim#undef ACPIMTX_OWNED 455193750Sjkim 456193750Sjkim/* 457193750Sjkim * ACPI_SPINLOCK 458193750Sjkim */ 459167910Sjkimstruct acpi_spinlock { 460193750Sjkim struct mtx al_lock; 461193750Sjkim char al_name[32]; 462193750Sjkim int al_nested; 463167908Snjl}; 464167908Snjl 465117530SnjlACPI_STATUS 466193750SjkimAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle) 467117530Snjl{ 468193750Sjkim struct acpi_spinlock *al; 469117530Snjl 470193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 471117530Snjl 472193750Sjkim if (OutHandle == NULL) 473193750Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 474193750Sjkim 475193750Sjkim if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 476193750Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 477193750Sjkim 478193750Sjkim#ifdef ACPI_DEBUG 479193750Sjkim if (OutHandle == &AcpiGbl_GpeLock) 480193750Sjkim snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)"); 481193750Sjkim else if (OutHandle == &AcpiGbl_HardwareLock) 482193750Sjkim snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)"); 483193750Sjkim else 484193750Sjkim#endif 485193750Sjkim snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al); 486193750Sjkim mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN); 487193750Sjkim 488193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name)); 489193750Sjkim 490193750Sjkim *OutHandle = (ACPI_SPINLOCK)al; 491193750Sjkim 492193750Sjkim return_ACPI_STATUS (AE_OK); 493117530Snjl} 494117530Snjl 495117530Snjlvoid 496193750SjkimAcpiOsDeleteLock(ACPI_SPINLOCK Handle) 497117530Snjl{ 498193750Sjkim struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 499117530Snjl 500193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 501193750Sjkim 502193750Sjkim if (al == NULL) { 503193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 504193750Sjkim "cannot delete null spinlock\n")); 505193750Sjkim return_VOID; 506193750Sjkim } 507193750Sjkim 508193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name)); 509193750Sjkim 510193750Sjkim mtx_destroy(&al->al_lock); 511193750Sjkim free(al, M_ACPISEM); 512117530Snjl} 513117530Snjl 514193530SjkimACPI_CPU_FLAGS 515193750SjkimAcpiOsAcquireLock(ACPI_SPINLOCK Handle) 516117530Snjl{ 517193750Sjkim struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 518117530Snjl 519193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 520193750Sjkim 521193750Sjkim if (al == NULL) { 522193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 523193750Sjkim "cannot acquire null spinlock\n")); 524193750Sjkim return (0); 525193750Sjkim } 526193750Sjkim 527193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name)); 528193750Sjkim 529193750Sjkim if (mtx_owned(&al->al_lock)) { 530193750Sjkim al->al_nested++; 531193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 532193750Sjkim "acquire nested %s, depth %d\n", 533193750Sjkim al->al_name, al->al_nested)); 534193750Sjkim } else 535193750Sjkim mtx_lock_spin(&al->al_lock); 536193750Sjkim 537151948Sjkim return (0); 538117530Snjl} 539117530Snjl 540117530Snjlvoid 541193750SjkimAcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) 542117530Snjl{ 543193750Sjkim struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 544117530Snjl 545193750Sjkim ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 546193750Sjkim 547193750Sjkim if (al == NULL) { 548193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 549193750Sjkim "cannot release null spinlock\n")); 550193750Sjkim return_VOID; 551193750Sjkim } 552193750Sjkim 553193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name)); 554193750Sjkim 555193750Sjkim if (mtx_owned(&al->al_lock)) { 556193750Sjkim if (al->al_nested > 0) { 557193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 558193750Sjkim "release nested %s, depth %d\n", 559193750Sjkim al->al_name, al->al_nested)); 560193750Sjkim al->al_nested--; 561193750Sjkim } else 562193750Sjkim mtx_unlock_spin(&al->al_lock); 563193750Sjkim } else 564193750Sjkim ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 565193750Sjkim "cannot release unowned %s\n", al->al_name)); 566117530Snjl} 567128979Snjl 568193750Sjkim/* Section 5.2.10.1: global lock acquire/release functions */ 569128979Snjl 570128979Snjl/* 571128979Snjl * Acquire the global lock. If busy, set the pending bit. The caller 572128979Snjl * will wait for notification from the BIOS that the lock is available 573128979Snjl * and then attempt to acquire it again. 574128979Snjl */ 575128979Snjlint 576254300Sjkimacpi_acquire_global_lock(volatile uint32_t *lock) 577128979Snjl{ 578193750Sjkim uint32_t new, old; 579128979Snjl 580128979Snjl do { 581128979Snjl old = *lock; 582254300Sjkim new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED; 583254300Sjkim if ((old & ACPI_GLOCK_OWNED) != 0) 584254300Sjkim new |= ACPI_GLOCK_PENDING; 585254300Sjkim } while (atomic_cmpset_32(lock, old, new) == 0); 586128979Snjl 587254300Sjkim return ((new & ACPI_GLOCK_PENDING) == 0); 588128979Snjl} 589128979Snjl 590128979Snjl/* 591128979Snjl * Release the global lock, returning whether there is a waiter pending. 592128979Snjl * If the BIOS set the pending bit, OSPM must notify the BIOS when it 593128979Snjl * releases the lock. 594128979Snjl */ 595128979Snjlint 596254300Sjkimacpi_release_global_lock(volatile uint32_t *lock) 597128979Snjl{ 598193750Sjkim uint32_t new, old; 599128979Snjl 600128979Snjl do { 601128979Snjl old = *lock; 602254300Sjkim new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED); 603254300Sjkim } while (atomic_cmpset_32(lock, old, new) == 0); 604128979Snjl 605254300Sjkim return ((old & ACPI_GLOCK_PENDING) != 0); 606128979Snjl} 607