xref: /OK3568_Linux_fs/kernel/drivers/acpi/acpica/dbexec.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2*4882a593Smuzhiyun /*******************************************************************************
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Module Name: dbexec - debugger control method execution
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  ******************************************************************************/
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <acpi/acpi.h>
9*4882a593Smuzhiyun #include "accommon.h"
10*4882a593Smuzhiyun #include "acdebug.h"
11*4882a593Smuzhiyun #include "acnamesp.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #define _COMPONENT          ACPI_CA_DEBUGGER
14*4882a593Smuzhiyun ACPI_MODULE_NAME("dbexec")
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun static struct acpi_db_method_info acpi_gbl_db_method_info;
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /* Local prototypes */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun static acpi_status
21*4882a593Smuzhiyun acpi_db_execute_method(struct acpi_db_method_info *info,
22*4882a593Smuzhiyun 		       struct acpi_buffer *return_obj);
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info);
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun static u32 acpi_db_get_outstanding_allocations(void);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context);
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun static acpi_status
31*4882a593Smuzhiyun acpi_db_execution_walk(acpi_handle obj_handle,
32*4882a593Smuzhiyun 		       u32 nesting_level, void *context, void **return_value);
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context);
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun /*******************************************************************************
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * FUNCTION:    acpi_db_delete_objects
39*4882a593Smuzhiyun  *
40*4882a593Smuzhiyun  * PARAMETERS:  count               - Count of objects in the list
41*4882a593Smuzhiyun  *              objects             - Array of ACPI_OBJECTs to be deleted
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * RETURN:      None
44*4882a593Smuzhiyun  *
45*4882a593Smuzhiyun  * DESCRIPTION: Delete a list of ACPI_OBJECTS. Handles packages and nested
46*4882a593Smuzhiyun  *              packages via recursion.
47*4882a593Smuzhiyun  *
48*4882a593Smuzhiyun  ******************************************************************************/
49*4882a593Smuzhiyun 
acpi_db_delete_objects(u32 count,union acpi_object * objects)50*4882a593Smuzhiyun void acpi_db_delete_objects(u32 count, union acpi_object *objects)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	u32 i;
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
55*4882a593Smuzhiyun 		switch (objects[i].type) {
56*4882a593Smuzhiyun 		case ACPI_TYPE_BUFFER:
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 			ACPI_FREE(objects[i].buffer.pointer);
59*4882a593Smuzhiyun 			break;
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun 		case ACPI_TYPE_PACKAGE:
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 			/* Recursive call to delete package elements */
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 			acpi_db_delete_objects(objects[i].package.count,
66*4882a593Smuzhiyun 					       objects[i].package.elements);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 			/* Free the elements array */
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 			ACPI_FREE(objects[i].package.elements);
71*4882a593Smuzhiyun 			break;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 		default:
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 			break;
76*4882a593Smuzhiyun 		}
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun /*******************************************************************************
81*4882a593Smuzhiyun  *
82*4882a593Smuzhiyun  * FUNCTION:    acpi_db_execute_method
83*4882a593Smuzhiyun  *
84*4882a593Smuzhiyun  * PARAMETERS:  info            - Valid info segment
85*4882a593Smuzhiyun  *              return_obj      - Where to put return object
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun  * RETURN:      Status
88*4882a593Smuzhiyun  *
89*4882a593Smuzhiyun  * DESCRIPTION: Execute a control method. Used to evaluate objects via the
90*4882a593Smuzhiyun  *              "EXECUTE" or "EVALUATE" commands.
91*4882a593Smuzhiyun  *
92*4882a593Smuzhiyun  ******************************************************************************/
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun static acpi_status
acpi_db_execute_method(struct acpi_db_method_info * info,struct acpi_buffer * return_obj)95*4882a593Smuzhiyun acpi_db_execute_method(struct acpi_db_method_info *info,
96*4882a593Smuzhiyun 		       struct acpi_buffer *return_obj)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	acpi_status status;
99*4882a593Smuzhiyun 	struct acpi_object_list param_objects;
100*4882a593Smuzhiyun 	union acpi_object params[ACPI_DEBUGGER_MAX_ARGS + 1];
101*4882a593Smuzhiyun 	u32 i;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	ACPI_FUNCTION_TRACE(db_execute_method);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (acpi_gbl_db_output_to_file && !acpi_dbg_level) {
106*4882a593Smuzhiyun 		acpi_os_printf("Warning: debug output is not enabled!\n");
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	param_objects.count = 0;
110*4882a593Smuzhiyun 	param_objects.pointer = NULL;
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	/* Pass through any command-line arguments */
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	if (info->args && info->args[0]) {
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 		/* Get arguments passed on the command line */
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 		for (i = 0; (info->args[i] && *(info->args[i])); i++) {
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 			/* Convert input string (token) to an actual union acpi_object */
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 			status = acpi_db_convert_to_object(info->types[i],
123*4882a593Smuzhiyun 							   info->args[i],
124*4882a593Smuzhiyun 							   &params[i]);
125*4882a593Smuzhiyun 			if (ACPI_FAILURE(status)) {
126*4882a593Smuzhiyun 				ACPI_EXCEPTION((AE_INFO, status,
127*4882a593Smuzhiyun 						"While parsing method arguments"));
128*4882a593Smuzhiyun 				goto cleanup;
129*4882a593Smuzhiyun 			}
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 		param_objects.count = i;
133*4882a593Smuzhiyun 		param_objects.pointer = params;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	/* Prepare for a return object of arbitrary size */
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	return_obj->pointer = acpi_gbl_db_buffer;
139*4882a593Smuzhiyun 	return_obj->length = ACPI_DEBUG_BUFFER_SIZE;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	/* Do the actual method execution */
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	acpi_gbl_method_executing = TRUE;
144*4882a593Smuzhiyun 	status = acpi_evaluate_object(NULL, info->pathname,
145*4882a593Smuzhiyun 				      &param_objects, return_obj);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	acpi_gbl_cm_single_step = FALSE;
148*4882a593Smuzhiyun 	acpi_gbl_method_executing = FALSE;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
151*4882a593Smuzhiyun 		if ((status == AE_ABORT_METHOD) || acpi_gbl_abort_method) {
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 			/* Clear the abort and fall back to the debugger prompt */
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 			ACPI_EXCEPTION((AE_INFO, status,
156*4882a593Smuzhiyun 					"Aborting top-level method"));
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 			acpi_gbl_abort_method = FALSE;
159*4882a593Smuzhiyun 			status = AE_OK;
160*4882a593Smuzhiyun 			goto cleanup;
161*4882a593Smuzhiyun 		}
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 		ACPI_EXCEPTION((AE_INFO, status,
164*4882a593Smuzhiyun 				"while executing %s from AML Debugger",
165*4882a593Smuzhiyun 				info->pathname));
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		if (status == AE_BUFFER_OVERFLOW) {
168*4882a593Smuzhiyun 			ACPI_ERROR((AE_INFO,
169*4882a593Smuzhiyun 				    "Possible buffer overflow within AML Debugger "
170*4882a593Smuzhiyun 				    "buffer (size 0x%X needed 0x%X)",
171*4882a593Smuzhiyun 				    ACPI_DEBUG_BUFFER_SIZE,
172*4882a593Smuzhiyun 				    (u32)return_obj->length));
173*4882a593Smuzhiyun 		}
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun cleanup:
177*4882a593Smuzhiyun 	acpi_db_delete_objects(param_objects.count, params);
178*4882a593Smuzhiyun 	return_ACPI_STATUS(status);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /*******************************************************************************
182*4882a593Smuzhiyun  *
183*4882a593Smuzhiyun  * FUNCTION:    acpi_db_execute_setup
184*4882a593Smuzhiyun  *
185*4882a593Smuzhiyun  * PARAMETERS:  info            - Valid method info
186*4882a593Smuzhiyun  *
187*4882a593Smuzhiyun  * RETURN:      None
188*4882a593Smuzhiyun  *
189*4882a593Smuzhiyun  * DESCRIPTION: Setup info segment prior to method execution
190*4882a593Smuzhiyun  *
191*4882a593Smuzhiyun  ******************************************************************************/
192*4882a593Smuzhiyun 
acpi_db_execute_setup(struct acpi_db_method_info * info)193*4882a593Smuzhiyun static acpi_status acpi_db_execute_setup(struct acpi_db_method_info *info)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	acpi_status status;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	ACPI_FUNCTION_NAME(db_execute_setup);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* Concatenate the current scope to the supplied name */
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	info->pathname[0] = 0;
202*4882a593Smuzhiyun 	if ((info->name[0] != '\\') && (info->name[0] != '/')) {
203*4882a593Smuzhiyun 		if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
204*4882a593Smuzhiyun 					acpi_gbl_db_scope_buf)) {
205*4882a593Smuzhiyun 			status = AE_BUFFER_OVERFLOW;
206*4882a593Smuzhiyun 			goto error_exit;
207*4882a593Smuzhiyun 		}
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (acpi_ut_safe_strcat(info->pathname, sizeof(info->pathname),
211*4882a593Smuzhiyun 				info->name)) {
212*4882a593Smuzhiyun 		status = AE_BUFFER_OVERFLOW;
213*4882a593Smuzhiyun 		goto error_exit;
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	acpi_db_prep_namestring(info->pathname);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
219*4882a593Smuzhiyun 	acpi_os_printf("Evaluating %s\n", info->pathname);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	if (info->flags & EX_SINGLE_STEP) {
222*4882a593Smuzhiyun 		acpi_gbl_cm_single_step = TRUE;
223*4882a593Smuzhiyun 		acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
224*4882a593Smuzhiyun 	}
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	else {
227*4882a593Smuzhiyun 		/* No single step, allow redirection to a file */
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	return (AE_OK);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun error_exit:
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	ACPI_EXCEPTION((AE_INFO, status, "During setup for method execution"));
237*4882a593Smuzhiyun 	return (status);
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun #ifdef ACPI_DBG_TRACK_ALLOCATIONS
acpi_db_get_cache_info(struct acpi_memory_list * cache)241*4882a593Smuzhiyun u32 acpi_db_get_cache_info(struct acpi_memory_list *cache)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return (cache->total_allocated - cache->total_freed -
245*4882a593Smuzhiyun 		cache->current_depth);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun #endif
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /*******************************************************************************
250*4882a593Smuzhiyun  *
251*4882a593Smuzhiyun  * FUNCTION:    acpi_db_get_outstanding_allocations
252*4882a593Smuzhiyun  *
253*4882a593Smuzhiyun  * PARAMETERS:  None
254*4882a593Smuzhiyun  *
255*4882a593Smuzhiyun  * RETURN:      Current global allocation count minus cache entries
256*4882a593Smuzhiyun  *
257*4882a593Smuzhiyun  * DESCRIPTION: Determine the current number of "outstanding" allocations --
258*4882a593Smuzhiyun  *              those allocations that have not been freed and also are not
259*4882a593Smuzhiyun  *              in one of the various object caches.
260*4882a593Smuzhiyun  *
261*4882a593Smuzhiyun  ******************************************************************************/
262*4882a593Smuzhiyun 
acpi_db_get_outstanding_allocations(void)263*4882a593Smuzhiyun static u32 acpi_db_get_outstanding_allocations(void)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun 	u32 outstanding = 0;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun #ifdef ACPI_DBG_TRACK_ALLOCATIONS
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	outstanding += acpi_db_get_cache_info(acpi_gbl_state_cache);
270*4882a593Smuzhiyun 	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_cache);
271*4882a593Smuzhiyun 	outstanding += acpi_db_get_cache_info(acpi_gbl_ps_node_ext_cache);
272*4882a593Smuzhiyun 	outstanding += acpi_db_get_cache_info(acpi_gbl_operand_cache);
273*4882a593Smuzhiyun #endif
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return (outstanding);
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun /*******************************************************************************
279*4882a593Smuzhiyun  *
280*4882a593Smuzhiyun  * FUNCTION:    acpi_db_execution_walk
281*4882a593Smuzhiyun  *
282*4882a593Smuzhiyun  * PARAMETERS:  WALK_CALLBACK
283*4882a593Smuzhiyun  *
284*4882a593Smuzhiyun  * RETURN:      Status
285*4882a593Smuzhiyun  *
286*4882a593Smuzhiyun  * DESCRIPTION: Execute a control method. Name is relative to the current
287*4882a593Smuzhiyun  *              scope.
288*4882a593Smuzhiyun  *
289*4882a593Smuzhiyun  ******************************************************************************/
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun static acpi_status
acpi_db_execution_walk(acpi_handle obj_handle,u32 nesting_level,void * context,void ** return_value)292*4882a593Smuzhiyun acpi_db_execution_walk(acpi_handle obj_handle,
293*4882a593Smuzhiyun 		       u32 nesting_level, void *context, void **return_value)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun 	union acpi_operand_object *obj_desc;
296*4882a593Smuzhiyun 	struct acpi_namespace_node *node =
297*4882a593Smuzhiyun 	    (struct acpi_namespace_node *)obj_handle;
298*4882a593Smuzhiyun 	struct acpi_buffer return_obj;
299*4882a593Smuzhiyun 	acpi_status status;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	obj_desc = acpi_ns_get_attached_object(node);
302*4882a593Smuzhiyun 	if (obj_desc->method.param_count) {
303*4882a593Smuzhiyun 		return (AE_OK);
304*4882a593Smuzhiyun 	}
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	return_obj.pointer = NULL;
307*4882a593Smuzhiyun 	return_obj.length = ACPI_ALLOCATE_BUFFER;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	acpi_ns_print_node_pathname(node, "Evaluating");
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	/* Do the actual method execution */
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	acpi_os_printf("\n");
314*4882a593Smuzhiyun 	acpi_gbl_method_executing = TRUE;
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	acpi_gbl_method_executing = FALSE;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
321*4882a593Smuzhiyun 		       acpi_ut_get_node_name(node),
322*4882a593Smuzhiyun 		       acpi_format_exception(status));
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	return (AE_OK);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun /*******************************************************************************
328*4882a593Smuzhiyun  *
329*4882a593Smuzhiyun  * FUNCTION:    acpi_db_execute
330*4882a593Smuzhiyun  *
331*4882a593Smuzhiyun  * PARAMETERS:  name                - Name of method to execute
332*4882a593Smuzhiyun  *              args                - Parameters to the method
333*4882a593Smuzhiyun  *              Types               -
334*4882a593Smuzhiyun  *              flags               - single step/no single step
335*4882a593Smuzhiyun  *
336*4882a593Smuzhiyun  * RETURN:      None
337*4882a593Smuzhiyun  *
338*4882a593Smuzhiyun  * DESCRIPTION: Execute a control method. Name is relative to the current
339*4882a593Smuzhiyun  *              scope. Function used for the "EXECUTE", "EVALUATE", and
340*4882a593Smuzhiyun  *              "ALL" commands
341*4882a593Smuzhiyun  *
342*4882a593Smuzhiyun  ******************************************************************************/
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun void
acpi_db_execute(char * name,char ** args,acpi_object_type * types,u32 flags)345*4882a593Smuzhiyun acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	acpi_status status;
348*4882a593Smuzhiyun 	struct acpi_buffer return_obj;
349*4882a593Smuzhiyun 	char *name_string;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun #ifdef ACPI_DEBUG_OUTPUT
352*4882a593Smuzhiyun 	u32 previous_allocations;
353*4882a593Smuzhiyun 	u32 allocations;
354*4882a593Smuzhiyun #endif
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	/*
357*4882a593Smuzhiyun 	 * Allow one execution to be performed by debugger or single step
358*4882a593Smuzhiyun 	 * execution will be dead locked by the interpreter mutexes.
359*4882a593Smuzhiyun 	 */
360*4882a593Smuzhiyun 	if (acpi_gbl_method_executing) {
361*4882a593Smuzhiyun 		acpi_os_printf("Only one debugger execution is allowed.\n");
362*4882a593Smuzhiyun 		return;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun #ifdef ACPI_DEBUG_OUTPUT
365*4882a593Smuzhiyun 	/* Memory allocation tracking */
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	previous_allocations = acpi_db_get_outstanding_allocations();
368*4882a593Smuzhiyun #endif
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	if (*name == '*') {
371*4882a593Smuzhiyun 		(void)acpi_walk_namespace(ACPI_TYPE_METHOD, ACPI_ROOT_OBJECT,
372*4882a593Smuzhiyun 					  ACPI_UINT32_MAX,
373*4882a593Smuzhiyun 					  acpi_db_execution_walk, NULL, NULL,
374*4882a593Smuzhiyun 					  NULL);
375*4882a593Smuzhiyun 		return;
376*4882a593Smuzhiyun 	}
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if ((flags & EX_ALL) && (strlen(name) > 4)) {
379*4882a593Smuzhiyun 		acpi_os_printf("Input name (%s) must be a 4-char NameSeg\n",
380*4882a593Smuzhiyun 			       name);
381*4882a593Smuzhiyun 		return;
382*4882a593Smuzhiyun 	}
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	name_string = ACPI_ALLOCATE(strlen(name) + 1);
385*4882a593Smuzhiyun 	if (!name_string) {
386*4882a593Smuzhiyun 		return;
387*4882a593Smuzhiyun 	}
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
390*4882a593Smuzhiyun 	strcpy(name_string, name);
391*4882a593Smuzhiyun 	acpi_ut_strupr(name_string);
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	/* Subcommand to Execute all predefined names in the namespace */
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (!strncmp(name_string, "PREDEF", 6)) {
396*4882a593Smuzhiyun 		acpi_db_evaluate_predefined_names();
397*4882a593Smuzhiyun 		ACPI_FREE(name_string);
398*4882a593Smuzhiyun 		return;
399*4882a593Smuzhiyun 	}
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	/* Command (ALL <nameseg>) to execute all methods of a particular name */
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	else if (flags & EX_ALL) {
404*4882a593Smuzhiyun 		acpi_gbl_db_method_info.name = name_string;
405*4882a593Smuzhiyun 		return_obj.pointer = NULL;
406*4882a593Smuzhiyun 		return_obj.length = ACPI_ALLOCATE_BUFFER;
407*4882a593Smuzhiyun 		acpi_db_evaluate_all(name_string);
408*4882a593Smuzhiyun 		ACPI_FREE(name_string);
409*4882a593Smuzhiyun 		return;
410*4882a593Smuzhiyun 	} else {
411*4882a593Smuzhiyun 		acpi_gbl_db_method_info.name = name_string;
412*4882a593Smuzhiyun 		acpi_gbl_db_method_info.args = args;
413*4882a593Smuzhiyun 		acpi_gbl_db_method_info.types = types;
414*4882a593Smuzhiyun 		acpi_gbl_db_method_info.flags = flags;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 		return_obj.pointer = NULL;
417*4882a593Smuzhiyun 		return_obj.length = ACPI_ALLOCATE_BUFFER;
418*4882a593Smuzhiyun 	}
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
421*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
422*4882a593Smuzhiyun 		ACPI_FREE(name_string);
423*4882a593Smuzhiyun 		return;
424*4882a593Smuzhiyun 	}
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	/* Get the NS node, determines existence also */
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
429*4882a593Smuzhiyun 				 &acpi_gbl_db_method_info.method);
430*4882a593Smuzhiyun 	if (ACPI_SUCCESS(status)) {
431*4882a593Smuzhiyun 		status = acpi_db_execute_method(&acpi_gbl_db_method_info,
432*4882a593Smuzhiyun 						&return_obj);
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 	ACPI_FREE(name_string);
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	/*
437*4882a593Smuzhiyun 	 * Allow any handlers in separate threads to complete.
438*4882a593Smuzhiyun 	 * (Such as Notify handlers invoked from AML executed above).
439*4882a593Smuzhiyun 	 */
440*4882a593Smuzhiyun 	acpi_os_sleep((u64)10);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun #ifdef ACPI_DEBUG_OUTPUT
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	/* Memory allocation tracking */
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	allocations =
447*4882a593Smuzhiyun 	    acpi_db_get_outstanding_allocations() - previous_allocations;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	if (allocations > 0) {
452*4882a593Smuzhiyun 		acpi_os_printf
453*4882a593Smuzhiyun 		    ("0x%X Outstanding allocations after evaluation of %s\n",
454*4882a593Smuzhiyun 		     allocations, acpi_gbl_db_method_info.pathname);
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun #endif
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
459*4882a593Smuzhiyun 		acpi_os_printf("Evaluation of %s failed with status %s\n",
460*4882a593Smuzhiyun 			       acpi_gbl_db_method_info.pathname,
461*4882a593Smuzhiyun 			       acpi_format_exception(status));
462*4882a593Smuzhiyun 	} else {
463*4882a593Smuzhiyun 		/* Display a return object, if any */
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 		if (return_obj.length) {
466*4882a593Smuzhiyun 			acpi_os_printf("Evaluation of %s returned object %p, "
467*4882a593Smuzhiyun 				       "external buffer length %X\n",
468*4882a593Smuzhiyun 				       acpi_gbl_db_method_info.pathname,
469*4882a593Smuzhiyun 				       return_obj.pointer,
470*4882a593Smuzhiyun 				       (u32)return_obj.length);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 			acpi_db_dump_external_object(return_obj.pointer, 1);
473*4882a593Smuzhiyun 			acpi_os_printf("\n");
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 			/* Dump a _PLD buffer if present */
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 			if (ACPI_COMPARE_NAMESEG
478*4882a593Smuzhiyun 			    ((ACPI_CAST_PTR
479*4882a593Smuzhiyun 			      (struct acpi_namespace_node,
480*4882a593Smuzhiyun 			       acpi_gbl_db_method_info.method)->name.ascii),
481*4882a593Smuzhiyun 			     METHOD_NAME__PLD)) {
482*4882a593Smuzhiyun 				acpi_db_dump_pld_buffer(return_obj.pointer);
483*4882a593Smuzhiyun 			}
484*4882a593Smuzhiyun 		} else {
485*4882a593Smuzhiyun 			acpi_os_printf
486*4882a593Smuzhiyun 			    ("No object was returned from evaluation of %s\n",
487*4882a593Smuzhiyun 			     acpi_gbl_db_method_info.pathname);
488*4882a593Smuzhiyun 		}
489*4882a593Smuzhiyun 	}
490*4882a593Smuzhiyun 
491*4882a593Smuzhiyun 	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun /*******************************************************************************
495*4882a593Smuzhiyun  *
496*4882a593Smuzhiyun  * FUNCTION:    acpi_db_method_thread
497*4882a593Smuzhiyun  *
498*4882a593Smuzhiyun  * PARAMETERS:  context             - Execution info segment
499*4882a593Smuzhiyun  *
500*4882a593Smuzhiyun  * RETURN:      None
501*4882a593Smuzhiyun  *
502*4882a593Smuzhiyun  * DESCRIPTION: Debugger execute thread. Waits for a command line, then
503*4882a593Smuzhiyun  *              simply dispatches it.
504*4882a593Smuzhiyun  *
505*4882a593Smuzhiyun  ******************************************************************************/
506*4882a593Smuzhiyun 
acpi_db_method_thread(void * context)507*4882a593Smuzhiyun static void ACPI_SYSTEM_XFACE acpi_db_method_thread(void *context)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun 	acpi_status status;
510*4882a593Smuzhiyun 	struct acpi_db_method_info *info = context;
511*4882a593Smuzhiyun 	struct acpi_db_method_info local_info;
512*4882a593Smuzhiyun 	u32 i;
513*4882a593Smuzhiyun 	u8 allow;
514*4882a593Smuzhiyun 	struct acpi_buffer return_obj;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	/*
517*4882a593Smuzhiyun 	 * acpi_gbl_db_method_info.Arguments will be passed as method arguments.
518*4882a593Smuzhiyun 	 * Prevent acpi_gbl_db_method_info from being modified by multiple threads
519*4882a593Smuzhiyun 	 * concurrently.
520*4882a593Smuzhiyun 	 *
521*4882a593Smuzhiyun 	 * Note: The arguments we are passing are used by the ASL test suite
522*4882a593Smuzhiyun 	 * (aslts). Do not change them without updating the tests.
523*4882a593Smuzhiyun 	 */
524*4882a593Smuzhiyun 	(void)acpi_os_wait_semaphore(info->info_gate, 1, ACPI_WAIT_FOREVER);
525*4882a593Smuzhiyun 
526*4882a593Smuzhiyun 	if (info->init_args) {
527*4882a593Smuzhiyun 		acpi_db_uint32_to_hex_string(info->num_created,
528*4882a593Smuzhiyun 					     info->index_of_thread_str);
529*4882a593Smuzhiyun 		acpi_db_uint32_to_hex_string((u32)acpi_os_get_thread_id(),
530*4882a593Smuzhiyun 					     info->id_of_thread_str);
531*4882a593Smuzhiyun 	}
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun 	if (info->threads && (info->num_created < info->num_threads)) {
534*4882a593Smuzhiyun 		info->threads[info->num_created++] = acpi_os_get_thread_id();
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	local_info = *info;
538*4882a593Smuzhiyun 	local_info.args = local_info.arguments;
539*4882a593Smuzhiyun 	local_info.arguments[0] = local_info.num_threads_str;
540*4882a593Smuzhiyun 	local_info.arguments[1] = local_info.id_of_thread_str;
541*4882a593Smuzhiyun 	local_info.arguments[2] = local_info.index_of_thread_str;
542*4882a593Smuzhiyun 	local_info.arguments[3] = NULL;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	local_info.types = local_info.arg_types;
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	(void)acpi_os_signal_semaphore(info->info_gate, 1);
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	for (i = 0; i < info->num_loops; i++) {
549*4882a593Smuzhiyun 		status = acpi_db_execute_method(&local_info, &return_obj);
550*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
551*4882a593Smuzhiyun 			acpi_os_printf
552*4882a593Smuzhiyun 			    ("%s During evaluation of %s at iteration %X\n",
553*4882a593Smuzhiyun 			     acpi_format_exception(status), info->pathname, i);
554*4882a593Smuzhiyun 			if (status == AE_ABORT_METHOD) {
555*4882a593Smuzhiyun 				break;
556*4882a593Smuzhiyun 			}
557*4882a593Smuzhiyun 		}
558*4882a593Smuzhiyun #if 0
559*4882a593Smuzhiyun 		if ((i % 100) == 0) {
560*4882a593Smuzhiyun 			acpi_os_printf("%u loops, Thread 0x%x\n",
561*4882a593Smuzhiyun 				       i, acpi_os_get_thread_id());
562*4882a593Smuzhiyun 		}
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun 		if (return_obj.length) {
565*4882a593Smuzhiyun 			acpi_os_printf
566*4882a593Smuzhiyun 			    ("Evaluation of %s returned object %p Buflen %X\n",
567*4882a593Smuzhiyun 			     info->pathname, return_obj.pointer,
568*4882a593Smuzhiyun 			     (u32)return_obj.length);
569*4882a593Smuzhiyun 			acpi_db_dump_external_object(return_obj.pointer, 1);
570*4882a593Smuzhiyun 		}
571*4882a593Smuzhiyun #endif
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	/* Signal our completion */
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	allow = 0;
577*4882a593Smuzhiyun 	(void)acpi_os_wait_semaphore(info->thread_complete_gate,
578*4882a593Smuzhiyun 				     1, ACPI_WAIT_FOREVER);
579*4882a593Smuzhiyun 	info->num_completed++;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	if (info->num_completed == info->num_threads) {
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 		/* Do signal for main thread once only */
584*4882a593Smuzhiyun 		allow = 1;
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	(void)acpi_os_signal_semaphore(info->thread_complete_gate, 1);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	if (allow) {
590*4882a593Smuzhiyun 		status = acpi_os_signal_semaphore(info->main_thread_gate, 1);
591*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
592*4882a593Smuzhiyun 			acpi_os_printf
593*4882a593Smuzhiyun 			    ("Could not signal debugger thread sync semaphore, %s\n",
594*4882a593Smuzhiyun 			     acpi_format_exception(status));
595*4882a593Smuzhiyun 		}
596*4882a593Smuzhiyun 	}
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun /*******************************************************************************
600*4882a593Smuzhiyun  *
601*4882a593Smuzhiyun  * FUNCTION:    acpi_db_single_execution_thread
602*4882a593Smuzhiyun  *
603*4882a593Smuzhiyun  * PARAMETERS:  context                 - Method info struct
604*4882a593Smuzhiyun  *
605*4882a593Smuzhiyun  * RETURN:      None
606*4882a593Smuzhiyun  *
607*4882a593Smuzhiyun  * DESCRIPTION: Create one thread and execute a method
608*4882a593Smuzhiyun  *
609*4882a593Smuzhiyun  ******************************************************************************/
610*4882a593Smuzhiyun 
acpi_db_single_execution_thread(void * context)611*4882a593Smuzhiyun static void ACPI_SYSTEM_XFACE acpi_db_single_execution_thread(void *context)
612*4882a593Smuzhiyun {
613*4882a593Smuzhiyun 	struct acpi_db_method_info *info = context;
614*4882a593Smuzhiyun 	acpi_status status;
615*4882a593Smuzhiyun 	struct acpi_buffer return_obj;
616*4882a593Smuzhiyun 
617*4882a593Smuzhiyun 	acpi_os_printf("\n");
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun 	status = acpi_db_execute_method(info, &return_obj);
620*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
621*4882a593Smuzhiyun 		acpi_os_printf("%s During evaluation of %s\n",
622*4882a593Smuzhiyun 			       acpi_format_exception(status), info->pathname);
623*4882a593Smuzhiyun 		return;
624*4882a593Smuzhiyun 	}
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	/* Display a return object, if any */
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	if (return_obj.length) {
629*4882a593Smuzhiyun 		acpi_os_printf("Evaluation of %s returned object %p, "
630*4882a593Smuzhiyun 			       "external buffer length %X\n",
631*4882a593Smuzhiyun 			       acpi_gbl_db_method_info.pathname,
632*4882a593Smuzhiyun 			       return_obj.pointer, (u32)return_obj.length);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 		acpi_db_dump_external_object(return_obj.pointer, 1);
635*4882a593Smuzhiyun 	}
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	acpi_os_printf("\nBackground thread completed\n%c ",
638*4882a593Smuzhiyun 		       ACPI_DEBUGGER_COMMAND_PROMPT);
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun /*******************************************************************************
642*4882a593Smuzhiyun  *
643*4882a593Smuzhiyun  * FUNCTION:    acpi_db_create_execution_thread
644*4882a593Smuzhiyun  *
645*4882a593Smuzhiyun  * PARAMETERS:  method_name_arg         - Control method to execute
646*4882a593Smuzhiyun  *              arguments               - Array of arguments to the method
647*4882a593Smuzhiyun  *              types                   - Corresponding array of object types
648*4882a593Smuzhiyun  *
649*4882a593Smuzhiyun  * RETURN:      None
650*4882a593Smuzhiyun  *
651*4882a593Smuzhiyun  * DESCRIPTION: Create a single thread to evaluate a namespace object. Handles
652*4882a593Smuzhiyun  *              arguments passed on command line for control methods.
653*4882a593Smuzhiyun  *
654*4882a593Smuzhiyun  ******************************************************************************/
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun void
acpi_db_create_execution_thread(char * method_name_arg,char ** arguments,acpi_object_type * types)657*4882a593Smuzhiyun acpi_db_create_execution_thread(char *method_name_arg,
658*4882a593Smuzhiyun 				char **arguments, acpi_object_type *types)
659*4882a593Smuzhiyun {
660*4882a593Smuzhiyun 	acpi_status status;
661*4882a593Smuzhiyun 	u32 i;
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun 	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
664*4882a593Smuzhiyun 	acpi_gbl_db_method_info.name = method_name_arg;
665*4882a593Smuzhiyun 	acpi_gbl_db_method_info.init_args = 1;
666*4882a593Smuzhiyun 	acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
667*4882a593Smuzhiyun 	acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	/* Setup method arguments, up to 7 (0-6) */
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && *arguments; i++) {
672*4882a593Smuzhiyun 		acpi_gbl_db_method_info.arguments[i] = *arguments;
673*4882a593Smuzhiyun 		arguments++;
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 		acpi_gbl_db_method_info.arg_types[i] = *types;
676*4882a593Smuzhiyun 		types++;
677*4882a593Smuzhiyun 	}
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
680*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
681*4882a593Smuzhiyun 		return;
682*4882a593Smuzhiyun 	}
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	/* Get the NS node, determines existence also */
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
687*4882a593Smuzhiyun 				 &acpi_gbl_db_method_info.method);
688*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
689*4882a593Smuzhiyun 		acpi_os_printf("%s Could not get handle for %s\n",
690*4882a593Smuzhiyun 			       acpi_format_exception(status),
691*4882a593Smuzhiyun 			       acpi_gbl_db_method_info.pathname);
692*4882a593Smuzhiyun 		return;
693*4882a593Smuzhiyun 	}
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	status = acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
696*4882a593Smuzhiyun 				 acpi_db_single_execution_thread,
697*4882a593Smuzhiyun 				 &acpi_gbl_db_method_info);
698*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
699*4882a593Smuzhiyun 		return;
700*4882a593Smuzhiyun 	}
701*4882a593Smuzhiyun 
702*4882a593Smuzhiyun 	acpi_os_printf("\nBackground thread started\n");
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun /*******************************************************************************
706*4882a593Smuzhiyun  *
707*4882a593Smuzhiyun  * FUNCTION:    acpi_db_create_execution_threads
708*4882a593Smuzhiyun  *
709*4882a593Smuzhiyun  * PARAMETERS:  num_threads_arg         - Number of threads to create
710*4882a593Smuzhiyun  *              num_loops_arg           - Loop count for the thread(s)
711*4882a593Smuzhiyun  *              method_name_arg         - Control method to execute
712*4882a593Smuzhiyun  *
713*4882a593Smuzhiyun  * RETURN:      None
714*4882a593Smuzhiyun  *
715*4882a593Smuzhiyun  * DESCRIPTION: Create threads to execute method(s)
716*4882a593Smuzhiyun  *
717*4882a593Smuzhiyun  ******************************************************************************/
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun void
acpi_db_create_execution_threads(char * num_threads_arg,char * num_loops_arg,char * method_name_arg)720*4882a593Smuzhiyun acpi_db_create_execution_threads(char *num_threads_arg,
721*4882a593Smuzhiyun 				 char *num_loops_arg, char *method_name_arg)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun 	acpi_status status;
724*4882a593Smuzhiyun 	u32 num_threads;
725*4882a593Smuzhiyun 	u32 num_loops;
726*4882a593Smuzhiyun 	u32 i;
727*4882a593Smuzhiyun 	u32 size;
728*4882a593Smuzhiyun 	acpi_mutex main_thread_gate;
729*4882a593Smuzhiyun 	acpi_mutex thread_complete_gate;
730*4882a593Smuzhiyun 	acpi_mutex info_gate;
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	/* Get the arguments */
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 	num_threads = strtoul(num_threads_arg, NULL, 0);
735*4882a593Smuzhiyun 	num_loops = strtoul(num_loops_arg, NULL, 0);
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	if (!num_threads || !num_loops) {
738*4882a593Smuzhiyun 		acpi_os_printf("Bad argument: Threads %X, Loops %X\n",
739*4882a593Smuzhiyun 			       num_threads, num_loops);
740*4882a593Smuzhiyun 		return;
741*4882a593Smuzhiyun 	}
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	/*
744*4882a593Smuzhiyun 	 * Create the semaphore for synchronization of
745*4882a593Smuzhiyun 	 * the created threads with the main thread.
746*4882a593Smuzhiyun 	 */
747*4882a593Smuzhiyun 	status = acpi_os_create_semaphore(1, 0, &main_thread_gate);
748*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
749*4882a593Smuzhiyun 		acpi_os_printf("Could not create semaphore for "
750*4882a593Smuzhiyun 			       "synchronization with the main thread, %s\n",
751*4882a593Smuzhiyun 			       acpi_format_exception(status));
752*4882a593Smuzhiyun 		return;
753*4882a593Smuzhiyun 	}
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	/*
756*4882a593Smuzhiyun 	 * Create the semaphore for synchronization
757*4882a593Smuzhiyun 	 * between the created threads.
758*4882a593Smuzhiyun 	 */
759*4882a593Smuzhiyun 	status = acpi_os_create_semaphore(1, 1, &thread_complete_gate);
760*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
761*4882a593Smuzhiyun 		acpi_os_printf("Could not create semaphore for "
762*4882a593Smuzhiyun 			       "synchronization between the created threads, %s\n",
763*4882a593Smuzhiyun 			       acpi_format_exception(status));
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun 		(void)acpi_os_delete_semaphore(main_thread_gate);
766*4882a593Smuzhiyun 		return;
767*4882a593Smuzhiyun 	}
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 	status = acpi_os_create_semaphore(1, 1, &info_gate);
770*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
771*4882a593Smuzhiyun 		acpi_os_printf("Could not create semaphore for "
772*4882a593Smuzhiyun 			       "synchronization of AcpiGbl_DbMethodInfo, %s\n",
773*4882a593Smuzhiyun 			       acpi_format_exception(status));
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 		(void)acpi_os_delete_semaphore(thread_complete_gate);
776*4882a593Smuzhiyun 		(void)acpi_os_delete_semaphore(main_thread_gate);
777*4882a593Smuzhiyun 		return;
778*4882a593Smuzhiyun 	}
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	memset(&acpi_gbl_db_method_info, 0, sizeof(struct acpi_db_method_info));
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	/* Array to store IDs of threads */
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	acpi_gbl_db_method_info.num_threads = num_threads;
785*4882a593Smuzhiyun 	size = sizeof(acpi_thread_id) * acpi_gbl_db_method_info.num_threads;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	acpi_gbl_db_method_info.threads = acpi_os_allocate(size);
788*4882a593Smuzhiyun 	if (acpi_gbl_db_method_info.threads == NULL) {
789*4882a593Smuzhiyun 		acpi_os_printf("No memory for thread IDs array\n");
790*4882a593Smuzhiyun 		(void)acpi_os_delete_semaphore(main_thread_gate);
791*4882a593Smuzhiyun 		(void)acpi_os_delete_semaphore(thread_complete_gate);
792*4882a593Smuzhiyun 		(void)acpi_os_delete_semaphore(info_gate);
793*4882a593Smuzhiyun 		return;
794*4882a593Smuzhiyun 	}
795*4882a593Smuzhiyun 	memset(acpi_gbl_db_method_info.threads, 0, size);
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	/* Setup the context to be passed to each thread */
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	acpi_gbl_db_method_info.name = method_name_arg;
800*4882a593Smuzhiyun 	acpi_gbl_db_method_info.flags = 0;
801*4882a593Smuzhiyun 	acpi_gbl_db_method_info.num_loops = num_loops;
802*4882a593Smuzhiyun 	acpi_gbl_db_method_info.main_thread_gate = main_thread_gate;
803*4882a593Smuzhiyun 	acpi_gbl_db_method_info.thread_complete_gate = thread_complete_gate;
804*4882a593Smuzhiyun 	acpi_gbl_db_method_info.info_gate = info_gate;
805*4882a593Smuzhiyun 
806*4882a593Smuzhiyun 	/* Init arguments to be passed to method */
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	acpi_gbl_db_method_info.init_args = 1;
809*4882a593Smuzhiyun 	acpi_gbl_db_method_info.args = acpi_gbl_db_method_info.arguments;
810*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arguments[0] =
811*4882a593Smuzhiyun 	    acpi_gbl_db_method_info.num_threads_str;
812*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arguments[1] =
813*4882a593Smuzhiyun 	    acpi_gbl_db_method_info.id_of_thread_str;
814*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arguments[2] =
815*4882a593Smuzhiyun 	    acpi_gbl_db_method_info.index_of_thread_str;
816*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arguments[3] = NULL;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 	acpi_gbl_db_method_info.types = acpi_gbl_db_method_info.arg_types;
819*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arg_types[0] = ACPI_TYPE_INTEGER;
820*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arg_types[1] = ACPI_TYPE_INTEGER;
821*4882a593Smuzhiyun 	acpi_gbl_db_method_info.arg_types[2] = ACPI_TYPE_INTEGER;
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	acpi_db_uint32_to_hex_string(num_threads,
824*4882a593Smuzhiyun 				     acpi_gbl_db_method_info.num_threads_str);
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 	status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
827*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
828*4882a593Smuzhiyun 		goto cleanup_and_exit;
829*4882a593Smuzhiyun 	}
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	/* Get the NS node, determines existence also */
832*4882a593Smuzhiyun 
833*4882a593Smuzhiyun 	status = acpi_get_handle(NULL, acpi_gbl_db_method_info.pathname,
834*4882a593Smuzhiyun 				 &acpi_gbl_db_method_info.method);
835*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
836*4882a593Smuzhiyun 		acpi_os_printf("%s Could not get handle for %s\n",
837*4882a593Smuzhiyun 			       acpi_format_exception(status),
838*4882a593Smuzhiyun 			       acpi_gbl_db_method_info.pathname);
839*4882a593Smuzhiyun 		goto cleanup_and_exit;
840*4882a593Smuzhiyun 	}
841*4882a593Smuzhiyun 
842*4882a593Smuzhiyun 	/* Create the threads */
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 	acpi_os_printf("Creating %X threads to execute %X times each\n",
845*4882a593Smuzhiyun 		       num_threads, num_loops);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 	for (i = 0; i < (num_threads); i++) {
848*4882a593Smuzhiyun 		status =
849*4882a593Smuzhiyun 		    acpi_os_execute(OSL_DEBUGGER_EXEC_THREAD,
850*4882a593Smuzhiyun 				    acpi_db_method_thread,
851*4882a593Smuzhiyun 				    &acpi_gbl_db_method_info);
852*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
853*4882a593Smuzhiyun 			break;
854*4882a593Smuzhiyun 		}
855*4882a593Smuzhiyun 	}
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	/* Wait for all threads to complete */
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	(void)acpi_os_wait_semaphore(main_thread_gate, 1, ACPI_WAIT_FOREVER);
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	acpi_db_set_output_destination(ACPI_DB_DUPLICATE_OUTPUT);
862*4882a593Smuzhiyun 	acpi_os_printf("All threads (%X) have completed\n", num_threads);
863*4882a593Smuzhiyun 	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
864*4882a593Smuzhiyun 
865*4882a593Smuzhiyun cleanup_and_exit:
866*4882a593Smuzhiyun 
867*4882a593Smuzhiyun 	/* Cleanup and exit */
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	(void)acpi_os_delete_semaphore(main_thread_gate);
870*4882a593Smuzhiyun 	(void)acpi_os_delete_semaphore(thread_complete_gate);
871*4882a593Smuzhiyun 	(void)acpi_os_delete_semaphore(info_gate);
872*4882a593Smuzhiyun 
873*4882a593Smuzhiyun 	acpi_os_free(acpi_gbl_db_method_info.threads);
874*4882a593Smuzhiyun 	acpi_gbl_db_method_info.threads = NULL;
875*4882a593Smuzhiyun }
876