]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/acpi/events/evmisc.c
ACPICA: Allow processor to be declared with the Device() instead of Processor()
[mirror_ubuntu-bionic-kernel.git] / drivers / acpi / events / evmisc.c
CommitLineData
1da177e4
LT
1/******************************************************************************
2 *
3 * Module Name: evmisc - Miscellaneous event manager support functions
4 *
5 *****************************************************************************/
6
7/*
4a90c7e8 8 * Copyright (C) 2000 - 2006, R. Byron Moore
1da177e4
LT
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 <acpi/acevents.h>
46#include <acpi/acnamesp.h>
47#include <acpi/acinterp.h>
48
49#define _COMPONENT ACPI_EVENTS
4be44fcd 50ACPI_MODULE_NAME("evmisc")
1da177e4 51
4119532c 52/* Names for Notify() values, used for debug output */
44f6c012 53#ifdef ACPI_DEBUG_OUTPUT
4be44fcd 54static const char *acpi_notify_value_names[] = {
44f6c012
RM
55 "Bus Check",
56 "Device Check",
57 "Device Wake",
4119532c 58 "Eject Request",
44f6c012
RM
59 "Device Check Light",
60 "Frequency Mismatch",
61 "Bus Mode Mismatch",
62 "Power Fault"
63};
64#endif
65
f3d2e786
BM
66/* Pointer to FACS needed for the Global Lock */
67
68static struct acpi_table_facs *facs = NULL;
69
44f6c012
RM
70/* Local prototypes */
71
4be44fcd 72static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
44f6c012 73
4be44fcd 74static u32 acpi_ev_global_lock_handler(void *context);
44f6c012 75
8876016b
BM
76static acpi_status acpi_ev_remove_global_lock_handler(void);
77
1da177e4
LT
78/*******************************************************************************
79 *
80 * FUNCTION: acpi_ev_is_notify_object
81 *
82 * PARAMETERS: Node - Node to check
83 *
84 * RETURN: TRUE if notifies allowed on this object
85 *
86 * DESCRIPTION: Check type of node for a object that supports notifies.
87 *
88 * TBD: This could be replaced by a flag bit in the node.
89 *
90 ******************************************************************************/
91
4be44fcd 92u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
1da177e4
LT
93{
94 switch (node->type) {
95 case ACPI_TYPE_DEVICE:
96 case ACPI_TYPE_PROCESSOR:
97 case ACPI_TYPE_POWER:
98 case ACPI_TYPE_THERMAL:
99 /*
100 * These are the ONLY objects that can receive ACPI notifications
101 */
102 return (TRUE);
103
104 default:
105 return (FALSE);
106 }
107}
108
1da177e4
LT
109/*******************************************************************************
110 *
111 * FUNCTION: acpi_ev_queue_notify_request
112 *
113 * PARAMETERS: Node - NS node for the notified object
114 * notify_value - Value from the Notify() request
115 *
116 * RETURN: Status
117 *
118 * DESCRIPTION: Dispatch a device notification event to a previously
119 * installed handler.
120 *
121 ******************************************************************************/
122
1da177e4 123acpi_status
4be44fcd
LB
124acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
125 u32 notify_value)
1da177e4 126{
4be44fcd
LB
127 union acpi_operand_object *obj_desc;
128 union acpi_operand_object *handler_obj = NULL;
129 union acpi_generic_state *notify_info;
130 acpi_status status = AE_OK;
1da177e4 131
b229cf92 132 ACPI_FUNCTION_NAME(ev_queue_notify_request);
1da177e4
LT
133
134 /*
135 * For value 3 (Ejection Request), some device method may need to be run.
44f6c012
RM
136 * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
137 * to be run.
1da177e4 138 * For value 0x80 (Status Change) on the power button or sleep button,
44f6c012 139 * initiate soft-off or sleep operation?
1da177e4 140 */
4be44fcd
LB
141 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
142 "Dispatching Notify(%X) on node %p\n", notify_value,
143 node));
1da177e4
LT
144
145 if (notify_value <= 7) {
4be44fcd
LB
146 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n",
147 acpi_notify_value_names[notify_value]));
148 } else {
149 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
150 "Notify value: 0x%2.2X **Device Specific**\n",
151 notify_value));
1da177e4
LT
152 }
153
154 /* Get the notify object attached to the NS Node */
155
4be44fcd 156 obj_desc = acpi_ns_get_attached_object(node);
1da177e4 157 if (obj_desc) {
52fc0b02 158
1da177e4
LT
159 /* We have the notify object, Get the right handler */
160
161 switch (node->type) {
162 case ACPI_TYPE_DEVICE:
163 case ACPI_TYPE_THERMAL:
164 case ACPI_TYPE_PROCESSOR:
165 case ACPI_TYPE_POWER:
166
167 if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
4be44fcd
LB
168 handler_obj =
169 obj_desc->common_notify.system_notify;
170 } else {
171 handler_obj =
172 obj_desc->common_notify.device_notify;
1da177e4
LT
173 }
174 break;
175
176 default:
177 /* All other types are not supported */
178 return (AE_TYPE);
179 }
180 }
181
182 /* If there is any handler to run, schedule the dispatcher */
183
4be44fcd
LB
184 if ((acpi_gbl_system_notify.handler
185 && (notify_value <= ACPI_MAX_SYS_NOTIFY))
186 || (acpi_gbl_device_notify.handler
187 && (notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
188 notify_info = acpi_ut_create_generic_state();
1da177e4
LT
189 if (!notify_info) {
190 return (AE_NO_MEMORY);
191 }
192
61686124
BM
193 notify_info->common.descriptor_type =
194 ACPI_DESC_TYPE_STATE_NOTIFY;
4be44fcd
LB
195 notify_info->notify.node = node;
196 notify_info->notify.value = (u16) notify_value;
1da177e4
LT
197 notify_info->notify.handler_obj = handler_obj;
198
4119532c
BM
199 status =
200 acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
201 notify_info);
4be44fcd
LB
202 if (ACPI_FAILURE(status)) {
203 acpi_ut_delete_generic_state(notify_info);
1da177e4
LT
204 }
205 }
206
207 if (!handler_obj) {
208 /*
209 * There is no per-device notify handler for this device.
210 * This may or may not be a problem.
211 */
4be44fcd
LB
212 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
213 "No notify handler for Notify(%4.4s, %X) node %p\n",
214 acpi_ut_get_node_name(node), notify_value,
215 node));
1da177e4
LT
216 }
217
218 return (status);
219}
220
1da177e4
LT
221/*******************************************************************************
222 *
223 * FUNCTION: acpi_ev_notify_dispatch
224 *
44f6c012 225 * PARAMETERS: Context - To be passed to the notify handler
1da177e4
LT
226 *
227 * RETURN: None.
228 *
229 * DESCRIPTION: Dispatch a device notification event to a previously
230 * installed handler.
231 *
232 ******************************************************************************/
233
4be44fcd 234static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
1da177e4 235{
4be44fcd
LB
236 union acpi_generic_state *notify_info =
237 (union acpi_generic_state *)context;
238 acpi_notify_handler global_handler = NULL;
239 void *global_context = NULL;
240 union acpi_operand_object *handler_obj;
1da177e4 241
4be44fcd 242 ACPI_FUNCTION_ENTRY();
1da177e4
LT
243
244 /*
245 * We will invoke a global notify handler if installed.
44f6c012
RM
246 * This is done _before_ we invoke the per-device handler attached
247 * to the device.
1da177e4
LT
248 */
249 if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
52fc0b02 250
1da177e4
LT
251 /* Global system notification handler */
252
253 if (acpi_gbl_system_notify.handler) {
254 global_handler = acpi_gbl_system_notify.handler;
255 global_context = acpi_gbl_system_notify.context;
256 }
4be44fcd 257 } else {
1da177e4
LT
258 /* Global driver notification handler */
259
260 if (acpi_gbl_device_notify.handler) {
261 global_handler = acpi_gbl_device_notify.handler;
262 global_context = acpi_gbl_device_notify.context;
263 }
264 }
265
266 /* Invoke the system handler first, if present */
267
268 if (global_handler) {
4be44fcd
LB
269 global_handler(notify_info->notify.node,
270 notify_info->notify.value, global_context);
1da177e4
LT
271 }
272
273 /* Now invoke the per-device handler, if present */
274
275 handler_obj = notify_info->notify.handler_obj;
276 if (handler_obj) {
4be44fcd
LB
277 handler_obj->notify.handler(notify_info->notify.node,
278 notify_info->notify.value,
279 handler_obj->notify.context);
1da177e4
LT
280 }
281
282 /* All done with the info object */
283
4be44fcd 284 acpi_ut_delete_generic_state(notify_info);
1da177e4
LT
285}
286
1da177e4
LT
287/*******************************************************************************
288 *
289 * FUNCTION: acpi_ev_global_lock_handler
290 *
291 * PARAMETERS: Context - From thread interface, not used
292 *
a72d4756 293 * RETURN: ACPI_INTERRUPT_HANDLED
1da177e4
LT
294 *
295 * DESCRIPTION: Invoked directly from the SCI handler when a global lock
a72d4756
BM
296 * release interrupt occurs. Attempt to acquire the global lock,
297 * if successful, signal the thread waiting for the lock.
298 *
299 * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
300 * this is not possible for some reason, a separate thread will have to be
301 * scheduled to do this.
1da177e4
LT
302 *
303 ******************************************************************************/
304
4be44fcd 305static u32 acpi_ev_global_lock_handler(void *context)
1da177e4 306{
4be44fcd 307 u8 acquired = FALSE;
1da177e4
LT
308
309 /*
c81da666
BM
310 * Attempt to get the lock.
311 *
1da177e4
LT
312 * If we don't get it now, it will be marked pending and we will
313 * take another interrupt when it becomes free.
314 */
f3d2e786 315 ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
1da177e4 316 if (acquired) {
52fc0b02 317
1da177e4 318 /* Got the lock, now wake all threads waiting for it */
c81da666 319
1da177e4 320 acpi_gbl_global_lock_acquired = TRUE;
a72d4756
BM
321 /* Send a unit to the semaphore */
322
323 if (ACPI_FAILURE(acpi_os_signal_semaphore(
324 acpi_gbl_global_lock_semaphore, 1))) {
325 ACPI_ERROR((AE_INFO,
326 "Could not signal Global Lock semaphore"));
327 }
1da177e4
LT
328 }
329
330 return (ACPI_INTERRUPT_HANDLED);
331}
332
1da177e4
LT
333/*******************************************************************************
334 *
335 * FUNCTION: acpi_ev_init_global_lock_handler
336 *
337 * PARAMETERS: None
338 *
339 * RETURN: Status
340 *
341 * DESCRIPTION: Install a handler for the global lock release event
342 *
343 ******************************************************************************/
344
4be44fcd 345acpi_status acpi_ev_init_global_lock_handler(void)
1da177e4 346{
4be44fcd 347 acpi_status status;
1da177e4 348
b229cf92 349 ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
1da177e4 350
f3d2e786 351 status =
310a7f7f
BM
352 acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
353 (struct acpi_table_header **)&facs);
f3d2e786
BM
354 if (ACPI_FAILURE(status)) {
355 return_ACPI_STATUS(status);
356 }
357
1da177e4 358 acpi_gbl_global_lock_present = TRUE;
4be44fcd
LB
359 status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
360 acpi_ev_global_lock_handler,
361 NULL);
1da177e4
LT
362
363 /*
364 * If the global lock does not exist on this platform, the attempt
365 * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick)
366 * Map to AE_OK, but mark global lock as not present.
367 * Any attempt to actually use the global lock will be flagged
368 * with an error.
369 */
370 if (status == AE_NO_HARDWARE_RESPONSE) {
b8e4d893
BM
371 ACPI_ERROR((AE_INFO,
372 "No response from Global Lock hardware, disabling lock"));
0c9938cc 373
1da177e4
LT
374 acpi_gbl_global_lock_present = FALSE;
375 status = AE_OK;
376 }
377
4be44fcd 378 return_ACPI_STATUS(status);
1da177e4
LT
379}
380
8876016b
BM
381/*******************************************************************************
382 *
383 * FUNCTION: acpi_ev_remove_global_lock_handler
384 *
385 * PARAMETERS: None
386 *
387 * RETURN: Status
388 *
389 * DESCRIPTION: Remove the handler for the Global Lock
390 *
391 ******************************************************************************/
392
393static acpi_status acpi_ev_remove_global_lock_handler(void)
394{
395 acpi_status status;
396
397 ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
398
399 acpi_gbl_global_lock_present = FALSE;
400 status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
401 acpi_ev_global_lock_handler);
402
403 return_ACPI_STATUS(status);
404}
405
1da177e4
LT
406/******************************************************************************
407 *
408 * FUNCTION: acpi_ev_acquire_global_lock
409 *
410 * PARAMETERS: Timeout - Max time to wait for the lock, in millisec.
411 *
412 * RETURN: Status
413 *
414 * DESCRIPTION: Attempt to gain ownership of the Global Lock.
415 *
c81da666
BM
416 * MUTEX: Interpreter must be locked
417 *
418 * Note: The original implementation allowed multiple threads to "acquire" the
419 * Global Lock, and the OS would hold the lock until the last thread had
420 * released it. However, this could potentially starve the BIOS out of the
421 * lock, especially in the case where there is a tight handshake between the
422 * Embedded Controller driver and the BIOS. Therefore, this implementation
423 * allows only one thread to acquire the HW Global Lock at a time, and makes
424 * the global lock appear as a standard mutex on the OS side.
425 *
1da177e4
LT
426 *****************************************************************************/
427
4be44fcd 428acpi_status acpi_ev_acquire_global_lock(u16 timeout)
1da177e4 429{
4be44fcd
LB
430 acpi_status status = AE_OK;
431 u8 acquired = FALSE;
1da177e4 432
b229cf92 433 ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
1da177e4 434
c81da666
BM
435 /*
436 * Only one thread can acquire the GL at a time, the global_lock_mutex
437 * enforces this. This interface releases the interpreter if we must wait.
438 */
439 status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
440 if (ACPI_FAILURE(status)) {
441 return_ACPI_STATUS(status);
1da177e4 442 }
1da177e4 443
44f6c012 444 /*
c81da666
BM
445 * Make sure that a global lock actually exists. If not, just treat
446 * the lock as a standard mutex.
44f6c012 447 */
c81da666
BM
448 if (!acpi_gbl_global_lock_present) {
449 acpi_gbl_global_lock_acquired = TRUE;
4be44fcd 450 return_ACPI_STATUS(AE_OK);
1da177e4
LT
451 }
452
c81da666 453 /* Attempt to acquire the actual hardware lock */
1da177e4 454
f3d2e786 455 ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
1da177e4 456 if (acquired) {
52fc0b02 457
4be44fcd 458 /* We got the lock */
1da177e4 459
4be44fcd 460 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
c81da666 461 "Acquired hardware Global Lock\n"));
1da177e4
LT
462
463 acpi_gbl_global_lock_acquired = TRUE;
4be44fcd 464 return_ACPI_STATUS(AE_OK);
1da177e4
LT
465 }
466
467 /*
c81da666 468 * Did not get the lock. The pending bit was set above, and we must now
1da177e4
LT
469 * wait until we get the global lock released interrupt.
470 */
c81da666 471 ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
1da177e4
LT
472
473 /*
c81da666
BM
474 * Wait for handshake with the global lock interrupt handler.
475 * This interface releases the interpreter if we must wait.
1da177e4 476 */
c81da666
BM
477 status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
478 ACPI_WAIT_FOREVER);
f3d2e786 479
4be44fcd 480 return_ACPI_STATUS(status);
1da177e4
LT
481}
482
1da177e4
LT
483/*******************************************************************************
484 *
485 * FUNCTION: acpi_ev_release_global_lock
486 *
487 * PARAMETERS: None
488 *
489 * RETURN: Status
490 *
491 * DESCRIPTION: Releases ownership of the Global Lock.
492 *
493 ******************************************************************************/
494
4be44fcd 495acpi_status acpi_ev_release_global_lock(void)
1da177e4 496{
4be44fcd
LB
497 u8 pending = FALSE;
498 acpi_status status = AE_OK;
1da177e4 499
b229cf92 500 ACPI_FUNCTION_TRACE(ev_release_global_lock);
1da177e4 501
a72d4756 502 /* Lock must be already acquired */
c81da666
BM
503
504 if (!acpi_gbl_global_lock_acquired) {
b8e4d893 505 ACPI_WARNING((AE_INFO,
c81da666 506 "Cannot release the ACPI Global Lock, it has not been acquired"));
4be44fcd 507 return_ACPI_STATUS(AE_NOT_ACQUIRED);
1da177e4
LT
508 }
509
c81da666 510 if (acpi_gbl_global_lock_present) {
1da177e4 511
c81da666 512 /* Allow any thread to release the lock */
52fc0b02 513
f3d2e786 514 ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
1da177e4 515
c81da666
BM
516 /*
517 * If the pending bit was set, we must write GBL_RLS to the control
518 * register
519 */
520 if (pending) {
521 status =
522 acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
d8c71b6d 523 1);
c81da666
BM
524 }
525
526 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
527 "Released hardware Global Lock\n"));
1da177e4
LT
528 }
529
1da177e4
LT
530 acpi_gbl_global_lock_acquired = FALSE;
531
c81da666 532 /* Release the local GL mutex */
1da177e4 533
c81da666 534 acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
4be44fcd 535 return_ACPI_STATUS(status);
1da177e4
LT
536}
537
1da177e4
LT
538/******************************************************************************
539 *
540 * FUNCTION: acpi_ev_terminate
541 *
542 * PARAMETERS: none
543 *
544 * RETURN: none
545 *
546 * DESCRIPTION: Disable events and free memory allocated for table storage.
547 *
548 ******************************************************************************/
549
4be44fcd 550void acpi_ev_terminate(void)
1da177e4 551{
4be44fcd
LB
552 acpi_native_uint i;
553 acpi_status status;
1da177e4 554
b229cf92 555 ACPI_FUNCTION_TRACE(ev_terminate);
1da177e4
LT
556
557 if (acpi_gbl_events_initialized) {
558 /*
559 * Disable all event-related functionality.
560 * In all cases, on error, print a message but obviously we don't abort.
561 */
562
563 /* Disable all fixed events */
564
565 for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
4be44fcd
LB
566 status = acpi_disable_event((u32) i, 0);
567 if (ACPI_FAILURE(status)) {
b8e4d893
BM
568 ACPI_ERROR((AE_INFO,
569 "Could not disable fixed event %d",
570 (u32) i));
1da177e4
LT
571 }
572 }
573
574 /* Disable all GPEs in all GPE blocks */
575
4be44fcd 576 status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block);
1da177e4
LT
577
578 /* Remove SCI handler */
579
4be44fcd 580 status = acpi_ev_remove_sci_handler();
1da177e4 581 if (ACPI_FAILURE(status)) {
b8e4d893 582 ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
1da177e4 583 }
8876016b
BM
584
585 status = acpi_ev_remove_global_lock_handler();
586 if (ACPI_FAILURE(status)) {
587 ACPI_ERROR((AE_INFO,
588 "Could not remove Global Lock handler"));
589 }
1da177e4
LT
590 }
591
592 /* Deallocate all handler objects installed within GPE info structs */
593
4be44fcd 594 status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers);
1da177e4
LT
595
596 /* Return to original mode if necessary */
597
598 if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
4be44fcd
LB
599 status = acpi_disable();
600 if (ACPI_FAILURE(status)) {
b229cf92 601 ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
1da177e4
LT
602 }
603 }
604 return_VOID;
605}