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