1/* $NetBSD: OsdSynch.c,v 1.12 2009/03/31 17:17:47 drochner Exp $ */ 2 3/* 4 * Copyright 2001 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38/*- 39 * Copyright (c) 2000 Michael Smith 40 * Copyright (c) 2000 BSDi 41 * All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65/* 66 * OS Services Layer 67 * 68 * 6.4: Mutual Exclusion and Synchronization 69 */ 70 71#include <sys/cdefs.h> 72__KERNEL_RCSID(0, "$NetBSD: OsdSynch.c,v 1.12 2009/03/31 17:17:47 drochner Exp $"); 73 74#include <sys/param.h> 75#include <sys/malloc.h> 76#include <sys/mutex.h> 77#include <sys/condvar.h> 78#include <sys/kernel.h> 79#include <sys/proc.h> 80 81extern int acpi_suspended; 82 83#include <dev/acpi/acpica.h> 84 85MALLOC_DECLARE(M_ACPI); 86 87#define _COMPONENT ACPI_OS_SERVICES 88ACPI_MODULE_NAME("SYNCH") 89 90/* 91 * Simple counting semaphore implemented using a mutex. This is 92 * subsequently used in the OSI code to implement a mutex. Go figure. 93 */ 94struct acpi_semaphore { 95 kcondvar_t as_cv; 96 kmutex_t as_slock; 97 UINT32 as_units; 98 UINT32 as_maxunits; 99}; 100 101struct acpi_lock { 102 kmutex_t al_slock; 103}; 104 105/* 106 * AcpiOsCreateSemaphore: 107 * 108 * Create a semaphore. 109 */ 110ACPI_STATUS 111AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 112 ACPI_HANDLE *OutHandle) 113{ 114 struct acpi_semaphore *as; 115 116 if (OutHandle == NULL) 117 return AE_BAD_PARAMETER; 118 if (InitialUnits > MaxUnits) 119 return AE_BAD_PARAMETER; 120 121 as = malloc(sizeof(*as), M_ACPI, M_NOWAIT); 122 if (as == NULL) 123 return AE_NO_MEMORY; 124 125 mutex_init(&as->as_slock, MUTEX_DEFAULT, IPL_NONE); 126 cv_init(&as->as_cv, "acpisem"); 127 as->as_units = InitialUnits; 128 as->as_maxunits = MaxUnits; 129 130 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 131 "created semaphore %p max %u initial %u\n", 132 as, as->as_maxunits, as->as_units)); 133 134 *OutHandle = (ACPI_HANDLE) as; 135 return AE_OK; 136} 137 138/* 139 * AcpiOsDeleteSemaphore: 140 * 141 * Delete a semaphore. 142 */ 143ACPI_STATUS 144AcpiOsDeleteSemaphore(ACPI_HANDLE Handle) 145{ 146 struct acpi_semaphore *as = (void *) Handle; 147 148 if (as == NULL) 149 return AE_BAD_PARAMETER; 150 151 cv_destroy(&as->as_cv); 152 mutex_destroy(&as->as_slock); 153 free(as, M_ACPI); 154 155 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed semaphore %p\n", as)); 156 157 return AE_OK; 158} 159 160/* 161 * AcpiOsWaitSemaphore: 162 * 163 * Wait for units from a semaphore. 164 */ 165ACPI_STATUS 166AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 167{ 168 struct acpi_semaphore *as = (void *) Handle; 169 ACPI_STATUS rv; 170 int timo, error; 171 172 /* 173 * This implementation has a bug: It has to stall for the entire 174 * timeout before it will return AE_TIME. A better implementation 175 * would adjust the amount of time left after being awakened. 176 */ 177 178 if (as == NULL) 179 return AE_BAD_PARAMETER; 180 if (cold || doing_shutdown || acpi_suspended) 181 return AE_OK; 182 183 /* A timeout of 0xFFFF means "forever". */ 184 if (Timeout == 0xFFFF) 185 timo = 0; 186 else { 187 /* Compute the timeout using uSec per tick. */ 188 timo = (Timeout * 1000) / (1000000 / hz); 189 if (timo <= 0) 190 timo = 1; 191 } 192 193 mutex_enter(&as->as_slock); 194 195 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 196 "get %d units from semaphore %p (has %d) timeout %d\n", 197 Units, as, as->as_units, Timeout)); 198 199 for (;;) { 200 if (as->as_units >= Units) { 201 as->as_units -= Units; 202 rv = AE_OK; 203 break; 204 } 205 206 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 207 "semaphore blocked, sleeping %d ticks\n", timo)); 208 209 error = cv_timedwait(&as->as_cv, &as->as_slock, timo); 210 if (error == EWOULDBLOCK) { 211 rv = AE_TIME; 212 break; 213 } 214 } 215 216 mutex_exit(&as->as_slock); 217 218 return rv; 219} 220 221/* 222 * AcpiOsSignalSemaphore: 223 * 224 * Send units to a semaphore. 225 */ 226ACPI_STATUS 227AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units) 228{ 229 struct acpi_semaphore *as = (void *) Handle; 230 231 if (as == NULL) 232 return AE_BAD_PARAMETER; 233 234 mutex_enter(&as->as_slock); 235 236 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 237 "return %d units to semaphore %p (has %d)\n", 238 Units, as, as->as_units)); 239 240 as->as_units += Units; 241 if (as->as_units > as->as_maxunits) 242 as->as_units = as->as_maxunits; 243 cv_broadcast(&as->as_cv); 244 245 mutex_exit(&as->as_slock); 246 247 return AE_OK; 248} 249 250/* 251 * AcpiOsCreateLock: 252 * 253 * Create a lock. 254 */ 255ACPI_STATUS 256AcpiOsCreateLock(ACPI_HANDLE *OutHandle) 257{ 258 struct acpi_lock *al; 259 260 if (OutHandle == NULL) 261 return AE_BAD_PARAMETER; 262 263 al = malloc(sizeof(*al), M_ACPI, M_NOWAIT); 264 if (al == NULL) 265 return AE_NO_MEMORY; 266 267 mutex_init(&al->al_slock, MUTEX_DEFAULT, IPL_VM); 268 269 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 270 "created lock %p\n", al)); 271 272 *OutHandle = (ACPI_HANDLE) al; 273 return AE_OK; 274} 275 276/* 277 * AcpiOsDeleteLock: 278 * 279 * Delete a lock. 280 */ 281void 282AcpiOsDeleteLock(ACPI_SPINLOCK Handle) 283{ 284 struct acpi_lock *al = (void *) Handle; 285 286 if (al == NULL) 287 return; 288 289 mutex_destroy(&al->al_slock); 290 free(al, M_ACPI); 291 292 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed lock %p\n", al)); 293 294 return; 295} 296 297/* 298 * AcpiOsAcquireLock: 299 * 300 * Acquire a lock. 301 */ 302ACPI_CPU_FLAGS 303AcpiOsAcquireLock(ACPI_SPINLOCK Handle) 304{ 305 struct acpi_lock *al = (void *) Handle; 306 307 if (al == NULL) 308 return 0; 309 310 mutex_enter(&al->al_slock); 311 312 return 0; 313} 314 315/* 316 * AcpiOsReleaseLock: 317 * 318 * Release a lock. 319 */ 320void 321AcpiOsReleaseLock(ACPI_HANDLE Handle, ACPI_CPU_FLAGS Flags) 322{ 323 struct acpi_lock *al = (void *) Handle; 324 325 if (al == NULL) 326 return; 327 328 mutex_exit(&al->al_slock); 329 330 return; 331} 332