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