xref: /freebsd/sys/dev/acpica/Osd/OsdSynch.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2000 BSDi
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  *	$FreeBSD$
28  */
29 
30 /*
31  * 6.1 : Mutual Exclusion and Synchronisation
32  */
33 
34 #include "acpi.h"
35 
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/mutex.h>
39 
40 MALLOC_DEFINE(M_ACPISEM, "acpisem", "ACPI semaphore");
41 
42 /*
43  * Simple counting semaphore implemented using a mutex. (Subsequently used
44  * in the OSI code to implement a mutex.  Go figure.)
45  */
46 struct acpi_semaphore {
47     struct mtx	as_mtx;
48     UINT32	as_units;
49     UINT32	as_maxunits;
50 };
51 
52 ACPI_STATUS
53 AcpiOsCreateSemaphore(UINT32 MaxUnits, UINT32 InitialUnits, ACPI_HANDLE *OutHandle)
54 {
55     struct acpi_semaphore	*as;
56 
57     if (OutHandle == NULL)
58 	return(AE_BAD_PARAMETER);
59     if (InitialUnits > MaxUnits)
60 	return(AE_BAD_PARAMETER);
61 
62     if ((as = malloc(sizeof(*as), M_ACPISEM, M_NOWAIT)) == NULL)
63 	return(AE_NO_MEMORY);
64 
65     mtx_init(&as->as_mtx, "ACPI semaphore", MTX_DEF);
66     as->as_units = InitialUnits;
67     as->as_maxunits = MaxUnits;
68 
69     *OutHandle = (ACPI_HANDLE)as;
70     return(AE_OK);
71 }
72 
73 ACPI_STATUS
74 AcpiOsDeleteSemaphore (ACPI_HANDLE Handle)
75 {
76     free(Handle, M_ACPISEM);
77     return(AE_OK);
78 }
79 
80 /*
81  * This implementation has a bug, in that it has to stall for the entire
82  * timeout before it will return AE_TIME.  A better implementation would
83  * use getmicrotime() to correctly adjust the timeout after being woken up.
84  */
85 ACPI_STATUS
86 AcpiOsWaitSemaphore(ACPI_HANDLE Handle, UINT32 Units, UINT32 Timeout)
87 {
88     struct acpi_semaphore	*as = (struct acpi_semaphore *)Handle;
89     int				result;
90 
91     if (as == NULL)
92 	return(AE_BAD_PARAMETER);
93 
94     mtx_enter(&as->as_mtx, MTX_DEF);
95     for (;;) {
96 	if (as->as_units >= Units) {
97 	    as->as_units -= Units;
98 	    result = AE_OK;
99 	    break;
100 	}
101 	if (Timeout < 0) {
102 	    result = AE_TIME;
103 	    break;
104 	}
105 	if (msleep(as, &as->as_mtx, 0, "acpisem", Timeout / (1000 * hz)) == EWOULDBLOCK) {
106 	    result = AE_TIME;
107 	    break;
108 	}
109     }
110     mtx_exit(&as->as_mtx, MTX_DEF);
111 
112     return(result);
113 }
114 
115 ACPI_STATUS
116 AcpiOsSignalSemaphore(ACPI_HANDLE Handle, UINT32 Units)
117 {
118     struct acpi_semaphore	*as = (struct acpi_semaphore *)Handle;
119 
120     if (as == NULL)
121 	return(AE_BAD_PARAMETER);
122 
123     mtx_enter(&as->as_mtx, MTX_DEF);
124     as->as_units += Units;
125     if (as->as_units > as->as_maxunits)
126 	as->as_units = as->as_maxunits;
127     wakeup(as);
128     mtx_exit(&as->as_mtx, MTX_DEF);
129 
130     return(AE_OK);
131 }
132