Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
acpi
acpica
evglock.c
Go to the documentation of this file.
1
/******************************************************************************
2
*
3
* Module Name: evglock - Global Lock support
4
*
5
*****************************************************************************/
6
7
/*
8
* Copyright (C) 2000 - 2012, Intel Corp.
9
* All rights reserved.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions, and the following disclaimer,
16
* without modification.
17
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
18
* substantially similar to the "NO WARRANTY" disclaimer below
19
* ("Disclaimer") and any redistribution must be conditioned upon
20
* including a substantially similar Disclaimer requirement for further
21
* binary redistribution.
22
* 3. Neither the names of the above-listed copyright holders nor the names
23
* of any contributors may be used to endorse or promote products derived
24
* from this software without specific prior written permission.
25
*
26
* Alternatively, this software may be distributed under the terms of the
27
* GNU General Public License ("GPL") version 2 as published by the Free
28
* Software Foundation.
29
*
30
* NO WARRANTY
31
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41
* POSSIBILITY OF SUCH DAMAGES.
42
*/
43
44
#include <
acpi/acpi.h
>
45
#include "
accommon.h
"
46
#include "
acevents.h
"
47
#include "
acinterp.h
"
48
49
#define _COMPONENT ACPI_EVENTS
50
ACPI_MODULE_NAME
(
"evglock"
)
51
#if (!ACPI_REDUCED_HARDWARE)
/* Entire module */
52
/* Local prototypes */
53
static
u32
acpi_ev_global_lock_handler(
void
*
context
);
54
55
/*******************************************************************************
56
*
57
* FUNCTION: acpi_ev_init_global_lock_handler
58
*
59
* PARAMETERS: None
60
*
61
* RETURN: Status
62
*
63
* DESCRIPTION: Install a handler for the global lock release event
64
*
65
******************************************************************************/
66
67
acpi_status
acpi_ev_init_global_lock_handler
(
void
)
68
{
69
acpi_status
status
;
70
71
ACPI_FUNCTION_TRACE
(ev_init_global_lock_handler);
72
73
/* If Hardware Reduced flag is set, there is no global lock */
74
75
if
(
acpi_gbl_reduced_hardware
) {
76
return_ACPI_STATUS
(
AE_OK
);
77
}
78
79
/* Attempt installation of the global lock handler */
80
81
status =
acpi_install_fixed_event_handler
(
ACPI_EVENT_GLOBAL
,
82
acpi_ev_global_lock_handler,
83
NULL
);
84
85
/*
86
* If the global lock does not exist on this platform, the attempt to
87
* enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick).
88
* Map to AE_OK, but mark global lock as not present. Any attempt to
89
* actually use the global lock will be flagged with an error.
90
*/
91
acpi_gbl_global_lock_present
=
FALSE
;
92
if
(status ==
AE_NO_HARDWARE_RESPONSE
) {
93
ACPI_ERROR
((
AE_INFO
,
94
"No response from Global Lock hardware, disabling lock"
));
95
96
return_ACPI_STATUS
(
AE_OK
);
97
}
98
99
status =
acpi_os_create_lock
(&
acpi_gbl_global_lock_pending_lock
);
100
if
(
ACPI_FAILURE
(status)) {
101
return_ACPI_STATUS
(status);
102
}
103
104
acpi_gbl_global_lock_pending
=
FALSE
;
105
acpi_gbl_global_lock_present
=
TRUE
;
106
return_ACPI_STATUS
(status);
107
}
108
109
/*******************************************************************************
110
*
111
* FUNCTION: acpi_ev_remove_global_lock_handler
112
*
113
* PARAMETERS: None
114
*
115
* RETURN: Status
116
*
117
* DESCRIPTION: Remove the handler for the Global Lock
118
*
119
******************************************************************************/
120
121
acpi_status
acpi_ev_remove_global_lock_handler
(
void
)
122
{
123
acpi_status
status
;
124
125
ACPI_FUNCTION_TRACE
(ev_remove_global_lock_handler);
126
127
acpi_gbl_global_lock_present
=
FALSE
;
128
status =
acpi_remove_fixed_event_handler
(
ACPI_EVENT_GLOBAL
,
129
acpi_ev_global_lock_handler);
130
131
return_ACPI_STATUS
(status);
132
}
133
134
/*******************************************************************************
135
*
136
* FUNCTION: acpi_ev_global_lock_handler
137
*
138
* PARAMETERS: context - From thread interface, not used
139
*
140
* RETURN: ACPI_INTERRUPT_HANDLED
141
*
142
* DESCRIPTION: Invoked directly from the SCI handler when a global lock
143
* release interrupt occurs. If there is actually a pending
144
* request for the lock, signal the waiting thread.
145
*
146
******************************************************************************/
147
148
static
u32
acpi_ev_global_lock_handler(
void
*
context
)
149
{
150
acpi_status
status
;
151
acpi_cpu_flags
flags
;
152
153
flags =
acpi_os_acquire_lock
(
acpi_gbl_global_lock_pending_lock
);
154
155
/*
156
* If a request for the global lock is not actually pending,
157
* we are done. This handles "spurious" global lock interrupts
158
* which are possible (and have been seen) with bad BIOSs.
159
*/
160
if
(!
acpi_gbl_global_lock_pending
) {
161
goto
cleanup_and_exit;
162
}
163
164
/*
165
* Send a unit to the global lock semaphore. The actual acquisition
166
* of the global lock will be performed by the waiting thread.
167
*/
168
status =
acpi_os_signal_semaphore
(
acpi_gbl_global_lock_semaphore
, 1);
169
if
(
ACPI_FAILURE
(status)) {
170
ACPI_ERROR
((
AE_INFO
,
"Could not signal Global Lock semaphore"
));
171
}
172
173
acpi_gbl_global_lock_pending
=
FALSE
;
174
175
cleanup_and_exit:
176
177
acpi_os_release_lock
(
acpi_gbl_global_lock_pending_lock
, flags);
178
return
(
ACPI_INTERRUPT_HANDLED
);
179
}
180
181
/******************************************************************************
182
*
183
* FUNCTION: acpi_ev_acquire_global_lock
184
*
185
* PARAMETERS: timeout - Max time to wait for the lock, in millisec.
186
*
187
* RETURN: Status
188
*
189
* DESCRIPTION: Attempt to gain ownership of the Global Lock.
190
*
191
* MUTEX: Interpreter must be locked
192
*
193
* Note: The original implementation allowed multiple threads to "acquire" the
194
* Global Lock, and the OS would hold the lock until the last thread had
195
* released it. However, this could potentially starve the BIOS out of the
196
* lock, especially in the case where there is a tight handshake between the
197
* Embedded Controller driver and the BIOS. Therefore, this implementation
198
* allows only one thread to acquire the HW Global Lock at a time, and makes
199
* the global lock appear as a standard mutex on the OS side.
200
*
201
*****************************************************************************/
202
203
acpi_status
acpi_ev_acquire_global_lock
(
u16
timeout)
204
{
205
acpi_cpu_flags
flags
;
206
acpi_status
status
;
207
u8
acquired =
FALSE
;
208
209
ACPI_FUNCTION_TRACE
(ev_acquire_global_lock);
210
211
/*
212
* Only one thread can acquire the GL at a time, the global_lock_mutex
213
* enforces this. This interface releases the interpreter if we must wait.
214
*/
215
status =
216
acpi_ex_system_wait_mutex
(
acpi_gbl_global_lock_mutex
->
mutex
.
217
os_mutex, timeout);
218
if
(
ACPI_FAILURE
(status)) {
219
return_ACPI_STATUS
(status);
220
}
221
222
/*
223
* Update the global lock handle and check for wraparound. The handle is
224
* only used for the external global lock interfaces, but it is updated
225
* here to properly handle the case where a single thread may acquire the
226
* lock via both the AML and the acpi_acquire_global_lock interfaces. The
227
* handle is therefore updated on the first acquire from a given thread
228
* regardless of where the acquisition request originated.
229
*/
230
acpi_gbl_global_lock_handle
++;
231
if
(
acpi_gbl_global_lock_handle
== 0) {
232
acpi_gbl_global_lock_handle
= 1;
233
}
234
235
/*
236
* Make sure that a global lock actually exists. If not, just
237
* treat the lock as a standard mutex.
238
*/
239
if
(!
acpi_gbl_global_lock_present
) {
240
acpi_gbl_global_lock_acquired
=
TRUE
;
241
return_ACPI_STATUS
(
AE_OK
);
242
}
243
244
flags =
acpi_os_acquire_lock
(
acpi_gbl_global_lock_pending_lock
);
245
246
do
{
247
248
/* Attempt to acquire the actual hardware lock */
249
250
ACPI_ACQUIRE_GLOBAL_LOCK
(
acpi_gbl_FACS
, acquired);
251
if
(acquired) {
252
acpi_gbl_global_lock_acquired
=
TRUE
;
253
ACPI_DEBUG_PRINT
((
ACPI_DB_EXEC
,
254
"Acquired hardware Global Lock\n"
));
255
break
;
256
}
257
258
/*
259
* Did not get the lock. The pending bit was set above, and
260
* we must now wait until we receive the global lock
261
* released interrupt.
262
*/
263
acpi_gbl_global_lock_pending
=
TRUE
;
264
acpi_os_release_lock
(
acpi_gbl_global_lock_pending_lock
, flags);
265
266
ACPI_DEBUG_PRINT
((
ACPI_DB_EXEC
,
267
"Waiting for hardware Global Lock\n"
));
268
269
/*
270
* Wait for handshake with the global lock interrupt handler.
271
* This interface releases the interpreter if we must wait.
272
*/
273
status =
274
acpi_ex_system_wait_semaphore
275
(
acpi_gbl_global_lock_semaphore
,
ACPI_WAIT_FOREVER
);
276
277
flags =
acpi_os_acquire_lock
(
acpi_gbl_global_lock_pending_lock
);
278
279
}
while
(
ACPI_SUCCESS
(status));
280
281
acpi_gbl_global_lock_pending
=
FALSE
;
282
acpi_os_release_lock
(
acpi_gbl_global_lock_pending_lock
, flags);
283
284
return_ACPI_STATUS
(status);
285
}
286
287
/*******************************************************************************
288
*
289
* FUNCTION: acpi_ev_release_global_lock
290
*
291
* PARAMETERS: None
292
*
293
* RETURN: Status
294
*
295
* DESCRIPTION: Releases ownership of the Global Lock.
296
*
297
******************************************************************************/
298
299
acpi_status
acpi_ev_release_global_lock
(
void
)
300
{
301
u8
pending =
FALSE
;
302
acpi_status
status =
AE_OK
;
303
304
ACPI_FUNCTION_TRACE
(ev_release_global_lock);
305
306
/* Lock must be already acquired */
307
308
if
(!
acpi_gbl_global_lock_acquired
) {
309
ACPI_WARNING
((
AE_INFO
,
310
"Cannot release the ACPI Global Lock, it has not been acquired"
));
311
return_ACPI_STATUS
(
AE_NOT_ACQUIRED
);
312
}
313
314
if
(
acpi_gbl_global_lock_present
) {
315
316
/* Allow any thread to release the lock */
317
318
ACPI_RELEASE_GLOBAL_LOCK
(
acpi_gbl_FACS
, pending);
319
320
/*
321
* If the pending bit was set, we must write GBL_RLS to the control
322
* register
323
*/
324
if
(pending) {
325
status =
326
acpi_write_bit_register
327
(
ACPI_BITREG_GLOBAL_LOCK_RELEASE
,
328
ACPI_ENABLE_EVENT
);
329
}
330
331
ACPI_DEBUG_PRINT
((
ACPI_DB_EXEC
,
332
"Released hardware Global Lock\n"
));
333
}
334
335
acpi_gbl_global_lock_acquired
=
FALSE
;
336
337
/* Release the local GL mutex */
338
339
acpi_os_release_mutex
(
acpi_gbl_global_lock_mutex
->
mutex
.os_mutex);
340
return_ACPI_STATUS
(status);
341
}
342
343
#endif
/* !ACPI_REDUCED_HARDWARE */
Generated on Thu Jan 10 2013 13:23:28 for Linux Kernel by
1.8.2