162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: rslist - Linked list utilities 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci ******************************************************************************/ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <acpi/acpi.h> 962306a36Sopenharmony_ci#include "accommon.h" 1062306a36Sopenharmony_ci#include "acresrc.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define _COMPONENT ACPI_RESOURCES 1362306a36Sopenharmony_ciACPI_MODULE_NAME("rslist") 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/******************************************************************************* 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * FUNCTION: acpi_rs_convert_aml_to_resources 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * PARAMETERS: acpi_walk_aml_callback 2062306a36Sopenharmony_ci * resource_ptr - Pointer to the buffer that will 2162306a36Sopenharmony_ci * contain the output structures 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * RETURN: Status 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * DESCRIPTION: Convert an AML resource to an internal representation of the 2662306a36Sopenharmony_ci * resource that is aligned and easier to access. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci ******************************************************************************/ 2962306a36Sopenharmony_ciacpi_status 3062306a36Sopenharmony_ciacpi_rs_convert_aml_to_resources(u8 * aml, 3162306a36Sopenharmony_ci u32 length, 3262306a36Sopenharmony_ci u32 offset, u8 resource_index, void **context) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct acpi_resource **resource_ptr = 3562306a36Sopenharmony_ci ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context); 3662306a36Sopenharmony_ci struct acpi_resource *resource; 3762306a36Sopenharmony_ci union aml_resource *aml_resource; 3862306a36Sopenharmony_ci struct acpi_rsconvert_info *conversion_table; 3962306a36Sopenharmony_ci acpi_status status; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * Check that the input buffer and all subsequent pointers into it 4562306a36Sopenharmony_ci * are aligned on a native word boundary. Most important on IA64 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_ci resource = *resource_ptr; 4862306a36Sopenharmony_ci if (ACPI_IS_MISALIGNED(resource)) { 4962306a36Sopenharmony_ci ACPI_WARNING((AE_INFO, 5062306a36Sopenharmony_ci "Misaligned resource pointer %p", resource)); 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* Get the appropriate conversion info table */ 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci aml_resource = ACPI_CAST_PTR(union aml_resource, aml); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /* Avoid undefined behavior: member access within misaligned address */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci struct aml_resource_common_serialbus common_serial_bus; 6262306a36Sopenharmony_ci memcpy(&common_serial_bus, aml_resource, 6362306a36Sopenharmony_ci sizeof(common_serial_bus)); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE) { 6662306a36Sopenharmony_ci conversion_table = NULL; 6762306a36Sopenharmony_ci } else { 6862306a36Sopenharmony_ci /* This is an I2C, SPI, UART, or CSI2 serial_bus descriptor */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci conversion_table = 7162306a36Sopenharmony_ci acpi_gbl_convert_resource_serial_bus_dispatch 7262306a36Sopenharmony_ci [common_serial_bus.type]; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci conversion_table = 7662306a36Sopenharmony_ci acpi_gbl_get_resource_dispatch[resource_index]; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!conversion_table) { 8062306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 8162306a36Sopenharmony_ci "Invalid/unsupported resource descriptor: Type 0x%2.2X", 8262306a36Sopenharmony_ci resource_index)); 8362306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Convert the AML byte stream resource to a local resource struct */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci status = 8962306a36Sopenharmony_ci acpi_rs_convert_aml_to_resource(resource, aml_resource, 9062306a36Sopenharmony_ci conversion_table); 9162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 9262306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 9362306a36Sopenharmony_ci "Could not convert AML resource (Type 0x%X)", 9462306a36Sopenharmony_ci *aml)); 9562306a36Sopenharmony_ci return_ACPI_STATUS(status); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (!resource->length) { 9962306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 10062306a36Sopenharmony_ci "Zero-length resource returned from RsConvertAmlToResource")); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_RESOURCES, 10462306a36Sopenharmony_ci "Type %.2X, AmlLength %.2X InternalLength %.2X\n", 10562306a36Sopenharmony_ci acpi_ut_get_resource_type(aml), length, 10662306a36Sopenharmony_ci resource->length)); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* Point to the next structure in the output buffer */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci *resource_ptr = ACPI_NEXT_RESOURCE(resource); 11162306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/******************************************************************************* 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * FUNCTION: acpi_rs_convert_resources_to_aml 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * PARAMETERS: resource - Pointer to the resource linked list 11962306a36Sopenharmony_ci * aml_size_needed - Calculated size of the byte stream 12062306a36Sopenharmony_ci * needed from calling acpi_rs_get_aml_length() 12162306a36Sopenharmony_ci * The size of the output_buffer is 12262306a36Sopenharmony_ci * guaranteed to be >= aml_size_needed 12362306a36Sopenharmony_ci * output_buffer - Pointer to the buffer that will 12462306a36Sopenharmony_ci * contain the byte stream 12562306a36Sopenharmony_ci * 12662306a36Sopenharmony_ci * RETURN: Status 12762306a36Sopenharmony_ci * 12862306a36Sopenharmony_ci * DESCRIPTION: Takes the resource linked list and parses it, creating a 12962306a36Sopenharmony_ci * byte stream of resources in the caller's output buffer 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci ******************************************************************************/ 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciacpi_status 13462306a36Sopenharmony_ciacpi_rs_convert_resources_to_aml(struct acpi_resource *resource, 13562306a36Sopenharmony_ci acpi_size aml_size_needed, u8 * output_buffer) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci u8 *aml = output_buffer; 13862306a36Sopenharmony_ci u8 *end_aml = output_buffer + aml_size_needed; 13962306a36Sopenharmony_ci struct acpi_rsconvert_info *conversion_table; 14062306a36Sopenharmony_ci acpi_status status; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* Walk the resource descriptor list, convert each descriptor */ 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci while (aml < end_aml) { 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* Validate the (internal) Resource Type */ 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (resource->type > ACPI_RESOURCE_TYPE_MAX) { 15162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 15262306a36Sopenharmony_ci "Invalid descriptor type (0x%X) in resource list", 15362306a36Sopenharmony_ci resource->type)); 15462306a36Sopenharmony_ci return_ACPI_STATUS(AE_BAD_DATA); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Sanity check the length. It must not be zero, or we loop forever */ 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!resource->length) { 16062306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 16162306a36Sopenharmony_ci "Invalid zero length descriptor in resource list\n")); 16262306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_BAD_RESOURCE_LENGTH); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Perform the conversion */ 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { 16862306a36Sopenharmony_ci if (resource->data.common_serial_bus.type > 16962306a36Sopenharmony_ci AML_RESOURCE_MAX_SERIALBUSTYPE) { 17062306a36Sopenharmony_ci conversion_table = NULL; 17162306a36Sopenharmony_ci } else { 17262306a36Sopenharmony_ci /* This is an I2C, SPI, UART or CSI2 serial_bus descriptor */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci conversion_table = 17562306a36Sopenharmony_ci acpi_gbl_convert_resource_serial_bus_dispatch 17662306a36Sopenharmony_ci [resource->data.common_serial_bus.type]; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci conversion_table = 18062306a36Sopenharmony_ci acpi_gbl_set_resource_dispatch[resource->type]; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!conversion_table) { 18462306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 18562306a36Sopenharmony_ci "Invalid/unsupported resource descriptor: Type 0x%2.2X", 18662306a36Sopenharmony_ci resource->type)); 18762306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INVALID_RESOURCE_TYPE); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci status = acpi_rs_convert_resource_to_aml(resource, 19162306a36Sopenharmony_ci ACPI_CAST_PTR(union 19262306a36Sopenharmony_ci aml_resource, 19362306a36Sopenharmony_ci aml), 19462306a36Sopenharmony_ci conversion_table); 19562306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 19662306a36Sopenharmony_ci ACPI_EXCEPTION((AE_INFO, status, 19762306a36Sopenharmony_ci "Could not convert resource (type 0x%X) to AML", 19862306a36Sopenharmony_ci resource->type)); 19962306a36Sopenharmony_ci return_ACPI_STATUS(status); 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* Perform final sanity check on the new AML resource descriptor */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci status = 20562306a36Sopenharmony_ci acpi_ut_validate_resource(NULL, 20662306a36Sopenharmony_ci ACPI_CAST_PTR(union aml_resource, 20762306a36Sopenharmony_ci aml), NULL); 20862306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 20962306a36Sopenharmony_ci return_ACPI_STATUS(status); 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Check for end-of-list, normal exit */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (resource->type == ACPI_RESOURCE_TYPE_END_TAG) { 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* An End Tag indicates the end of the input Resource Template */ 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * Extract the total length of the new descriptor and set the 22362306a36Sopenharmony_ci * Aml to point to the next (output) resource descriptor 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ci aml += acpi_ut_get_descriptor_length(aml); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Point to the next input resource descriptor */ 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci resource = ACPI_NEXT_RESOURCE(resource); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Completed buffer, but did not find an end_tag resource descriptor */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); 23562306a36Sopenharmony_ci} 236