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