OsdSynch.c revision 254300
1203288Srnoland/*- 2203288Srnoland * Copyright (c) 2000 Michael Smith 3203288Srnoland * Copyright (c) 2000 BSDi 4203288Srnoland * Copyright (c) 2007-2009 Jung-uk Kim <jkim@FreeBSD.org> 5203288Srnoland * All rights reserved. 6203288Srnoland * 7203288Srnoland * Redistribution and use in source and binary forms, with or without 8203288Srnoland * modification, are permitted provided that the following conditions 9203288Srnoland * are met: 10203288Srnoland * 1. Redistributions of source code must retain the above copyright 11203288Srnoland * notice, this list of conditions and the following disclaimer. 12203288Srnoland * 2. Redistributions in binary form must reproduce the above copyright 13203288Srnoland * notice, this list of conditions and the following disclaimer in the 14203288Srnoland * documentation and/or other materials provided with the distribution. 15203288Srnoland * 16203288Srnoland * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17203288Srnoland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18203288Srnoland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19203288Srnoland * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20203288Srnoland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21203288Srnoland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22203288Srnoland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23203288Srnoland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24203288Srnoland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25203288Srnoland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26203288Srnoland * SUCH DAMAGE. 27203288Srnoland */ 28203288Srnoland 29203288Srnoland/* 30203288Srnoland * 6.1 : Mutual Exclusion and Synchronisation 31203288Srnoland */ 32203288Srnoland 33203288Srnoland#include <sys/cdefs.h> 34203288Srnoland__FBSDID("$FreeBSD: head/sys/dev/acpica/Osd/OsdSynch.c 254300 2013-08-13 21:34:03Z jkim $"); 35203288Srnoland 36203288Srnoland#include <contrib/dev/acpica/include/acpi.h> 37203288Srnoland#include <contrib/dev/acpica/include/accommon.h> 38203288Srnoland 39203288Srnoland#include <sys/condvar.h> 40203288Srnoland#include <sys/kernel.h> 41203288Srnoland#include <sys/lock.h> 42203288Srnoland#include <sys/malloc.h> 43203288Srnoland#include <sys/mutex.h> 44203288Srnoland 45203288Srnoland#define _COMPONENT ACPI_OS_SERVICES 46203288SrnolandACPI_MODULE_NAME("SYNCH") 47203288Srnoland 48203288Srnolandstatic MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore"); 49203288Srnoland 50203288Srnoland/* 51203288Srnoland * Convert milliseconds to ticks. 52203288Srnoland */ 53203288Srnolandstatic int 54203288Srnolandtimeout2hz(UINT16 Timeout) 55203288Srnoland{ 56203288Srnoland struct timeval tv; 57203288Srnoland 58203288Srnoland tv.tv_sec = (time_t)(Timeout / 1000); 59203288Srnoland tv.tv_usec = (suseconds_t)(Timeout % 1000) * 1000; 60203288Srnoland 61203288Srnoland return (tvtohz(&tv)); 62203288Srnoland} 63203288Srnoland 64203288Srnoland/* 65203288Srnoland * ACPI_SEMAPHORE 66203288Srnoland */ 67203288Srnolandstruct acpi_sema { 68203288Srnoland struct mtx as_lock; 69203288Srnoland char as_name[32]; 70203288Srnoland struct cv as_cv; 71203288Srnoland UINT32 as_maxunits; 72203288Srnoland UINT32 as_units; 73203288Srnoland int as_waiters; 74203288Srnoland int as_reset; 75203288Srnoland}; 76203288Srnoland 77203288SrnolandACPI_STATUS 78203288SrnolandAcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 79203288Srnoland ACPI_SEMAPHORE *OutHandle) 80203288Srnoland{ 81203288Srnoland struct acpi_sema *as; 82203288Srnoland 83203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 84203288Srnoland 85203288Srnoland if (OutHandle == NULL || MaxUnits == 0 || InitialUnits > MaxUnits) 86203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 87203288Srnoland 88203288Srnoland if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 89203288Srnoland return_ACPI_STATUS (AE_NO_MEMORY); 90203288Srnoland 91203288Srnoland snprintf(as->as_name, sizeof(as->as_name), "ACPI sema (%p)", as); 92203288Srnoland mtx_init(&as->as_lock, as->as_name, NULL, MTX_DEF); 93203288Srnoland cv_init(&as->as_cv, as->as_name); 94203288Srnoland as->as_maxunits = MaxUnits; 95203288Srnoland as->as_units = InitialUnits; 96203288Srnoland 97203288Srnoland *OutHandle = (ACPI_SEMAPHORE)as; 98203288Srnoland 99203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s, max %u, initial %u\n", 100203288Srnoland as->as_name, MaxUnits, InitialUnits)); 101203288Srnoland 102203288Srnoland return_ACPI_STATUS (AE_OK); 103203288Srnoland} 104203288Srnoland 105203288SrnolandACPI_STATUS 106203288SrnolandAcpiOsDeleteSemaphore(ACPI_SEMAPHORE Handle) 107203288Srnoland{ 108203288Srnoland struct acpi_sema *as = (struct acpi_sema *)Handle; 109203288Srnoland 110203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 111203288Srnoland 112203288Srnoland if (as == NULL) 113203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 114203288Srnoland 115203288Srnoland mtx_lock(&as->as_lock); 116203288Srnoland 117203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", as->as_name)); 118203288Srnoland 119203288Srnoland if (as->as_waiters > 0) { 120203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 121203288Srnoland "reset %s, units %u, waiters %d\n", 122203288Srnoland as->as_name, as->as_units, as->as_waiters)); 123203288Srnoland as->as_reset = 1; 124203288Srnoland cv_broadcast(&as->as_cv); 125203288Srnoland while (as->as_waiters > 0) { 126203288Srnoland if (mtx_sleep(&as->as_reset, &as->as_lock, 127203288Srnoland PCATCH, "acsrst", hz) == EINTR) { 128203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 129203288Srnoland "failed to reset %s, waiters %d\n", 130203288Srnoland as->as_name, as->as_waiters)); 131203288Srnoland mtx_unlock(&as->as_lock); 132203288Srnoland return_ACPI_STATUS (AE_ERROR); 133203288Srnoland } 134203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 135203288Srnoland "wait %s, units %u, waiters %d\n", 136203288Srnoland as->as_name, as->as_units, as->as_waiters)); 137203288Srnoland } 138203288Srnoland } 139203288Srnoland 140203288Srnoland mtx_unlock(&as->as_lock); 141203288Srnoland 142203288Srnoland mtx_destroy(&as->as_lock); 143203288Srnoland cv_destroy(&as->as_cv); 144203288Srnoland free(as, M_ACPISEM); 145203288Srnoland 146203288Srnoland return_ACPI_STATUS (AE_OK); 147203288Srnoland} 148203288Srnoland 149203288Srnoland#define ACPISEM_AVAIL(s, u) ((s)->as_units >= (u)) 150203288Srnoland 151203288SrnolandACPI_STATUS 152203288SrnolandAcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 153203288Srnoland{ 154203288Srnoland struct acpi_sema *as = (struct acpi_sema *)Handle; 155203288Srnoland int error, prevtick, slptick, tmo; 156203288Srnoland ACPI_STATUS status = AE_OK; 157203288Srnoland 158203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 159203288Srnoland 160203288Srnoland if (as == NULL || Units == 0) 161203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 162203288Srnoland 163203288Srnoland mtx_lock(&as->as_lock); 164203288Srnoland 165203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 166203288Srnoland "get %u unit(s) from %s, units %u, waiters %d, timeout %u\n", 167203288Srnoland Units, as->as_name, as->as_units, as->as_waiters, Timeout)); 168203288Srnoland 169203288Srnoland if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && as->as_maxunits < Units) { 170203288Srnoland mtx_unlock(&as->as_lock); 171203288Srnoland return_ACPI_STATUS (AE_LIMIT); 172203288Srnoland } 173203288Srnoland 174203288Srnoland switch (Timeout) { 175203288Srnoland case ACPI_DO_NOT_WAIT: 176203288Srnoland if (!ACPISEM_AVAIL(as, Units)) 177203288Srnoland status = AE_TIME; 178203288Srnoland break; 179203288Srnoland case ACPI_WAIT_FOREVER: 180216699Salc while (!ACPISEM_AVAIL(as, Units)) { 181216699Salc as->as_waiters++; 182216699Salc error = cv_wait_sig(&as->as_cv, &as->as_lock); 183216699Salc as->as_waiters--; 184203288Srnoland if (error == EINTR || as->as_reset) { 185203288Srnoland status = AE_ERROR; 186203288Srnoland break; 187203288Srnoland } 188203288Srnoland } 189203288Srnoland break; 190203288Srnoland default: 191203288Srnoland tmo = timeout2hz(Timeout); 192203288Srnoland while (!ACPISEM_AVAIL(as, Units)) { 193203288Srnoland prevtick = ticks; 194203288Srnoland as->as_waiters++; 195203288Srnoland error = cv_timedwait_sig(&as->as_cv, &as->as_lock, tmo); 196203288Srnoland as->as_waiters--; 197203288Srnoland if (error == EINTR || as->as_reset) { 198203288Srnoland status = AE_ERROR; 199203288Srnoland break; 200203288Srnoland } 201203288Srnoland if (ACPISEM_AVAIL(as, Units)) 202203288Srnoland break; 203203288Srnoland slptick = ticks - prevtick; 204203288Srnoland if (slptick >= tmo || slptick < 0) { 205203288Srnoland status = AE_TIME; 206203288Srnoland break; 207203288Srnoland } 208203288Srnoland tmo -= slptick; 209203288Srnoland } 210203288Srnoland } 211203288Srnoland if (ACPI_SUCCESS(status)) 212203288Srnoland as->as_units -= Units; 213203288Srnoland 214203288Srnoland mtx_unlock(&as->as_lock); 215203288Srnoland 216203288Srnoland return_ACPI_STATUS (status); 217203288Srnoland} 218203288Srnoland 219203288SrnolandACPI_STATUS 220203288SrnolandAcpiOsSignalSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units) 221203288Srnoland{ 222203288Srnoland struct acpi_sema *as = (struct acpi_sema *)Handle; 223203288Srnoland UINT32 i; 224203288Srnoland 225203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 226203288Srnoland 227203288Srnoland if (as == NULL || Units == 0) 228203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 229203288Srnoland 230203288Srnoland mtx_lock(&as->as_lock); 231203288Srnoland 232216699Salc ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 233203288Srnoland "return %u units to %s, units %u, waiters %d\n", 234203288Srnoland Units, as->as_name, as->as_units, as->as_waiters)); 235216699Salc 236216699Salc if (as->as_maxunits != ACPI_NO_UNIT_LIMIT && 237216699Salc (as->as_maxunits < Units || 238216699Salc as->as_maxunits - Units < as->as_units)) { 239216699Salc ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 240216699Salc "exceeded max units %u\n", as->as_maxunits)); 241216699Salc mtx_unlock(&as->as_lock); 242216699Salc return_ACPI_STATUS (AE_LIMIT); 243216699Salc } 244207410Skmacy 245203288Srnoland as->as_units += Units; 246203288Srnoland if (as->as_waiters > 0 && ACPISEM_AVAIL(as, Units)) 247207410Skmacy for (i = 0; i < Units; i++) 248203288Srnoland cv_signal(&as->as_cv); 249203288Srnoland 250203288Srnoland mtx_unlock(&as->as_lock); 251203288Srnoland 252203288Srnoland return_ACPI_STATUS (AE_OK); 253203288Srnoland} 254203288Srnoland 255203288Srnoland#undef ACPISEM_AVAIL 256203288Srnoland 257203288Srnoland/* 258203288Srnoland * ACPI_MUTEX 259203288Srnoland */ 260203288Srnolandstruct acpi_mutex { 261203288Srnoland struct mtx am_lock; 262203288Srnoland char am_name[32]; 263203288Srnoland struct thread *am_owner; 264203288Srnoland int am_nested; 265203288Srnoland int am_waiters; 266203288Srnoland int am_reset; 267203288Srnoland}; 268203288Srnoland 269203288SrnolandACPI_STATUS 270203288SrnolandAcpiOsCreateMutex(ACPI_MUTEX *OutHandle) 271203288Srnoland{ 272203288Srnoland struct acpi_mutex *am; 273203288Srnoland 274203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 275203288Srnoland 276203288Srnoland if (OutHandle == NULL) 277203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 278203288Srnoland 279203288Srnoland if ((am = malloc(sizeof(*am), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 280203288Srnoland return_ACPI_STATUS (AE_NO_MEMORY); 281203288Srnoland 282203288Srnoland snprintf(am->am_name, sizeof(am->am_name), "ACPI mutex (%p)", am); 283203288Srnoland mtx_init(&am->am_lock, am->am_name, NULL, MTX_DEF); 284203288Srnoland 285203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", am->am_name)); 286203288Srnoland 287203288Srnoland *OutHandle = (ACPI_MUTEX)am; 288203288Srnoland 289203288Srnoland return_ACPI_STATUS (AE_OK); 290203288Srnoland} 291203288Srnoland 292203288Srnoland#define ACPIMTX_AVAIL(m) ((m)->am_owner == NULL) 293203288Srnoland#define ACPIMTX_OWNED(m) ((m)->am_owner == curthread) 294203288Srnoland 295203288Srnolandvoid 296203288SrnolandAcpiOsDeleteMutex(ACPI_MUTEX Handle) 297203288Srnoland{ 298203288Srnoland struct acpi_mutex *am = (struct acpi_mutex *)Handle; 299203288Srnoland 300203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 301203288Srnoland 302203288Srnoland if (am == NULL) { 303203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "cannot delete null mutex\n")); 304203288Srnoland return_VOID; 305203288Srnoland } 306203288Srnoland 307203288Srnoland mtx_lock(&am->am_lock); 308203288Srnoland 309203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", am->am_name)); 310203288Srnoland 311203288Srnoland if (am->am_waiters > 0) { 312203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 313203288Srnoland "reset %s, owner %p\n", am->am_name, am->am_owner)); 314203288Srnoland am->am_reset = 1; 315203288Srnoland wakeup(am); 316203288Srnoland while (am->am_waiters > 0) { 317203288Srnoland if (mtx_sleep(&am->am_reset, &am->am_lock, 318203288Srnoland PCATCH, "acmrst", hz) == EINTR) { 319203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 320203288Srnoland "failed to reset %s, waiters %d\n", 321203288Srnoland am->am_name, am->am_waiters)); 322203288Srnoland mtx_unlock(&am->am_lock); 323203288Srnoland return_VOID; 324203288Srnoland } 325203288Srnoland if (ACPIMTX_AVAIL(am)) 326203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 327203288Srnoland "wait %s, waiters %d\n", 328203288Srnoland am->am_name, am->am_waiters)); 329203288Srnoland else 330203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 331203288Srnoland "wait %s, owner %p, waiters %d\n", 332203288Srnoland am->am_name, am->am_owner, am->am_waiters)); 333203288Srnoland } 334203288Srnoland } 335203288Srnoland 336203288Srnoland mtx_unlock(&am->am_lock); 337203288Srnoland 338203288Srnoland mtx_destroy(&am->am_lock); 339203288Srnoland free(am, M_ACPISEM); 340203288Srnoland} 341203288Srnoland 342203288SrnolandACPI_STATUS 343203288SrnolandAcpiOsAcquireMutex(ACPI_MUTEX Handle, UINT16 Timeout) 344203288Srnoland{ 345203288Srnoland struct acpi_mutex *am = (struct acpi_mutex *)Handle; 346203288Srnoland int error, prevtick, slptick, tmo; 347203288Srnoland ACPI_STATUS status = AE_OK; 348203288Srnoland 349203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 350203288Srnoland 351203288Srnoland if (am == NULL) 352203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 353203288Srnoland 354203288Srnoland mtx_lock(&am->am_lock); 355203288Srnoland 356203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", am->am_name)); 357203288Srnoland 358203288Srnoland if (ACPIMTX_OWNED(am)) { 359203288Srnoland am->am_nested++; 360203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 361203288Srnoland "acquire nested %s, depth %d\n", 362203288Srnoland am->am_name, am->am_nested)); 363203288Srnoland mtx_unlock(&am->am_lock); 364203288Srnoland return_ACPI_STATUS (AE_OK); 365203288Srnoland } 366203288Srnoland 367203288Srnoland switch (Timeout) { 368203288Srnoland case ACPI_DO_NOT_WAIT: 369203288Srnoland if (!ACPIMTX_AVAIL(am)) 370203288Srnoland status = AE_TIME; 371203288Srnoland break; 372203288Srnoland case ACPI_WAIT_FOREVER: 373203288Srnoland while (!ACPIMTX_AVAIL(am)) { 374203288Srnoland am->am_waiters++; 375203288Srnoland error = mtx_sleep(am, &am->am_lock, PCATCH, "acmtx", 0); 376203288Srnoland am->am_waiters--; 377203288Srnoland if (error == EINTR || am->am_reset) { 378203288Srnoland status = AE_ERROR; 379203288Srnoland break; 380203288Srnoland } 381203288Srnoland } 382203288Srnoland break; 383203288Srnoland default: 384203288Srnoland tmo = timeout2hz(Timeout); 385203288Srnoland while (!ACPIMTX_AVAIL(am)) { 386203288Srnoland prevtick = ticks; 387203288Srnoland am->am_waiters++; 388203288Srnoland error = mtx_sleep(am, &am->am_lock, PCATCH, 389203288Srnoland "acmtx", tmo); 390203288Srnoland am->am_waiters--; 391203288Srnoland if (error == EINTR || am->am_reset) { 392203288Srnoland status = AE_ERROR; 393203288Srnoland break; 394203288Srnoland } 395203288Srnoland if (ACPIMTX_AVAIL(am)) 396203288Srnoland break; 397203288Srnoland slptick = ticks - prevtick; 398203288Srnoland if (slptick >= tmo || slptick < 0) { 399203288Srnoland status = AE_TIME; 400203288Srnoland break; 401203288Srnoland } 402203288Srnoland tmo -= slptick; 403203288Srnoland } 404203288Srnoland } 405203288Srnoland if (ACPI_SUCCESS(status)) 406203288Srnoland am->am_owner = curthread; 407203288Srnoland 408203288Srnoland mtx_unlock(&am->am_lock); 409203288Srnoland 410203288Srnoland return_ACPI_STATUS (status); 411203288Srnoland} 412203288Srnoland 413203288Srnolandvoid 414203288SrnolandAcpiOsReleaseMutex(ACPI_MUTEX Handle) 415203288Srnoland{ 416203288Srnoland struct acpi_mutex *am = (struct acpi_mutex *)Handle; 417203288Srnoland 418203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 419203288Srnoland 420203288Srnoland if (am == NULL) { 421203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 422203288Srnoland "cannot release null mutex\n")); 423203288Srnoland return_VOID; 424203288Srnoland } 425203288Srnoland 426203288Srnoland mtx_lock(&am->am_lock); 427203288Srnoland 428203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", am->am_name)); 429203288Srnoland 430203288Srnoland if (ACPIMTX_OWNED(am)) { 431203288Srnoland if (am->am_nested > 0) { 432203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 433203288Srnoland "release nested %s, depth %d\n", 434203288Srnoland am->am_name, am->am_nested)); 435203288Srnoland am->am_nested--; 436203288Srnoland } else 437203288Srnoland am->am_owner = NULL; 438203288Srnoland } else { 439203288Srnoland if (ACPIMTX_AVAIL(am)) 440203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 441203288Srnoland "release already available %s\n", am->am_name)); 442203288Srnoland else 443203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 444203288Srnoland "release unowned %s from %p, depth %d\n", 445203288Srnoland am->am_name, am->am_owner, am->am_nested)); 446203288Srnoland } 447203288Srnoland if (am->am_waiters > 0 && ACPIMTX_AVAIL(am)) 448203288Srnoland wakeup_one(am); 449203288Srnoland 450203288Srnoland mtx_unlock(&am->am_lock); 451203288Srnoland} 452203288Srnoland 453203288Srnoland#undef ACPIMTX_AVAIL 454203288Srnoland#undef ACPIMTX_OWNED 455203288Srnoland 456203288Srnoland/* 457203288Srnoland * ACPI_SPINLOCK 458203288Srnoland */ 459203288Srnolandstruct acpi_spinlock { 460203288Srnoland struct mtx al_lock; 461203288Srnoland char al_name[32]; 462203288Srnoland int al_nested; 463203288Srnoland}; 464203288Srnoland 465203288SrnolandACPI_STATUS 466203288SrnolandAcpiOsCreateLock(ACPI_SPINLOCK *OutHandle) 467203288Srnoland{ 468203288Srnoland struct acpi_spinlock *al; 469203288Srnoland 470203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 471203288Srnoland 472203288Srnoland if (OutHandle == NULL) 473203288Srnoland return_ACPI_STATUS (AE_BAD_PARAMETER); 474203288Srnoland 475203288Srnoland if ((al = malloc(sizeof(*al), M_ACPISEM, M_NOWAIT | M_ZERO)) == NULL) 476203288Srnoland return_ACPI_STATUS (AE_NO_MEMORY); 477203288Srnoland 478203288Srnoland#ifdef ACPI_DEBUG 479203288Srnoland if (OutHandle == &AcpiGbl_GpeLock) 480203288Srnoland snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (GPE)"); 481203288Srnoland else if (OutHandle == &AcpiGbl_HardwareLock) 482203288Srnoland snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (HW)"); 483203288Srnoland else 484203288Srnoland#endif 485203288Srnoland snprintf(al->al_name, sizeof(al->al_name), "ACPI lock (%p)", al); 486203288Srnoland mtx_init(&al->al_lock, al->al_name, NULL, MTX_SPIN); 487203288Srnoland 488203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "created %s\n", al->al_name)); 489203288Srnoland 490203288Srnoland *OutHandle = (ACPI_SPINLOCK)al; 491203288Srnoland 492203288Srnoland return_ACPI_STATUS (AE_OK); 493203288Srnoland} 494203288Srnoland 495203288Srnolandvoid 496203288SrnolandAcpiOsDeleteLock(ACPI_SPINLOCK Handle) 497203288Srnoland{ 498203288Srnoland struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 499203288Srnoland 500203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 501203288Srnoland 502203288Srnoland if (al == NULL) { 503203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 504203288Srnoland "cannot delete null spinlock\n")); 505203288Srnoland return_VOID; 506203288Srnoland } 507203288Srnoland 508203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "delete %s\n", al->al_name)); 509203288Srnoland 510203288Srnoland mtx_destroy(&al->al_lock); 511203288Srnoland free(al, M_ACPISEM); 512203288Srnoland} 513203288Srnoland 514203288SrnolandACPI_CPU_FLAGS 515203288SrnolandAcpiOsAcquireLock(ACPI_SPINLOCK Handle) 516203288Srnoland{ 517203288Srnoland struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 518203288Srnoland 519203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 520203288Srnoland 521203288Srnoland if (al == NULL) { 522203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 523203288Srnoland "cannot acquire null spinlock\n")); 524203288Srnoland return (0); 525203288Srnoland } 526203288Srnoland 527203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "acquire %s\n", al->al_name)); 528203288Srnoland 529203288Srnoland if (mtx_owned(&al->al_lock)) { 530203288Srnoland al->al_nested++; 531203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 532203288Srnoland "acquire nested %s, depth %d\n", 533203288Srnoland al->al_name, al->al_nested)); 534203288Srnoland } else 535203288Srnoland mtx_lock_spin(&al->al_lock); 536203288Srnoland 537203288Srnoland return (0); 538203288Srnoland} 539203288Srnoland 540203288Srnolandvoid 541203288SrnolandAcpiOsReleaseLock(ACPI_SPINLOCK Handle, ACPI_CPU_FLAGS Flags) 542203288Srnoland{ 543203288Srnoland struct acpi_spinlock *al = (struct acpi_spinlock *)Handle; 544203288Srnoland 545203288Srnoland ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 546203288Srnoland 547203288Srnoland if (al == NULL) { 548203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 549203288Srnoland "cannot release null spinlock\n")); 550203288Srnoland return_VOID; 551203288Srnoland } 552203288Srnoland 553203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "release %s\n", al->al_name)); 554203288Srnoland 555203288Srnoland if (mtx_owned(&al->al_lock)) { 556203288Srnoland if (al->al_nested > 0) { 557203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 558203288Srnoland "release nested %s, depth %d\n", 559203288Srnoland al->al_name, al->al_nested)); 560203288Srnoland al->al_nested--; 561203288Srnoland } else 562203288Srnoland mtx_unlock_spin(&al->al_lock); 563203288Srnoland } else 564203288Srnoland ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 565203288Srnoland "cannot release unowned %s\n", al->al_name)); 566203288Srnoland} 567203288Srnoland 568203288Srnoland/* Section 5.2.10.1: global lock acquire/release functions */ 569203288Srnoland 570203288Srnoland/* 571203288Srnoland * Acquire the global lock. If busy, set the pending bit. The caller 572203288Srnoland * will wait for notification from the BIOS that the lock is available 573203288Srnoland * and then attempt to acquire it again. 574203288Srnoland */ 575203288Srnolandint 576203288Srnolandacpi_acquire_global_lock(volatile uint32_t *lock) 577203288Srnoland{ 578203288Srnoland uint32_t new, old; 579203288Srnoland 580203288Srnoland do { 581203288Srnoland old = *lock; 582203288Srnoland new = (old & ~ACPI_GLOCK_PENDING) | ACPI_GLOCK_OWNED; 583203288Srnoland if ((old & ACPI_GLOCK_OWNED) != 0) 584203288Srnoland new |= ACPI_GLOCK_PENDING; 585203288Srnoland } while (atomic_cmpset_32(lock, old, new) == 0); 586203288Srnoland 587203288Srnoland return ((new & ACPI_GLOCK_PENDING) == 0); 588203288Srnoland} 589203288Srnoland 590203288Srnoland/* 591203288Srnoland * Release the global lock, returning whether there is a waiter pending. 592203288Srnoland * If the BIOS set the pending bit, OSPM must notify the BIOS when it 593203288Srnoland * releases the lock. 594203288Srnoland */ 595203288Srnolandint 596203288Srnolandacpi_release_global_lock(volatile uint32_t *lock) 597203288Srnoland{ 598203288Srnoland uint32_t new, old; 599203288Srnoland 600203288Srnoland do { 601203288Srnoland old = *lock; 602203288Srnoland new = old & ~(ACPI_GLOCK_PENDING | ACPI_GLOCK_OWNED); 603203288Srnoland } while (atomic_cmpset_32(lock, old, new) == 0); 604203288Srnoland 605203288Srnoland return ((old & ACPI_GLOCK_PENDING) != 0); 606203288Srnoland} 607203288Srnoland