xref: /openbmc/linux/drivers/acpi/acpica/dbcmds.c (revision 3a35093a)
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
3  *
4  * Module Name: dbcmds - Miscellaneous debug commands and output routines
5  *
6  ******************************************************************************/
7 
8 #include <acpi/acpi.h>
9 #include "accommon.h"
10 #include "acevents.h"
11 #include "acdebug.h"
12 #include "acnamesp.h"
13 #include "acresrc.h"
14 #include "actables.h"
15 
16 #define _COMPONENT          ACPI_CA_DEBUGGER
17 ACPI_MODULE_NAME("dbcmds")
18 
19 /* Local prototypes */
20 static void
21 acpi_dm_compare_aml_resources(u8 *aml1_buffer,
22 			      acpi_rsdesc_size aml1_buffer_length,
23 			      u8 *aml2_buffer,
24 			      acpi_rsdesc_size aml2_buffer_length);
25 
26 static acpi_status
27 acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name);
28 
29 static acpi_status
30 acpi_db_resource_callback(struct acpi_resource *resource, void *context);
31 
32 static acpi_status
33 acpi_db_device_resources(acpi_handle obj_handle,
34 			 u32 nesting_level, void *context, void **return_value);
35 
36 static void acpi_db_do_one_sleep_state(u8 sleep_state);
37 
38 static char *acpi_db_trace_method_name = NULL;
39 
40 /*******************************************************************************
41  *
42  * FUNCTION:    acpi_db_convert_to_node
43  *
44  * PARAMETERS:  in_string           - String to convert
45  *
46  * RETURN:      Pointer to a NS node
47  *
48  * DESCRIPTION: Convert a string to a valid NS pointer. Handles numeric or
49  *              alphanumeric strings.
50  *
51  ******************************************************************************/
52 
53 struct acpi_namespace_node *acpi_db_convert_to_node(char *in_string)
54 {
55 	struct acpi_namespace_node *node;
56 	acpi_size address;
57 
58 	if ((*in_string >= 0x30) && (*in_string <= 0x39)) {
59 
60 		/* Numeric argument, convert */
61 
62 		address = strtoul(in_string, NULL, 16);
63 		node = ACPI_TO_POINTER(address);
64 		if (!acpi_os_readable(node, sizeof(struct acpi_namespace_node))) {
65 			acpi_os_printf("Address %p is invalid", node);
66 			return (NULL);
67 		}
68 
69 		/* Make sure pointer is valid NS node */
70 
71 		if (ACPI_GET_DESCRIPTOR_TYPE(node) != ACPI_DESC_TYPE_NAMED) {
72 			acpi_os_printf
73 			    ("Address %p is not a valid namespace node [%s]\n",
74 			     node, acpi_ut_get_descriptor_name(node));
75 			return (NULL);
76 		}
77 	} else {
78 		/*
79 		 * Alpha argument: The parameter is a name string that must be
80 		 * resolved to a Namespace object.
81 		 */
82 		node = acpi_db_local_ns_lookup(in_string);
83 		if (!node) {
84 			acpi_os_printf
85 			    ("Could not find [%s] in namespace, defaulting to root node\n",
86 			     in_string);
87 			node = acpi_gbl_root_node;
88 		}
89 	}
90 
91 	return (node);
92 }
93 
94 /*******************************************************************************
95  *
96  * FUNCTION:    acpi_db_sleep
97  *
98  * PARAMETERS:  object_arg          - Desired sleep state (0-5). NULL means
99  *                                    invoke all possible sleep states.
100  *
101  * RETURN:      Status
102  *
103  * DESCRIPTION: Simulate sleep/wake sequences
104  *
105  ******************************************************************************/
106 
107 acpi_status acpi_db_sleep(char *object_arg)
108 {
109 	u8 sleep_state;
110 	u32 i;
111 
112 	ACPI_FUNCTION_TRACE(acpi_db_sleep);
113 
114 	/* Null input (no arguments) means to invoke all sleep states */
115 
116 	if (!object_arg) {
117 		acpi_os_printf("Invoking all possible sleep states, 0-%d\n",
118 			       ACPI_S_STATES_MAX);
119 
120 		for (i = 0; i <= ACPI_S_STATES_MAX; i++) {
121 			acpi_db_do_one_sleep_state((u8)i);
122 		}
123 
124 		return_ACPI_STATUS(AE_OK);
125 	}
126 
127 	/* Convert argument to binary and invoke the sleep state */
128 
129 	sleep_state = (u8)strtoul(object_arg, NULL, 0);
130 	acpi_db_do_one_sleep_state(sleep_state);
131 	return_ACPI_STATUS(AE_OK);
132 }
133 
134 /*******************************************************************************
135  *
136  * FUNCTION:    acpi_db_do_one_sleep_state
137  *
138  * PARAMETERS:  sleep_state         - Desired sleep state (0-5)
139  *
140  * RETURN:      None
141  *
142  * DESCRIPTION: Simulate a sleep/wake sequence
143  *
144  ******************************************************************************/
145 
146 static void acpi_db_do_one_sleep_state(u8 sleep_state)
147 {
148 	acpi_status status;
149 	u8 sleep_type_a;
150 	u8 sleep_type_b;
151 
152 	/* Validate parameter */
153 
154 	if (sleep_state > ACPI_S_STATES_MAX) {
155 		acpi_os_printf("Sleep state %d out of range (%d max)\n",
156 			       sleep_state, ACPI_S_STATES_MAX);
157 		return;
158 	}
159 
160 	acpi_os_printf("\n---- Invoking sleep state S%d (%s):\n",
161 		       sleep_state, acpi_gbl_sleep_state_names[sleep_state]);
162 
163 	/* Get the values for the sleep type registers (for display only) */
164 
165 	status =
166 	    acpi_get_sleep_type_data(sleep_state, &sleep_type_a, &sleep_type_b);
167 	if (ACPI_FAILURE(status)) {
168 		acpi_os_printf("Could not evaluate [%s] method, %s\n",
169 			       acpi_gbl_sleep_state_names[sleep_state],
170 			       acpi_format_exception(status));
171 		return;
172 	}
173 
174 	acpi_os_printf
175 	    ("Register values for sleep state S%d: Sleep-A: %.2X, Sleep-B: %.2X\n",
176 	     sleep_state, sleep_type_a, sleep_type_b);
177 
178 	/* Invoke the various sleep/wake interfaces */
179 
180 	acpi_os_printf("**** Sleep: Prepare to sleep (S%d) ****\n",
181 		       sleep_state);
182 	status = acpi_enter_sleep_state_prep(sleep_state);
183 	if (ACPI_FAILURE(status)) {
184 		goto error_exit;
185 	}
186 
187 	acpi_os_printf("**** Sleep: Going to sleep (S%d) ****\n", sleep_state);
188 	status = acpi_enter_sleep_state(sleep_state);
189 	if (ACPI_FAILURE(status)) {
190 		goto error_exit;
191 	}
192 
193 	acpi_os_printf("**** Wake: Prepare to return from sleep (S%d) ****\n",
194 		       sleep_state);
195 	status = acpi_leave_sleep_state_prep(sleep_state);
196 	if (ACPI_FAILURE(status)) {
197 		goto error_exit;
198 	}
199 
200 	acpi_os_printf("**** Wake: Return from sleep (S%d) ****\n",
201 		       sleep_state);
202 	status = acpi_leave_sleep_state(sleep_state);
203 	if (ACPI_FAILURE(status)) {
204 		goto error_exit;
205 	}
206 
207 	return;
208 
209 error_exit:
210 	ACPI_EXCEPTION((AE_INFO, status, "During invocation of sleep state S%d",
211 			sleep_state));
212 }
213 
214 /*******************************************************************************
215  *
216  * FUNCTION:    acpi_db_display_locks
217  *
218  * PARAMETERS:  None
219  *
220  * RETURN:      None
221  *
222  * DESCRIPTION: Display information about internal mutexes.
223  *
224  ******************************************************************************/
225 
226 void acpi_db_display_locks(void)
227 {
228 	u32 i;
229 
230 	for (i = 0; i < ACPI_MAX_MUTEX; i++) {
231 		acpi_os_printf("%26s : %s\n", acpi_ut_get_mutex_name(i),
232 			       acpi_gbl_mutex_info[i].thread_id ==
233 			       ACPI_MUTEX_NOT_ACQUIRED ? "Locked" : "Unlocked");
234 	}
235 }
236 
237 /*******************************************************************************
238  *
239  * FUNCTION:    acpi_db_display_table_info
240  *
241  * PARAMETERS:  table_arg           - Name of table to be displayed
242  *
243  * RETURN:      None
244  *
245  * DESCRIPTION: Display information about loaded tables. Current
246  *              implementation displays all loaded tables.
247  *
248  ******************************************************************************/
249 
250 void acpi_db_display_table_info(char *table_arg)
251 {
252 	u32 i;
253 	struct acpi_table_desc *table_desc;
254 	acpi_status status;
255 
256 	/* Header */
257 
258 	acpi_os_printf("Idx ID  Status Type                    "
259 		       "TableHeader (Sig, Address, Length, Misc)\n");
260 
261 	/* Walk the entire root table list */
262 
263 	for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
264 		table_desc = &acpi_gbl_root_table_list.tables[i];
265 
266 		/* Index and Table ID */
267 
268 		acpi_os_printf("%3u %.2u ", i, table_desc->owner_id);
269 
270 		/* Decode the table flags */
271 
272 		if (!(table_desc->flags & ACPI_TABLE_IS_LOADED)) {
273 			acpi_os_printf("NotLoaded ");
274 		} else {
275 			acpi_os_printf(" Loaded ");
276 		}
277 
278 		switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
279 		case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
280 
281 			acpi_os_printf("External/virtual ");
282 			break;
283 
284 		case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
285 
286 			acpi_os_printf("Internal/physical ");
287 			break;
288 
289 		case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
290 
291 			acpi_os_printf("Internal/virtual ");
292 			break;
293 
294 		default:
295 
296 			acpi_os_printf("INVALID TYPE    ");
297 			break;
298 		}
299 
300 		/* Make sure that the table is mapped */
301 
302 		status = acpi_tb_validate_table(table_desc);
303 		if (ACPI_FAILURE(status)) {
304 			return;
305 		}
306 
307 		/* Dump the table header */
308 
309 		if (table_desc->pointer) {
310 			acpi_tb_print_table_header(table_desc->address,
311 						   table_desc->pointer);
312 		} else {
313 			/* If the pointer is null, the table has been unloaded */
314 
315 			ACPI_INFO(("%4.4s - Table has been unloaded",
316 				   table_desc->signature.ascii));
317 		}
318 	}
319 }
320 
321 /*******************************************************************************
322  *
323  * FUNCTION:    acpi_db_unload_acpi_table
324  *
325  * PARAMETERS:  object_name         - Namespace pathname for an object that
326  *                                    is owned by the table to be unloaded
327  *
328  * RETURN:      None
329  *
330  * DESCRIPTION: Unload an ACPI table, via any namespace node that is owned
331  *              by the table.
332  *
333  ******************************************************************************/
334 
335 void acpi_db_unload_acpi_table(char *object_name)
336 {
337 	struct acpi_namespace_node *node;
338 	acpi_status status;
339 
340 	/* Translate name to an Named object */
341 
342 	node = acpi_db_convert_to_node(object_name);
343 	if (!node) {
344 		return;
345 	}
346 
347 	status = acpi_unload_parent_table(ACPI_CAST_PTR(acpi_handle, node));
348 	if (ACPI_SUCCESS(status)) {
349 		acpi_os_printf("Parent of [%s] (%p) unloaded and uninstalled\n",
350 			       object_name, node);
351 	} else {
352 		acpi_os_printf("%s, while unloading parent table of [%s]\n",
353 			       acpi_format_exception(status), object_name);
354 	}
355 }
356 
357 /*******************************************************************************
358  *
359  * FUNCTION:    acpi_db_send_notify
360  *
361  * PARAMETERS:  name                - Name of ACPI object where to send notify
362  *              value               - Value of the notify to send.
363  *
364  * RETURN:      None
365  *
366  * DESCRIPTION: Send an ACPI notification. The value specified is sent to the
367  *              named object as an ACPI notify.
368  *
369  ******************************************************************************/
370 
371 void acpi_db_send_notify(char *name, u32 value)
372 {
373 	struct acpi_namespace_node *node;
374 	acpi_status status;
375 
376 	/* Translate name to an Named object */
377 
378 	node = acpi_db_convert_to_node(name);
379 	if (!node) {
380 		return;
381 	}
382 
383 	/* Dispatch the notify if legal */
384 
385 	if (acpi_ev_is_notify_object(node)) {
386 		status = acpi_ev_queue_notify_request(node, value);
387 		if (ACPI_FAILURE(status)) {
388 			acpi_os_printf("Could not queue notify\n");
389 		}
390 	} else {
391 		acpi_os_printf("Named object [%4.4s] Type %s, "
392 			       "must be Device/Thermal/Processor type\n",
393 			       acpi_ut_get_node_name(node),
394 			       acpi_ut_get_type_name(node->type));
395 	}
396 }
397 
398 /*******************************************************************************
399  *
400  * FUNCTION:    acpi_db_display_interfaces
401  *
402  * PARAMETERS:  action_arg          - Null, "install", or "remove"
403  *              interface_name_arg  - Name for install/remove options
404  *
405  * RETURN:      None
406  *
407  * DESCRIPTION: Display or modify the global _OSI interface list
408  *
409  ******************************************************************************/
410 
411 void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg)
412 {
413 	struct acpi_interface_info *next_interface;
414 	char *sub_string;
415 	acpi_status status;
416 
417 	/* If no arguments, just display current interface list */
418 
419 	if (!action_arg) {
420 		(void)acpi_os_acquire_mutex(acpi_gbl_osi_mutex,
421 					    ACPI_WAIT_FOREVER);
422 
423 		next_interface = acpi_gbl_supported_interfaces;
424 		while (next_interface) {
425 			if (!(next_interface->flags & ACPI_OSI_INVALID)) {
426 				acpi_os_printf("%s\n", next_interface->name);
427 			}
428 
429 			next_interface = next_interface->next;
430 		}
431 
432 		acpi_os_release_mutex(acpi_gbl_osi_mutex);
433 		return;
434 	}
435 
436 	/* If action_arg exists, so must interface_name_arg */
437 
438 	if (!interface_name_arg) {
439 		acpi_os_printf("Missing Interface Name argument\n");
440 		return;
441 	}
442 
443 	/* Uppercase the action for match below */
444 
445 	acpi_ut_strupr(action_arg);
446 
447 	/* install - install an interface */
448 
449 	sub_string = strstr("INSTALL", action_arg);
450 	if (sub_string) {
451 		status = acpi_install_interface(interface_name_arg);
452 		if (ACPI_FAILURE(status)) {
453 			acpi_os_printf("%s, while installing \"%s\"\n",
454 				       acpi_format_exception(status),
455 				       interface_name_arg);
456 		}
457 		return;
458 	}
459 
460 	/* remove - remove an interface */
461 
462 	sub_string = strstr("REMOVE", action_arg);
463 	if (sub_string) {
464 		status = acpi_remove_interface(interface_name_arg);
465 		if (ACPI_FAILURE(status)) {
466 			acpi_os_printf("%s, while removing \"%s\"\n",
467 				       acpi_format_exception(status),
468 				       interface_name_arg);
469 		}
470 		return;
471 	}
472 
473 	/* Invalid action_arg */
474 
475 	acpi_os_printf("Invalid action argument: %s\n", action_arg);
476 	return;
477 }
478 
479 /*******************************************************************************
480  *
481  * FUNCTION:    acpi_db_display_template
482  *
483  * PARAMETERS:  buffer_arg          - Buffer name or address
484  *
485  * RETURN:      None
486  *
487  * DESCRIPTION: Dump a buffer that contains a resource template
488  *
489  ******************************************************************************/
490 
491 void acpi_db_display_template(char *buffer_arg)
492 {
493 	struct acpi_namespace_node *node;
494 	acpi_status status;
495 	struct acpi_buffer return_buffer;
496 
497 	/* Translate buffer_arg to an Named object */
498 
499 	node = acpi_db_convert_to_node(buffer_arg);
500 	if (!node || (node == acpi_gbl_root_node)) {
501 		acpi_os_printf("Invalid argument: %s\n", buffer_arg);
502 		return;
503 	}
504 
505 	/* We must have a buffer object */
506 
507 	if (node->type != ACPI_TYPE_BUFFER) {
508 		acpi_os_printf
509 		    ("Not a Buffer object, cannot be a template: %s\n",
510 		     buffer_arg);
511 		return;
512 	}
513 
514 	return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
515 	return_buffer.pointer = acpi_gbl_db_buffer;
516 
517 	/* Attempt to convert the raw buffer to a resource list */
518 
519 	status = acpi_rs_create_resource_list(node->object, &return_buffer);
520 
521 	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
522 	acpi_dbg_level |= ACPI_LV_RESOURCES;
523 
524 	if (ACPI_FAILURE(status)) {
525 		acpi_os_printf
526 		    ("Could not convert Buffer to a resource list: %s, %s\n",
527 		     buffer_arg, acpi_format_exception(status));
528 		goto dump_buffer;
529 	}
530 
531 	/* Now we can dump the resource list */
532 
533 	acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
534 						 return_buffer.pointer));
535 
536 dump_buffer:
537 	acpi_os_printf("\nRaw data buffer:\n");
538 	acpi_ut_debug_dump_buffer((u8 *)node->object->buffer.pointer,
539 				  node->object->buffer.length,
540 				  DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
541 
542 	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
543 	return;
544 }
545 
546 /*******************************************************************************
547  *
548  * FUNCTION:    acpi_dm_compare_aml_resources
549  *
550  * PARAMETERS:  aml1_buffer         - Contains first resource list
551  *              aml1_buffer_length  - Length of first resource list
552  *              aml2_buffer         - Contains second resource list
553  *              aml2_buffer_length  - Length of second resource list
554  *
555  * RETURN:      None
556  *
557  * DESCRIPTION: Compare two AML resource lists, descriptor by descriptor (in
558  *              order to isolate a miscompare to an individual resource)
559  *
560  ******************************************************************************/
561 
562 static void
563 acpi_dm_compare_aml_resources(u8 *aml1_buffer,
564 			      acpi_rsdesc_size aml1_buffer_length,
565 			      u8 *aml2_buffer,
566 			      acpi_rsdesc_size aml2_buffer_length)
567 {
568 	u8 *aml1;
569 	u8 *aml2;
570 	u8 *aml1_end;
571 	u8 *aml2_end;
572 	acpi_rsdesc_size aml1_length;
573 	acpi_rsdesc_size aml2_length;
574 	acpi_rsdesc_size offset = 0;
575 	u8 resource_type;
576 	u32 count = 0;
577 	u32 i;
578 
579 	/* Compare overall buffer sizes (may be different due to size rounding) */
580 
581 	if (aml1_buffer_length != aml2_buffer_length) {
582 		acpi_os_printf("**** Buffer length mismatch in converted "
583 			       "AML: Original %X, New %X ****\n",
584 			       aml1_buffer_length, aml2_buffer_length);
585 	}
586 
587 	aml1 = aml1_buffer;
588 	aml2 = aml2_buffer;
589 	aml1_end = aml1_buffer + aml1_buffer_length;
590 	aml2_end = aml2_buffer + aml2_buffer_length;
591 
592 	/* Walk the descriptor lists, comparing each descriptor */
593 
594 	while ((aml1 < aml1_end) && (aml2 < aml2_end)) {
595 
596 		/* Get the lengths of each descriptor */
597 
598 		aml1_length = acpi_ut_get_descriptor_length(aml1);
599 		aml2_length = acpi_ut_get_descriptor_length(aml2);
600 		resource_type = acpi_ut_get_resource_type(aml1);
601 
602 		/* Check for descriptor length match */
603 
604 		if (aml1_length != aml2_length) {
605 			acpi_os_printf
606 			    ("**** Length mismatch in descriptor [%.2X] type %2.2X, "
607 			     "Offset %8.8X Len1 %X, Len2 %X ****\n", count,
608 			     resource_type, offset, aml1_length, aml2_length);
609 		}
610 
611 		/* Check for descriptor byte match */
612 
613 		else if (memcmp(aml1, aml2, aml1_length)) {
614 			acpi_os_printf
615 			    ("**** Data mismatch in descriptor [%.2X] type %2.2X, "
616 			     "Offset %8.8X ****\n", count, resource_type,
617 			     offset);
618 
619 			for (i = 0; i < aml1_length; i++) {
620 				if (aml1[i] != aml2[i]) {
621 					acpi_os_printf
622 					    ("Mismatch at byte offset %.2X: is %2.2X, "
623 					     "should be %2.2X\n", i, aml2[i],
624 					     aml1[i]);
625 				}
626 			}
627 		}
628 
629 		/* Exit on end_tag descriptor */
630 
631 		if (resource_type == ACPI_RESOURCE_NAME_END_TAG) {
632 			return;
633 		}
634 
635 		/* Point to next descriptor in each buffer */
636 
637 		count++;
638 		offset += aml1_length;
639 		aml1 += aml1_length;
640 		aml2 += aml2_length;
641 	}
642 }
643 
644 /*******************************************************************************
645  *
646  * FUNCTION:    acpi_dm_test_resource_conversion
647  *
648  * PARAMETERS:  node                - Parent device node
649  *              name                - resource method name (_CRS)
650  *
651  * RETURN:      Status
652  *
653  * DESCRIPTION: Compare the original AML with a conversion of the AML to
654  *              internal resource list, then back to AML.
655  *
656  ******************************************************************************/
657 
658 static acpi_status
659 acpi_dm_test_resource_conversion(struct acpi_namespace_node *node, char *name)
660 {
661 	acpi_status status;
662 	struct acpi_buffer return_buffer;
663 	struct acpi_buffer resource_buffer;
664 	struct acpi_buffer new_aml;
665 	union acpi_object *original_aml;
666 
667 	acpi_os_printf("Resource Conversion Comparison:\n");
668 
669 	new_aml.length = ACPI_ALLOCATE_LOCAL_BUFFER;
670 	return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
671 	resource_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
672 
673 	/* Get the original _CRS AML resource template */
674 
675 	status = acpi_evaluate_object(node, name, NULL, &return_buffer);
676 	if (ACPI_FAILURE(status)) {
677 		acpi_os_printf("Could not obtain %s: %s\n",
678 			       name, acpi_format_exception(status));
679 		return (status);
680 	}
681 
682 	/* Get the AML resource template, converted to internal resource structs */
683 
684 	status = acpi_get_current_resources(node, &resource_buffer);
685 	if (ACPI_FAILURE(status)) {
686 		acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
687 			       acpi_format_exception(status));
688 		goto exit1;
689 	}
690 
691 	/* Convert internal resource list to external AML resource template */
692 
693 	status = acpi_rs_create_aml_resources(&resource_buffer, &new_aml);
694 	if (ACPI_FAILURE(status)) {
695 		acpi_os_printf("AcpiRsCreateAmlResources failed: %s\n",
696 			       acpi_format_exception(status));
697 		goto exit2;
698 	}
699 
700 	/* Compare original AML to the newly created AML resource list */
701 
702 	original_aml = return_buffer.pointer;
703 
704 	acpi_dm_compare_aml_resources(original_aml->buffer.pointer,
705 				      (acpi_rsdesc_size)original_aml->buffer.
706 				      length, new_aml.pointer,
707 				      (acpi_rsdesc_size)new_aml.length);
708 
709 	/* Cleanup and exit */
710 
711 	ACPI_FREE(new_aml.pointer);
712 exit2:
713 	ACPI_FREE(resource_buffer.pointer);
714 exit1:
715 	ACPI_FREE(return_buffer.pointer);
716 	return (status);
717 }
718 
719 /*******************************************************************************
720  *
721  * FUNCTION:    acpi_db_resource_callback
722  *
723  * PARAMETERS:  acpi_walk_resource_callback
724  *
725  * RETURN:      Status
726  *
727  * DESCRIPTION: Simple callback to exercise acpi_walk_resources and
728  *              acpi_walk_resource_buffer.
729  *
730  ******************************************************************************/
731 
732 static acpi_status
733 acpi_db_resource_callback(struct acpi_resource *resource, void *context)
734 {
735 
736 	return (AE_OK);
737 }
738 
739 /*******************************************************************************
740  *
741  * FUNCTION:    acpi_db_device_resources
742  *
743  * PARAMETERS:  acpi_walk_callback
744  *
745  * RETURN:      Status
746  *
747  * DESCRIPTION: Display the _PRT/_CRS/_PRS resources for a device object.
748  *
749  ******************************************************************************/
750 
751 static acpi_status
752 acpi_db_device_resources(acpi_handle obj_handle,
753 			 u32 nesting_level, void *context, void **return_value)
754 {
755 	struct acpi_namespace_node *node;
756 	struct acpi_namespace_node *prt_node = NULL;
757 	struct acpi_namespace_node *crs_node = NULL;
758 	struct acpi_namespace_node *prs_node = NULL;
759 	struct acpi_namespace_node *aei_node = NULL;
760 	char *parent_path;
761 	struct acpi_buffer return_buffer;
762 	acpi_status status;
763 
764 	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);
765 	parent_path = acpi_ns_get_normalized_pathname(node, TRUE);
766 	if (!parent_path) {
767 		return (AE_NO_MEMORY);
768 	}
769 
770 	/* Get handles to the resource methods for this device */
771 
772 	(void)acpi_get_handle(node, METHOD_NAME__PRT,
773 			      ACPI_CAST_PTR(acpi_handle, &prt_node));
774 	(void)acpi_get_handle(node, METHOD_NAME__CRS,
775 			      ACPI_CAST_PTR(acpi_handle, &crs_node));
776 	(void)acpi_get_handle(node, METHOD_NAME__PRS,
777 			      ACPI_CAST_PTR(acpi_handle, &prs_node));
778 	(void)acpi_get_handle(node, METHOD_NAME__AEI,
779 			      ACPI_CAST_PTR(acpi_handle, &aei_node));
780 
781 	if (!prt_node && !crs_node && !prs_node && !aei_node) {
782 		goto cleanup;	/* Nothing to do */
783 	}
784 
785 	acpi_os_printf("\nDevice: %s\n", parent_path);
786 
787 	/* Prepare for a return object of arbitrary size */
788 
789 	return_buffer.pointer = acpi_gbl_db_buffer;
790 	return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
791 
792 	/* _PRT */
793 
794 	if (prt_node) {
795 		acpi_os_printf("Evaluating _PRT\n");
796 
797 		status =
798 		    acpi_evaluate_object(prt_node, NULL, NULL, &return_buffer);
799 		if (ACPI_FAILURE(status)) {
800 			acpi_os_printf("Could not evaluate _PRT: %s\n",
801 				       acpi_format_exception(status));
802 			goto get_crs;
803 		}
804 
805 		return_buffer.pointer = acpi_gbl_db_buffer;
806 		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
807 
808 		status = acpi_get_irq_routing_table(node, &return_buffer);
809 		if (ACPI_FAILURE(status)) {
810 			acpi_os_printf("GetIrqRoutingTable failed: %s\n",
811 				       acpi_format_exception(status));
812 			goto get_crs;
813 		}
814 
815 		acpi_rs_dump_irq_list(ACPI_CAST_PTR(u8, acpi_gbl_db_buffer));
816 	}
817 
818 	/* _CRS */
819 
820 get_crs:
821 	if (crs_node) {
822 		acpi_os_printf("Evaluating _CRS\n");
823 
824 		return_buffer.pointer = acpi_gbl_db_buffer;
825 		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
826 
827 		status =
828 		    acpi_evaluate_object(crs_node, NULL, NULL, &return_buffer);
829 		if (ACPI_FAILURE(status)) {
830 			acpi_os_printf("Could not evaluate _CRS: %s\n",
831 				       acpi_format_exception(status));
832 			goto get_prs;
833 		}
834 
835 		/* This code exercises the acpi_walk_resources interface */
836 
837 		status = acpi_walk_resources(node, METHOD_NAME__CRS,
838 					     acpi_db_resource_callback, NULL);
839 		if (ACPI_FAILURE(status)) {
840 			acpi_os_printf("AcpiWalkResources failed: %s\n",
841 				       acpi_format_exception(status));
842 			goto get_prs;
843 		}
844 
845 		/* Get the _CRS resource list (test ALLOCATE buffer) */
846 
847 		return_buffer.pointer = NULL;
848 		return_buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
849 
850 		status = acpi_get_current_resources(node, &return_buffer);
851 		if (ACPI_FAILURE(status)) {
852 			acpi_os_printf("AcpiGetCurrentResources failed: %s\n",
853 				       acpi_format_exception(status));
854 			goto get_prs;
855 		}
856 
857 		/* This code exercises the acpi_walk_resource_buffer interface */
858 
859 		status = acpi_walk_resource_buffer(&return_buffer,
860 						   acpi_db_resource_callback,
861 						   NULL);
862 		if (ACPI_FAILURE(status)) {
863 			acpi_os_printf("AcpiWalkResourceBuffer failed: %s\n",
864 				       acpi_format_exception(status));
865 			goto end_crs;
866 		}
867 
868 		/* Dump the _CRS resource list */
869 
870 		acpi_rs_dump_resource_list(ACPI_CAST_PTR(struct acpi_resource,
871 							 return_buffer.
872 							 pointer));
873 
874 		/*
875 		 * Perform comparison of original AML to newly created AML. This
876 		 * tests both the AML->Resource conversion and the Resource->AML
877 		 * conversion.
878 		 */
879 		(void)acpi_dm_test_resource_conversion(node, METHOD_NAME__CRS);
880 
881 		/* Execute _SRS with the resource list */
882 
883 		acpi_os_printf("Evaluating _SRS\n");
884 
885 		status = acpi_set_current_resources(node, &return_buffer);
886 		if (ACPI_FAILURE(status)) {
887 			acpi_os_printf("AcpiSetCurrentResources failed: %s\n",
888 				       acpi_format_exception(status));
889 			goto end_crs;
890 		}
891 
892 end_crs:
893 		ACPI_FREE(return_buffer.pointer);
894 	}
895 
896 	/* _PRS */
897 
898 get_prs:
899 	if (prs_node) {
900 		acpi_os_printf("Evaluating _PRS\n");
901 
902 		return_buffer.pointer = acpi_gbl_db_buffer;
903 		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
904 
905 		status =
906 		    acpi_evaluate_object(prs_node, NULL, NULL, &return_buffer);
907 		if (ACPI_FAILURE(status)) {
908 			acpi_os_printf("Could not evaluate _PRS: %s\n",
909 				       acpi_format_exception(status));
910 			goto get_aei;
911 		}
912 
913 		return_buffer.pointer = acpi_gbl_db_buffer;
914 		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
915 
916 		status = acpi_get_possible_resources(node, &return_buffer);
917 		if (ACPI_FAILURE(status)) {
918 			acpi_os_printf("AcpiGetPossibleResources failed: %s\n",
919 				       acpi_format_exception(status));
920 			goto get_aei;
921 		}
922 
923 		acpi_rs_dump_resource_list(ACPI_CAST_PTR
924 					   (struct acpi_resource,
925 					    acpi_gbl_db_buffer));
926 	}
927 
928 	/* _AEI */
929 
930 get_aei:
931 	if (aei_node) {
932 		acpi_os_printf("Evaluating _AEI\n");
933 
934 		return_buffer.pointer = acpi_gbl_db_buffer;
935 		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
936 
937 		status =
938 		    acpi_evaluate_object(aei_node, NULL, NULL, &return_buffer);
939 		if (ACPI_FAILURE(status)) {
940 			acpi_os_printf("Could not evaluate _AEI: %s\n",
941 				       acpi_format_exception(status));
942 			goto cleanup;
943 		}
944 
945 		return_buffer.pointer = acpi_gbl_db_buffer;
946 		return_buffer.length = ACPI_DEBUG_BUFFER_SIZE;
947 
948 		status = acpi_get_event_resources(node, &return_buffer);
949 		if (ACPI_FAILURE(status)) {
950 			acpi_os_printf("AcpiGetEventResources failed: %s\n",
951 				       acpi_format_exception(status));
952 			goto cleanup;
953 		}
954 
955 		acpi_rs_dump_resource_list(ACPI_CAST_PTR
956 					   (struct acpi_resource,
957 					    acpi_gbl_db_buffer));
958 	}
959 
960 cleanup:
961 	ACPI_FREE(parent_path);
962 	return (AE_OK);
963 }
964 
965 /*******************************************************************************
966  *
967  * FUNCTION:    acpi_db_display_resources
968  *
969  * PARAMETERS:  object_arg          - String object name or object pointer.
970  *                                    NULL or "*" means "display resources for
971  *                                    all devices"
972  *
973  * RETURN:      None
974  *
975  * DESCRIPTION: Display the resource objects associated with a device.
976  *
977  ******************************************************************************/
978 
979 void acpi_db_display_resources(char *object_arg)
980 {
981 	struct acpi_namespace_node *node;
982 
983 	acpi_db_set_output_destination(ACPI_DB_REDIRECTABLE_OUTPUT);
984 	acpi_dbg_level |= ACPI_LV_RESOURCES;
985 
986 	/* Asterisk means "display resources for all devices" */
987 
988 	if (!object_arg || (!strcmp(object_arg, "*"))) {
989 		(void)acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
990 					  ACPI_UINT32_MAX,
991 					  acpi_db_device_resources, NULL, NULL,
992 					  NULL);
993 	} else {
994 		/* Convert string to object pointer */
995 
996 		node = acpi_db_convert_to_node(object_arg);
997 		if (node) {
998 			if (node->type != ACPI_TYPE_DEVICE) {
999 				acpi_os_printf
1000 				    ("%4.4s: Name is not a device object (%s)\n",
1001 				     node->name.ascii,
1002 				     acpi_ut_get_type_name(node->type));
1003 			} else {
1004 				(void)acpi_db_device_resources(node, 0, NULL,
1005 							       NULL);
1006 			}
1007 		}
1008 	}
1009 
1010 	acpi_db_set_output_destination(ACPI_DB_CONSOLE_OUTPUT);
1011 }
1012 
1013 #if (!ACPI_REDUCED_HARDWARE)
1014 /*******************************************************************************
1015  *
1016  * FUNCTION:    acpi_db_generate_gpe
1017  *
1018  * PARAMETERS:  gpe_arg             - Raw GPE number, ascii string
1019  *              block_arg           - GPE block number, ascii string
1020  *                                    0 or 1 for FADT GPE blocks
1021  *
1022  * RETURN:      None
1023  *
1024  * DESCRIPTION: Simulate firing of a GPE
1025  *
1026  ******************************************************************************/
1027 
1028 void acpi_db_generate_gpe(char *gpe_arg, char *block_arg)
1029 {
1030 	u32 block_number = 0;
1031 	u32 gpe_number;
1032 	struct acpi_gpe_event_info *gpe_event_info;
1033 
1034 	gpe_number = strtoul(gpe_arg, NULL, 0);
1035 
1036 	/*
1037 	 * If no block arg, or block arg == 0 or 1, use the FADT-defined
1038 	 * GPE blocks.
1039 	 */
1040 	if (block_arg) {
1041 		block_number = strtoul(block_arg, NULL, 0);
1042 		if (block_number == 1) {
1043 			block_number = 0;
1044 		}
1045 	}
1046 
1047 	gpe_event_info =
1048 	    acpi_ev_get_gpe_event_info(ACPI_TO_POINTER(block_number),
1049 				       gpe_number);
1050 	if (!gpe_event_info) {
1051 		acpi_os_printf("Invalid GPE\n");
1052 		return;
1053 	}
1054 
1055 	(void)acpi_ev_gpe_dispatch(NULL, gpe_event_info, gpe_number);
1056 }
1057 
1058 /*******************************************************************************
1059  *
1060  * FUNCTION:    acpi_db_generate_sci
1061  *
1062  * PARAMETERS:  None
1063  *
1064  * RETURN:      None
1065  *
1066  * DESCRIPTION: Simulate an SCI -- just call the SCI dispatch.
1067  *
1068  ******************************************************************************/
1069 
1070 void acpi_db_generate_sci(void)
1071 {
1072 	acpi_ev_sci_dispatch();
1073 }
1074 
1075 #endif				/* !ACPI_REDUCED_HARDWARE */
1076 
1077 /*******************************************************************************
1078  *
1079  * FUNCTION:    acpi_db_trace
1080  *
1081  * PARAMETERS:  enable_arg          - ENABLE/AML to enable tracer
1082  *                                    DISABLE to disable tracer
1083  *              method_arg          - Method to trace
1084  *              once_arg            - Whether trace once
1085  *
1086  * RETURN:      None
1087  *
1088  * DESCRIPTION: Control method tracing facility
1089  *
1090  ******************************************************************************/
1091 
1092 void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg)
1093 {
1094 	u32 debug_level = 0;
1095 	u32 debug_layer = 0;
1096 	u32 flags = 0;
1097 
1098 	acpi_ut_strupr(enable_arg);
1099 	acpi_ut_strupr(once_arg);
1100 
1101 	if (method_arg) {
1102 		if (acpi_db_trace_method_name) {
1103 			ACPI_FREE(acpi_db_trace_method_name);
1104 			acpi_db_trace_method_name = NULL;
1105 		}
1106 
1107 		acpi_db_trace_method_name =
1108 		    ACPI_ALLOCATE(strlen(method_arg) + 1);
1109 		if (!acpi_db_trace_method_name) {
1110 			acpi_os_printf("Failed to allocate method name (%s)\n",
1111 				       method_arg);
1112 			return;
1113 		}
1114 
1115 		strcpy(acpi_db_trace_method_name, method_arg);
1116 	}
1117 
1118 	if (!strcmp(enable_arg, "ENABLE") ||
1119 	    !strcmp(enable_arg, "METHOD") || !strcmp(enable_arg, "OPCODE")) {
1120 		if (!strcmp(enable_arg, "ENABLE")) {
1121 
1122 			/* Inherit current console settings */
1123 
1124 			debug_level = acpi_gbl_db_console_debug_level;
1125 			debug_layer = acpi_dbg_layer;
1126 		} else {
1127 			/* Restrict console output to trace points only */
1128 
1129 			debug_level = ACPI_LV_TRACE_POINT;
1130 			debug_layer = ACPI_EXECUTER;
1131 		}
1132 
1133 		flags = ACPI_TRACE_ENABLED;
1134 
1135 		if (!strcmp(enable_arg, "OPCODE")) {
1136 			flags |= ACPI_TRACE_OPCODE;
1137 		}
1138 
1139 		if (once_arg && !strcmp(once_arg, "ONCE")) {
1140 			flags |= ACPI_TRACE_ONESHOT;
1141 		}
1142 	}
1143 
1144 	(void)acpi_debug_trace(acpi_db_trace_method_name,
1145 			       debug_level, debug_layer, flags);
1146 }
1147