162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: exprep - ACPI AML field prep utilities 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "acinterp.h" 1362306a36Sopenharmony_ci#include "amlcode.h" 1462306a36Sopenharmony_ci#include "acnamesp.h" 1562306a36Sopenharmony_ci#include "acdispat.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define _COMPONENT ACPI_EXECUTER 1862306a36Sopenharmony_ciACPI_MODULE_NAME("exprep") 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* Local prototypes */ 2162306a36Sopenharmony_cistatic u32 2262306a36Sopenharmony_ciacpi_ex_decode_field_access(union acpi_operand_object *obj_desc, 2362306a36Sopenharmony_ci u8 field_flags, u32 * return_byte_alignment); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifdef ACPI_UNDER_DEVELOPMENT 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic u32 2862306a36Sopenharmony_ciacpi_ex_generate_access(u32 field_bit_offset, 2962306a36Sopenharmony_ci u32 field_bit_length, u32 region_length); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/******************************************************************************* 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * FUNCTION: acpi_ex_generate_access 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * PARAMETERS: field_bit_offset - Start of field within parent region/buffer 3662306a36Sopenharmony_ci * field_bit_length - Length of field in bits 3762306a36Sopenharmony_ci * region_length - Length of parent in bytes 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * RETURN: Field granularity (8, 16, 32 or 64) and 4062306a36Sopenharmony_ci * byte_alignment (1, 2, 3, or 4) 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * DESCRIPTION: Generate an optimal access width for fields defined with the 4362306a36Sopenharmony_ci * any_acc keyword. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * NOTE: Need to have the region_length in order to check for boundary 4662306a36Sopenharmony_ci * conditions (end-of-region). However, the region_length is a deferred 4762306a36Sopenharmony_ci * operation. Therefore, to complete this implementation, the generation 4862306a36Sopenharmony_ci * of this access width must be deferred until the region length has 4962306a36Sopenharmony_ci * been evaluated. 5062306a36Sopenharmony_ci * 5162306a36Sopenharmony_ci ******************************************************************************/ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic u32 5462306a36Sopenharmony_ciacpi_ex_generate_access(u32 field_bit_offset, 5562306a36Sopenharmony_ci u32 field_bit_length, u32 region_length) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci u32 field_byte_length; 5862306a36Sopenharmony_ci u32 field_byte_offset; 5962306a36Sopenharmony_ci u32 field_byte_end_offset; 6062306a36Sopenharmony_ci u32 access_byte_width; 6162306a36Sopenharmony_ci u32 field_start_offset; 6262306a36Sopenharmony_ci u32 field_end_offset; 6362306a36Sopenharmony_ci u32 minimum_access_width = 0xFFFFFFFF; 6462306a36Sopenharmony_ci u32 minimum_accesses = 0xFFFFFFFF; 6562306a36Sopenharmony_ci u32 accesses; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_generate_access); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* Round Field start offset and length to "minimal" byte boundaries */ 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci field_byte_offset = ACPI_DIV_8(ACPI_ROUND_DOWN(field_bit_offset, 8)); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci field_byte_end_offset = 7462306a36Sopenharmony_ci ACPI_DIV_8(ACPI_ROUND_UP(field_bit_length + field_bit_offset, 8)); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci field_byte_length = field_byte_end_offset - field_byte_offset; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 7962306a36Sopenharmony_ci "Bit length %u, Bit offset %u\n", 8062306a36Sopenharmony_ci field_bit_length, field_bit_offset)); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 8362306a36Sopenharmony_ci "Byte Length %u, Byte Offset %u, End Offset %u\n", 8462306a36Sopenharmony_ci field_byte_length, field_byte_offset, 8562306a36Sopenharmony_ci field_byte_end_offset)); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci /* 8862306a36Sopenharmony_ci * Iterative search for the maximum access width that is both aligned 8962306a36Sopenharmony_ci * and does not go beyond the end of the region 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes) 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ci for (access_byte_width = 1; access_byte_width <= 8; 9462306a36Sopenharmony_ci access_byte_width <<= 1) { 9562306a36Sopenharmony_ci /* 9662306a36Sopenharmony_ci * 1) Round end offset up to next access boundary and make sure that 9762306a36Sopenharmony_ci * this does not go beyond the end of the parent region. 9862306a36Sopenharmony_ci * 2) When the Access width is greater than the field_byte_length, we 9962306a36Sopenharmony_ci * are done. (This does not optimize for the perfectly aligned 10062306a36Sopenharmony_ci * case yet). 10162306a36Sopenharmony_ci */ 10262306a36Sopenharmony_ci if (ACPI_ROUND_UP(field_byte_end_offset, access_byte_width) <= 10362306a36Sopenharmony_ci region_length) { 10462306a36Sopenharmony_ci field_start_offset = 10562306a36Sopenharmony_ci ACPI_ROUND_DOWN(field_byte_offset, 10662306a36Sopenharmony_ci access_byte_width) / 10762306a36Sopenharmony_ci access_byte_width; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci field_end_offset = 11062306a36Sopenharmony_ci ACPI_ROUND_UP((field_byte_length + 11162306a36Sopenharmony_ci field_byte_offset), 11262306a36Sopenharmony_ci access_byte_width) / 11362306a36Sopenharmony_ci access_byte_width; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci accesses = field_end_offset - field_start_offset; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 11862306a36Sopenharmony_ci "AccessWidth %u end is within region\n", 11962306a36Sopenharmony_ci access_byte_width)); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 12262306a36Sopenharmony_ci "Field Start %u, Field End %u -- requires %u accesses\n", 12362306a36Sopenharmony_ci field_start_offset, field_end_offset, 12462306a36Sopenharmony_ci accesses)); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* Single access is optimal */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (accesses <= 1) { 12962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 13062306a36Sopenharmony_ci "Entire field can be accessed " 13162306a36Sopenharmony_ci "with one operation of size %u\n", 13262306a36Sopenharmony_ci access_byte_width)); 13362306a36Sopenharmony_ci return_VALUE(access_byte_width); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* 13762306a36Sopenharmony_ci * Fits in the region, but requires more than one read/write. 13862306a36Sopenharmony_ci * try the next wider access on next iteration 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci if (accesses < minimum_accesses) { 14162306a36Sopenharmony_ci minimum_accesses = accesses; 14262306a36Sopenharmony_ci minimum_access_width = access_byte_width; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci } else { 14562306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 14662306a36Sopenharmony_ci "AccessWidth %u end is NOT within region\n", 14762306a36Sopenharmony_ci access_byte_width)); 14862306a36Sopenharmony_ci if (access_byte_width == 1) { 14962306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 15062306a36Sopenharmony_ci "Field goes beyond end-of-region!\n")); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci /* Field does not fit in the region at all */ 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return_VALUE(0); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * This width goes beyond the end-of-region, back off to 15962306a36Sopenharmony_ci * previous access 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 16262306a36Sopenharmony_ci "Backing off to previous optimal access width of %u\n", 16362306a36Sopenharmony_ci minimum_access_width)); 16462306a36Sopenharmony_ci return_VALUE(minimum_access_width); 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * Could not read/write field with one operation, 17062306a36Sopenharmony_ci * just use max access width 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 17362306a36Sopenharmony_ci "Cannot access field in one operation, using width 8\n")); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return_VALUE(8); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci#endif /* ACPI_UNDER_DEVELOPMENT */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/******************************************************************************* 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * FUNCTION: acpi_ex_decode_field_access 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * PARAMETERS: obj_desc - Field object 18462306a36Sopenharmony_ci * field_flags - Encoded fieldflags (contains access bits) 18562306a36Sopenharmony_ci * return_byte_alignment - Where the byte alignment is returned 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * RETURN: Field granularity (8, 16, 32 or 64) and 18862306a36Sopenharmony_ci * byte_alignment (1, 2, 3, or 4) 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * DESCRIPTION: Decode the access_type bits of a field definition. 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci ******************************************************************************/ 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic u32 19562306a36Sopenharmony_ciacpi_ex_decode_field_access(union acpi_operand_object *obj_desc, 19662306a36Sopenharmony_ci u8 field_flags, u32 * return_byte_alignment) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci u32 access; 19962306a36Sopenharmony_ci u32 byte_alignment; 20062306a36Sopenharmony_ci u32 bit_length; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_decode_field_access); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci switch (access) { 20762306a36Sopenharmony_ci case AML_FIELD_ACCESS_ANY: 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci#ifdef ACPI_UNDER_DEVELOPMENT 21062306a36Sopenharmony_ci byte_alignment = 21162306a36Sopenharmony_ci acpi_ex_generate_access(obj_desc->common_field. 21262306a36Sopenharmony_ci start_field_bit_offset, 21362306a36Sopenharmony_ci obj_desc->common_field.bit_length, 21462306a36Sopenharmony_ci 0xFFFFFFFF 21562306a36Sopenharmony_ci /* Temp until we pass region_length as parameter */ 21662306a36Sopenharmony_ci ); 21762306a36Sopenharmony_ci bit_length = byte_alignment * 8; 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci byte_alignment = 1; 22162306a36Sopenharmony_ci bit_length = 8; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci case AML_FIELD_ACCESS_BYTE: 22562306a36Sopenharmony_ci case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */ 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci byte_alignment = 1; 22862306a36Sopenharmony_ci bit_length = 8; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci case AML_FIELD_ACCESS_WORD: 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci byte_alignment = 2; 23462306a36Sopenharmony_ci bit_length = 16; 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci case AML_FIELD_ACCESS_DWORD: 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci byte_alignment = 4; 24062306a36Sopenharmony_ci bit_length = 32; 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci byte_alignment = 8; 24662306a36Sopenharmony_ci bit_length = 64; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci default: 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Invalid field access type */ 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Unknown field access type 0x%X", access)); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return_UINT32(0); 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (obj_desc->common.type == ACPI_TYPE_BUFFER_FIELD) { 25962306a36Sopenharmony_ci /* 26062306a36Sopenharmony_ci * buffer_field access can be on any byte boundary, so the 26162306a36Sopenharmony_ci * byte_alignment is always 1 byte -- regardless of any byte_alignment 26262306a36Sopenharmony_ci * implied by the field access type. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_ci byte_alignment = 1; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci *return_byte_alignment = byte_alignment; 26862306a36Sopenharmony_ci return_UINT32(bit_length); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/******************************************************************************* 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * FUNCTION: acpi_ex_prep_common_field_object 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * PARAMETERS: obj_desc - The field object 27662306a36Sopenharmony_ci * field_flags - Access, lock_rule, and update_rule. 27762306a36Sopenharmony_ci * The format of a field_flag is described 27862306a36Sopenharmony_ci * in the ACPI specification 27962306a36Sopenharmony_ci * field_attribute - Special attributes (not used) 28062306a36Sopenharmony_ci * field_bit_position - Field start position 28162306a36Sopenharmony_ci * field_bit_length - Field length in number of bits 28262306a36Sopenharmony_ci * 28362306a36Sopenharmony_ci * RETURN: Status 28462306a36Sopenharmony_ci * 28562306a36Sopenharmony_ci * DESCRIPTION: Initialize the areas of the field object that are common 28662306a36Sopenharmony_ci * to the various types of fields. Note: This is very "sensitive" 28762306a36Sopenharmony_ci * code because we are solving the general case for field 28862306a36Sopenharmony_ci * alignment. 28962306a36Sopenharmony_ci * 29062306a36Sopenharmony_ci ******************************************************************************/ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ciacpi_status 29362306a36Sopenharmony_ciacpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, 29462306a36Sopenharmony_ci u8 field_flags, 29562306a36Sopenharmony_ci u8 field_attribute, 29662306a36Sopenharmony_ci u32 field_bit_position, u32 field_bit_length) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci u32 access_bit_width; 29962306a36Sopenharmony_ci u32 byte_alignment; 30062306a36Sopenharmony_ci u32 nearest_byte_address; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_prep_common_field_object); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* 30562306a36Sopenharmony_ci * Note: the structure being initialized is the 30662306a36Sopenharmony_ci * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common 30762306a36Sopenharmony_ci * area are initialized by this procedure. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci obj_desc->common_field.field_flags = field_flags; 31062306a36Sopenharmony_ci obj_desc->common_field.attribute = field_attribute; 31162306a36Sopenharmony_ci obj_desc->common_field.bit_length = field_bit_length; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * Decode the access type so we can compute offsets. The access type gives 31562306a36Sopenharmony_ci * two pieces of information - the width of each field access and the 31662306a36Sopenharmony_ci * necessary byte_alignment (address granularity) of the access. 31762306a36Sopenharmony_ci * 31862306a36Sopenharmony_ci * For any_acc, the access_bit_width is the largest width that is both 31962306a36Sopenharmony_ci * necessary and possible in an attempt to access the whole field in one 32062306a36Sopenharmony_ci * I/O operation. However, for any_acc, the byte_alignment is always one 32162306a36Sopenharmony_ci * byte. 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * For all Buffer Fields, the byte_alignment is always one byte. 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is 32662306a36Sopenharmony_ci * the same (equivalent) as the byte_alignment. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci access_bit_width = 32962306a36Sopenharmony_ci acpi_ex_decode_field_access(obj_desc, field_flags, &byte_alignment); 33062306a36Sopenharmony_ci if (!access_bit_width) { 33162306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_VALUE); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */ 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci obj_desc->common_field.access_byte_width = (u8) 33762306a36Sopenharmony_ci ACPI_DIV_8(access_bit_width); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * base_byte_offset is the address of the start of the field within the 34162306a36Sopenharmony_ci * region. It is the byte address of the first *datum* (field-width data 34262306a36Sopenharmony_ci * unit) of the field. (i.e., the first datum that contains at least the 34362306a36Sopenharmony_ci * first *bit* of the field.) 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * Note: byte_alignment is always either equal to the access_bit_width or 8 34662306a36Sopenharmony_ci * (Byte access), and it defines the addressing granularity of the parent 34762306a36Sopenharmony_ci * region or buffer. 34862306a36Sopenharmony_ci */ 34962306a36Sopenharmony_ci nearest_byte_address = 35062306a36Sopenharmony_ci ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position); 35162306a36Sopenharmony_ci obj_desc->common_field.base_byte_offset = (u32) 35262306a36Sopenharmony_ci ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* 35562306a36Sopenharmony_ci * start_field_bit_offset is the offset of the first bit of the field within 35662306a36Sopenharmony_ci * a field datum. 35762306a36Sopenharmony_ci */ 35862306a36Sopenharmony_ci obj_desc->common_field.start_field_bit_offset = (u8) 35962306a36Sopenharmony_ci (field_bit_position - 36062306a36Sopenharmony_ci ACPI_MUL_8(obj_desc->common_field.base_byte_offset)); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/******************************************************************************* 36662306a36Sopenharmony_ci * 36762306a36Sopenharmony_ci * FUNCTION: acpi_ex_prep_field_value 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * PARAMETERS: info - Contains all field creation info 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * RETURN: Status 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * DESCRIPTION: Construct an object of type union acpi_operand_object with a 37462306a36Sopenharmony_ci * subtype of def_field and connect it to the parent Node. 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci ******************************************************************************/ 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ciacpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci union acpi_operand_object *obj_desc; 38162306a36Sopenharmony_ci union acpi_operand_object *second_desc = NULL; 38262306a36Sopenharmony_ci acpi_status status; 38362306a36Sopenharmony_ci u32 access_byte_width; 38462306a36Sopenharmony_ci u32 type; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(ex_prep_field_value); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Parameter validation */ 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { 39162306a36Sopenharmony_ci if (!info->region_node) { 39262306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, "Null RegionNode")); 39362306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_NO_OPERAND); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci type = acpi_ns_get_type(info->region_node); 39762306a36Sopenharmony_ci if (type != ACPI_TYPE_REGION) { 39862306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 39962306a36Sopenharmony_ci "Needed Region, found type 0x%X (%s)", type, 40062306a36Sopenharmony_ci acpi_ut_get_type_name(type))); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_OPERAND_TYPE); 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Allocate a new field object */ 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci obj_desc = acpi_ut_create_internal_object(info->field_type); 40962306a36Sopenharmony_ci if (!obj_desc) { 41062306a36Sopenharmony_ci return_ACPI_STATUS(AE_NO_MEMORY); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci /* Initialize areas of the object that are common to all fields */ 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci obj_desc->common_field.node = info->field_node; 41662306a36Sopenharmony_ci status = acpi_ex_prep_common_field_object(obj_desc, 41762306a36Sopenharmony_ci info->field_flags, 41862306a36Sopenharmony_ci info->attribute, 41962306a36Sopenharmony_ci info->field_bit_position, 42062306a36Sopenharmony_ci info->field_bit_length); 42162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 42262306a36Sopenharmony_ci acpi_ut_delete_object_desc(obj_desc); 42362306a36Sopenharmony_ci return_ACPI_STATUS(status); 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Initialize areas of the object that are specific to the field type */ 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci switch (info->field_type) { 42962306a36Sopenharmony_ci case ACPI_TYPE_LOCAL_REGION_FIELD: 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci obj_desc->field.region_obj = 43262306a36Sopenharmony_ci acpi_ns_get_attached_object(info->region_node); 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci /* Fields specific to generic_serial_bus fields */ 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci obj_desc->field.access_length = info->access_length; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (info->connection_node) { 43962306a36Sopenharmony_ci second_desc = info->connection_node->object; 44062306a36Sopenharmony_ci if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { 44162306a36Sopenharmony_ci status = 44262306a36Sopenharmony_ci acpi_ds_get_buffer_arguments(second_desc); 44362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 44462306a36Sopenharmony_ci acpi_ut_delete_object_desc(obj_desc); 44562306a36Sopenharmony_ci return_ACPI_STATUS(status); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci obj_desc->field.resource_buffer = 45062306a36Sopenharmony_ci second_desc->buffer.pointer; 45162306a36Sopenharmony_ci obj_desc->field.resource_length = 45262306a36Sopenharmony_ci (u16)second_desc->buffer.length; 45362306a36Sopenharmony_ci } else if (info->resource_buffer) { 45462306a36Sopenharmony_ci obj_desc->field.resource_buffer = info->resource_buffer; 45562306a36Sopenharmony_ci obj_desc->field.resource_length = info->resource_length; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci obj_desc->field.pin_number_index = info->pin_number_index; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Allow full data read from EC address space */ 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if ((obj_desc->field.region_obj->region.space_id == 46362306a36Sopenharmony_ci ACPI_ADR_SPACE_EC) 46462306a36Sopenharmony_ci && (obj_desc->common_field.bit_length > 8)) { 46562306a36Sopenharmony_ci access_byte_width = 46662306a36Sopenharmony_ci ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field. 46762306a36Sopenharmony_ci bit_length); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Maximum byte width supported is 255 */ 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (access_byte_width < 256) { 47262306a36Sopenharmony_ci obj_desc->common_field.access_byte_width = 47362306a36Sopenharmony_ci (u8)access_byte_width; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 47762306a36Sopenharmony_ci "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", 47862306a36Sopenharmony_ci obj_desc->field.start_field_bit_offset, 47962306a36Sopenharmony_ci obj_desc->field.base_byte_offset, 48062306a36Sopenharmony_ci obj_desc->field.access_byte_width, 48162306a36Sopenharmony_ci obj_desc->field.region_obj)); 48262306a36Sopenharmony_ci break; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci case ACPI_TYPE_LOCAL_BANK_FIELD: 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci obj_desc->bank_field.value = info->bank_value; 48762306a36Sopenharmony_ci obj_desc->bank_field.region_obj = 48862306a36Sopenharmony_ci acpi_ns_get_attached_object(info->region_node); 48962306a36Sopenharmony_ci obj_desc->bank_field.bank_obj = 49062306a36Sopenharmony_ci acpi_ns_get_attached_object(info->register_node); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* An additional reference for the attached objects */ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci acpi_ut_add_reference(obj_desc->bank_field.region_obj); 49562306a36Sopenharmony_ci acpi_ut_add_reference(obj_desc->bank_field.bank_obj); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 49862306a36Sopenharmony_ci "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", 49962306a36Sopenharmony_ci obj_desc->bank_field.start_field_bit_offset, 50062306a36Sopenharmony_ci obj_desc->bank_field.base_byte_offset, 50162306a36Sopenharmony_ci obj_desc->field.access_byte_width, 50262306a36Sopenharmony_ci obj_desc->bank_field.region_obj, 50362306a36Sopenharmony_ci obj_desc->bank_field.bank_obj)); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * Remember location in AML stream of the field unit 50762306a36Sopenharmony_ci * opcode and operands -- since the bank_value 50862306a36Sopenharmony_ci * operands must be evaluated. 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci second_desc = obj_desc->common.next_object; 51162306a36Sopenharmony_ci second_desc->extra.aml_start = 51262306a36Sopenharmony_ci ACPI_CAST_PTR(union acpi_parse_object, 51362306a36Sopenharmony_ci info->data_register_node)->named.data; 51462306a36Sopenharmony_ci second_desc->extra.aml_length = 51562306a36Sopenharmony_ci ACPI_CAST_PTR(union acpi_parse_object, 51662306a36Sopenharmony_ci info->data_register_node)->named.length; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci case ACPI_TYPE_LOCAL_INDEX_FIELD: 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Get the Index and Data registers */ 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci obj_desc->index_field.index_obj = 52562306a36Sopenharmony_ci acpi_ns_get_attached_object(info->register_node); 52662306a36Sopenharmony_ci obj_desc->index_field.data_obj = 52762306a36Sopenharmony_ci acpi_ns_get_attached_object(info->data_register_node); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci if (!obj_desc->index_field.data_obj 53062306a36Sopenharmony_ci || !obj_desc->index_field.index_obj) { 53162306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 53262306a36Sopenharmony_ci "Null Index Object during field prep")); 53362306a36Sopenharmony_ci acpi_ut_delete_object_desc(obj_desc); 53462306a36Sopenharmony_ci return_ACPI_STATUS(AE_AML_INTERNAL); 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* An additional reference for the attached objects */ 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci acpi_ut_add_reference(obj_desc->index_field.data_obj); 54062306a36Sopenharmony_ci acpi_ut_add_reference(obj_desc->index_field.index_obj); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * April 2006: Changed to match MS behavior 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * The value written to the Index register is the byte offset of the 54662306a36Sopenharmony_ci * target field in units of the granularity of the index_field 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * Previously, the value was calculated as an index in terms of the 54962306a36Sopenharmony_ci * width of the Data register, as below: 55062306a36Sopenharmony_ci * 55162306a36Sopenharmony_ci * obj_desc->index_field.Value = (u32) 55262306a36Sopenharmony_ci * (Info->field_bit_position / ACPI_MUL_8 ( 55362306a36Sopenharmony_ci * obj_desc->Field.access_byte_width)); 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * February 2006: Tried value as a byte offset: 55662306a36Sopenharmony_ci * obj_desc->index_field.Value = (u32) 55762306a36Sopenharmony_ci * ACPI_DIV_8 (Info->field_bit_position); 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ci obj_desc->index_field.value = 56062306a36Sopenharmony_ci (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), 56162306a36Sopenharmony_ci obj_desc->index_field. 56262306a36Sopenharmony_ci access_byte_width); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 56562306a36Sopenharmony_ci "IndexField: BitOff %X, Off %X, Value %X, " 56662306a36Sopenharmony_ci "Gran %X, Index %p, Data %p\n", 56762306a36Sopenharmony_ci obj_desc->index_field.start_field_bit_offset, 56862306a36Sopenharmony_ci obj_desc->index_field.base_byte_offset, 56962306a36Sopenharmony_ci obj_desc->index_field.value, 57062306a36Sopenharmony_ci obj_desc->field.access_byte_width, 57162306a36Sopenharmony_ci obj_desc->index_field.index_obj, 57262306a36Sopenharmony_ci obj_desc->index_field.data_obj)); 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci default: 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* No other types should get here */ 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci break; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* 58362306a36Sopenharmony_ci * Store the constructed descriptor (obj_desc) into the parent Node, 58462306a36Sopenharmony_ci * preserving the current type of that named_obj. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci status = 58762306a36Sopenharmony_ci acpi_ns_attach_object(info->field_node, obj_desc, 58862306a36Sopenharmony_ci acpi_ns_get_type(info->field_node)); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, 59162306a36Sopenharmony_ci "Set NamedObj %p [%4.4s], ObjDesc %p\n", 59262306a36Sopenharmony_ci info->field_node, 59362306a36Sopenharmony_ci acpi_ut_get_node_name(info->field_node), obj_desc)); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Remove local reference to the object */ 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci acpi_ut_remove_reference(obj_desc); 59862306a36Sopenharmony_ci return_ACPI_STATUS(status); 59962306a36Sopenharmony_ci} 600