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