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 81 extern int acpi_suspended; 82 83 #include <dev/acpi/acpica.h> 84 85 MALLOC_DECLARE(M_ACPI); 86 87 #define _COMPONENT ACPI_OS_SERVICES 88 ACPI_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 */ 94 struct acpi_semaphore { 95 kcondvar_t as_cv; 96 kmutex_t as_slock; 97 UINT32 as_units; 98 UINT32 as_maxunits; 99 }; 100 101 struct acpi_lock { 102 kmutex_t al_slock; 103 }; 104 105 /* 106 * AcpiOsCreateSemaphore: 107 * 108 * Create a semaphore. 109 */ 110 ACPI_STATUS 111 AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, 112 ACPI_HANDLE *OutHandle) 113 { 114 struct acpi_semaphore *as; 115 116 ACPI_FUNCTION_TRACE(__func__); 117 118 if (OutHandle == NULL) 119 return_ACPI_STATUS(AE_BAD_PARAMETER); 120 if (InitialUnits > MaxUnits) 121 return_ACPI_STATUS(AE_BAD_PARAMETER); 122 123 as = malloc(sizeof(*as), M_ACPI, M_NOWAIT); 124 if (as == NULL) 125 return_ACPI_STATUS(AE_NO_MEMORY); 126 127 mutex_init(&as->as_slock, MUTEX_DEFAULT, IPL_NONE); 128 cv_init(&as->as_cv, "acpisem"); 129 as->as_units = InitialUnits; 130 as->as_maxunits = MaxUnits; 131 132 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 133 "created semaphore %p max %u initial %u\n", 134 as, as->as_maxunits, as->as_units)); 135 136 *OutHandle = (ACPI_HANDLE) as; 137 return_ACPI_STATUS(AE_OK); 138 } 139 140 /* 141 * AcpiOsDeleteSemaphore: 142 * 143 * Delete a semaphore. 144 */ 145 ACPI_STATUS 146 AcpiOsDeleteSemaphore(ACPI_HANDLE Handle) 147 { 148 struct acpi_semaphore *as = (void *) Handle; 149 150 ACPI_FUNCTION_TRACE(__func__); 151 152 if (as == NULL) 153 return_ACPI_STATUS(AE_BAD_PARAMETER); 154 155 cv_destroy(&as->as_cv); 156 mutex_destroy(&as->as_slock); 157 free(as, M_ACPI); 158 159 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed semaphore %p\n", as)); 160 161 return_ACPI_STATUS(AE_OK); 162 } 163 164 /* 165 * AcpiOsWaitSemaphore: 166 * 167 * Wait for units from a semaphore. 168 */ 169 ACPI_STATUS 170 AcpiOsWaitSemaphore(ACPI_SEMAPHORE Handle, UINT32 Units, UINT16 Timeout) 171 { 172 struct acpi_semaphore *as = (void *) Handle; 173 ACPI_STATUS rv; 174 int timo, error; 175 176 /* 177 * This implementation has a bug: It has to stall for the entire 178 * timeout before it will return AE_TIME. A better implementation 179 * would adjust the amount of time left after being awakened. 180 */ 181 182 ACPI_FUNCTION_TRACE(__func__); 183 184 if (as == NULL) 185 return_ACPI_STATUS(AE_BAD_PARAMETER); 186 if (cold || doing_shutdown || acpi_suspended) 187 return_ACPI_STATUS(AE_OK); 188 189 /* A timeout of 0xFFFF means "forever". */ 190 if (Timeout == 0xFFFF) 191 timo = 0; 192 else { 193 /* Compute the timeout using uSec per tick. */ 194 timo = (Timeout * 1000) / (1000000 / hz); 195 if (timo <= 0) 196 timo = 1; 197 } 198 199 mutex_enter(&as->as_slock); 200 201 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 202 "get %d units from semaphore %p (has %d) timeout %d\n", 203 Units, as, as->as_units, Timeout)); 204 205 for (;;) { 206 if (as->as_units >= Units) { 207 as->as_units -= Units; 208 rv = AE_OK; 209 break; 210 } 211 212 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 213 "semaphore blocked, sleeping %d ticks\n", timo)); 214 215 error = cv_timedwait(&as->as_cv, &as->as_slock, timo); 216 if (error == EWOULDBLOCK) { 217 rv = AE_TIME; 218 break; 219 } 220 } 221 222 mutex_exit(&as->as_slock); 223 224 return_ACPI_STATUS(rv); 225 } 226 227 /* 228 * AcpiOsSignalSemaphore: 229 * 230 * Send units to a semaphore. 231 */ 232 ACPI_STATUS 233 AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units) 234 { 235 struct acpi_semaphore *as = (void *) Handle; 236 237 ACPI_FUNCTION_TRACE(__func__); 238 239 if (as == NULL) 240 return_ACPI_STATUS(AE_BAD_PARAMETER); 241 242 mutex_enter(&as->as_slock); 243 244 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 245 "return %d units to semaphore %p (has %d)\n", 246 Units, as, as->as_units)); 247 248 as->as_units += Units; 249 if (as->as_units > as->as_maxunits) 250 as->as_units = as->as_maxunits; 251 cv_broadcast(&as->as_cv); 252 253 mutex_exit(&as->as_slock); 254 255 return_ACPI_STATUS(AE_OK); 256 } 257 258 /* 259 * AcpiOsCreateLock: 260 * 261 * Create a lock. 262 */ 263 ACPI_STATUS 264 AcpiOsCreateLock(ACPI_HANDLE *OutHandle) 265 { 266 struct acpi_lock *al; 267 268 ACPI_FUNCTION_TRACE(__func__); 269 270 if (OutHandle == NULL) 271 return_ACPI_STATUS(AE_BAD_PARAMETER); 272 273 al = malloc(sizeof(*al), M_ACPI, M_NOWAIT); 274 if (al == NULL) 275 return_ACPI_STATUS(AE_NO_MEMORY); 276 277 mutex_init(&al->al_slock, MUTEX_DEFAULT, IPL_VM); 278 279 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 280 "created lock %p\n", al)); 281 282 *OutHandle = (ACPI_HANDLE) al; 283 return_ACPI_STATUS(AE_OK); 284 } 285 286 /* 287 * AcpiOsDeleteLock: 288 * 289 * Delete a lock. 290 */ 291 void 292 AcpiOsDeleteLock(ACPI_SPINLOCK Handle) 293 { 294 struct acpi_lock *al = (void *) Handle; 295 296 ACPI_FUNCTION_TRACE(__func__); 297 298 if (al == NULL) 299 return; 300 301 mutex_destroy(&al->al_slock); 302 free(al, M_ACPI); 303 304 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed lock %p\n", al)); 305 306 return; 307 } 308 309 /* 310 * AcpiOsAcquireLock: 311 * 312 * Acquire a lock. 313 */ 314 ACPI_NATIVE_UINT 315 AcpiOsAcquireLock(ACPI_SPINLOCK Handle) 316 { 317 struct acpi_lock *al = (void *) Handle; 318 319 ACPI_FUNCTION_TRACE(__func__); 320 321 if (al == NULL) 322 return 0; 323 324 mutex_enter(&al->al_slock); 325 326 return 0; 327 } 328 329 /* 330 * AcpiOsReleaseLock: 331 * 332 * Release a lock. 333 */ 334 void 335 AcpiOsReleaseLock(ACPI_HANDLE Handle, ACPI_NATIVE_UINT Flags) 336 { 337 struct acpi_lock *al = (void *) Handle; 338 339 ACPI_FUNCTION_TRACE(__func__); 340 341 if (al == NULL) 342 return; 343 344 mutex_exit(&al->al_slock); 345 346 return; 347 } 348