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, ®ion_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 ®ion_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 = ®ion_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, ®_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