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