1 /* $NetBSD: OsdSynch.c,v 1.7 2007/02/19 22:32:52 ad 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.7 2007/02/19 22:32:52 ad 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(__FUNCTION__); 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_DRIVER, 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(__FUNCTION__); 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_HANDLE 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(__FUNCTION__); 181 182 if (as == NULL) 183 return_ACPI_STATUS(AE_BAD_PARAMETER); 184 185 /* A timeout of 0xFFFF means "forever". */ 186 if (Timeout == 0xFFFF) 187 timo = 0; 188 else { 189 /* Compute the timeout using uSec per tick. */ 190 timo = (Timeout * 1000) / (1000000 / hz); 191 if (timo <= 0) 192 timo = 1; 193 } 194 195 mutex_enter(&as->as_slock); 196 197 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 198 "get %d units from semaphore %p (has %d) timeout %d\n", 199 Units, as, as->as_units, Timeout)); 200 201 for (;;) { 202 if (as->as_units >= Units) { 203 as->as_units -= Units; 204 rv = AE_OK; 205 break; 206 } 207 208 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 209 "semaphore blocked, sleeping %d ticks\n", timo)); 210 211 error = cv_timedwait(&as->as_cv, &as->as_slock, timo); 212 if (error == EWOULDBLOCK) { 213 rv = AE_TIME; 214 break; 215 } 216 } 217 218 mutex_exit(&as->as_slock); 219 220 return_ACPI_STATUS(rv); 221 } 222 223 /* 224 * AcpiOsSignalSemaphore: 225 * 226 * Send units to a semaphore. 227 */ 228 ACPI_STATUS 229 AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units) 230 { 231 struct acpi_semaphore *as = (void *) Handle; 232 233 ACPI_FUNCTION_TRACE(__FUNCTION__); 234 235 if (as == NULL) 236 return_ACPI_STATUS(AE_BAD_PARAMETER); 237 238 mutex_enter(&as->as_slock); 239 240 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 241 "return %d units to semaphore %p (has %d)\n", 242 Units, as, as->as_units)); 243 244 as->as_units += Units; 245 if (as->as_units > as->as_maxunits) 246 as->as_units = as->as_maxunits; 247 cv_broadcast(&as->as_cv); 248 249 mutex_exit(&as->as_slock); 250 251 return_ACPI_STATUS(AE_OK); 252 } 253 254 /* 255 * AcpiOsCreateLock: 256 * 257 * Create a lock. 258 */ 259 ACPI_STATUS 260 AcpiOsCreateLock(ACPI_HANDLE *OutHandle) 261 { 262 struct acpi_lock *al; 263 264 ACPI_FUNCTION_TRACE(__FUNCTION__); 265 266 if (OutHandle == NULL) 267 return_ACPI_STATUS(AE_BAD_PARAMETER); 268 269 al = malloc(sizeof(*al), M_ACPI, M_NOWAIT); 270 if (al == NULL) 271 return_ACPI_STATUS(AE_NO_MEMORY); 272 273 mutex_init(&al->al_slock, MUTEX_DRIVER, IPL_VM); 274 275 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 276 "created lock %p\n", al)); 277 278 *OutHandle = (ACPI_HANDLE) al; 279 return_ACPI_STATUS(AE_OK); 280 } 281 282 /* 283 * AcpiOsDeleteLock: 284 * 285 * Delete a lock. 286 */ 287 void 288 AcpiOsDeleteLock(ACPI_HANDLE Handle) 289 { 290 struct acpi_lock *al = (void *) Handle; 291 292 ACPI_FUNCTION_TRACE(__FUNCTION__); 293 294 if (al == NULL) 295 return; 296 297 mutex_destroy(&al->al_slock); 298 free(al, M_ACPI); 299 300 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "destroyed lock %p\n", al)); 301 302 return; 303 } 304 305 /* 306 * AcpiOsAcquireLock: 307 * 308 * Acquire a lock. 309 */ 310 ACPI_NATIVE_UINT 311 AcpiOsAcquireLock(ACPI_HANDLE Handle) 312 { 313 struct acpi_lock *al = (void *) Handle; 314 315 ACPI_FUNCTION_TRACE(__FUNCTION__); 316 317 if (al == NULL) 318 return 0; 319 320 mutex_enter(&al->al_slock); 321 322 return 0; 323 } 324 325 /* 326 * AcpiOsReleaseLock: 327 * 328 * Release a lock. 329 */ 330 void 331 AcpiOsReleaseLock(ACPI_HANDLE Handle, ACPI_NATIVE_UINT Flags) 332 { 333 struct acpi_lock *al = (void *) Handle; 334 335 ACPI_FUNCTION_TRACE(__FUNCTION__); 336 337 if (al == NULL) 338 return; 339 340 mutex_exit(&al->al_slock); 341 342 return; 343 } 344