File: /usr/src/linux/drivers/acpi/events/evrgnini.c

1     /******************************************************************************
2      *
3      * Module Name: evrgnini- ACPI Address_space (Op_region) init
4      *              $Revision: 46 $
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         ("evrgnini")
35     
36     
37     /*******************************************************************************
38      *
39      * FUNCTION:    Acpi_ev_system_memory_region_setup
40      *
41      * PARAMETERS:  Region_obj          - region we are interested in
42      *              Function            - start or stop
43      *              Handler_context     - Address space handler context
44      *              Region_context      - Region specific context
45      *
46      * RETURN:      Status
47      *
48      * DESCRIPTION: Do any prep work for region handling, a nop for now
49      *
50      ******************************************************************************/
51     
52     acpi_status
53     acpi_ev_system_memory_region_setup (
54     	acpi_handle             handle,
55     	u32                     function,
56     	void                    *handler_context,
57     	void                    **region_context)
58     {
59     	FUNCTION_TRACE ("Ev_system_memory_region_setup");
60     
61     
62     	if (function == ACPI_REGION_DEACTIVATE) {
63     		if (*region_context) {
64     			ACPI_MEM_FREE (*region_context);
65     			*region_context = NULL;
66     		}
67     		return_ACPI_STATUS (AE_OK);
68     	}
69     
70     
71     	/* Activate.  Create a new context */
72     
73     	*region_context = ACPI_MEM_CALLOCATE (sizeof (acpi_mem_space_context));
74     	if (!(*region_context)) {
75     		return_ACPI_STATUS (AE_NO_MEMORY);
76     	}
77     
78     	return_ACPI_STATUS (AE_OK);
79     }
80     
81     
82     /*******************************************************************************
83      *
84      * FUNCTION:    Acpi_ev_io_space_region_setup
85      *
86      * PARAMETERS:  Region_obj          - region we are interested in
87      *              Function            - start or stop
88      *              Handler_context     - Address space handler context
89      *              Region_context      - Region specific context
90      *
91      * RETURN:      Status
92      *
93      * DESCRIPTION: Do any prep work for region handling
94      *
95      ******************************************************************************/
96     
97     acpi_status
98     acpi_ev_io_space_region_setup (
99     	acpi_handle             handle,
100     	u32                     function,
101     	void                    *handler_context,
102     	void                    **region_context)
103     {
104     	FUNCTION_TRACE ("Ev_io_space_region_setup");
105     
106     
107     	if (function == ACPI_REGION_DEACTIVATE) {
108     		*region_context = NULL;
109     	}
110     	else {
111     		*region_context = handler_context;
112     	}
113     
114     	return_ACPI_STATUS (AE_OK);
115     }
116     
117     
118     /*******************************************************************************
119      *
120      * FUNCTION:    Acpi_ev_pci_config_region_setup
121      *
122      * PARAMETERS:  Region_obj          - region we are interested in
123      *              Function            - start or stop
124      *              Handler_context     - Address space handler context
125      *              Region_context      - Region specific context
126      *
127      * RETURN:      Status
128      *
129      * DESCRIPTION: Do any prep work for region handling
130      *
131      * MUTEX:       Assumes namespace is not locked
132      *
133      ******************************************************************************/
134     
135     acpi_status
136     acpi_ev_pci_config_region_setup (
137     	acpi_handle             handle,
138     	u32                     function,
139     	void                    *handler_context,
140     	void                    **region_context)
141     {
142     	acpi_status             status = AE_OK;
143     	acpi_integer            temp;
144     	acpi_pci_id             *pci_id = *region_context;
145     	acpi_operand_object     *handler_obj;
146     	acpi_namespace_node     *node;
147     	acpi_operand_object     *region_obj = (acpi_operand_object *) handle;
148     	ACPI_DEVICE_ID          object_hID;
149     
150     
151     	FUNCTION_TRACE ("Ev_pci_config_region_setup");
152     
153     
154     	handler_obj = region_obj->region.addr_handler;
155     	if (!handler_obj) {
156     		/*
157     		 *  No installed handler. This shouldn't happen because the dispatch
158     		 *  routine checks before we get here, but we check again just in case.
159     		 */
160     		ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
161     			"Attempting to init a region %X, with no handler\n", region_obj));
162     		return_ACPI_STATUS (AE_NOT_EXIST);
163     	}
164     
165     	if (function == ACPI_REGION_DEACTIVATE) {
166     		if (pci_id) {
167     			ACPI_MEM_FREE (pci_id);
168     			*region_context = NULL;
169     		}
170     
171     		return_ACPI_STATUS (status);
172     	}
173     
174     
175     	/* Create a new context */
176     
177     	pci_id = ACPI_MEM_CALLOCATE (sizeof (acpi_pci_id));
178     	if (!pci_id) {
179     		return_ACPI_STATUS (AE_NO_MEMORY);
180     	}
181     
182     	/*
183     	 *  For PCI Config space access, we have to pass the segment, bus,
184     	 *  device and function numbers.  This routine must acquire those.
185     	 */
186     
187     	/*
188     	 *  First get device and function numbers from the _ADR object
189     	 *  in the parent's scope.
190     	 */
191     	node = acpi_ns_get_parent_object (region_obj->region.node);
192     
193     
194     	/* Acpi_evaluate the _ADR object */
195     
196     	status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node, &temp);
197     
198     	/*
199     	 *  The default is zero, since the allocation above zeroed the data, just
200     	 *  do nothing on failures.
201     	 */
202     	if (ACPI_SUCCESS (status)) {
203     		pci_id->device = HIWORD (temp);
204     		pci_id->function = LOWORD (temp);
205     	}
206     
207     	/*
208     	 *  Get the _SEG and _BBN values from the device upon which the handler
209     	 *  is installed.
210     	 *
211     	 *  We need to get the _SEG and _BBN objects relative to the PCI BUS device.
212     	 *  This is the device the handler has been registered to handle.
213     	 */
214     
215     	/*
216     	 *  If the Addr_handler.Node is still pointing to the root, we need
217     	 *  to scan upward for a PCI Root bridge and re-associate the Op_region
218     	 *  handlers with that device.
219     	 */
220     	if (handler_obj->addr_handler.node == acpi_gbl_root_node) {
221     		/*
222     		 * Node is currently the parent object
223     		 */
224     		while (node != acpi_gbl_root_node) {
225     			status = acpi_ut_execute_HID (node, &object_hID);
226     			if (ACPI_SUCCESS (status)) {
227     				if (!(STRNCMP (object_hID.buffer, PCI_ROOT_HID_STRING,
228     						   sizeof (PCI_ROOT_HID_STRING)))) {
229     					acpi_install_address_space_handler (node,
230     							   ACPI_ADR_SPACE_PCI_CONFIG,
231     							   ACPI_DEFAULT_HANDLER, NULL, NULL);
232     					break;
233     				}
234     			}
235     
236     			node = acpi_ns_get_parent_object (node);
237     		}
238     	}
239     	else {
240     		node = handler_obj->addr_handler.node;
241     	}
242     
243     	/*
244     	 * The PCI segment number comes from the _SEG method
245     	 */
246     	status = acpi_ut_evaluate_numeric_object (METHOD_NAME__SEG, node, &temp);
247     	if (ACPI_SUCCESS (status)) {
248     		pci_id->segment = LOWORD (temp);
249     	}
250     
251     	/*
252     	 * The PCI bus number comes from the _BBN method
253     	 */
254     	status = acpi_ut_evaluate_numeric_object (METHOD_NAME__BBN, node, &temp);
255     	if (ACPI_SUCCESS (status)) {
256     		pci_id->bus = LOWORD (temp);
257     	}
258     
259     	*region_context = pci_id;
260     	return_ACPI_STATUS (AE_OK);
261     }
262     
263     
264     /*******************************************************************************
265      *
266      * FUNCTION:    Acpi_ev_default_region_setup
267      *
268      * PARAMETERS:  Region_obj          - region we are interested in
269      *              Function            - start or stop
270      *              Handler_context     - Address space handler context
271      *              Region_context      - Region specific context
272      *
273      * RETURN:      Status
274      *
275      * DESCRIPTION: Do any prep work for region handling
276      *
277      ******************************************************************************/
278     
279     acpi_status
280     acpi_ev_default_region_setup (
281     	acpi_handle             handle,
282     	u32                     function,
283     	void                    *handler_context,
284     	void                    **region_context)
285     {
286     	FUNCTION_TRACE ("Ev_default_region_setup");
287     
288     
289     	if (function == ACPI_REGION_DEACTIVATE) {
290     		*region_context = NULL;
291     	}
292     	else {
293     		*region_context = handler_context;
294     	}
295     
296     	return_ACPI_STATUS (AE_OK);
297     }
298     
299     
300     /*******************************************************************************
301      *
302      * FUNCTION:    Acpi_ev_initialize_region
303      *
304      * PARAMETERS:  Region_obj - Region we are initializing
305      *
306      * RETURN:      Status
307      *
308      * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
309      *              for execution at a later time
310      *
311      *              Get the appropriate address space handler for a newly
312      *              created region.
313      *
314      *              This also performs address space specific intialization.  For
315      *              example, PCI regions must have an _ADR object that contains
316      *              a PCI address in the scope of the definition.  This address is
317      *              required to perform an access to PCI config space.
318      *
319      ******************************************************************************/
320     
321     acpi_status
322     acpi_ev_initialize_region (
323     	acpi_operand_object     *region_obj,
324     	u8                      acpi_ns_locked)
325     {
326     	acpi_operand_object     *handler_obj;
327     	acpi_operand_object     *obj_desc;
328     	ACPI_ADR_SPACE_TYPE     space_id;
329     	acpi_namespace_node     *node;
330     	acpi_status             status;
331     	acpi_namespace_node     *method_node;
332     	acpi_name               *reg_name_ptr = (acpi_name *) METHOD_NAME__REG;
333     
334     
335     	FUNCTION_TRACE_U32 ("Ev_initialize_region", acpi_ns_locked);
336     
337     
338     	if (!region_obj) {
339     		return_ACPI_STATUS (AE_BAD_PARAMETER);
340     	}
341     
342     	node = acpi_ns_get_parent_object (region_obj->region.node);
343     	space_id = region_obj->region.space_id;
344     
345     	region_obj->region.addr_handler = NULL;
346     	region_obj->region.extra->extra.method_REG = NULL;
347     	region_obj->region.flags &= ~(AOPOBJ_INITIALIZED);
348     
349     	/*
350     	 *  Find any "_REG" associated with this region definition
351     	 */
352     	status = acpi_ns_search_node (*reg_name_ptr, node,
353     			  ACPI_TYPE_METHOD, &method_node);
354     	if (ACPI_SUCCESS (status)) {
355     		/*
356     		 *  The _REG method is optional and there can be only one per region
357     		 *  definition.  This will be executed when the handler is attached
358     		 *  or removed
359     		 */
360     		region_obj->region.extra->extra.method_REG = method_node;
361     	}
362     
363     	/*
364     	 *  The following loop depends upon the root Node having no parent
365     	 *  ie: Acpi_gbl_Root_node->Parent_entry being set to NULL
366     	 */
367     	while (node) {
368     		/*
369     		 *  Check to see if a handler exists
370     		 */
371     		handler_obj = NULL;
372     		obj_desc = acpi_ns_get_attached_object (node);
373     		if (obj_desc) {
374     			/*
375     			 *  can only be a handler if the object exists
376     			 */
377     			switch (node->type) {
378     			case ACPI_TYPE_DEVICE:
379     
380     				handler_obj = obj_desc->device.addr_handler;
381     				break;
382     
383     			case ACPI_TYPE_PROCESSOR:
384     
385     				handler_obj = obj_desc->processor.addr_handler;
386     				break;
387     
388     			case ACPI_TYPE_THERMAL:
389     
390     				handler_obj = obj_desc->thermal_zone.addr_handler;
391     				break;
392     			}
393     
394     			while (handler_obj) {
395     				/*
396     				 *  This guy has at least one address handler
397     				 *  see if it has the type we want
398     				 */
399     				if (handler_obj->addr_handler.space_id == space_id) {
400     					ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
401     						"Found handler %p for region %p in obj %p\n",
402     						handler_obj, region_obj, obj_desc));
403     
404     					/*
405     					 *  Found it! Now update the region and the handler
406     					 */
407     					acpi_ev_associate_region_and_handler (handler_obj, region_obj,
408     							acpi_ns_locked);
409     					return_ACPI_STATUS (AE_OK);
410     				}
411     
412     				handler_obj = handler_obj->addr_handler.next;
413     
414     			} /* while handlerobj */
415     		}
416     
417     		/*
418     		 *  This one does not have the handler we need
419     		 *  Pop up one level
420     		 */
421     		node = acpi_ns_get_parent_object (node);
422     
423     	} /* while Node != ROOT */
424     
425     	/*
426     	 *  If we get here, there is no handler for this region
427     	 */
428     	ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
429     		"No handler for Region_type %s(%X) (Region_obj %p)\n",
430     		acpi_ut_get_region_name (space_id), space_id, region_obj));
431     
432     	return_ACPI_STATUS (AE_NOT_EXIST);
433     }
434     
435