xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/evregion.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /******************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Module Name: evregion - Operation Region support
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) 2000 - 2020, Intel Corp.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  *****************************************************************************/
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <acpi/acpi.h>
11*4882a593Smuzhiyun #include "accommon.h"
12*4882a593Smuzhiyun #include "acevents.h"
13*4882a593Smuzhiyun #include "acnamesp.h"
14*4882a593Smuzhiyun #include "acinterp.h"
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #define _COMPONENT          ACPI_EVENTS
17*4882a593Smuzhiyun ACPI_MODULE_NAME("evregion")
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun extern u8 acpi_gbl_default_address_spaces[];
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun /* Local prototypes */
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static void
24*4882a593Smuzhiyun acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node);
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static acpi_status
27*4882a593Smuzhiyun acpi_ev_reg_run(acpi_handle obj_handle,
28*4882a593Smuzhiyun 		u32 level, void *context, void **return_value);
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /*******************************************************************************
31*4882a593Smuzhiyun  *
32*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_initialize_op_regions
33*4882a593Smuzhiyun  *
34*4882a593Smuzhiyun  * PARAMETERS:  None
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * RETURN:      Status
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * DESCRIPTION: Execute _REG methods for all Operation Regions that have
39*4882a593Smuzhiyun  *              an installed default region handler.
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  ******************************************************************************/
42*4882a593Smuzhiyun 
acpi_ev_initialize_op_regions(void)43*4882a593Smuzhiyun acpi_status acpi_ev_initialize_op_regions(void)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	acpi_status status;
46*4882a593Smuzhiyun 	u32 i;
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_initialize_op_regions);
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
51*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
52*4882a593Smuzhiyun 		return_ACPI_STATUS(status);
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* Run the _REG methods for op_regions in each default address space */
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 	for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
58*4882a593Smuzhiyun 		/*
59*4882a593Smuzhiyun 		 * Make sure the installed handler is the DEFAULT handler. If not the
60*4882a593Smuzhiyun 		 * default, the _REG methods will have already been run (when the
61*4882a593Smuzhiyun 		 * handler was installed)
62*4882a593Smuzhiyun 		 */
63*4882a593Smuzhiyun 		if (acpi_ev_has_default_handler(acpi_gbl_root_node,
64*4882a593Smuzhiyun 						acpi_gbl_default_address_spaces
65*4882a593Smuzhiyun 						[i])) {
66*4882a593Smuzhiyun 			acpi_ev_execute_reg_methods(acpi_gbl_root_node,
67*4882a593Smuzhiyun 						    acpi_gbl_default_address_spaces
68*4882a593Smuzhiyun 						    [i], ACPI_REG_CONNECT);
69*4882a593Smuzhiyun 		}
70*4882a593Smuzhiyun 	}
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
73*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /*******************************************************************************
77*4882a593Smuzhiyun  *
78*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_address_space_dispatch
79*4882a593Smuzhiyun  *
80*4882a593Smuzhiyun  * PARAMETERS:  region_obj          - Internal region object
81*4882a593Smuzhiyun  *              field_obj           - Corresponding field. Can be NULL.
82*4882a593Smuzhiyun  *              function            - Read or Write operation
83*4882a593Smuzhiyun  *              region_offset       - Where in the region to read or write
84*4882a593Smuzhiyun  *              bit_width           - Field width in bits (8, 16, 32, or 64)
85*4882a593Smuzhiyun  *              value               - Pointer to in or out value, must be
86*4882a593Smuzhiyun  *                                    a full 64-bit integer
87*4882a593Smuzhiyun  *
88*4882a593Smuzhiyun  * RETURN:      Status
89*4882a593Smuzhiyun  *
90*4882a593Smuzhiyun  * DESCRIPTION: Dispatch an address space or operation region access to
91*4882a593Smuzhiyun  *              a previously installed handler.
92*4882a593Smuzhiyun  *
93*4882a593Smuzhiyun  * NOTE: During early initialization, we always install the default region
94*4882a593Smuzhiyun  * handlers for Memory, I/O and PCI_Config. This ensures that these operation
95*4882a593Smuzhiyun  * region address spaces are always available as per the ACPI specification.
96*4882a593Smuzhiyun  * This is especially needed in order to support the execution of
97*4882a593Smuzhiyun  * module-level AML code during loading of the ACPI tables.
98*4882a593Smuzhiyun  *
99*4882a593Smuzhiyun  ******************************************************************************/
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun acpi_status
acpi_ev_address_space_dispatch(union acpi_operand_object * region_obj,union acpi_operand_object * field_obj,u32 function,u32 region_offset,u32 bit_width,u64 * value)102*4882a593Smuzhiyun acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
103*4882a593Smuzhiyun 			       union acpi_operand_object *field_obj,
104*4882a593Smuzhiyun 			       u32 function,
105*4882a593Smuzhiyun 			       u32 region_offset, u32 bit_width, u64 *value)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	acpi_status status;
108*4882a593Smuzhiyun 	acpi_adr_space_handler handler;
109*4882a593Smuzhiyun 	acpi_adr_space_setup region_setup;
110*4882a593Smuzhiyun 	union acpi_operand_object *handler_desc;
111*4882a593Smuzhiyun 	union acpi_operand_object *region_obj2;
112*4882a593Smuzhiyun 	void *region_context = NULL;
113*4882a593Smuzhiyun 	struct acpi_connection_info *context;
114*4882a593Smuzhiyun 	acpi_mutex context_mutex;
115*4882a593Smuzhiyun 	u8 context_locked;
116*4882a593Smuzhiyun 	acpi_physical_address address;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_address_space_dispatch);
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	region_obj2 = acpi_ns_get_secondary_object(region_obj);
121*4882a593Smuzhiyun 	if (!region_obj2) {
122*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NOT_EXIST);
123*4882a593Smuzhiyun 	}
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	/* Ensure that there is a handler associated with this region */
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	handler_desc = region_obj->region.handler;
128*4882a593Smuzhiyun 	if (!handler_desc) {
129*4882a593Smuzhiyun 		ACPI_ERROR((AE_INFO,
130*4882a593Smuzhiyun 			    "No handler for Region [%4.4s] (%p) [%s]",
131*4882a593Smuzhiyun 			    acpi_ut_get_node_name(region_obj->region.node),
132*4882a593Smuzhiyun 			    region_obj,
133*4882a593Smuzhiyun 			    acpi_ut_get_region_name(region_obj->region.
134*4882a593Smuzhiyun 						    space_id)));
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NOT_EXIST);
137*4882a593Smuzhiyun 	}
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	context = handler_desc->address_space.context;
140*4882a593Smuzhiyun 	context_mutex = handler_desc->address_space.context_mutex;
141*4882a593Smuzhiyun 	context_locked = FALSE;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/*
144*4882a593Smuzhiyun 	 * It may be the case that the region has never been initialized.
145*4882a593Smuzhiyun 	 * Some types of regions require special init code
146*4882a593Smuzhiyun 	 */
147*4882a593Smuzhiyun 	if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 		/* This region has not been initialized yet, do it */
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 		region_setup = handler_desc->address_space.setup;
152*4882a593Smuzhiyun 		if (!region_setup) {
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 			/* No initialization routine, exit with error */
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
157*4882a593Smuzhiyun 				    "No init routine for region(%p) [%s]",
158*4882a593Smuzhiyun 				    region_obj,
159*4882a593Smuzhiyun 				    acpi_ut_get_region_name(region_obj->region.
160*4882a593Smuzhiyun 							    space_id)));
161*4882a593Smuzhiyun 			return_ACPI_STATUS(AE_NOT_EXIST);
162*4882a593Smuzhiyun 		}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 		/*
165*4882a593Smuzhiyun 		 * We must exit the interpreter because the region setup will
166*4882a593Smuzhiyun 		 * potentially execute control methods (for example, the _REG method
167*4882a593Smuzhiyun 		 * for this region)
168*4882a593Smuzhiyun 		 */
169*4882a593Smuzhiyun 		acpi_ex_exit_interpreter();
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
172*4882a593Smuzhiyun 				      context, &region_context);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 		/* Re-enter the interpreter */
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 		acpi_ex_enter_interpreter();
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 		/* Check for failure of the Region Setup */
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
181*4882a593Smuzhiyun 			ACPI_EXCEPTION((AE_INFO, status,
182*4882a593Smuzhiyun 					"During region initialization: [%s]",
183*4882a593Smuzhiyun 					acpi_ut_get_region_name(region_obj->
184*4882a593Smuzhiyun 								region.
185*4882a593Smuzhiyun 								space_id)));
186*4882a593Smuzhiyun 			return_ACPI_STATUS(status);
187*4882a593Smuzhiyun 		}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 		/* Region initialization may have been completed by region_setup */
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
192*4882a593Smuzhiyun 			region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 			/*
195*4882a593Smuzhiyun 			 * Save the returned context for use in all accesses to
196*4882a593Smuzhiyun 			 * the handler for this particular region
197*4882a593Smuzhiyun 			 */
198*4882a593Smuzhiyun 			if (!(region_obj2->extra.region_context)) {
199*4882a593Smuzhiyun 				region_obj2->extra.region_context =
200*4882a593Smuzhiyun 				    region_context;
201*4882a593Smuzhiyun 			}
202*4882a593Smuzhiyun 		}
203*4882a593Smuzhiyun 	}
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	/* We have everything we need, we can invoke the address space handler */
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	handler = handler_desc->address_space.handler;
208*4882a593Smuzhiyun 	address = (region_obj->region.address + region_offset);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
211*4882a593Smuzhiyun 			  "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
212*4882a593Smuzhiyun 			  &region_obj->region.handler->address_space, handler,
213*4882a593Smuzhiyun 			  ACPI_FORMAT_UINT64(address),
214*4882a593Smuzhiyun 			  acpi_ut_get_region_name(region_obj->region.
215*4882a593Smuzhiyun 						  space_id)));
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	if (!(handler_desc->address_space.handler_flags &
218*4882a593Smuzhiyun 	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
219*4882a593Smuzhiyun 		/*
220*4882a593Smuzhiyun 		 * For handlers other than the default (supplied) handlers, we must
221*4882a593Smuzhiyun 		 * exit the interpreter because the handler *might* block -- we don't
222*4882a593Smuzhiyun 		 * know what it will do, so we can't hold the lock on the interpreter.
223*4882a593Smuzhiyun 		 */
224*4882a593Smuzhiyun 		acpi_ex_exit_interpreter();
225*4882a593Smuzhiyun 	}
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	/*
228*4882a593Smuzhiyun 	 * Special handling for generic_serial_bus and general_purpose_io:
229*4882a593Smuzhiyun 	 * There are three extra parameters that must be passed to the
230*4882a593Smuzhiyun 	 * handler via the context:
231*4882a593Smuzhiyun 	 *   1) Connection buffer, a resource template from Connection() op
232*4882a593Smuzhiyun 	 *   2) Length of the above buffer
233*4882a593Smuzhiyun 	 *   3) Actual access length from the access_as() op
234*4882a593Smuzhiyun 	 *
235*4882a593Smuzhiyun 	 * Since we pass these extra parameters via the context, which is
236*4882a593Smuzhiyun 	 * shared between threads, we must lock the context to avoid these
237*4882a593Smuzhiyun 	 * parameters being changed from another thread before the handler
238*4882a593Smuzhiyun 	 * has completed running.
239*4882a593Smuzhiyun 	 *
240*4882a593Smuzhiyun 	 * In addition, for general_purpose_io, the Address and bit_width fields
241*4882a593Smuzhiyun 	 * are defined as follows:
242*4882a593Smuzhiyun 	 *   1) Address is the pin number index of the field (bit offset from
243*4882a593Smuzhiyun 	 *      the previous Connection)
244*4882a593Smuzhiyun 	 *   2) bit_width is the actual bit length of the field (number of pins)
245*4882a593Smuzhiyun 	 */
246*4882a593Smuzhiyun 	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) &&
247*4882a593Smuzhiyun 	    context && field_obj) {
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 		status =
250*4882a593Smuzhiyun 		    acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
251*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
252*4882a593Smuzhiyun 			goto re_enter_interpreter;
253*4882a593Smuzhiyun 		}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 		context_locked = TRUE;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 		/* Get the Connection (resource_template) buffer */
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 		context->connection = field_obj->field.resource_buffer;
260*4882a593Smuzhiyun 		context->length = field_obj->field.resource_length;
261*4882a593Smuzhiyun 		context->access_length = field_obj->field.access_length;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 	if ((region_obj->region.space_id == ACPI_ADR_SPACE_GPIO) &&
264*4882a593Smuzhiyun 	    context && field_obj) {
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 		status =
267*4882a593Smuzhiyun 		    acpi_os_acquire_mutex(context_mutex, ACPI_WAIT_FOREVER);
268*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
269*4882a593Smuzhiyun 			goto re_enter_interpreter;
270*4882a593Smuzhiyun 		}
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 		context_locked = TRUE;
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 		/* Get the Connection (resource_template) buffer */
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 		context->connection = field_obj->field.resource_buffer;
277*4882a593Smuzhiyun 		context->length = field_obj->field.resource_length;
278*4882a593Smuzhiyun 		context->access_length = field_obj->field.access_length;
279*4882a593Smuzhiyun 		address = field_obj->field.pin_number_index;
280*4882a593Smuzhiyun 		bit_width = field_obj->field.bit_length;
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	/* Call the handler */
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	status = handler(function, address, bit_width, value, context,
286*4882a593Smuzhiyun 			 region_obj2->extra.region_context);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	if (context_locked) {
289*4882a593Smuzhiyun 		acpi_os_release_mutex(context_mutex);
290*4882a593Smuzhiyun 	}
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
293*4882a593Smuzhiyun 		ACPI_EXCEPTION((AE_INFO, status, "Returned by Handler for [%s]",
294*4882a593Smuzhiyun 				acpi_ut_get_region_name(region_obj->region.
295*4882a593Smuzhiyun 							space_id)));
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 		/*
298*4882a593Smuzhiyun 		 * Special case for an EC timeout. These are seen so frequently
299*4882a593Smuzhiyun 		 * that an additional error message is helpful
300*4882a593Smuzhiyun 		 */
301*4882a593Smuzhiyun 		if ((region_obj->region.space_id == ACPI_ADR_SPACE_EC) &&
302*4882a593Smuzhiyun 		    (status == AE_TIME)) {
303*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
304*4882a593Smuzhiyun 				    "Timeout from EC hardware or EC device driver"));
305*4882a593Smuzhiyun 		}
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun re_enter_interpreter:
309*4882a593Smuzhiyun 	if (!(handler_desc->address_space.handler_flags &
310*4882a593Smuzhiyun 	      ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
311*4882a593Smuzhiyun 		/*
312*4882a593Smuzhiyun 		 * We just returned from a non-default handler, we must re-enter the
313*4882a593Smuzhiyun 		 * interpreter
314*4882a593Smuzhiyun 		 */
315*4882a593Smuzhiyun 		acpi_ex_enter_interpreter();
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun /*******************************************************************************
322*4882a593Smuzhiyun  *
323*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_detach_region
324*4882a593Smuzhiyun  *
325*4882a593Smuzhiyun  * PARAMETERS:  region_obj          - Region Object
326*4882a593Smuzhiyun  *              acpi_ns_is_locked   - Namespace Region Already Locked?
327*4882a593Smuzhiyun  *
328*4882a593Smuzhiyun  * RETURN:      None
329*4882a593Smuzhiyun  *
330*4882a593Smuzhiyun  * DESCRIPTION: Break the association between the handler and the region
331*4882a593Smuzhiyun  *              this is a two way association.
332*4882a593Smuzhiyun  *
333*4882a593Smuzhiyun  ******************************************************************************/
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun void
acpi_ev_detach_region(union acpi_operand_object * region_obj,u8 acpi_ns_is_locked)336*4882a593Smuzhiyun acpi_ev_detach_region(union acpi_operand_object *region_obj,
337*4882a593Smuzhiyun 		      u8 acpi_ns_is_locked)
338*4882a593Smuzhiyun {
339*4882a593Smuzhiyun 	union acpi_operand_object *handler_obj;
340*4882a593Smuzhiyun 	union acpi_operand_object *obj_desc;
341*4882a593Smuzhiyun 	union acpi_operand_object *start_desc;
342*4882a593Smuzhiyun 	union acpi_operand_object **last_obj_ptr;
343*4882a593Smuzhiyun 	acpi_adr_space_setup region_setup;
344*4882a593Smuzhiyun 	void **region_context;
345*4882a593Smuzhiyun 	union acpi_operand_object *region_obj2;
346*4882a593Smuzhiyun 	acpi_status status;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_detach_region);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	region_obj2 = acpi_ns_get_secondary_object(region_obj);
351*4882a593Smuzhiyun 	if (!region_obj2) {
352*4882a593Smuzhiyun 		return_VOID;
353*4882a593Smuzhiyun 	}
354*4882a593Smuzhiyun 	region_context = &region_obj2->extra.region_context;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	/* Get the address handler from the region object */
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	handler_obj = region_obj->region.handler;
359*4882a593Smuzhiyun 	if (!handler_obj) {
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		/* This region has no handler, all done */
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 		return_VOID;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* Find this region in the handler's list */
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	obj_desc = handler_obj->address_space.region_list;
369*4882a593Smuzhiyun 	start_desc = obj_desc;
370*4882a593Smuzhiyun 	last_obj_ptr = &handler_obj->address_space.region_list;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	while (obj_desc) {
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		/* Is this the correct Region? */
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 		if (obj_desc == region_obj) {
377*4882a593Smuzhiyun 			ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
378*4882a593Smuzhiyun 					  "Removing Region %p from address handler %p\n",
379*4882a593Smuzhiyun 					  region_obj, handler_obj));
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 			/* This is it, remove it from the handler's list */
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 			*last_obj_ptr = obj_desc->region.next;
384*4882a593Smuzhiyun 			obj_desc->region.next = NULL;	/* Must clear field */
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 			if (acpi_ns_is_locked) {
387*4882a593Smuzhiyun 				status =
388*4882a593Smuzhiyun 				    acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
389*4882a593Smuzhiyun 				if (ACPI_FAILURE(status)) {
390*4882a593Smuzhiyun 					return_VOID;
391*4882a593Smuzhiyun 				}
392*4882a593Smuzhiyun 			}
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 			/* Now stop region accesses by executing the _REG method */
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 			status =
397*4882a593Smuzhiyun 			    acpi_ev_execute_reg_method(region_obj,
398*4882a593Smuzhiyun 						       ACPI_REG_DISCONNECT);
399*4882a593Smuzhiyun 			if (ACPI_FAILURE(status)) {
400*4882a593Smuzhiyun 				ACPI_EXCEPTION((AE_INFO, status,
401*4882a593Smuzhiyun 						"from region _REG, [%s]",
402*4882a593Smuzhiyun 						acpi_ut_get_region_name
403*4882a593Smuzhiyun 						(region_obj->region.space_id)));
404*4882a593Smuzhiyun 			}
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 			if (acpi_ns_is_locked) {
407*4882a593Smuzhiyun 				status =
408*4882a593Smuzhiyun 				    acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
409*4882a593Smuzhiyun 				if (ACPI_FAILURE(status)) {
410*4882a593Smuzhiyun 					return_VOID;
411*4882a593Smuzhiyun 				}
412*4882a593Smuzhiyun 			}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 			/*
415*4882a593Smuzhiyun 			 * If the region has been activated, call the setup handler with
416*4882a593Smuzhiyun 			 * the deactivate notification
417*4882a593Smuzhiyun 			 */
418*4882a593Smuzhiyun 			if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
419*4882a593Smuzhiyun 				region_setup = handler_obj->address_space.setup;
420*4882a593Smuzhiyun 				status =
421*4882a593Smuzhiyun 				    region_setup(region_obj,
422*4882a593Smuzhiyun 						 ACPI_REGION_DEACTIVATE,
423*4882a593Smuzhiyun 						 handler_obj->address_space.
424*4882a593Smuzhiyun 						 context, region_context);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 				/*
427*4882a593Smuzhiyun 				 * region_context should have been released by the deactivate
428*4882a593Smuzhiyun 				 * operation. We don't need access to it anymore here.
429*4882a593Smuzhiyun 				 */
430*4882a593Smuzhiyun 				if (region_context) {
431*4882a593Smuzhiyun 					*region_context = NULL;
432*4882a593Smuzhiyun 				}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 				/* Init routine may fail, Just ignore errors */
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 				if (ACPI_FAILURE(status)) {
437*4882a593Smuzhiyun 					ACPI_EXCEPTION((AE_INFO, status,
438*4882a593Smuzhiyun 							"from region handler - deactivate, [%s]",
439*4882a593Smuzhiyun 							acpi_ut_get_region_name
440*4882a593Smuzhiyun 							(region_obj->region.
441*4882a593Smuzhiyun 							 space_id)));
442*4882a593Smuzhiyun 				}
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 				region_obj->region.flags &=
445*4882a593Smuzhiyun 				    ~(AOPOBJ_SETUP_COMPLETE);
446*4882a593Smuzhiyun 			}
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 			/*
449*4882a593Smuzhiyun 			 * Remove handler reference in the region
450*4882a593Smuzhiyun 			 *
451*4882a593Smuzhiyun 			 * NOTE: this doesn't mean that the region goes away, the region
452*4882a593Smuzhiyun 			 * is just inaccessible as indicated to the _REG method
453*4882a593Smuzhiyun 			 *
454*4882a593Smuzhiyun 			 * If the region is on the handler's list, this must be the
455*4882a593Smuzhiyun 			 * region's handler
456*4882a593Smuzhiyun 			 */
457*4882a593Smuzhiyun 			region_obj->region.handler = NULL;
458*4882a593Smuzhiyun 			acpi_ut_remove_reference(handler_obj);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 			return_VOID;
461*4882a593Smuzhiyun 		}
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 		/* Walk the linked list of handlers */
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 		last_obj_ptr = &obj_desc->region.next;
466*4882a593Smuzhiyun 		obj_desc = obj_desc->region.next;
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 		/* Prevent infinite loop if list is corrupted */
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		if (obj_desc == start_desc) {
471*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
472*4882a593Smuzhiyun 				    "Circular handler list in region object %p",
473*4882a593Smuzhiyun 				    region_obj));
474*4882a593Smuzhiyun 			return_VOID;
475*4882a593Smuzhiyun 		}
476*4882a593Smuzhiyun 	}
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	/* If we get here, the region was not in the handler's region list */
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
481*4882a593Smuzhiyun 			  "Cannot remove region %p from address handler %p\n",
482*4882a593Smuzhiyun 			  region_obj, handler_obj));
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	return_VOID;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun /*******************************************************************************
488*4882a593Smuzhiyun  *
489*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_attach_region
490*4882a593Smuzhiyun  *
491*4882a593Smuzhiyun  * PARAMETERS:  handler_obj         - Handler Object
492*4882a593Smuzhiyun  *              region_obj          - Region Object
493*4882a593Smuzhiyun  *              acpi_ns_is_locked   - Namespace Region Already Locked?
494*4882a593Smuzhiyun  *
495*4882a593Smuzhiyun  * RETURN:      None
496*4882a593Smuzhiyun  *
497*4882a593Smuzhiyun  * DESCRIPTION: Create the association between the handler and the region
498*4882a593Smuzhiyun  *              this is a two way association.
499*4882a593Smuzhiyun  *
500*4882a593Smuzhiyun  ******************************************************************************/
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun acpi_status
acpi_ev_attach_region(union acpi_operand_object * handler_obj,union acpi_operand_object * region_obj,u8 acpi_ns_is_locked)503*4882a593Smuzhiyun acpi_ev_attach_region(union acpi_operand_object *handler_obj,
504*4882a593Smuzhiyun 		      union acpi_operand_object *region_obj,
505*4882a593Smuzhiyun 		      u8 acpi_ns_is_locked)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_attach_region);
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	/* Install the region's handler */
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	if (region_obj->region.handler) {
513*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_ALREADY_EXISTS);
514*4882a593Smuzhiyun 	}
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
517*4882a593Smuzhiyun 			  "Adding Region [%4.4s] %p to address handler %p [%s]\n",
518*4882a593Smuzhiyun 			  acpi_ut_get_node_name(region_obj->region.node),
519*4882a593Smuzhiyun 			  region_obj, handler_obj,
520*4882a593Smuzhiyun 			  acpi_ut_get_region_name(region_obj->region.
521*4882a593Smuzhiyun 						  space_id)));
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun 	/* Link this region to the front of the handler's list */
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	region_obj->region.next = handler_obj->address_space.region_list;
526*4882a593Smuzhiyun 	handler_obj->address_space.region_list = region_obj;
527*4882a593Smuzhiyun 	region_obj->region.handler = handler_obj;
528*4882a593Smuzhiyun 	acpi_ut_add_reference(handler_obj);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return_ACPI_STATUS(AE_OK);
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun /*******************************************************************************
534*4882a593Smuzhiyun  *
535*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_execute_reg_method
536*4882a593Smuzhiyun  *
537*4882a593Smuzhiyun  * PARAMETERS:  region_obj          - Region object
538*4882a593Smuzhiyun  *              function            - Passed to _REG: On (1) or Off (0)
539*4882a593Smuzhiyun  *
540*4882a593Smuzhiyun  * RETURN:      Status
541*4882a593Smuzhiyun  *
542*4882a593Smuzhiyun  * DESCRIPTION: Execute _REG method for a region
543*4882a593Smuzhiyun  *
544*4882a593Smuzhiyun  ******************************************************************************/
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun acpi_status
acpi_ev_execute_reg_method(union acpi_operand_object * region_obj,u32 function)547*4882a593Smuzhiyun acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function)
548*4882a593Smuzhiyun {
549*4882a593Smuzhiyun 	struct acpi_evaluate_info *info;
550*4882a593Smuzhiyun 	union acpi_operand_object *args[3];
551*4882a593Smuzhiyun 	union acpi_operand_object *region_obj2;
552*4882a593Smuzhiyun 	const acpi_name *reg_name_ptr =
553*4882a593Smuzhiyun 	    ACPI_CAST_PTR(acpi_name, METHOD_NAME__REG);
554*4882a593Smuzhiyun 	struct acpi_namespace_node *method_node;
555*4882a593Smuzhiyun 	struct acpi_namespace_node *node;
556*4882a593Smuzhiyun 	acpi_status status;
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_execute_reg_method);
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	if (!acpi_gbl_namespace_initialized ||
561*4882a593Smuzhiyun 	    region_obj->region.handler == NULL) {
562*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_OK);
563*4882a593Smuzhiyun 	}
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	region_obj2 = acpi_ns_get_secondary_object(region_obj);
566*4882a593Smuzhiyun 	if (!region_obj2) {
567*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NOT_EXIST);
568*4882a593Smuzhiyun 	}
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/*
571*4882a593Smuzhiyun 	 * Find any "_REG" method associated with this region definition.
572*4882a593Smuzhiyun 	 * The method should always be updated as this function may be
573*4882a593Smuzhiyun 	 * invoked after a namespace change.
574*4882a593Smuzhiyun 	 */
575*4882a593Smuzhiyun 	node = region_obj->region.node->parent;
576*4882a593Smuzhiyun 	status =
577*4882a593Smuzhiyun 	    acpi_ns_search_one_scope(*reg_name_ptr, node, ACPI_TYPE_METHOD,
578*4882a593Smuzhiyun 				     &method_node);
579*4882a593Smuzhiyun 	if (ACPI_SUCCESS(status)) {
580*4882a593Smuzhiyun 		/*
581*4882a593Smuzhiyun 		 * The _REG method is optional and there can be only one per
582*4882a593Smuzhiyun 		 * region definition. This will be executed when the handler is
583*4882a593Smuzhiyun 		 * attached or removed.
584*4882a593Smuzhiyun 		 */
585*4882a593Smuzhiyun 		region_obj2->extra.method_REG = method_node;
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 	if (region_obj2->extra.method_REG == NULL) {
588*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_OK);
589*4882a593Smuzhiyun 	}
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	/* _REG(DISCONNECT) should be paired with _REG(CONNECT) */
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	if ((function == ACPI_REG_CONNECT &&
594*4882a593Smuzhiyun 	     region_obj->common.flags & AOPOBJ_REG_CONNECTED) ||
595*4882a593Smuzhiyun 	    (function == ACPI_REG_DISCONNECT &&
596*4882a593Smuzhiyun 	     !(region_obj->common.flags & AOPOBJ_REG_CONNECTED))) {
597*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_OK);
598*4882a593Smuzhiyun 	}
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	/* Allocate and initialize the evaluation information block */
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
603*4882a593Smuzhiyun 	if (!info) {
604*4882a593Smuzhiyun 		return_ACPI_STATUS(AE_NO_MEMORY);
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	info->prefix_node = region_obj2->extra.method_REG;
608*4882a593Smuzhiyun 	info->relative_pathname = NULL;
609*4882a593Smuzhiyun 	info->parameters = args;
610*4882a593Smuzhiyun 	info->flags = ACPI_IGNORE_RETURN_VALUE;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	/*
613*4882a593Smuzhiyun 	 * The _REG method has two arguments:
614*4882a593Smuzhiyun 	 *
615*4882a593Smuzhiyun 	 * arg0 - Integer:
616*4882a593Smuzhiyun 	 *  Operation region space ID Same value as region_obj->Region.space_id
617*4882a593Smuzhiyun 	 *
618*4882a593Smuzhiyun 	 * arg1 - Integer:
619*4882a593Smuzhiyun 	 *  connection status 1 for connecting the handler, 0 for disconnecting
620*4882a593Smuzhiyun 	 *  the handler (Passed as a parameter)
621*4882a593Smuzhiyun 	 */
622*4882a593Smuzhiyun 	args[0] =
623*4882a593Smuzhiyun 	    acpi_ut_create_integer_object((u64)region_obj->region.space_id);
624*4882a593Smuzhiyun 	if (!args[0]) {
625*4882a593Smuzhiyun 		status = AE_NO_MEMORY;
626*4882a593Smuzhiyun 		goto cleanup1;
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	args[1] = acpi_ut_create_integer_object((u64)function);
630*4882a593Smuzhiyun 	if (!args[1]) {
631*4882a593Smuzhiyun 		status = AE_NO_MEMORY;
632*4882a593Smuzhiyun 		goto cleanup2;
633*4882a593Smuzhiyun 	}
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	args[2] = NULL;		/* Terminate list */
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	/* Execute the method, no return value */
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
640*4882a593Smuzhiyun 			(ACPI_TYPE_METHOD, info->prefix_node, NULL));
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	status = acpi_ns_evaluate(info);
643*4882a593Smuzhiyun 	acpi_ut_remove_reference(args[1]);
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
646*4882a593Smuzhiyun 		goto cleanup2;
647*4882a593Smuzhiyun 	}
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun 	if (function == ACPI_REG_CONNECT) {
650*4882a593Smuzhiyun 		region_obj->common.flags |= AOPOBJ_REG_CONNECTED;
651*4882a593Smuzhiyun 	} else {
652*4882a593Smuzhiyun 		region_obj->common.flags &= ~AOPOBJ_REG_CONNECTED;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun cleanup2:
656*4882a593Smuzhiyun 	acpi_ut_remove_reference(args[0]);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun cleanup1:
659*4882a593Smuzhiyun 	ACPI_FREE(info);
660*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun /*******************************************************************************
664*4882a593Smuzhiyun  *
665*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_execute_reg_methods
666*4882a593Smuzhiyun  *
667*4882a593Smuzhiyun  * PARAMETERS:  node            - Namespace node for the device
668*4882a593Smuzhiyun  *              space_id        - The address space ID
669*4882a593Smuzhiyun  *              function        - Passed to _REG: On (1) or Off (0)
670*4882a593Smuzhiyun  *
671*4882a593Smuzhiyun  * RETURN:      None
672*4882a593Smuzhiyun  *
673*4882a593Smuzhiyun  * DESCRIPTION: Run all _REG methods for the input Space ID;
674*4882a593Smuzhiyun  *              Note: assumes namespace is locked, or system init time.
675*4882a593Smuzhiyun  *
676*4882a593Smuzhiyun  ******************************************************************************/
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun void
acpi_ev_execute_reg_methods(struct acpi_namespace_node * node,acpi_adr_space_type space_id,u32 function)679*4882a593Smuzhiyun acpi_ev_execute_reg_methods(struct acpi_namespace_node *node,
680*4882a593Smuzhiyun 			    acpi_adr_space_type space_id, u32 function)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun 	struct acpi_reg_walk_info info;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_execute_reg_methods);
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	/*
687*4882a593Smuzhiyun 	 * These address spaces do not need a call to _REG, since the ACPI
688*4882a593Smuzhiyun 	 * specification defines them as: "must always be accessible". Since
689*4882a593Smuzhiyun 	 * they never change state (never become unavailable), no need to ever
690*4882a593Smuzhiyun 	 * call _REG on them. Also, a data_table is not a "real" address space,
691*4882a593Smuzhiyun 	 * so do not call _REG. September 2018.
692*4882a593Smuzhiyun 	 */
693*4882a593Smuzhiyun 	if ((space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) ||
694*4882a593Smuzhiyun 	    (space_id == ACPI_ADR_SPACE_SYSTEM_IO) ||
695*4882a593Smuzhiyun 	    (space_id == ACPI_ADR_SPACE_DATA_TABLE)) {
696*4882a593Smuzhiyun 		return_VOID;
697*4882a593Smuzhiyun 	}
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	info.space_id = space_id;
700*4882a593Smuzhiyun 	info.function = function;
701*4882a593Smuzhiyun 	info.reg_run_count = 0;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES,
704*4882a593Smuzhiyun 			      "    Running _REG methods for SpaceId %s\n",
705*4882a593Smuzhiyun 			      acpi_ut_get_region_name(info.space_id)));
706*4882a593Smuzhiyun 
707*4882a593Smuzhiyun 	/*
708*4882a593Smuzhiyun 	 * Run all _REG methods for all Operation Regions for this space ID. This
709*4882a593Smuzhiyun 	 * is a separate walk in order to handle any interdependencies between
710*4882a593Smuzhiyun 	 * regions and _REG methods. (i.e. handlers must be installed for all
711*4882a593Smuzhiyun 	 * regions of this Space ID before we can run any _REG methods)
712*4882a593Smuzhiyun 	 */
713*4882a593Smuzhiyun 	(void)acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
714*4882a593Smuzhiyun 				     ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, NULL,
715*4882a593Smuzhiyun 				     &info, NULL);
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	/* Special case for EC: handle "orphan" _REG methods with no region */
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	if (space_id == ACPI_ADR_SPACE_EC) {
720*4882a593Smuzhiyun 		acpi_ev_orphan_ec_reg_method(node);
721*4882a593Smuzhiyun 	}
722*4882a593Smuzhiyun 
723*4882a593Smuzhiyun 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES,
724*4882a593Smuzhiyun 			      "    Executed %u _REG methods for SpaceId %s\n",
725*4882a593Smuzhiyun 			      info.reg_run_count,
726*4882a593Smuzhiyun 			      acpi_ut_get_region_name(info.space_id)));
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	return_VOID;
729*4882a593Smuzhiyun }
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun /*******************************************************************************
732*4882a593Smuzhiyun  *
733*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_reg_run
734*4882a593Smuzhiyun  *
735*4882a593Smuzhiyun  * PARAMETERS:  walk_namespace callback
736*4882a593Smuzhiyun  *
737*4882a593Smuzhiyun  * DESCRIPTION: Run _REG method for region objects of the requested spaceID
738*4882a593Smuzhiyun  *
739*4882a593Smuzhiyun  ******************************************************************************/
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun static acpi_status
acpi_ev_reg_run(acpi_handle obj_handle,u32 level,void * context,void ** return_value)742*4882a593Smuzhiyun acpi_ev_reg_run(acpi_handle obj_handle,
743*4882a593Smuzhiyun 		u32 level, void *context, void **return_value)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun 	union acpi_operand_object *obj_desc;
746*4882a593Smuzhiyun 	struct acpi_namespace_node *node;
747*4882a593Smuzhiyun 	acpi_status status;
748*4882a593Smuzhiyun 	struct acpi_reg_walk_info *info;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	info = ACPI_CAST_PTR(struct acpi_reg_walk_info, context);
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	/* Convert and validate the device handle */
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	node = acpi_ns_validate_handle(obj_handle);
755*4882a593Smuzhiyun 	if (!node) {
756*4882a593Smuzhiyun 		return (AE_BAD_PARAMETER);
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	/*
760*4882a593Smuzhiyun 	 * We only care about regions and objects that are allowed to have
761*4882a593Smuzhiyun 	 * address space handlers
762*4882a593Smuzhiyun 	 */
763*4882a593Smuzhiyun 	if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) {
764*4882a593Smuzhiyun 		return (AE_OK);
765*4882a593Smuzhiyun 	}
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	/* Check for an existing internal object */
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	obj_desc = acpi_ns_get_attached_object(node);
770*4882a593Smuzhiyun 	if (!obj_desc) {
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 		/* No object, just exit */
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 		return (AE_OK);
775*4882a593Smuzhiyun 	}
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	/* Object is a Region */
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun 	if (obj_desc->region.space_id != info->space_id) {
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 		/* This region is for a different address space, just ignore it */
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 		return (AE_OK);
784*4882a593Smuzhiyun 	}
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	info->reg_run_count++;
787*4882a593Smuzhiyun 	status = acpi_ev_execute_reg_method(obj_desc, info->function);
788*4882a593Smuzhiyun 	return (status);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun /*******************************************************************************
792*4882a593Smuzhiyun  *
793*4882a593Smuzhiyun  * FUNCTION:    acpi_ev_orphan_ec_reg_method
794*4882a593Smuzhiyun  *
795*4882a593Smuzhiyun  * PARAMETERS:  ec_device_node      - Namespace node for an EC device
796*4882a593Smuzhiyun  *
797*4882a593Smuzhiyun  * RETURN:      None
798*4882a593Smuzhiyun  *
799*4882a593Smuzhiyun  * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC
800*4882a593Smuzhiyun  *              device. This is a _REG method that has no corresponding region
801*4882a593Smuzhiyun  *              within the EC device scope. The orphan _REG method appears to
802*4882a593Smuzhiyun  *              have been enabled by the description of the ECDT in the ACPI
803*4882a593Smuzhiyun  *              specification: "The availability of the region space can be
804*4882a593Smuzhiyun  *              detected by providing a _REG method object underneath the
805*4882a593Smuzhiyun  *              Embedded Controller device."
806*4882a593Smuzhiyun  *
807*4882a593Smuzhiyun  *              To quickly access the EC device, we use the ec_device_node used
808*4882a593Smuzhiyun  *              during EC handler installation. Otherwise, we would need to
809*4882a593Smuzhiyun  *              perform a time consuming namespace walk, executing _HID
810*4882a593Smuzhiyun  *              methods to find the EC device.
811*4882a593Smuzhiyun  *
812*4882a593Smuzhiyun  *  MUTEX:      Assumes the namespace is locked
813*4882a593Smuzhiyun  *
814*4882a593Smuzhiyun  ******************************************************************************/
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun static void
acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node * ec_device_node)817*4882a593Smuzhiyun acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun 	acpi_handle reg_method;
820*4882a593Smuzhiyun 	struct acpi_namespace_node *next_node;
821*4882a593Smuzhiyun 	acpi_status status;
822*4882a593Smuzhiyun 	struct acpi_object_list args;
823*4882a593Smuzhiyun 	union acpi_object objects[2];
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(ev_orphan_ec_reg_method);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	if (!ec_device_node) {
828*4882a593Smuzhiyun 		return_VOID;
829*4882a593Smuzhiyun 	}
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	/* Namespace is currently locked, must release */
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
834*4882a593Smuzhiyun 
835*4882a593Smuzhiyun 	/* Get a handle to a _REG method immediately under the EC device */
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	status = acpi_get_handle(ec_device_node, METHOD_NAME__REG, &reg_method);
838*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
839*4882a593Smuzhiyun 		goto exit;	/* There is no _REG method present */
840*4882a593Smuzhiyun 	}
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	/*
843*4882a593Smuzhiyun 	 * Execute the _REG method only if there is no Operation Region in
844*4882a593Smuzhiyun 	 * this scope with the Embedded Controller space ID. Otherwise, it
845*4882a593Smuzhiyun 	 * will already have been executed. Note, this allows for Regions
846*4882a593Smuzhiyun 	 * with other space IDs to be present; but the code below will then
847*4882a593Smuzhiyun 	 * execute the _REG method with the embedded_control space_ID argument.
848*4882a593Smuzhiyun 	 */
849*4882a593Smuzhiyun 	next_node = acpi_ns_get_next_node(ec_device_node, NULL);
850*4882a593Smuzhiyun 	while (next_node) {
851*4882a593Smuzhiyun 		if ((next_node->type == ACPI_TYPE_REGION) &&
852*4882a593Smuzhiyun 		    (next_node->object) &&
853*4882a593Smuzhiyun 		    (next_node->object->region.space_id == ACPI_ADR_SPACE_EC)) {
854*4882a593Smuzhiyun 			goto exit;	/* Do not execute the _REG */
855*4882a593Smuzhiyun 		}
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 		next_node = acpi_ns_get_next_node(ec_device_node, next_node);
858*4882a593Smuzhiyun 	}
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 	/* Evaluate the _REG(embedded_control,Connect) method */
861*4882a593Smuzhiyun 
862*4882a593Smuzhiyun 	args.count = 2;
863*4882a593Smuzhiyun 	args.pointer = objects;
864*4882a593Smuzhiyun 	objects[0].type = ACPI_TYPE_INTEGER;
865*4882a593Smuzhiyun 	objects[0].integer.value = ACPI_ADR_SPACE_EC;
866*4882a593Smuzhiyun 	objects[1].type = ACPI_TYPE_INTEGER;
867*4882a593Smuzhiyun 	objects[1].integer.value = ACPI_REG_CONNECT;
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	(void)acpi_evaluate_object(reg_method, NULL, &args, NULL);
870*4882a593Smuzhiyun 
871*4882a593Smuzhiyun exit:
872*4882a593Smuzhiyun 	/* We ignore all errors from above, don't care */
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun 	(void)acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
875*4882a593Smuzhiyun 	return_VOID;
876*4882a593Smuzhiyun }
877