Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/acpi/acpica/evxfregn.c
15111 views
1
/******************************************************************************
2
*
3
* Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
4
* Address Spaces.
5
*
6
*****************************************************************************/
7
8
/*
9
* Copyright (C) 2000 - 2011, Intel Corp.
10
* All rights reserved.
11
*
12
* Redistribution and use in source and binary forms, with or without
13
* modification, are permitted provided that the following conditions
14
* are met:
15
* 1. Redistributions of source code must retain the above copyright
16
* notice, this list of conditions, and the following disclaimer,
17
* without modification.
18
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
19
* substantially similar to the "NO WARRANTY" disclaimer below
20
* ("Disclaimer") and any redistribution must be conditioned upon
21
* including a substantially similar Disclaimer requirement for further
22
* binary redistribution.
23
* 3. Neither the names of the above-listed copyright holders nor the names
24
* of any contributors may be used to endorse or promote products derived
25
* from this software without specific prior written permission.
26
*
27
* Alternatively, this software may be distributed under the terms of the
28
* GNU General Public License ("GPL") version 2 as published by the Free
29
* Software Foundation.
30
*
31
* NO WARRANTY
32
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42
* POSSIBILITY OF SUCH DAMAGES.
43
*/
44
45
#include <acpi/acpi.h>
46
#include "accommon.h"
47
#include "acnamesp.h"
48
#include "acevents.h"
49
50
#define _COMPONENT ACPI_EVENTS
51
ACPI_MODULE_NAME("evxfregn")
52
53
/*******************************************************************************
54
*
55
* FUNCTION: acpi_install_address_space_handler
56
*
57
* PARAMETERS: Device - Handle for the device
58
* space_id - The address space ID
59
* Handler - Address of the handler
60
* Setup - Address of the setup function
61
* Context - Value passed to the handler on each access
62
*
63
* RETURN: Status
64
*
65
* DESCRIPTION: Install a handler for all op_regions of a given space_id.
66
*
67
* NOTE: This function should only be called after acpi_enable_subsystem has
68
* been called. This is because any _REG methods associated with the Space ID
69
* are executed here, and these methods can only be safely executed after
70
* the default handlers have been installed and the hardware has been
71
* initialized (via acpi_enable_subsystem.)
72
*
73
******************************************************************************/
74
acpi_status
75
acpi_install_address_space_handler(acpi_handle device,
76
acpi_adr_space_type space_id,
77
acpi_adr_space_handler handler,
78
acpi_adr_space_setup setup, void *context)
79
{
80
struct acpi_namespace_node *node;
81
acpi_status status;
82
83
ACPI_FUNCTION_TRACE(acpi_install_address_space_handler);
84
85
/* Parameter validation */
86
87
if (!device) {
88
return_ACPI_STATUS(AE_BAD_PARAMETER);
89
}
90
91
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
92
if (ACPI_FAILURE(status)) {
93
return_ACPI_STATUS(status);
94
}
95
96
/* Convert and validate the device handle */
97
98
node = acpi_ns_validate_handle(device);
99
if (!node) {
100
status = AE_BAD_PARAMETER;
101
goto unlock_and_exit;
102
}
103
104
/* Install the handler for all Regions for this Space ID */
105
106
status =
107
acpi_ev_install_space_handler(node, space_id, handler, setup,
108
context);
109
if (ACPI_FAILURE(status)) {
110
goto unlock_and_exit;
111
}
112
113
/*
114
* For the default space_iDs, (the IDs for which there are default region handlers
115
* installed) Only execute the _REG methods if the global initialization _REG
116
* methods have already been run (via acpi_initialize_objects). In other words,
117
* we will defer the execution of the _REG methods for these space_iDs until
118
* execution of acpi_initialize_objects. This is done because we need the handlers
119
* for the default spaces (mem/io/pci/table) to be installed before we can run
120
* any control methods (or _REG methods). There is known BIOS code that depends
121
* on this.
122
*
123
* For all other space_iDs, we can safely execute the _REG methods immediately.
124
* This means that for IDs like embedded_controller, this function should be called
125
* only after acpi_enable_subsystem has been called.
126
*/
127
switch (space_id) {
128
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
129
case ACPI_ADR_SPACE_SYSTEM_IO:
130
case ACPI_ADR_SPACE_PCI_CONFIG:
131
case ACPI_ADR_SPACE_DATA_TABLE:
132
133
if (!acpi_gbl_reg_methods_executed) {
134
135
/* We will defer execution of the _REG methods for this space */
136
goto unlock_and_exit;
137
}
138
break;
139
140
default:
141
break;
142
}
143
144
/* Run all _REG methods for this address space */
145
146
status = acpi_ev_execute_reg_methods(node, space_id);
147
148
unlock_and_exit:
149
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
150
return_ACPI_STATUS(status);
151
}
152
153
ACPI_EXPORT_SYMBOL(acpi_install_address_space_handler)
154
155
/*******************************************************************************
156
*
157
* FUNCTION: acpi_remove_address_space_handler
158
*
159
* PARAMETERS: Device - Handle for the device
160
* space_id - The address space ID
161
* Handler - Address of the handler
162
*
163
* RETURN: Status
164
*
165
* DESCRIPTION: Remove a previously installed handler.
166
*
167
******************************************************************************/
168
acpi_status
169
acpi_remove_address_space_handler(acpi_handle device,
170
acpi_adr_space_type space_id,
171
acpi_adr_space_handler handler)
172
{
173
union acpi_operand_object *obj_desc;
174
union acpi_operand_object *handler_obj;
175
union acpi_operand_object *region_obj;
176
union acpi_operand_object **last_obj_ptr;
177
struct acpi_namespace_node *node;
178
acpi_status status;
179
180
ACPI_FUNCTION_TRACE(acpi_remove_address_space_handler);
181
182
/* Parameter validation */
183
184
if (!device) {
185
return_ACPI_STATUS(AE_BAD_PARAMETER);
186
}
187
188
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
189
if (ACPI_FAILURE(status)) {
190
return_ACPI_STATUS(status);
191
}
192
193
/* Convert and validate the device handle */
194
195
node = acpi_ns_validate_handle(device);
196
if (!node ||
197
((node->type != ACPI_TYPE_DEVICE) &&
198
(node->type != ACPI_TYPE_PROCESSOR) &&
199
(node->type != ACPI_TYPE_THERMAL) &&
200
(node != acpi_gbl_root_node))) {
201
status = AE_BAD_PARAMETER;
202
goto unlock_and_exit;
203
}
204
205
/* Make sure the internal object exists */
206
207
obj_desc = acpi_ns_get_attached_object(node);
208
if (!obj_desc) {
209
status = AE_NOT_EXIST;
210
goto unlock_and_exit;
211
}
212
213
/* Find the address handler the user requested */
214
215
handler_obj = obj_desc->device.handler;
216
last_obj_ptr = &obj_desc->device.handler;
217
while (handler_obj) {
218
219
/* We have a handler, see if user requested this one */
220
221
if (handler_obj->address_space.space_id == space_id) {
222
223
/* Handler must be the same as the installed handler */
224
225
if (handler_obj->address_space.handler != handler) {
226
status = AE_BAD_PARAMETER;
227
goto unlock_and_exit;
228
}
229
230
/* Matched space_id, first dereference this in the Regions */
231
232
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
233
"Removing address handler %p(%p) for region %s "
234
"on Device %p(%p)\n",
235
handler_obj, handler,
236
acpi_ut_get_region_name(space_id),
237
node, obj_desc));
238
239
region_obj = handler_obj->address_space.region_list;
240
241
/* Walk the handler's region list */
242
243
while (region_obj) {
244
/*
245
* First disassociate the handler from the region.
246
*
247
* NOTE: this doesn't mean that the region goes away
248
* The region is just inaccessible as indicated to
249
* the _REG method
250
*/
251
acpi_ev_detach_region(region_obj, TRUE);
252
253
/*
254
* Walk the list: Just grab the head because the
255
* detach_region removed the previous head.
256
*/
257
region_obj =
258
handler_obj->address_space.region_list;
259
260
}
261
262
/* Remove this Handler object from the list */
263
264
*last_obj_ptr = handler_obj->address_space.next;
265
266
/* Now we can delete the handler object */
267
268
acpi_ut_remove_reference(handler_obj);
269
goto unlock_and_exit;
270
}
271
272
/* Walk the linked list of handlers */
273
274
last_obj_ptr = &handler_obj->address_space.next;
275
handler_obj = handler_obj->address_space.next;
276
}
277
278
/* The handler does not exist */
279
280
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
281
"Unable to remove address handler %p for %s(%X), DevNode %p, obj %p\n",
282
handler, acpi_ut_get_region_name(space_id), space_id,
283
node, obj_desc));
284
285
status = AE_NOT_EXIST;
286
287
unlock_and_exit:
288
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
289
return_ACPI_STATUS(status);
290
}
291
292
ACPI_EXPORT_SYMBOL(acpi_remove_address_space_handler)
293
294