File: /usr/src/linux/drivers/acpi/events/evregion.c
1 /******************************************************************************
2 *
3 * Module Name: evregion - ACPI Address_space (Op_region) handler dispatch
4 * $Revision: 110 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include "acpi.h"
28 #include "acevents.h"
29 #include "acnamesp.h"
30 #include "acinterp.h"
31 #include "amlcode.h"
32
33 #define _COMPONENT ACPI_EVENTS
34 MODULE_NAME ("evregion")
35
36
37 /*******************************************************************************
38 *
39 * FUNCTION: Acpi_ev_install_default_address_space_handlers
40 *
41 * PARAMETERS:
42 *
43 * RETURN: Status
44 *
45 * DESCRIPTION: Installs the core subsystem address space handlers.
46 *
47 ******************************************************************************/
48
49 acpi_status
50 acpi_ev_install_default_address_space_handlers (
51 void)
52 {
53 acpi_status status;
54
55
56 FUNCTION_TRACE ("Ev_install_default_address_space_handlers");
57
58
59 /*
60 * All address spaces (PCI Config, EC, SMBus) are scope dependent
61 * and registration must occur for a specific device. In the case
62 * system memory and IO address spaces there is currently no device
63 * associated with the address space. For these we use the root.
64 * We install the default PCI config space handler at the root so
65 * that this space is immediately available even though the we have
66 * not enumerated all the PCI Root Buses yet. This is to conform
67 * to the ACPI specification which states that the PCI config
68 * space must be always available -- even though we are nowhere
69 * near ready to find the PCI root buses at this point.
70 *
71 * NOTE: We ignore AE_EXIST because this means that a handler has
72 * already been installed (via Acpi_install_address_space_handler)
73 */
74 status = acpi_install_address_space_handler (acpi_gbl_root_node,
75 ACPI_ADR_SPACE_SYSTEM_MEMORY,
76 ACPI_DEFAULT_HANDLER, NULL, NULL);
77 if ((ACPI_FAILURE (status)) &&
78 (status != AE_EXIST)) {
79 return_ACPI_STATUS (status);
80 }
81
82 status = acpi_install_address_space_handler (acpi_gbl_root_node,
83 ACPI_ADR_SPACE_SYSTEM_IO,
84 ACPI_DEFAULT_HANDLER, NULL, NULL);
85 if ((ACPI_FAILURE (status)) &&
86 (status != AE_EXIST)) {
87 return_ACPI_STATUS (status);
88 }
89
90 status = acpi_install_address_space_handler (acpi_gbl_root_node,
91 ACPI_ADR_SPACE_PCI_CONFIG,
92 ACPI_DEFAULT_HANDLER, NULL, NULL);
93 if ((ACPI_FAILURE (status)) &&
94 (status != AE_EXIST)) {
95 return_ACPI_STATUS (status);
96 }
97
98
99 return_ACPI_STATUS (AE_OK);
100 }
101
102
103 /* TBD: [Restructure] Move elsewhere */
104
105 /*******************************************************************************
106 *
107 * FUNCTION: Acpi_ev_execute_reg_method
108 *
109 * PARAMETERS: Region_obj - Object structure
110 * Function - On (1) or Off (0)
111 *
112 * RETURN: Status
113 *
114 * DESCRIPTION: Execute _REG method for a region
115 *
116 ******************************************************************************/
117
118 static acpi_status
119 acpi_ev_execute_reg_method (
120 acpi_operand_object *region_obj,
121 u32 function)
122 {
123 acpi_operand_object *params[3];
124 acpi_status status;
125
126
127 FUNCTION_TRACE ("Ev_execute_reg_method");
128
129
130 if (region_obj->region.extra->extra.method_REG == NULL) {
131 return_ACPI_STATUS (AE_OK);
132 }
133
134 /*
135 * _REG method has two arguments
136 * Arg0: Integer: Operation region space ID
137 * Same value as Region_obj->Region.Space_id
138 * Arg1: Integer: connection status
139 * 1 for connecting the handler,
140 * 0 for disconnecting the handler
141 * Passed as a parameter
142 */
143 params[0] = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
144 if (!params[0]) {
145 return_ACPI_STATUS (AE_NO_MEMORY);
146 }
147
148 params[1] = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
149 if (!params[1]) {
150 acpi_ut_remove_reference (params[0]);
151 return_ACPI_STATUS (AE_NO_MEMORY);
152 }
153
154 params[2] = NULL;
155
156 /*
157 * Set up the parameter objects
158 */
159 params[0]->integer.value = region_obj->region.space_id;
160 params[1]->integer.value = function;
161
162 /*
163 * Execute the method, no return value
164 */
165 DEBUG_EXEC(acpi_ut_display_init_pathname (region_obj->region.extra->extra.method_REG, " [Method]"));
166 status = acpi_ns_evaluate_by_handle (region_obj->region.extra->extra.method_REG, params, NULL);
167
168
169 acpi_ut_remove_reference (params[0]);
170 acpi_ut_remove_reference (params[1]);
171
172 return_ACPI_STATUS (status);
173 }
174
175
176 /*******************************************************************************
177 *
178 * FUNCTION: Acpi_ev_address_space_dispatch
179 *
180 * PARAMETERS: Region_obj - internal region object
181 * Space_id - ID of the address space (0-255)
182 * Function - Read or Write operation
183 * Address - Where in the space to read or write
184 * Bit_width - Field width in bits (8, 16, or 32)
185 * Value - Pointer to in or out value
186 *
187 * RETURN: Status
188 *
189 * DESCRIPTION: Dispatch an address space or operation region access to
190 * a previously installed handler.
191 *
192 ******************************************************************************/
193
194 acpi_status
195 acpi_ev_address_space_dispatch (
196 acpi_operand_object *region_obj,
197 u32 function,
198 ACPI_PHYSICAL_ADDRESS address,
199 u32 bit_width,
200 u32 *value)
201 {
202 acpi_status status;
203 ACPI_ADR_SPACE_HANDLER handler;
204 ACPI_ADR_SPACE_SETUP region_setup;
205 acpi_operand_object *handler_desc;
206 void *region_context = NULL;
207
208
209 FUNCTION_TRACE ("Ev_address_space_dispatch");
210
211
212 /*
213 * Ensure that there is a handler associated with this region
214 */
215 handler_desc = region_obj->region.addr_handler;
216 if (!handler_desc) {
217 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "no handler for region(%p) [%s]\n",
218 region_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
219
220 return_ACPI_STATUS(AE_NOT_EXIST);
221 }
222
223 /*
224 * It may be the case that the region has never been initialized
225 * Some types of regions require special init code
226 */
227 if (!(region_obj->region.flags & AOPOBJ_INITIALIZED)) {
228 /*
229 * This region has not been initialized yet, do it
230 */
231 region_setup = handler_desc->addr_handler.setup;
232 if (!region_setup) {
233 /*
234 * Bad news, no init routine and not init'd
235 */
236 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No init routine for region(%p) [%s]\n",
237 region_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
238 return_ACPI_STATUS (AE_UNKNOWN_STATUS);
239 }
240
241 /*
242 * We must exit the interpreter because the region setup will potentially
243 * execute control methods
244 */
245 acpi_ex_exit_interpreter ();
246
247 status = region_setup (region_obj, ACPI_REGION_ACTIVATE,
248 handler_desc->addr_handler.context, ®ion_context);
249
250 /* Re-enter the interpreter */
251
252 acpi_ex_enter_interpreter ();
253
254 /*
255 * Init routine may fail
256 */
257 if (ACPI_FAILURE (status)) {
258 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region Init: %s [%s]\n",
259 acpi_format_exception (status),
260 acpi_ut_get_region_name (region_obj->region.space_id)));
261 return_ACPI_STATUS(status);
262 }
263
264 region_obj->region.flags |= AOPOBJ_INITIALIZED;
265
266 /*
267 * Save the returned context for use in all accesses to
268 * this particular region.
269 */
270 region_obj->region.extra->extra.region_context = region_context;
271 }
272
273 /*
274 * We have everything we need, begin the process
275 */
276 handler = handler_desc->addr_handler.handler;
277
278 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
279 "Addrhandler %p (%p), Address %8.8lX%8.8lX\n",
280 ®ion_obj->region.addr_handler->addr_handler, handler, HIDWORD(address),
281 LODWORD(address)));
282
283 if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) {
284 /*
285 * For handlers other than the default (supplied) handlers, we must
286 * exit the interpreter because the handler *might* block -- we don't
287 * know what it will do, so we can't hold the lock on the intepreter.
288 */
289 acpi_ex_exit_interpreter();
290 }
291
292 /*
293 * Invoke the handler.
294 */
295 status = handler (function, address, bit_width, value,
296 handler_desc->addr_handler.context,
297 region_obj->region.extra->extra.region_context);
298
299 if (ACPI_FAILURE (status)) {
300 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region handler: %s [%s]\n",
301 acpi_format_exception (status),
302 acpi_ut_get_region_name (region_obj->region.space_id)));
303 }
304
305 if (!(handler_desc->addr_handler.flags & ADDR_HANDLER_DEFAULT_INSTALLED)) {
306 /*
307 * We just returned from a non-default handler, we must re-enter the
308 * interpreter
309 */
310 acpi_ex_enter_interpreter ();
311 }
312
313 return_ACPI_STATUS (status);
314 }
315
316 /*******************************************************************************
317 *
318 * FUNCTION: Acpi_ev_disassociate_region_from_handler
319 *
320 * PARAMETERS: Region_obj - Region Object
321 * Acpi_ns_is_locked - Namespace Region Already Locked?
322 *
323 * RETURN: None
324 *
325 * DESCRIPTION: Break the association between the handler and the region
326 * this is a two way association.
327 *
328 ******************************************************************************/
329
330 void
331 acpi_ev_disassociate_region_from_handler(
332 acpi_operand_object *region_obj,
333 u8 acpi_ns_is_locked)
334 {
335 acpi_operand_object *handler_obj;
336 acpi_operand_object *obj_desc;
337 acpi_operand_object **last_obj_ptr;
338 ACPI_ADR_SPACE_SETUP region_setup;
339 void *region_context;
340 acpi_status status;
341
342
343 FUNCTION_TRACE ("Ev_disassociate_region_from_handler");
344
345
346 region_context = region_obj->region.extra->extra.region_context;
347
348 /*
349 * Get the address handler from the region object
350 */
351 handler_obj = region_obj->region.addr_handler;
352 if (!handler_obj) {
353 /*
354 * This region has no handler, all done
355 */
356 return_VOID;
357 }
358
359
360 /*
361 * Find this region in the handler's list
362 */
363 obj_desc = handler_obj->addr_handler.region_list;
364 last_obj_ptr = &handler_obj->addr_handler.region_list;
365
366 while (obj_desc) {
367 /*
368 * See if this is the one
369 */
370 if (obj_desc == region_obj) {
371 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
372 "Removing Region %p from address handler %p\n",
373 region_obj, handler_obj));
374 /*
375 * This is it, remove it from the handler's list
376 */
377 *last_obj_ptr = obj_desc->region.next;
378 obj_desc->region.next = NULL; /* Must clear field */
379
380 if (acpi_ns_is_locked) {
381 acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
382 }
383
384 /*
385 * Now stop region accesses by executing the _REG method
386 */
387 acpi_ev_execute_reg_method (region_obj, 0);
388
389 if (acpi_ns_is_locked) {
390 acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
391 }
392
393 /*
394 * Call the setup handler with the deactivate notification
395 */
396 region_setup = handler_obj->addr_handler.setup;
397 status = region_setup (region_obj, ACPI_REGION_DEACTIVATE,
398 handler_obj->addr_handler.context, ®ion_context);
399
400 /*
401 * Init routine may fail, Just ignore errors
402 */
403 if (ACPI_FAILURE (status)) {
404 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s from region init, [%s]\n",
405 acpi_format_exception (status),
406 acpi_ut_get_region_name (region_obj->region.space_id)));
407 }
408
409 region_obj->region.flags &= ~(AOPOBJ_INITIALIZED);
410
411 /*
412 * Remove handler reference in the region
413 *
414 * NOTE: this doesn't mean that the region goes away
415 * The region is just inaccessible as indicated to
416 * the _REG method
417 *
418 * If the region is on the handler's list
419 * this better be the region's handler
420 */
421 region_obj->region.addr_handler = NULL;
422
423 return_VOID;
424
425 } /* found the right handler */
426
427 /*
428 * Move through the linked list of handlers
429 */
430 last_obj_ptr = &obj_desc->region.next;
431 obj_desc = obj_desc->region.next;
432 }
433
434 /*
435 * If we get here, the region was not in the handler's region list
436 */
437 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
438 "Cannot remove region %p from address handler %p\n",
439 region_obj, handler_obj));
440
441 return_VOID;
442 }
443
444
445 /*******************************************************************************
446 *
447 * FUNCTION: Acpi_ev_associate_region_and_handler
448 *
449 * PARAMETERS: Handler_obj - Handler Object
450 * Region_obj - Region Object
451 * Acpi_ns_is_locked - Namespace Region Already Locked?
452 *
453 * RETURN: None
454 *
455 * DESCRIPTION: Create the association between the handler and the region
456 * this is a two way association.
457 *
458 ******************************************************************************/
459
460 acpi_status
461 acpi_ev_associate_region_and_handler (
462 acpi_operand_object *handler_obj,
463 acpi_operand_object *region_obj,
464 u8 acpi_ns_is_locked)
465 {
466 acpi_status status;
467
468
469 FUNCTION_TRACE ("Ev_associate_region_and_handler");
470
471
472 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
473 "Adding Region %p to address handler %p [%s]\n",
474 region_obj, handler_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
475
476
477 /*
478 * Link this region to the front of the handler's list
479 */
480 region_obj->region.next = handler_obj->addr_handler.region_list;
481 handler_obj->addr_handler.region_list = region_obj;
482
483 /*
484 * set the region's handler
485 */
486 region_obj->region.addr_handler = handler_obj;
487
488 /*
489 * Last thing, tell all users that this region is usable
490 */
491 if (acpi_ns_is_locked) {
492 acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
493 }
494
495 status = acpi_ev_execute_reg_method (region_obj, 1);
496
497 if (acpi_ns_is_locked) {
498 acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
499 }
500
501 return_ACPI_STATUS (status);
502 }
503
504
505 /*******************************************************************************
506 *
507 * FUNCTION: Acpi_ev_addr_handler_helper
508 *
509 * PARAMETERS: Handle - Node to be dumped
510 * Level - Nesting level of the handle
511 * Context - Passed into Acpi_ns_walk_namespace
512 *
513 * DESCRIPTION: This routine checks to see if the object is a Region if it
514 * is then the address handler is installed in it.
515 *
516 * If the Object is a Device, and the device has a handler of
517 * the same type then the search is terminated in that branch.
518 *
519 * This is because the existing handler is closer in proximity
520 * to any more regions than the one we are trying to install.
521 *
522 ******************************************************************************/
523
524 acpi_status
525 acpi_ev_addr_handler_helper (
526 acpi_handle obj_handle,
527 u32 level,
528 void *context,
529 void **return_value)
530 {
531 acpi_operand_object *handler_obj;
532 acpi_operand_object *tmp_obj;
533 acpi_operand_object *obj_desc;
534 acpi_namespace_node *node;
535 acpi_status status;
536
537
538 PROC_NAME ("Ev_addr_handler_helper");
539
540
541 handler_obj = (acpi_operand_object *) context;
542
543 /* Parameter validation */
544
545 if (!handler_obj) {
546 return (AE_OK);
547 }
548
549 /* Convert and validate the device handle */
550
551 node = acpi_ns_convert_handle_to_entry (obj_handle);
552 if (!node) {
553 return (AE_BAD_PARAMETER);
554 }
555
556 /*
557 * We only care about regions.and objects
558 * that can have address handlers
559 */
560 if ((node->type != ACPI_TYPE_DEVICE) &&
561 (node->type != ACPI_TYPE_REGION) &&
562 (node != acpi_gbl_root_node)) {
563 return (AE_OK);
564 }
565
566 /* Check for an existing internal object */
567
568 obj_desc = acpi_ns_get_attached_object (node);
569 if (!obj_desc) {
570 /*
571 * The object DNE, we don't care about it
572 */
573 return (AE_OK);
574 }
575
576 /*
577 * Devices are handled different than regions
578 */
579 if (IS_THIS_OBJECT_TYPE (obj_desc, ACPI_TYPE_DEVICE)) {
580 /*
581 * See if this guy has any handlers
582 */
583 tmp_obj = obj_desc->device.addr_handler;
584 while (tmp_obj) {
585 /*
586 * Now let's see if it's for the same address space.
587 */
588 if (tmp_obj->addr_handler.space_id == handler_obj->addr_handler.space_id) {
589 /*
590 * It's for the same address space
591 */
592 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
593 "Found handler for region [%s] in device %p(%p) handler %p\n",
594 acpi_ut_get_region_name (handler_obj->addr_handler.space_id),
595 obj_desc, tmp_obj, handler_obj));
596
597 /*
598 * Since the object we found it on was a device, then it
599 * means that someone has already installed a handler for
600 * the branch of the namespace from this device on. Just
601 * bail out telling the walk routine to not traverse this
602 * branch. This preserves the scoping rule for handlers.
603 */
604 return (AE_CTRL_DEPTH);
605 }
606
607 /*
608 * Move through the linked list of handlers
609 */
610 tmp_obj = tmp_obj->addr_handler.next;
611 }
612
613 /*
614 * As long as the device didn't have a handler for this
615 * space we don't care about it. We just ignore it and
616 * proceed.
617 */
618 return (AE_OK);
619 }
620
621 /*
622 * Only here if it was a region
623 */
624 if (obj_desc->region.space_id != handler_obj->addr_handler.space_id) {
625 /*
626 * This region is for a different address space
627 * ignore it
628 */
629 return (AE_OK);
630 }
631
632 /*
633 * Now we have a region and it is for the handler's address
634 * space type.
635 *
636 * First disconnect region for any previous handler (if any)
637 */
638 acpi_ev_disassociate_region_from_handler (obj_desc, FALSE);
639
640 /*
641 * Then connect the region to the new handler
642 */
643 status = acpi_ev_associate_region_and_handler (handler_obj, obj_desc, FALSE);
644
645 return (status);
646 }
647
648
649