// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 /****************************************************************************** * * Module Name: exprep - ACPI AML field prep utilities * * Copyright (C) 2000 - 2023, Intel Corp. * *****************************************************************************/ #include <acpi/acpi.h> #include "accommon.h" #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" #include "acdispat.h" #define _COMPONENT … ACPI_MODULE_NAME("exprep") /* Local prototypes */ static u32 acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, u8 field_flags, u32 * return_byte_alignment); #ifdef ACPI_UNDER_DEVELOPMENT static u32 acpi_ex_generate_access(u32 field_bit_offset, u32 field_bit_length, u32 region_length); /******************************************************************************* * * FUNCTION: acpi_ex_generate_access * * PARAMETERS: field_bit_offset - Start of field within parent region/buffer * field_bit_length - Length of field in bits * region_length - Length of parent in bytes * * RETURN: Field granularity (8, 16, 32 or 64) and * byte_alignment (1, 2, 3, or 4) * * DESCRIPTION: Generate an optimal access width for fields defined with the * any_acc keyword. * * NOTE: Need to have the region_length in order to check for boundary * conditions (end-of-region). However, the region_length is a deferred * operation. Therefore, to complete this implementation, the generation * of this access width must be deferred until the region length has * been evaluated. * ******************************************************************************/ static u32 acpi_ex_generate_access(u32 field_bit_offset, u32 field_bit_length, u32 region_length) { u32 field_byte_length; u32 field_byte_offset; u32 field_byte_end_offset; u32 access_byte_width; u32 field_start_offset; u32 field_end_offset; u32 minimum_access_width = 0xFFFFFFFF; u32 minimum_accesses = 0xFFFFFFFF; u32 accesses; ACPI_FUNCTION_TRACE(ex_generate_access); /* Round Field start offset and length to "minimal" byte boundaries */ field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8)); field_byte_end_offset = ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8)); field_byte_length = field_byte_end_offset - field_byte_offset; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bit length %u, Bit offset %u\n", field_bit_length, field_bit_offset)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Byte Length %u, Byte Offset %u, End Offset %u\n", field_byte_length, field_byte_offset, field_byte_end_offset)); /* * Iterative search for the maximum access width that is both aligned * and does not go beyond the end of the region * * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes) */ for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) { /* * 1) Round end offset up to next access boundary and make sure that * this does not go beyond the end of the parent region. * 2) When the Access width is greater than the field_byte_length, we * are done. (This does not optimize for the perfectly aligned * case yet). */ if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <= region_length) { field_start_offset = ACPI_ROUND_DOWN(field_byte_offset, access_byte_width) / access_byte_width; field_end_offset = ACPI_ROUND_UP((field_byte_length + field_byte_offset), access_byte_width) / access_byte_width; accesses = field_end_offset - field_start_offset; ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "AccessWidth %u end is within region\n", access_byte_width)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Field Start %u, Field End %u -- requires %u accesses\n", field_start_offset, field_end_offset, accesses)); /* Single access is optimal */ if (accesses <= 1) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Entire field can be accessed " "with one operation of size %u\n", access_byte_width)); return_VALUE(access_byte_width); } /* * Fits in the region, but requires more than one read/write. * try the next wider access on next iteration */ if (accesses < minimum_accesses) { minimum_accesses = accesses; minimum_access_width = access_byte_width; } } else { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "AccessWidth %u end is NOT within region\n", access_byte_width)); if (access_byte_width == 1) { ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Field goes beyond end-of-region!\n")); /* Field does not fit in the region at all */ return_VALUE(0); } /* * This width goes beyond the end-of-region, back off to * previous access */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Backing off to previous optimal access width of %u\n", minimum_access_width)); return_VALUE(minimum_access_width); } } /* * Could not read/write field with one operation, * just use max access width */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Cannot access field in one operation, using width 8\n")); return_VALUE(8); } #endif /* ACPI_UNDER_DEVELOPMENT */ /******************************************************************************* * * FUNCTION: acpi_ex_decode_field_access * * PARAMETERS: obj_desc - Field object * field_flags - Encoded fieldflags (contains access bits) * return_byte_alignment - Where the byte alignment is returned * * RETURN: Field granularity (8, 16, 32 or 64) and * byte_alignment (1, 2, 3, or 4) * * DESCRIPTION: Decode the access_type bits of a field definition. * ******************************************************************************/ static u32 acpi_ex_decode_field_access(union acpi_operand_object *obj_desc, u8 field_flags, u32 * return_byte_alignment) { … } /******************************************************************************* * * FUNCTION: acpi_ex_prep_common_field_object * * PARAMETERS: obj_desc - The field object * field_flags - Access, lock_rule, and update_rule. * The format of a field_flag is described * in the ACPI specification * field_attribute - Special attributes (not used) * field_bit_position - Field start position * field_bit_length - Field length in number of bits * * RETURN: Status * * DESCRIPTION: Initialize the areas of the field object that are common * to the various types of fields. Note: This is very "sensitive" * code because we are solving the general case for field * alignment. * ******************************************************************************/ acpi_status acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, u8 field_flags, u8 field_attribute, u32 field_bit_position, u32 field_bit_length) { … } /******************************************************************************* * * FUNCTION: acpi_ex_prep_field_value * * PARAMETERS: info - Contains all field creation info * * RETURN: Status * * DESCRIPTION: Construct an object of type union acpi_operand_object with a * subtype of def_field and connect it to the parent Node. * ******************************************************************************/ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { … }