Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/acpi/acpica/evmisc.c
15109 views
1
/******************************************************************************
2
*
3
* Module Name: evmisc - Miscellaneous event manager support functions
4
*
5
*****************************************************************************/
6
7
/*
8
* Copyright (C) 2000 - 2011, 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 "acnamesp.h"
48
49
#define _COMPONENT ACPI_EVENTS
50
ACPI_MODULE_NAME("evmisc")
51
52
/* Local prototypes */
53
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
54
55
/*******************************************************************************
56
*
57
* FUNCTION: acpi_ev_is_notify_object
58
*
59
* PARAMETERS: Node - Node to check
60
*
61
* RETURN: TRUE if notifies allowed on this object
62
*
63
* DESCRIPTION: Check type of node for a object that supports notifies.
64
*
65
* TBD: This could be replaced by a flag bit in the node.
66
*
67
******************************************************************************/
68
69
u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node)
70
{
71
switch (node->type) {
72
case ACPI_TYPE_DEVICE:
73
case ACPI_TYPE_PROCESSOR:
74
case ACPI_TYPE_THERMAL:
75
/*
76
* These are the ONLY objects that can receive ACPI notifications
77
*/
78
return (TRUE);
79
80
default:
81
return (FALSE);
82
}
83
}
84
85
/*******************************************************************************
86
*
87
* FUNCTION: acpi_ev_queue_notify_request
88
*
89
* PARAMETERS: Node - NS node for the notified object
90
* notify_value - Value from the Notify() request
91
*
92
* RETURN: Status
93
*
94
* DESCRIPTION: Dispatch a device notification event to a previously
95
* installed handler.
96
*
97
******************************************************************************/
98
99
acpi_status
100
acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
101
u32 notify_value)
102
{
103
union acpi_operand_object *obj_desc;
104
union acpi_operand_object *handler_obj = NULL;
105
union acpi_generic_state *notify_info;
106
acpi_status status = AE_OK;
107
108
ACPI_FUNCTION_NAME(ev_queue_notify_request);
109
110
/*
111
* For value 3 (Ejection Request), some device method may need to be run.
112
* For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
113
* to be run.
114
* For value 0x80 (Status Change) on the power button or sleep button,
115
* initiate soft-off or sleep operation?
116
*/
117
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
118
"Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
119
acpi_ut_get_node_name(node), node, notify_value,
120
acpi_ut_get_notify_name(notify_value)));
121
122
/* Get the notify object attached to the NS Node */
123
124
obj_desc = acpi_ns_get_attached_object(node);
125
if (obj_desc) {
126
127
/* We have the notify object, Get the right handler */
128
129
switch (node->type) {
130
131
/* Notify allowed only on these types */
132
133
case ACPI_TYPE_DEVICE:
134
case ACPI_TYPE_THERMAL:
135
case ACPI_TYPE_PROCESSOR:
136
137
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
138
handler_obj =
139
obj_desc->common_notify.system_notify;
140
} else {
141
handler_obj =
142
obj_desc->common_notify.device_notify;
143
}
144
break;
145
146
default:
147
148
/* All other types are not supported */
149
150
return (AE_TYPE);
151
}
152
}
153
154
/*
155
* If there is any handler to run, schedule the dispatcher.
156
* Check for:
157
* 1) Global system notify handler
158
* 2) Global device notify handler
159
* 3) Per-device notify handler
160
*/
161
if ((acpi_gbl_system_notify.handler &&
162
(notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
163
(acpi_gbl_device_notify.handler &&
164
(notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
165
notify_info = acpi_ut_create_generic_state();
166
if (!notify_info) {
167
return (AE_NO_MEMORY);
168
}
169
170
if (!handler_obj) {
171
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
172
"Executing system notify handler for Notify (%4.4s, %X) "
173
"node %p\n",
174
acpi_ut_get_node_name(node),
175
notify_value, node));
176
}
177
178
notify_info->common.descriptor_type =
179
ACPI_DESC_TYPE_STATE_NOTIFY;
180
notify_info->notify.node = node;
181
notify_info->notify.value = (u16) notify_value;
182
notify_info->notify.handler_obj = handler_obj;
183
184
status =
185
acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
186
notify_info);
187
if (ACPI_FAILURE(status)) {
188
acpi_ut_delete_generic_state(notify_info);
189
}
190
} else {
191
/* There is no notify handler (per-device or system) for this device */
192
193
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
194
"No notify handler for Notify (%4.4s, %X) node %p\n",
195
acpi_ut_get_node_name(node), notify_value,
196
node));
197
}
198
199
return (status);
200
}
201
202
/*******************************************************************************
203
*
204
* FUNCTION: acpi_ev_notify_dispatch
205
*
206
* PARAMETERS: Context - To be passed to the notify handler
207
*
208
* RETURN: None.
209
*
210
* DESCRIPTION: Dispatch a device notification event to a previously
211
* installed handler.
212
*
213
******************************************************************************/
214
215
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
216
{
217
union acpi_generic_state *notify_info =
218
(union acpi_generic_state *)context;
219
acpi_notify_handler global_handler = NULL;
220
void *global_context = NULL;
221
union acpi_operand_object *handler_obj;
222
223
ACPI_FUNCTION_ENTRY();
224
225
/*
226
* We will invoke a global notify handler if installed. This is done
227
* _before_ we invoke the per-device handler attached to the device.
228
*/
229
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
230
231
/* Global system notification handler */
232
233
if (acpi_gbl_system_notify.handler) {
234
global_handler = acpi_gbl_system_notify.handler;
235
global_context = acpi_gbl_system_notify.context;
236
}
237
} else {
238
/* Global driver notification handler */
239
240
if (acpi_gbl_device_notify.handler) {
241
global_handler = acpi_gbl_device_notify.handler;
242
global_context = acpi_gbl_device_notify.context;
243
}
244
}
245
246
/* Invoke the system handler first, if present */
247
248
if (global_handler) {
249
global_handler(notify_info->notify.node,
250
notify_info->notify.value, global_context);
251
}
252
253
/* Now invoke the per-device handler, if present */
254
255
handler_obj = notify_info->notify.handler_obj;
256
if (handler_obj) {
257
struct acpi_object_notify_handler *notifier;
258
259
notifier = &handler_obj->notify;
260
while (notifier) {
261
notifier->handler(notify_info->notify.node,
262
notify_info->notify.value,
263
notifier->context);
264
notifier = notifier->next;
265
}
266
}
267
268
/* All done with the info object */
269
270
acpi_ut_delete_generic_state(notify_info);
271
}
272
273
/******************************************************************************
274
*
275
* FUNCTION: acpi_ev_terminate
276
*
277
* PARAMETERS: none
278
*
279
* RETURN: none
280
*
281
* DESCRIPTION: Disable events and free memory allocated for table storage.
282
*
283
******************************************************************************/
284
285
void acpi_ev_terminate(void)
286
{
287
u32 i;
288
acpi_status status;
289
290
ACPI_FUNCTION_TRACE(ev_terminate);
291
292
if (acpi_gbl_events_initialized) {
293
/*
294
* Disable all event-related functionality. In all cases, on error,
295
* print a message but obviously we don't abort.
296
*/
297
298
/* Disable all fixed events */
299
300
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
301
status = acpi_disable_event(i, 0);
302
if (ACPI_FAILURE(status)) {
303
ACPI_ERROR((AE_INFO,
304
"Could not disable fixed event %u",
305
(u32) i));
306
}
307
}
308
309
/* Disable all GPEs in all GPE blocks */
310
311
status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
312
313
/* Remove SCI handler */
314
315
status = acpi_ev_remove_sci_handler();
316
if (ACPI_FAILURE(status)) {
317
ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
318
}
319
320
status = acpi_ev_remove_global_lock_handler();
321
if (ACPI_FAILURE(status)) {
322
ACPI_ERROR((AE_INFO,
323
"Could not remove Global Lock handler"));
324
}
325
}
326
327
/* Deallocate all handler objects installed within GPE info structs */
328
329
status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
330
331
/* Return to original mode if necessary */
332
333
if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
334
status = acpi_disable();
335
if (ACPI_FAILURE(status)) {
336
ACPI_WARNING((AE_INFO, "AcpiDisable failed"));
337
}
338
}
339
return_VOID;
340
}
341
342