Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /****************************************************************************** |
2 | * | |
3 | * Module Name: evrgnini- ACPI address_space (op_region) init | |
4 | * | |
5 | *****************************************************************************/ | |
6 | ||
7 | /* | |
82a80941 | 8 | * Copyright (C) 2000 - 2015, Intel Corp. |
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 | ||
1da177e4 | 44 | #include <acpi/acpi.h> |
e2f7a777 LB |
45 | #include "accommon.h" |
46 | #include "acevents.h" | |
47 | #include "acnamesp.h" | |
1da177e4 LT |
48 | |
49 | #define _COMPONENT ACPI_EVENTS | |
4be44fcd | 50 | ACPI_MODULE_NAME("evrgnini") |
1da177e4 | 51 | |
b7a69806 | 52 | /* Local prototypes */ |
b7a69806 BM |
53 | static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node); |
54 | ||
1da177e4 LT |
55 | /******************************************************************************* |
56 | * | |
57 | * FUNCTION: acpi_ev_system_memory_region_setup | |
58 | * | |
ba494bee BM |
59 | * PARAMETERS: handle - Region we are interested in |
60 | * function - Start or stop | |
1da177e4 LT |
61 | * handler_context - Address space handler context |
62 | * region_context - Region specific context | |
63 | * | |
64 | * RETURN: Status | |
65 | * | |
44f6c012 | 66 | * DESCRIPTION: Setup a system_memory operation region |
1da177e4 LT |
67 | * |
68 | ******************************************************************************/ | |
b7a69806 | 69 | |
1da177e4 | 70 | acpi_status |
4be44fcd LB |
71 | acpi_ev_system_memory_region_setup(acpi_handle handle, |
72 | u32 function, | |
73 | void *handler_context, void **region_context) | |
1da177e4 | 74 | { |
4be44fcd LB |
75 | union acpi_operand_object *region_desc = |
76 | (union acpi_operand_object *)handle; | |
77 | struct acpi_mem_space_context *local_region_context; | |
1da177e4 | 78 | |
b229cf92 | 79 | ACPI_FUNCTION_TRACE(ev_system_memory_region_setup); |
1da177e4 LT |
80 | |
81 | if (function == ACPI_REGION_DEACTIVATE) { | |
82 | if (*region_context) { | |
793c2388 BM |
83 | local_region_context = |
84 | (struct acpi_mem_space_context *)*region_context; | |
85 | ||
86 | /* Delete a cached mapping if present */ | |
87 | ||
88 | if (local_region_context->mapped_length) { | |
89 | acpi_os_unmap_memory(local_region_context-> | |
90 | mapped_logical_address, | |
91 | local_region_context-> | |
92 | mapped_length); | |
93 | } | |
94 | ACPI_FREE(local_region_context); | |
1da177e4 LT |
95 | *region_context = NULL; |
96 | } | |
4be44fcd | 97 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
98 | } |
99 | ||
100 | /* Create a new context */ | |
101 | ||
4be44fcd | 102 | local_region_context = |
8313524a | 103 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_mem_space_context)); |
1da177e4 | 104 | if (!(local_region_context)) { |
4be44fcd | 105 | return_ACPI_STATUS(AE_NO_MEMORY); |
1da177e4 LT |
106 | } |
107 | ||
108 | /* Save the region length and address for use in the handler */ | |
109 | ||
110 | local_region_context->length = region_desc->region.length; | |
111 | local_region_context->address = region_desc->region.address; | |
112 | ||
113 | *region_context = local_region_context; | |
4be44fcd | 114 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
115 | } |
116 | ||
1da177e4 LT |
117 | /******************************************************************************* |
118 | * | |
119 | * FUNCTION: acpi_ev_io_space_region_setup | |
120 | * | |
ba494bee BM |
121 | * PARAMETERS: handle - Region we are interested in |
122 | * function - Start or stop | |
1da177e4 LT |
123 | * handler_context - Address space handler context |
124 | * region_context - Region specific context | |
125 | * | |
126 | * RETURN: Status | |
127 | * | |
44f6c012 | 128 | * DESCRIPTION: Setup a IO operation region |
1da177e4 LT |
129 | * |
130 | ******************************************************************************/ | |
131 | ||
132 | acpi_status | |
4be44fcd LB |
133 | acpi_ev_io_space_region_setup(acpi_handle handle, |
134 | u32 function, | |
135 | void *handler_context, void **region_context) | |
1da177e4 | 136 | { |
b229cf92 | 137 | ACPI_FUNCTION_TRACE(ev_io_space_region_setup); |
1da177e4 LT |
138 | |
139 | if (function == ACPI_REGION_DEACTIVATE) { | |
140 | *region_context = NULL; | |
4be44fcd | 141 | } else { |
1da177e4 LT |
142 | *region_context = handler_context; |
143 | } | |
144 | ||
4be44fcd | 145 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
146 | } |
147 | ||
1da177e4 LT |
148 | /******************************************************************************* |
149 | * | |
150 | * FUNCTION: acpi_ev_pci_config_region_setup | |
151 | * | |
ba494bee BM |
152 | * PARAMETERS: handle - Region we are interested in |
153 | * function - Start or stop | |
1da177e4 LT |
154 | * handler_context - Address space handler context |
155 | * region_context - Region specific context | |
156 | * | |
157 | * RETURN: Status | |
158 | * | |
44f6c012 | 159 | * DESCRIPTION: Setup a PCI_Config operation region |
1da177e4 LT |
160 | * |
161 | * MUTEX: Assumes namespace is not locked | |
162 | * | |
163 | ******************************************************************************/ | |
164 | ||
165 | acpi_status | |
4be44fcd LB |
166 | acpi_ev_pci_config_region_setup(acpi_handle handle, |
167 | u32 function, | |
168 | void *handler_context, void **region_context) | |
1da177e4 | 169 | { |
4be44fcd | 170 | acpi_status status = AE_OK; |
5df7e6cb | 171 | u64 pci_value; |
4be44fcd LB |
172 | struct acpi_pci_id *pci_id = *region_context; |
173 | union acpi_operand_object *handler_obj; | |
174 | struct acpi_namespace_node *parent_node; | |
175 | struct acpi_namespace_node *pci_root_node; | |
b7a69806 | 176 | struct acpi_namespace_node *pci_device_node; |
4be44fcd LB |
177 | union acpi_operand_object *region_obj = |
178 | (union acpi_operand_object *)handle; | |
4be44fcd | 179 | |
b229cf92 | 180 | ACPI_FUNCTION_TRACE(ev_pci_config_region_setup); |
1da177e4 LT |
181 | |
182 | handler_obj = region_obj->region.handler; | |
183 | if (!handler_obj) { | |
184 | /* | |
185 | * No installed handler. This shouldn't happen because the dispatch | |
186 | * routine checks before we get here, but we check again just in case. | |
187 | */ | |
4be44fcd LB |
188 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
189 | "Attempting to init a region %p, with no handler\n", | |
190 | region_obj)); | |
191 | return_ACPI_STATUS(AE_NOT_EXIST); | |
1da177e4 LT |
192 | } |
193 | ||
194 | *region_context = NULL; | |
195 | if (function == ACPI_REGION_DEACTIVATE) { | |
196 | if (pci_id) { | |
8313524a | 197 | ACPI_FREE(pci_id); |
1da177e4 | 198 | } |
4be44fcd | 199 | return_ACPI_STATUS(status); |
1da177e4 LT |
200 | } |
201 | ||
c45b5c09 | 202 | parent_node = region_obj->region.node->parent; |
1da177e4 LT |
203 | |
204 | /* | |
205 | * Get the _SEG and _BBN values from the device upon which the handler | |
206 | * is installed. | |
207 | * | |
208 | * We need to get the _SEG and _BBN objects relative to the PCI BUS device. | |
209 | * This is the device the handler has been registered to handle. | |
210 | */ | |
211 | ||
212 | /* | |
213 | * If the address_space.Node is still pointing to the root, we need | |
214 | * to scan upward for a PCI Root bridge and re-associate the op_region | |
215 | * handlers with that device. | |
216 | */ | |
217 | if (handler_obj->address_space.node == acpi_gbl_root_node) { | |
52fc0b02 | 218 | |
1da177e4 LT |
219 | /* Start search from the parent object */ |
220 | ||
221 | pci_root_node = parent_node; | |
222 | while (pci_root_node != acpi_gbl_root_node) { | |
b7a69806 BM |
223 | |
224 | /* Get the _HID/_CID in order to detect a root_bridge */ | |
225 | ||
226 | if (acpi_ev_is_pci_root_bridge(pci_root_node)) { | |
227 | ||
228 | /* Install a handler for this PCI root bridge */ | |
229 | ||
1f86e8c1 | 230 | status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL); |
b7a69806 BM |
231 | if (ACPI_FAILURE(status)) { |
232 | if (status == AE_SAME_HANDLER) { | |
233 | /* | |
9f15fc66 BM |
234 | * It is OK if the handler is already installed on the |
235 | * root bridge. Still need to return a context object | |
236 | * for the new PCI_Config operation region, however. | |
b7a69806 BM |
237 | */ |
238 | status = AE_OK; | |
239 | } else { | |
240 | ACPI_EXCEPTION((AE_INFO, status, | |
d4913dc6 BM |
241 | "Could not install PciConfig handler " |
242 | "for Root Bridge %4.4s", | |
b7a69806 BM |
243 | acpi_ut_get_node_name |
244 | (pci_root_node))); | |
1da177e4 | 245 | } |
1da177e4 | 246 | } |
b7a69806 | 247 | break; |
1da177e4 LT |
248 | } |
249 | ||
c45b5c09 | 250 | pci_root_node = pci_root_node->parent; |
1da177e4 LT |
251 | } |
252 | ||
253 | /* PCI root bridge not found, use namespace root node */ | |
4be44fcd | 254 | } else { |
1da177e4 LT |
255 | pci_root_node = handler_obj->address_space.node; |
256 | } | |
257 | ||
258 | /* | |
259 | * If this region is now initialized, we are done. | |
260 | * (install_address_space_handler could have initialized it) | |
261 | */ | |
262 | if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { | |
4be44fcd | 263 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
264 | } |
265 | ||
266 | /* Region is still not initialized. Create a new context */ | |
267 | ||
8313524a | 268 | pci_id = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_pci_id)); |
1da177e4 | 269 | if (!pci_id) { |
4be44fcd | 270 | return_ACPI_STATUS(AE_NO_MEMORY); |
1da177e4 LT |
271 | } |
272 | ||
273 | /* | |
9f15fc66 BM |
274 | * For PCI_Config space access, we need the segment, bus, device and |
275 | * function numbers. Acquire them here. | |
b7a69806 BM |
276 | * |
277 | * Find the parent device object. (This allows the operation region to be | |
278 | * within a subscope under the device, such as a control method.) | |
1da177e4 | 279 | */ |
b7a69806 BM |
280 | pci_device_node = region_obj->region.node; |
281 | while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) { | |
c45b5c09 | 282 | pci_device_node = pci_device_node->parent; |
b7a69806 BM |
283 | } |
284 | ||
285 | if (!pci_device_node) { | |
e6917317 | 286 | ACPI_FREE(pci_id); |
b7a69806 BM |
287 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
288 | } | |
1da177e4 LT |
289 | |
290 | /* | |
95abccb5 BM |
291 | * Get the PCI device and function numbers from the _ADR object |
292 | * contained in the parent's scope. | |
1da177e4 | 293 | */ |
d4913dc6 BM |
294 | status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, |
295 | pci_device_node, &pci_value); | |
1da177e4 LT |
296 | |
297 | /* | |
9f15fc66 BM |
298 | * The default is zero, and since the allocation above zeroed the data, |
299 | * just do nothing on failure. | |
1da177e4 | 300 | */ |
4be44fcd LB |
301 | if (ACPI_SUCCESS(status)) { |
302 | pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); | |
303 | pci_id->function = ACPI_LOWORD(ACPI_LODWORD(pci_value)); | |
1da177e4 LT |
304 | } |
305 | ||
306 | /* The PCI segment number comes from the _SEG method */ | |
307 | ||
d4913dc6 BM |
308 | status = acpi_ut_evaluate_numeric_object(METHOD_NAME__SEG, |
309 | pci_root_node, &pci_value); | |
4be44fcd LB |
310 | if (ACPI_SUCCESS(status)) { |
311 | pci_id->segment = ACPI_LOWORD(pci_value); | |
1da177e4 LT |
312 | } |
313 | ||
314 | /* The PCI bus number comes from the _BBN method */ | |
315 | ||
d4913dc6 BM |
316 | status = acpi_ut_evaluate_numeric_object(METHOD_NAME__BBN, |
317 | pci_root_node, &pci_value); | |
4be44fcd LB |
318 | if (ACPI_SUCCESS(status)) { |
319 | pci_id->bus = ACPI_LOWORD(pci_value); | |
1da177e4 LT |
320 | } |
321 | ||
95abccb5 | 322 | /* Complete/update the PCI ID for this device */ |
1da177e4 | 323 | |
95abccb5 BM |
324 | status = |
325 | acpi_hw_derive_pci_id(pci_id, pci_root_node, | |
326 | region_obj->region.node); | |
327 | if (ACPI_FAILURE(status)) { | |
328 | ACPI_FREE(pci_id); | |
329 | return_ACPI_STATUS(status); | |
330 | } | |
1da177e4 LT |
331 | |
332 | *region_context = pci_id; | |
4be44fcd | 333 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
334 | } |
335 | ||
b7a69806 BM |
336 | /******************************************************************************* |
337 | * | |
338 | * FUNCTION: acpi_ev_is_pci_root_bridge | |
339 | * | |
ba494bee | 340 | * PARAMETERS: node - Device node being examined |
b7a69806 BM |
341 | * |
342 | * RETURN: TRUE if device is a PCI/PCI-Express Root Bridge | |
343 | * | |
344 | * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by | |
345 | * examining the _HID and _CID for the device. | |
346 | * | |
347 | ******************************************************************************/ | |
348 | ||
349 | static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) | |
350 | { | |
351 | acpi_status status; | |
78e25fef LZ |
352 | struct acpi_pnp_device_id *hid; |
353 | struct acpi_pnp_device_id_list *cid; | |
67a119f9 | 354 | u32 i; |
15b8dd53 | 355 | u8 match; |
b7a69806 | 356 | |
9f15fc66 BM |
357 | /* Get the _HID and check for a PCI Root Bridge */ |
358 | ||
b7a69806 BM |
359 | status = acpi_ut_execute_HID(node, &hid); |
360 | if (ACPI_FAILURE(status)) { | |
361 | return (FALSE); | |
362 | } | |
363 | ||
15b8dd53 BM |
364 | match = acpi_ut_is_pci_root_bridge(hid->string); |
365 | ACPI_FREE(hid); | |
366 | ||
367 | if (match) { | |
b7a69806 BM |
368 | return (TRUE); |
369 | } | |
370 | ||
9f15fc66 BM |
371 | /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ |
372 | ||
b7a69806 BM |
373 | status = acpi_ut_execute_CID(node, &cid); |
374 | if (ACPI_FAILURE(status)) { | |
375 | return (FALSE); | |
376 | } | |
377 | ||
378 | /* Check all _CIDs in the returned list */ | |
379 | ||
380 | for (i = 0; i < cid->count; i++) { | |
15b8dd53 | 381 | if (acpi_ut_is_pci_root_bridge(cid->ids[i].string)) { |
b7a69806 BM |
382 | ACPI_FREE(cid); |
383 | return (TRUE); | |
384 | } | |
385 | } | |
386 | ||
387 | ACPI_FREE(cid); | |
388 | return (FALSE); | |
389 | } | |
390 | ||
1da177e4 LT |
391 | /******************************************************************************* |
392 | * | |
393 | * FUNCTION: acpi_ev_pci_bar_region_setup | |
394 | * | |
ba494bee BM |
395 | * PARAMETERS: handle - Region we are interested in |
396 | * function - Start or stop | |
1da177e4 LT |
397 | * handler_context - Address space handler context |
398 | * region_context - Region specific context | |
399 | * | |
400 | * RETURN: Status | |
401 | * | |
ba494bee | 402 | * DESCRIPTION: Setup a pci_BAR operation region |
1da177e4 LT |
403 | * |
404 | * MUTEX: Assumes namespace is not locked | |
405 | * | |
406 | ******************************************************************************/ | |
407 | ||
408 | acpi_status | |
4be44fcd LB |
409 | acpi_ev_pci_bar_region_setup(acpi_handle handle, |
410 | u32 function, | |
411 | void *handler_context, void **region_context) | |
1da177e4 | 412 | { |
b229cf92 | 413 | ACPI_FUNCTION_TRACE(ev_pci_bar_region_setup); |
1da177e4 | 414 | |
4be44fcd | 415 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
416 | } |
417 | ||
1da177e4 LT |
418 | /******************************************************************************* |
419 | * | |
420 | * FUNCTION: acpi_ev_cmos_region_setup | |
421 | * | |
ba494bee BM |
422 | * PARAMETERS: handle - Region we are interested in |
423 | * function - Start or stop | |
1da177e4 LT |
424 | * handler_context - Address space handler context |
425 | * region_context - Region specific context | |
426 | * | |
427 | * RETURN: Status | |
428 | * | |
44f6c012 | 429 | * DESCRIPTION: Setup a CMOS operation region |
1da177e4 LT |
430 | * |
431 | * MUTEX: Assumes namespace is not locked | |
432 | * | |
433 | ******************************************************************************/ | |
434 | ||
435 | acpi_status | |
4be44fcd LB |
436 | acpi_ev_cmos_region_setup(acpi_handle handle, |
437 | u32 function, | |
438 | void *handler_context, void **region_context) | |
1da177e4 | 439 | { |
b229cf92 | 440 | ACPI_FUNCTION_TRACE(ev_cmos_region_setup); |
1da177e4 | 441 | |
4be44fcd | 442 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
443 | } |
444 | ||
1da177e4 LT |
445 | /******************************************************************************* |
446 | * | |
447 | * FUNCTION: acpi_ev_default_region_setup | |
448 | * | |
ba494bee BM |
449 | * PARAMETERS: handle - Region we are interested in |
450 | * function - Start or stop | |
1da177e4 LT |
451 | * handler_context - Address space handler context |
452 | * region_context - Region specific context | |
453 | * | |
454 | * RETURN: Status | |
455 | * | |
44f6c012 | 456 | * DESCRIPTION: Default region initialization |
1da177e4 LT |
457 | * |
458 | ******************************************************************************/ | |
459 | ||
460 | acpi_status | |
4be44fcd LB |
461 | acpi_ev_default_region_setup(acpi_handle handle, |
462 | u32 function, | |
463 | void *handler_context, void **region_context) | |
1da177e4 | 464 | { |
b229cf92 | 465 | ACPI_FUNCTION_TRACE(ev_default_region_setup); |
1da177e4 LT |
466 | |
467 | if (function == ACPI_REGION_DEACTIVATE) { | |
468 | *region_context = NULL; | |
4be44fcd | 469 | } else { |
1da177e4 LT |
470 | *region_context = handler_context; |
471 | } | |
472 | ||
4be44fcd | 473 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
474 | } |
475 | ||
1da177e4 LT |
476 | /******************************************************************************* |
477 | * | |
478 | * FUNCTION: acpi_ev_initialize_region | |
479 | * | |
480 | * PARAMETERS: region_obj - Region we are initializing | |
481 | * acpi_ns_locked - Is namespace locked? | |
482 | * | |
483 | * RETURN: Status | |
484 | * | |
485 | * DESCRIPTION: Initializes the region, finds any _REG methods and saves them | |
486 | * for execution at a later time | |
487 | * | |
488 | * Get the appropriate address space handler for a newly | |
489 | * created region. | |
490 | * | |
9f15fc66 | 491 | * This also performs address space specific initialization. For |
1da177e4 | 492 | * example, PCI regions must have an _ADR object that contains |
9f15fc66 | 493 | * a PCI address in the scope of the definition. This address is |
1da177e4 LT |
494 | * required to perform an access to PCI config space. |
495 | * | |
c9e3ba2c BM |
496 | * MUTEX: Interpreter should be unlocked, because we may run the _REG |
497 | * method for this region. | |
498 | * | |
1da177e4 LT |
499 | ******************************************************************************/ |
500 | ||
501 | acpi_status | |
4be44fcd LB |
502 | acpi_ev_initialize_region(union acpi_operand_object *region_obj, |
503 | u8 acpi_ns_locked) | |
1da177e4 | 504 | { |
4be44fcd LB |
505 | union acpi_operand_object *handler_obj; |
506 | union acpi_operand_object *obj_desc; | |
507 | acpi_adr_space_type space_id; | |
508 | struct acpi_namespace_node *node; | |
509 | acpi_status status; | |
510 | struct acpi_namespace_node *method_node; | |
511 | acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG; | |
512 | union acpi_operand_object *region_obj2; | |
1da177e4 | 513 | |
b229cf92 | 514 | ACPI_FUNCTION_TRACE_U32(ev_initialize_region, acpi_ns_locked); |
1da177e4 LT |
515 | |
516 | if (!region_obj) { | |
4be44fcd | 517 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
1da177e4 LT |
518 | } |
519 | ||
520 | if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) { | |
4be44fcd | 521 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
522 | } |
523 | ||
4be44fcd | 524 | region_obj2 = acpi_ns_get_secondary_object(region_obj); |
1da177e4 | 525 | if (!region_obj2) { |
4be44fcd | 526 | return_ACPI_STATUS(AE_NOT_EXIST); |
1da177e4 LT |
527 | } |
528 | ||
c45b5c09 | 529 | node = region_obj->region.node->parent; |
1da177e4 LT |
530 | space_id = region_obj->region.space_id; |
531 | ||
532 | /* Setup defaults */ | |
533 | ||
534 | region_obj->region.handler = NULL; | |
535 | region_obj2->extra.method_REG = NULL; | |
536 | region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE); | |
537 | region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED; | |
538 | ||
539 | /* Find any "_REG" method associated with this region definition */ | |
540 | ||
4119532c BM |
541 | status = |
542 | acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD, | |
543 | &method_node); | |
4be44fcd | 544 | if (ACPI_SUCCESS(status)) { |
1da177e4 LT |
545 | /* |
546 | * The _REG method is optional and there can be only one per region | |
9f15fc66 | 547 | * definition. This will be executed when the handler is attached |
1da177e4 LT |
548 | * or removed |
549 | */ | |
550 | region_obj2->extra.method_REG = method_node; | |
551 | } | |
552 | ||
553 | /* | |
554 | * The following loop depends upon the root Node having no parent | |
7b738064 | 555 | * ie: acpi_gbl_root_node->Parent being set to NULL |
1da177e4 LT |
556 | */ |
557 | while (node) { | |
52fc0b02 | 558 | |
1da177e4 LT |
559 | /* Check to see if a handler exists */ |
560 | ||
561 | handler_obj = NULL; | |
4be44fcd | 562 | obj_desc = acpi_ns_get_attached_object(node); |
1da177e4 | 563 | if (obj_desc) { |
52fc0b02 | 564 | |
1da177e4 LT |
565 | /* Can only be a handler if the object exists */ |
566 | ||
567 | switch (node->type) { | |
568 | case ACPI_TYPE_DEVICE: | |
569 | ||
570 | handler_obj = obj_desc->device.handler; | |
571 | break; | |
572 | ||
573 | case ACPI_TYPE_PROCESSOR: | |
574 | ||
575 | handler_obj = obj_desc->processor.handler; | |
576 | break; | |
577 | ||
578 | case ACPI_TYPE_THERMAL: | |
579 | ||
580 | handler_obj = obj_desc->thermal_zone.handler; | |
581 | break; | |
582 | ||
e31c32cf LM |
583 | case ACPI_TYPE_METHOD: |
584 | /* | |
585 | * If we are executing module level code, the original | |
586 | * Node's object was replaced by this Method object and we | |
587 | * saved the handler in the method object. | |
588 | * | |
589 | * See acpi_ns_exec_module_code | |
590 | */ | |
591 | if (obj_desc->method. | |
26294842 | 592 | info_flags & ACPI_METHOD_MODULE_LEVEL) { |
e31c32cf | 593 | handler_obj = |
26294842 | 594 | obj_desc->method.dispatch.handler; |
e31c32cf LM |
595 | } |
596 | break; | |
597 | ||
1da177e4 | 598 | default: |
1d1ea1b7 | 599 | |
1da177e4 | 600 | /* Ignore other objects */ |
1d1ea1b7 | 601 | |
1da177e4 LT |
602 | break; |
603 | } | |
604 | ||
605 | while (handler_obj) { | |
52fc0b02 | 606 | |
1da177e4 LT |
607 | /* Is this handler of the correct type? */ |
608 | ||
4be44fcd LB |
609 | if (handler_obj->address_space.space_id == |
610 | space_id) { | |
52fc0b02 | 611 | |
1da177e4 LT |
612 | /* Found correct handler */ |
613 | ||
4be44fcd LB |
614 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
615 | "Found handler %p for region %p in obj %p\n", | |
616 | handler_obj, | |
617 | region_obj, | |
618 | obj_desc)); | |
1da177e4 | 619 | |
4be44fcd LB |
620 | status = |
621 | acpi_ev_attach_region(handler_obj, | |
622 | region_obj, | |
623 | acpi_ns_locked); | |
1da177e4 LT |
624 | |
625 | /* | |
d4913dc6 BM |
626 | * Tell all users that this region is usable by |
627 | * running the _REG method | |
1da177e4 LT |
628 | */ |
629 | if (acpi_ns_locked) { | |
4be44fcd LB |
630 | status = |
631 | acpi_ut_release_mutex | |
632 | (ACPI_MTX_NAMESPACE); | |
633 | if (ACPI_FAILURE(status)) { | |
634 | return_ACPI_STATUS | |
635 | (status); | |
1da177e4 LT |
636 | } |
637 | } | |
638 | ||
4be44fcd LB |
639 | status = |
640 | acpi_ev_execute_reg_method | |
e2066ca1 | 641 | (region_obj, ACPI_REG_CONNECT); |
1da177e4 LT |
642 | |
643 | if (acpi_ns_locked) { | |
4be44fcd LB |
644 | status = |
645 | acpi_ut_acquire_mutex | |
646 | (ACPI_MTX_NAMESPACE); | |
647 | if (ACPI_FAILURE(status)) { | |
648 | return_ACPI_STATUS | |
649 | (status); | |
1da177e4 LT |
650 | } |
651 | } | |
652 | ||
4be44fcd | 653 | return_ACPI_STATUS(AE_OK); |
1da177e4 LT |
654 | } |
655 | ||
656 | /* Try next handler in the list */ | |
657 | ||
658 | handler_obj = handler_obj->address_space.next; | |
659 | } | |
660 | } | |
661 | ||
9f15fc66 BM |
662 | /* This node does not have the handler we need; Pop up one level */ |
663 | ||
c45b5c09 | 664 | node = node->parent; |
1da177e4 LT |
665 | } |
666 | ||
667 | /* If we get here, there is no handler for this region */ | |
668 | ||
4be44fcd | 669 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
b229cf92 | 670 | "No handler for RegionType %s(%X) (RegionObj %p)\n", |
4be44fcd LB |
671 | acpi_ut_get_region_name(space_id), space_id, |
672 | region_obj)); | |
1da177e4 | 673 | |
4be44fcd | 674 | return_ACPI_STATUS(AE_NOT_EXIST); |
1da177e4 | 675 | } |