brintos

brintos / linux-shallow public Read only

0
0
Text · 18.8 KiB · 86d126f Raw
680 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: nsinit - namespace initialization5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "acnamesp.h"13#include "acdispat.h"14#include "acinterp.h"15#include "acevents.h"16 17#define _COMPONENT          ACPI_NAMESPACE18ACPI_MODULE_NAME("nsinit")19 20/* Local prototypes */21static acpi_status22acpi_ns_init_one_object(acpi_handle obj_handle,23			u32 level, void *context, void **return_value);24 25static acpi_status26acpi_ns_init_one_device(acpi_handle obj_handle,27			u32 nesting_level, void *context, void **return_value);28 29static acpi_status30acpi_ns_find_ini_methods(acpi_handle obj_handle,31			 u32 nesting_level, void *context, void **return_value);32 33/*******************************************************************************34 *35 * FUNCTION:    acpi_ns_initialize_objects36 *37 * PARAMETERS:  None38 *39 * RETURN:      Status40 *41 * DESCRIPTION: Walk the entire namespace and perform any necessary42 *              initialization on the objects found therein43 *44 ******************************************************************************/45 46acpi_status acpi_ns_initialize_objects(void)47{48	acpi_status status;49	struct acpi_init_walk_info info;50 51	ACPI_FUNCTION_TRACE(ns_initialize_objects);52 53	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,54			  "[Init] Completing Initialization of ACPI Objects\n"));55	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,56			  "**** Starting initialization of namespace objects ****\n"));57	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,58			      "Final data object initialization: "));59 60	/* Clear the info block */61 62	memset(&info, 0, sizeof(struct acpi_init_walk_info));63 64	/* Walk entire namespace from the supplied root */65 66	/*67	 * TBD: will become ACPI_TYPE_PACKAGE as this type object68	 * is now the only one that supports deferred initialization69	 * (forward references).70	 */71	status = acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,72				     ACPI_UINT32_MAX, acpi_ns_init_one_object,73				     NULL, &info, NULL);74	if (ACPI_FAILURE(status)) {75		ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));76	}77 78	ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,79			      "Namespace contains %u (0x%X) objects\n",80			      info.object_count, info.object_count));81 82	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,83			  "%u Control Methods found\n%u Op Regions found\n",84			  info.method_count, info.op_region_count));85 86	return_ACPI_STATUS(AE_OK);87}88 89/*******************************************************************************90 *91 * FUNCTION:    acpi_ns_initialize_devices92 *93 * PARAMETERS:  None94 *95 * RETURN:      acpi_status96 *97 * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices.98 *              This means running _INI on all present devices.99 *100 *              Note: We install PCI config space handler on region access,101 *              not here.102 *103 ******************************************************************************/104 105acpi_status acpi_ns_initialize_devices(u32 flags)106{107	acpi_status status = AE_OK;108	struct acpi_device_walk_info info;109	acpi_handle handle;110 111	ACPI_FUNCTION_TRACE(ns_initialize_devices);112 113	if (!(flags & ACPI_NO_DEVICE_INIT)) {114		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,115				  "[Init] Initializing ACPI Devices\n"));116 117		/* Init counters */118 119		info.device_count = 0;120		info.num_STA = 0;121		info.num_INI = 0;122 123		ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,124				      "Initializing Device/Processor/Thermal objects "125				      "and executing _INI/_STA methods:\n"));126 127		/* Tree analysis: find all subtrees that contain _INI methods */128 129		status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,130						ACPI_UINT32_MAX, FALSE,131						acpi_ns_find_ini_methods, NULL,132						&info, NULL);133		if (ACPI_FAILURE(status)) {134			goto error_exit;135		}136 137		/* Allocate the evaluation information block */138 139		info.evaluate_info =140		    ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));141		if (!info.evaluate_info) {142			status = AE_NO_MEMORY;143			goto error_exit;144		}145 146		/*147		 * Execute the "global" _INI method that may appear at the root.148		 * This support is provided for Windows compatibility (Vista+) and149		 * is not part of the ACPI specification.150		 */151		info.evaluate_info->prefix_node = acpi_gbl_root_node;152		info.evaluate_info->relative_pathname = METHOD_NAME__INI;153		info.evaluate_info->parameters = NULL;154		info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;155 156		status = acpi_ns_evaluate(info.evaluate_info);157		if (ACPI_SUCCESS(status)) {158			info.num_INI++;159		}160 161		/*162		 * Execute \_SB._INI.163		 * There appears to be a strict order requirement for \_SB._INI,164		 * which should be evaluated before any _REG evaluations.165		 */166		status = acpi_get_handle(NULL, "\\_SB", &handle);167		if (ACPI_SUCCESS(status)) {168			memset(info.evaluate_info, 0,169			       sizeof(struct acpi_evaluate_info));170			info.evaluate_info->prefix_node = handle;171			info.evaluate_info->relative_pathname =172			    METHOD_NAME__INI;173			info.evaluate_info->parameters = NULL;174			info.evaluate_info->flags = ACPI_IGNORE_RETURN_VALUE;175 176			status = acpi_ns_evaluate(info.evaluate_info);177			if (ACPI_SUCCESS(status)) {178				info.num_INI++;179			}180		}181	}182 183	/*184	 * Run all _REG methods185	 *186	 * Note: Any objects accessed by the _REG methods will be automatically187	 * initialized, even if they contain executable AML (see the call to188	 * acpi_ns_initialize_objects below).189	 *190	 * Note: According to the ACPI specification, we actually needn't execute191	 * _REG for system_memory/system_io operation regions, but for PCI_Config192	 * operation regions, it is required to evaluate _REG for those on a PCI193	 * root bus that doesn't contain _BBN object. So this code is kept here194	 * in order not to break things.195	 */196	if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {197		ACPI_DEBUG_PRINT((ACPI_DB_EXEC,198				  "[Init] Executing _REG OpRegion methods\n"));199 200		status = acpi_ev_initialize_op_regions();201		if (ACPI_FAILURE(status)) {202			goto error_exit;203		}204	}205 206	if (!(flags & ACPI_NO_DEVICE_INIT)) {207 208		/* Walk namespace to execute all _INIs on present devices */209 210		status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,211						ACPI_UINT32_MAX, FALSE,212						acpi_ns_init_one_device, NULL,213						&info, NULL);214 215		/*216		 * Any _OSI requests should be completed by now. If the BIOS has217		 * requested any Windows OSI strings, we will always truncate218		 * I/O addresses to 16 bits -- for Windows compatibility.219		 */220		if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) {221			acpi_gbl_truncate_io_addresses = TRUE;222		}223 224		ACPI_FREE(info.evaluate_info);225		if (ACPI_FAILURE(status)) {226			goto error_exit;227		}228 229		ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,230				      "    Executed %u _INI methods requiring %u _STA executions "231				      "(examined %u objects)\n",232				      info.num_INI, info.num_STA,233				      info.device_count));234	}235 236	return_ACPI_STATUS(status);237 238error_exit:239	ACPI_EXCEPTION((AE_INFO, status, "During device initialization"));240	return_ACPI_STATUS(status);241}242 243/*******************************************************************************244 *245 * FUNCTION:    acpi_ns_init_one_package246 *247 * PARAMETERS:  obj_handle      - Node248 *              level           - Current nesting level249 *              context         - Not used250 *              return_value    - Not used251 *252 * RETURN:      Status253 *254 * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every package255 *              within the namespace. Used during dynamic load of an SSDT.256 *257 ******************************************************************************/258 259acpi_status260acpi_ns_init_one_package(acpi_handle obj_handle,261			 u32 level, void *context, void **return_value)262{263	acpi_status status;264	union acpi_operand_object *obj_desc;265	struct acpi_namespace_node *node =266	    (struct acpi_namespace_node *)obj_handle;267 268	obj_desc = acpi_ns_get_attached_object(node);269	if (!obj_desc) {270		return (AE_OK);271	}272 273	/* Exit if package is already initialized */274 275	if (obj_desc->package.flags & AOPOBJ_DATA_VALID) {276		return (AE_OK);277	}278 279	status = acpi_ds_get_package_arguments(obj_desc);280	if (ACPI_FAILURE(status)) {281		return (AE_OK);282	}283 284	status =285	    acpi_ut_walk_package_tree(obj_desc, NULL,286				      acpi_ds_init_package_element, NULL);287	if (ACPI_FAILURE(status)) {288		return (AE_OK);289	}290 291	obj_desc->package.flags |= AOPOBJ_DATA_VALID;292	return (AE_OK);293}294 295/*******************************************************************************296 *297 * FUNCTION:    acpi_ns_init_one_object298 *299 * PARAMETERS:  obj_handle      - Node300 *              level           - Current nesting level301 *              context         - Points to a init info struct302 *              return_value    - Not used303 *304 * RETURN:      Status305 *306 * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object307 *              within the namespace.308 *309 *              Currently, the only objects that require initialization are:310 *              1) Methods311 *              2) Op Regions312 *313 ******************************************************************************/314 315static acpi_status316acpi_ns_init_one_object(acpi_handle obj_handle,317			u32 level, void *context, void **return_value)318{319	acpi_object_type type;320	acpi_status status = AE_OK;321	struct acpi_init_walk_info *info =322	    (struct acpi_init_walk_info *)context;323	struct acpi_namespace_node *node =324	    (struct acpi_namespace_node *)obj_handle;325	union acpi_operand_object *obj_desc;326 327	ACPI_FUNCTION_NAME(ns_init_one_object);328 329	info->object_count++;330 331	/* And even then, we are only interested in a few object types */332 333	type = acpi_ns_get_type(obj_handle);334	obj_desc = acpi_ns_get_attached_object(node);335	if (!obj_desc) {336		return (AE_OK);337	}338 339	/* Increment counters for object types we are looking for */340 341	switch (type) {342	case ACPI_TYPE_REGION:343 344		info->op_region_count++;345		break;346 347	case ACPI_TYPE_BUFFER_FIELD:348 349		info->field_count++;350		break;351 352	case ACPI_TYPE_LOCAL_BANK_FIELD:353 354		info->field_count++;355		break;356 357	case ACPI_TYPE_BUFFER:358 359		info->buffer_count++;360		break;361 362	case ACPI_TYPE_PACKAGE:363 364		info->package_count++;365		break;366 367	default:368 369		/* No init required, just exit now */370 371		return (AE_OK);372	}373 374	/* If the object is already initialized, nothing else to do */375 376	if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {377		return (AE_OK);378	}379 380	/* Must lock the interpreter before executing AML code */381 382	acpi_ex_enter_interpreter();383 384	/*385	 * Only initialization of Package objects can be deferred, in order386	 * to support forward references.387	 */388	switch (type) {389	case ACPI_TYPE_LOCAL_BANK_FIELD:390 391		/* TBD: bank_fields do not require deferred init, remove this code */392 393		info->field_init++;394		status = acpi_ds_get_bank_field_arguments(obj_desc);395		break;396 397	case ACPI_TYPE_PACKAGE:398 399		/* Complete the initialization/resolution of the package object */400 401		info->package_init++;402		status =403		    acpi_ns_init_one_package(obj_handle, level, NULL, NULL);404		break;405 406	default:407 408		/* No other types should get here */409 410		status = AE_TYPE;411		ACPI_EXCEPTION((AE_INFO, status,412				"Opcode is not deferred [%4.4s] (%s)",413				acpi_ut_get_node_name(node),414				acpi_ut_get_type_name(type)));415		break;416	}417 418	if (ACPI_FAILURE(status)) {419		ACPI_EXCEPTION((AE_INFO, status,420				"Could not execute arguments for [%4.4s] (%s)",421				acpi_ut_get_node_name(node),422				acpi_ut_get_type_name(type)));423	}424 425	/*426	 * We ignore errors from above, and always return OK, since we don't want427	 * to abort the walk on any single error.428	 */429	acpi_ex_exit_interpreter();430	return (AE_OK);431}432 433/*******************************************************************************434 *435 * FUNCTION:    acpi_ns_find_ini_methods436 *437 * PARAMETERS:  acpi_walk_callback438 *439 * RETURN:      acpi_status440 *441 * DESCRIPTION: Called during namespace walk. Finds objects named _INI under442 *              device/processor/thermal objects, and marks the entire subtree443 *              with a SUBTREE_HAS_INI flag. This flag is used during the444 *              subsequent device initialization walk to avoid entire subtrees445 *              that do not contain an _INI.446 *447 ******************************************************************************/448 449static acpi_status450acpi_ns_find_ini_methods(acpi_handle obj_handle,451			 u32 nesting_level, void *context, void **return_value)452{453	struct acpi_device_walk_info *info =454	    ACPI_CAST_PTR(struct acpi_device_walk_info, context);455	struct acpi_namespace_node *node;456	struct acpi_namespace_node *parent_node;457 458	/* Keep count of device/processor/thermal objects */459 460	node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);461	if ((node->type == ACPI_TYPE_DEVICE) ||462	    (node->type == ACPI_TYPE_PROCESSOR) ||463	    (node->type == ACPI_TYPE_THERMAL)) {464		info->device_count++;465		return (AE_OK);466	}467 468	/* We are only looking for methods named _INI */469 470	if (!ACPI_COMPARE_NAMESEG(node->name.ascii, METHOD_NAME__INI)) {471		return (AE_OK);472	}473 474	/*475	 * The only _INI methods that we care about are those that are476	 * present under Device, Processor, and Thermal objects.477	 */478	parent_node = node->parent;479	switch (parent_node->type) {480	case ACPI_TYPE_DEVICE:481	case ACPI_TYPE_PROCESSOR:482	case ACPI_TYPE_THERMAL:483 484		/* Mark parent and bubble up the INI present flag to the root */485 486		while (parent_node) {487			parent_node->flags |= ANOBJ_SUBTREE_HAS_INI;488			parent_node = parent_node->parent;489		}490		break;491 492	default:493 494		break;495	}496 497	return (AE_OK);498}499 500/*******************************************************************************501 *502 * FUNCTION:    acpi_ns_init_one_device503 *504 * PARAMETERS:  acpi_walk_callback505 *506 * RETURN:      acpi_status507 *508 * DESCRIPTION: This is called once per device soon after ACPI is enabled509 *              to initialize each device. It determines if the device is510 *              present, and if so, calls _INI.511 *512 ******************************************************************************/513 514static acpi_status515acpi_ns_init_one_device(acpi_handle obj_handle,516			u32 nesting_level, void *context, void **return_value)517{518	struct acpi_device_walk_info *walk_info =519	    ACPI_CAST_PTR(struct acpi_device_walk_info, context);520	struct acpi_evaluate_info *info = walk_info->evaluate_info;521	u32 flags;522	acpi_status status;523	struct acpi_namespace_node *device_node;524 525	ACPI_FUNCTION_TRACE(ns_init_one_device);526 527	/* We are interested in Devices, Processors and thermal_zones only */528 529	device_node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_handle);530	if ((device_node->type != ACPI_TYPE_DEVICE) &&531	    (device_node->type != ACPI_TYPE_PROCESSOR) &&532	    (device_node->type != ACPI_TYPE_THERMAL)) {533		return_ACPI_STATUS(AE_OK);534	}535 536	/*537	 * Because of an earlier namespace analysis, all subtrees that contain an538	 * _INI method are tagged.539	 *540	 * If this device subtree does not contain any _INI methods, we541	 * can exit now and stop traversing this entire subtree.542	 */543	if (!(device_node->flags & ANOBJ_SUBTREE_HAS_INI)) {544		return_ACPI_STATUS(AE_CTRL_DEPTH);545	}546 547	/*548	 * Run _STA to determine if this device is present and functioning. We549	 * must know this information for two important reasons (from ACPI spec):550	 *551	 * 1) We can only run _INI if the device is present.552	 * 2) We must abort the device tree walk on this subtree if the device is553	 *    not present and is not functional (we will not examine the children)554	 *555	 * The _STA method is not required to be present under the device, we556	 * assume the device is present if _STA does not exist.557	 */558	ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname559			(ACPI_TYPE_METHOD, device_node, METHOD_NAME__STA));560 561	status = acpi_ut_execute_STA(device_node, &flags);562	if (ACPI_FAILURE(status)) {563 564		/* Ignore error and move on to next device */565 566		return_ACPI_STATUS(AE_OK);567	}568 569	/*570	 * Flags == -1 means that _STA was not found. In this case, we assume that571	 * the device is both present and functional.572	 *573	 * From the ACPI spec, description of _STA:574	 *575	 * "If a device object (including the processor object) does not have an576	 * _STA object, then OSPM assumes that all of the above bits are set (in577	 * other words, the device is present, ..., and functioning)"578	 */579	if (flags != ACPI_UINT32_MAX) {580		walk_info->num_STA++;581	}582 583	/*584	 * Examine the PRESENT and FUNCTIONING status bits585	 *586	 * Note: ACPI spec does not seem to specify behavior for the present but587	 * not functioning case, so we assume functioning if present.588	 */589	if (!(flags & ACPI_STA_DEVICE_PRESENT)) {590 591		/* Device is not present, we must examine the Functioning bit */592 593		if (flags & ACPI_STA_DEVICE_FUNCTIONING) {594			/*595			 * Device is not present but is "functioning". In this case,596			 * we will not run _INI, but we continue to examine the children597			 * of this device.598			 *599			 * From the ACPI spec, description of _STA: (note - no mention600			 * of whether to run _INI or not on the device in question)601			 *602			 * "_STA may return bit 0 clear (not present) with bit 3 set603			 * (device is functional). This case is used to indicate a valid604			 * device for which no device driver should be loaded (for example,605			 * a bridge device.) Children of this device may be present and606			 * valid. OSPM should continue enumeration below a device whose607			 * _STA returns this bit combination"608			 */609			return_ACPI_STATUS(AE_OK);610		} else {611			/*612			 * Device is not present and is not functioning. We must abort the613			 * walk of this subtree immediately -- don't look at the children614			 * of such a device.615			 *616			 * From the ACPI spec, description of _INI:617			 *618			 * "If the _STA method indicates that the device is not present,619			 * OSPM will not run the _INI and will not examine the children620			 * of the device for _INI methods"621			 */622			return_ACPI_STATUS(AE_CTRL_DEPTH);623		}624	}625 626	/*627	 * The device is present or is assumed present if no _STA exists.628	 * Run the _INI if it exists (not required to exist)629	 *630	 * Note: We know there is an _INI within this subtree, but it may not be631	 * under this particular device, it may be lower in the branch.632	 */633	if (!ACPI_COMPARE_NAMESEG(device_node->name.ascii, "_SB_") ||634	    device_node->parent != acpi_gbl_root_node) {635		ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname636				(ACPI_TYPE_METHOD, device_node,637				 METHOD_NAME__INI));638 639		memset(info, 0, sizeof(struct acpi_evaluate_info));640		info->prefix_node = device_node;641		info->relative_pathname = METHOD_NAME__INI;642		info->parameters = NULL;643		info->flags = ACPI_IGNORE_RETURN_VALUE;644 645		status = acpi_ns_evaluate(info);646		if (ACPI_SUCCESS(status)) {647			walk_info->num_INI++;648		}649#ifdef ACPI_DEBUG_OUTPUT650		else if (status != AE_NOT_FOUND) {651 652			/* Ignore error and move on to next device */653 654			char *scope_name =655			    acpi_ns_get_normalized_pathname(device_node, TRUE);656 657			ACPI_EXCEPTION((AE_INFO, status,658					"during %s._INI execution",659					scope_name));660			ACPI_FREE(scope_name);661		}662#endif663	}664 665	/* Ignore errors from above */666 667	status = AE_OK;668 669	/*670	 * The _INI method has been run if present; call the Global Initialization671	 * Handler for this device.672	 */673	if (acpi_gbl_init_handler) {674		status =675		    acpi_gbl_init_handler(device_node, ACPI_INIT_DEVICE_INI);676	}677 678	return_ACPI_STATUS(status);679}680