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, &region_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     		&region_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, &region_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