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) { u32 access_bit_width; u32 byte_alignment; u32 nearest_byte_address; ACPI_FUNCTION_TRACE(ex_prep_common_field_object); obj_desc->common_field.field_flags = field_flags; obj_desc->common_field.attribute = field_attribute; obj_desc->common_field.bit_length = field_bit_length; access_bit_width = acpi_ex_decode_field_access(obj_desc, field_flags, &byte_alignment); if (!access_bit_width) { return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } obj_desc->common_field.access_byte_width = (u8) ACPI_DIV_8(access_bit_width); obj_desc->common_field.access_bit_width = (u8) access_bit_width; nearest_byte_address = ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position); obj_desc->common_field.base_byte_offset = (u32) ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment); obj_desc->common_field.start_field_bit_offset = (u8) (field_bit_position - ACPI_MUL_8(obj_desc->common_field.base_byte_offset)); if ((obj_desc->common_field.start_field_bit_offset + field_bit_length) <= (u16) access_bit_width) { obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM; } return_ACPI_STATUS(AE_OK); }
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); }
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { union acpi_operand_object *obj_desc; union acpi_operand_object *second_desc = NULL; u32 type; acpi_status status; ACPI_FUNCTION_TRACE(ex_prep_field_value); /* Parameter validation */ if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!info->region_node) { ACPI_ERROR((AE_INFO, "Null RegionNode")); return_ACPI_STATUS(AE_AML_NO_OPERAND); } type = acpi_ns_get_type(info->region_node); if (type != ACPI_TYPE_REGION) { ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)", type, acpi_ut_get_type_name(type))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } } /* Allocate a new field object */ obj_desc = acpi_ut_create_internal_object(info->field_type); if (!obj_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Initialize areas of the object that are common to all fields */ obj_desc->common_field.node = info->field_node; status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags, info->attribute, info->field_bit_position, info->field_bit_length); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } /* Initialize areas of the object that are specific to the field type */ switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); /* An additional reference for the container */ acpi_ut_add_reference(obj_desc->field.region_obj); /* allow full data read from EC address space */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_EC) { if (obj_desc->common_field.bit_length > 8) { unsigned width = ACPI_ROUND_BITS_UP_TO_BYTES( obj_desc->common_field.bit_length); // access_bit_width is u8, don't overflow it if (width > 8) width = 8; obj_desc->common_field.access_byte_width = width; obj_desc->common_field.access_bit_width = 8 * width; } } ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->field.region_obj)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; obj_desc->bank_field.region_obj = acpi_ns_get_attached_object(info->region_node); obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object(info->register_node); /* An additional reference for the attached objects */ acpi_ut_add_reference(obj_desc->bank_field.region_obj); acpi_ut_add_reference(obj_desc->bank_field.bank_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj, obj_desc->bank_field.bank_obj)); /* * Remember location in AML stream of the field unit * opcode and operands -- since the bank_value * operands must be evaluated. */ second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.data; second_desc->extra.aml_length = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.length; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* Get the Index and Data registers */ obj_desc->index_field.index_obj = acpi_ns_get_attached_object(info->register_node); obj_desc->index_field.data_obj = acpi_ns_get_attached_object(info->data_register_node); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_ERROR((AE_INFO, "Null Index Object during field prep")); acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(AE_AML_INTERNAL); } /* An additional reference for the attached objects */ acpi_ut_add_reference(obj_desc->index_field.data_obj); acpi_ut_add_reference(obj_desc->index_field.index_obj); /* * April 2006: Changed to match MS behavior * * The value written to the Index register is the byte offset of the * target field in units of the granularity of the index_field * * Previously, the value was calculated as an index in terms of the * width of the Data register, as below: * * obj_desc->index_field.Value = (u32) * (Info->field_bit_position / ACPI_MUL_8 ( * obj_desc->Field.access_byte_width)); * * February 2006: Tried value as a byte offset: * obj_desc->index_field.Value = (u32) * ACPI_DIV_8 (Info->field_bit_position); */ obj_desc->index_field.value = (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), obj_desc->index_field. access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, obj_desc->field.access_byte_width, obj_desc->index_field.index_obj, obj_desc->index_field.data_obj)); break; default: /* No other types should get here */ break; } /* * Store the constructed descriptor (obj_desc) into the parent Node, * preserving the current type of that named_obj. */ status = acpi_ns_attach_object(info->field_node, obj_desc, acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", info->field_node, acpi_ut_get_node_name(info->field_node), obj_desc)); /* Remove local reference to the object */ acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); }
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) { u32 access_bit_width; u32 byte_alignment; u32 nearest_byte_address; ACPI_FUNCTION_TRACE(ex_prep_common_field_object); /* * Note: the structure being initialized is the * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common * area are initialized by this procedure. */ obj_desc->common_field.field_flags = field_flags; obj_desc->common_field.attribute = field_attribute; obj_desc->common_field.bit_length = field_bit_length; /* * Decode the access type so we can compute offsets. The access type gives * two pieces of information - the width of each field access and the * necessary byte_alignment (address granularity) of the access. * * For any_acc, the access_bit_width is the largest width that is both * necessary and possible in an attempt to access the whole field in one * I/O operation. However, for any_acc, the byte_alignment is always one * byte. * * For all Buffer Fields, the byte_alignment is always one byte. * * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is * the same (equivalent) as the byte_alignment. */ access_bit_width = acpi_ex_decode_field_access(obj_desc, field_flags, &byte_alignment); if (!access_bit_width) { return_ACPI_STATUS(AE_AML_OPERAND_VALUE); } /* Setup width (access granularity) fields */ obj_desc->common_field.access_byte_width = (u8) ACPI_DIV_8(access_bit_width); /* 1, 2, 4, 8 */ obj_desc->common_field.access_bit_width = (u8) access_bit_width; /* * base_byte_offset is the address of the start of the field within the * region. It is the byte address of the first *datum* (field-width data * unit) of the field. (i.e., the first datum that contains at least the * first *bit* of the field.) * * Note: byte_alignment is always either equal to the access_bit_width or 8 * (Byte access), and it defines the addressing granularity of the parent * region or buffer. */ nearest_byte_address = ACPI_ROUND_BITS_DOWN_TO_BYTES(field_bit_position); obj_desc->common_field.base_byte_offset = (u32) ACPI_ROUND_DOWN(nearest_byte_address, byte_alignment); /* * start_field_bit_offset is the offset of the first bit of the field within * a field datum. */ obj_desc->common_field.start_field_bit_offset = (u8) (field_bit_position - ACPI_MUL_8(obj_desc->common_field.base_byte_offset)); return_ACPI_STATUS(AE_OK); }
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); /* */ 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)); /* */ for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) { /* */ 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)); /* */ 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); } /* */ 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")); /* */ return_VALUE(0); } /* */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Backing off to previous optimal access width of %u\n", minimum_access_width)); return_VALUE(minimum_access_width); } } /* */ ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Cannot access field in one operation, using width 8\n")); return_VALUE(8); }
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) { union acpi_operand_object *obj_desc; union acpi_operand_object *second_desc = NULL; acpi_status status; u32 access_byte_width; u32 type; ACPI_FUNCTION_TRACE(ex_prep_field_value); /* */ if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!info->region_node) { ACPI_ERROR((AE_INFO, "Null RegionNode")); return_ACPI_STATUS(AE_AML_NO_OPERAND); } type = acpi_ns_get_type(info->region_node); if (type != ACPI_TYPE_REGION) { ACPI_ERROR((AE_INFO, "Needed Region, found type 0x%X (%s)", type, acpi_ut_get_type_name(type))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } } /* */ obj_desc = acpi_ut_create_internal_object(info->field_type); if (!obj_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* */ obj_desc->common_field.node = info->field_node; status = acpi_ex_prep_common_field_object(obj_desc, info->field_flags, info->attribute, info->field_bit_position, info->field_bit_length); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } /* */ switch (info->field_type) { case ACPI_TYPE_LOCAL_REGION_FIELD: obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); /* */ obj_desc->field.access_length = info->access_length; if (info->connection_node) { second_desc = info->connection_node->object; if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { status = acpi_ds_get_buffer_arguments(second_desc); if (ACPI_FAILURE(status)) { acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(status); } } obj_desc->field.resource_buffer = second_desc->buffer.pointer; obj_desc->field.resource_length = (u16)second_desc->buffer.length; } else if (info->resource_buffer) { obj_desc->field.resource_buffer = info->resource_buffer; obj_desc->field.resource_length = info->resource_length; } /* */ if ((obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_EC) && (obj_desc->common_field.bit_length > 8)) { access_byte_width = ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field. bit_length); /* */ if (access_byte_width < 256) { obj_desc->common_field.access_byte_width = (u8)access_byte_width; } } /* */ acpi_ut_add_reference(obj_desc->field.region_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->field.region_obj)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: obj_desc->bank_field.value = info->bank_value; obj_desc->bank_field.region_obj = acpi_ns_get_attached_object(info->region_node); obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object(info->register_node); /* */ acpi_ut_add_reference(obj_desc->bank_field.region_obj); acpi_ut_add_reference(obj_desc->bank_field.bank_obj); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", obj_desc->bank_field.start_field_bit_offset, obj_desc->bank_field.base_byte_offset, obj_desc->field.access_byte_width, obj_desc->bank_field.region_obj, obj_desc->bank_field.bank_obj)); /* */ second_desc = obj_desc->common.next_object; second_desc->extra.aml_start = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.data; second_desc->extra.aml_length = ACPI_CAST_PTR(union acpi_parse_object, info->data_register_node)->named.length; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* */ obj_desc->index_field.index_obj = acpi_ns_get_attached_object(info->register_node); obj_desc->index_field.data_obj = acpi_ns_get_attached_object(info->data_register_node); if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) { ACPI_ERROR((AE_INFO, "Null Index Object during field prep")); acpi_ut_delete_object_desc(obj_desc); return_ACPI_STATUS(AE_AML_INTERNAL); } /* */ acpi_ut_add_reference(obj_desc->index_field.data_obj); acpi_ut_add_reference(obj_desc->index_field.index_obj); /* */ obj_desc->index_field.value = (u32) ACPI_ROUND_DOWN(ACPI_DIV_8(info->field_bit_position), obj_desc->index_field. access_byte_width); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", obj_desc->index_field.start_field_bit_offset, obj_desc->index_field.base_byte_offset, obj_desc->index_field.value, obj_desc->field.access_byte_width, obj_desc->index_field.index_obj, obj_desc->index_field.data_obj)); break; default: /* */ break; } /* */ status = acpi_ns_attach_object(info->field_node, obj_desc, acpi_ns_get_type(info->field_node)); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", info->field_node, acpi_ut_get_node_name(info->field_node), obj_desc)); /* */ acpi_ut_remove_reference(obj_desc); return_ACPI_STATUS(status); }
ACPI_STATUS AcpiExPrepFieldValue ( ACPI_CREATE_FIELD_INFO *Info) { ACPI_OPERAND_OBJECT *ObjDesc; ACPI_OPERAND_OBJECT *SecondDesc = NULL; ACPI_STATUS Status; UINT32 AccessByteWidth; UINT32 Type; ACPI_FUNCTION_TRACE (ExPrepFieldValue); /* Parameter validation */ if (Info->FieldType != ACPI_TYPE_LOCAL_INDEX_FIELD) { if (!Info->RegionNode) { ACPI_ERROR ((AE_INFO, "Null RegionNode")); return_ACPI_STATUS (AE_AML_NO_OPERAND); } Type = AcpiNsGetType (Info->RegionNode); if (Type != ACPI_TYPE_REGION) { ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", Type, AcpiUtGetTypeName (Type))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } } /* Allocate a new field object */ ObjDesc = AcpiUtCreateInternalObject (Info->FieldType); if (!ObjDesc) { return_ACPI_STATUS (AE_NO_MEMORY); } /* Initialize areas of the object that are common to all fields */ ObjDesc->CommonField.Node = Info->FieldNode; Status = AcpiExPrepCommonFieldObject (ObjDesc, Info->FieldFlags, Info->Attribute, Info->FieldBitPosition, Info->FieldBitLength); if (ACPI_FAILURE (Status)) { AcpiUtDeleteObjectDesc (ObjDesc); return_ACPI_STATUS (Status); } /* Initialize areas of the object that are specific to the field type */ switch (Info->FieldType) { case ACPI_TYPE_LOCAL_REGION_FIELD: ObjDesc->Field.RegionObj = AcpiNsGetAttachedObject (Info->RegionNode); /* Fields specific to GenericSerialBus fields */ ObjDesc->Field.AccessLength = Info->AccessLength; if (Info->ConnectionNode) { SecondDesc = Info->ConnectionNode->Object; if (!(SecondDesc->Common.Flags & AOPOBJ_DATA_VALID)) { Status = AcpiDsGetBufferArguments (SecondDesc); if (ACPI_FAILURE (Status)) { AcpiUtDeleteObjectDesc (ObjDesc); return_ACPI_STATUS (Status); } } ObjDesc->Field.ResourceBuffer = SecondDesc->Buffer.Pointer; ObjDesc->Field.ResourceLength = (UINT16) SecondDesc->Buffer.Length; } else if (Info->ResourceBuffer) { ObjDesc->Field.ResourceBuffer = Info->ResourceBuffer; ObjDesc->Field.ResourceLength = Info->ResourceLength; } /* Allow full data read from EC address space */ if ((ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_EC) && (ObjDesc->CommonField.BitLength > 8)) { AccessByteWidth = ACPI_ROUND_BITS_UP_TO_BYTES ( ObjDesc->CommonField.BitLength); /* Maximum byte width supported is 255 */ if (AccessByteWidth < 256) { ObjDesc->CommonField.AccessByteWidth = (UINT8) AccessByteWidth; } } /* An additional reference for the container */ AcpiUtAddReference (ObjDesc->Field.RegionObj); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", ObjDesc->Field.StartFieldBitOffset, ObjDesc->Field.BaseByteOffset, ObjDesc->Field.AccessByteWidth, ObjDesc->Field.RegionObj)); break; case ACPI_TYPE_LOCAL_BANK_FIELD: ObjDesc->BankField.Value = Info->BankValue; ObjDesc->BankField.RegionObj = AcpiNsGetAttachedObject (Info->RegionNode); ObjDesc->BankField.BankObj = AcpiNsGetAttachedObject (Info->RegisterNode); /* An additional reference for the attached objects */ AcpiUtAddReference (ObjDesc->BankField.RegionObj); AcpiUtAddReference (ObjDesc->BankField.BankObj); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Bank Field: BitOff %X, Off %X, Gran %X, Region %p, BankReg %p\n", ObjDesc->BankField.StartFieldBitOffset, ObjDesc->BankField.BaseByteOffset, ObjDesc->Field.AccessByteWidth, ObjDesc->BankField.RegionObj, ObjDesc->BankField.BankObj)); /* * Remember location in AML stream of the field unit * opcode and operands -- since the BankValue * operands must be evaluated. */ SecondDesc = ObjDesc->Common.NextObject; SecondDesc->Extra.AmlStart = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Info->DataRegisterNode)->Named.Data; SecondDesc->Extra.AmlLength = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Info->DataRegisterNode)->Named.Length; break; case ACPI_TYPE_LOCAL_INDEX_FIELD: /* Get the Index and Data registers */ ObjDesc->IndexField.IndexObj = AcpiNsGetAttachedObject (Info->RegisterNode); ObjDesc->IndexField.DataObj = AcpiNsGetAttachedObject (Info->DataRegisterNode); if (!ObjDesc->IndexField.DataObj || !ObjDesc->IndexField.IndexObj) { ACPI_ERROR ((AE_INFO, "Null Index Object during field prep")); AcpiUtDeleteObjectDesc (ObjDesc); return_ACPI_STATUS (AE_AML_INTERNAL); } /* An additional reference for the attached objects */ AcpiUtAddReference (ObjDesc->IndexField.DataObj); AcpiUtAddReference (ObjDesc->IndexField.IndexObj); /* * April 2006: Changed to match MS behavior * * The value written to the Index register is the byte offset of the * target field in units of the granularity of the IndexField * * Previously, the value was calculated as an index in terms of the * width of the Data register, as below: * * ObjDesc->IndexField.Value = (UINT32) * (Info->FieldBitPosition / ACPI_MUL_8 ( * ObjDesc->Field.AccessByteWidth)); * * February 2006: Tried value as a byte offset: * ObjDesc->IndexField.Value = (UINT32) * ACPI_DIV_8 (Info->FieldBitPosition); */ ObjDesc->IndexField.Value = (UINT32) ACPI_ROUND_DOWN ( ACPI_DIV_8 (Info->FieldBitPosition), ObjDesc->IndexField.AccessByteWidth); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "IndexField: BitOff %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n", ObjDesc->IndexField.StartFieldBitOffset, ObjDesc->IndexField.BaseByteOffset, ObjDesc->IndexField.Value, ObjDesc->Field.AccessByteWidth, ObjDesc->IndexField.IndexObj, ObjDesc->IndexField.DataObj)); break; default: /* No other types should get here */ break; } /* * Store the constructed descriptor (ObjDesc) into the parent Node, * preserving the current type of that NamedObj. */ Status = AcpiNsAttachObject (Info->FieldNode, ObjDesc, AcpiNsGetType (Info->FieldNode)); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n", Info->FieldNode, AcpiUtGetNodeName (Info->FieldNode), ObjDesc)); /* Remove local reference to the object */ AcpiUtRemoveReference (ObjDesc); return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiExPrepCommonFieldObject ( ACPI_OPERAND_OBJECT *ObjDesc, UINT8 FieldFlags, UINT8 FieldAttribute, UINT32 FieldBitPosition, UINT32 FieldBitLength) { UINT32 AccessBitWidth; UINT32 ByteAlignment; UINT32 NearestByteAddress; ACPI_FUNCTION_TRACE (ExPrepCommonFieldObject); /* * Note: the structure being initialized is the * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common * area are initialized by this procedure. */ ObjDesc->CommonField.FieldFlags = FieldFlags; ObjDesc->CommonField.Attribute = FieldAttribute; ObjDesc->CommonField.BitLength = FieldBitLength; /* * Decode the access type so we can compute offsets. The access type gives * two pieces of information - the width of each field access and the * necessary ByteAlignment (address granularity) of the access. * * For AnyAcc, the AccessBitWidth is the largest width that is both * necessary and possible in an attempt to access the whole field in one * I/O operation. However, for AnyAcc, the ByteAlignment is always one * byte. * * For all Buffer Fields, the ByteAlignment is always one byte. * * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is * the same (equivalent) as the ByteAlignment. */ AccessBitWidth = AcpiExDecodeFieldAccess (ObjDesc, FieldFlags, &ByteAlignment); if (!AccessBitWidth) { return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } /* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */ ObjDesc->CommonField.AccessByteWidth = (UINT8) ACPI_DIV_8 (AccessBitWidth); /* * BaseByteOffset is the address of the start of the field within the * region. It is the byte address of the first *datum* (field-width data * unit) of the field. (i.e., the first datum that contains at least the * first *bit* of the field.) * * Note: ByteAlignment is always either equal to the AccessBitWidth or 8 * (Byte access), and it defines the addressing granularity of the parent * region or buffer. */ NearestByteAddress = ACPI_ROUND_BITS_DOWN_TO_BYTES (FieldBitPosition); ObjDesc->CommonField.BaseByteOffset = (UINT32) ACPI_ROUND_DOWN (NearestByteAddress, ByteAlignment); /* * StartFieldBitOffset is the offset of the first bit of the field within * a field datum. */ ObjDesc->CommonField.StartFieldBitOffset = (UINT8) (FieldBitPosition - ACPI_MUL_8 (ObjDesc->CommonField.BaseByteOffset)); return_ACPI_STATUS (AE_OK); }
static UINT32 AcpiExGenerateAccess ( UINT32 FieldBitOffset, UINT32 FieldBitLength, UINT32 RegionLength) { UINT32 FieldByteLength; UINT32 FieldByteOffset; UINT32 FieldByteEndOffset; UINT32 AccessByteWidth; UINT32 FieldStartOffset; UINT32 FieldEndOffset; UINT32 MinimumAccessWidth = 0xFFFFFFFF; UINT32 MinimumAccesses = 0xFFFFFFFF; UINT32 Accesses; ACPI_FUNCTION_TRACE (ExGenerateAccess); /* Round Field start offset and length to "minimal" byte boundaries */ FieldByteOffset = ACPI_DIV_8 (ACPI_ROUND_DOWN (FieldBitOffset, 8)); FieldByteEndOffset = ACPI_DIV_8 (ACPI_ROUND_UP (FieldBitLength + FieldBitOffset, 8)); FieldByteLength = FieldByteEndOffset - FieldByteOffset; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Bit length %u, Bit offset %u\n", FieldBitLength, FieldBitOffset)); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Byte Length %u, Byte Offset %u, End Offset %u\n", FieldByteLength, FieldByteOffset, FieldByteEndOffset)); /* * Iterative search for the maximum access width that is both aligned * and does not go beyond the end of the region * * Start at ByteAcc and work upwards to QwordAcc max. (1,2,4,8 bytes) */ for (AccessByteWidth = 1; AccessByteWidth <= 8; AccessByteWidth <<= 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 FieldByteLength, we * are done. (This does not optimize for the perfectly aligned * case yet). */ if (ACPI_ROUND_UP (FieldByteEndOffset, AccessByteWidth) <= RegionLength) { FieldStartOffset = ACPI_ROUND_DOWN (FieldByteOffset, AccessByteWidth) / AccessByteWidth; FieldEndOffset = ACPI_ROUND_UP ((FieldByteLength + FieldByteOffset), AccessByteWidth) / AccessByteWidth; Accesses = FieldEndOffset - FieldStartOffset; ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "AccessWidth %u end is within region\n", AccessByteWidth)); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Field Start %u, Field End %u -- requires %u accesses\n", FieldStartOffset, FieldEndOffset, 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", AccessByteWidth)); return_VALUE (AccessByteWidth); } /* * Fits in the region, but requires more than one read/write. * try the next wider access on next iteration */ if (Accesses < MinimumAccesses) { MinimumAccesses = Accesses; MinimumAccessWidth = AccessByteWidth; } } else { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "AccessWidth %u end is NOT within region\n", AccessByteWidth)); if (AccessByteWidth == 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", MinimumAccessWidth)); return_VALUE (MinimumAccessWidth); } } /* * 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); }
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) { u32 access_bit_width; u32 byte_alignment; u32 nearest_byte_address; ACPI_FUNCTION_TRACE ("ex_prep_common_field_object"); /* * Note: the structure being initialized is the * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common * area are initialized by this procedure. */ obj_desc->common_field.field_flags = field_flags; obj_desc->common_field.attribute = field_attribute; obj_desc->common_field.bit_length = field_bit_length; /* * Decode the access type so we can compute offsets. The access type gives * two pieces of information - the width of each field access and the * necessary byte_alignment (address granularity) of the access. * * For any_acc, the access_bit_width is the largest width that is both * necessary and possible in an attempt to access the whole field in one * I/O operation. However, for any_acc, the byte_alignment is always one * byte. * * For all Buffer Fields, the byte_alignment is always one byte. * * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is * the same (equivalent) as the byte_alignment. */ access_bit_width = acpi_ex_decode_field_access (obj_desc, field_flags, &byte_alignment); if (!access_bit_width) { return_ACPI_STATUS (AE_AML_OPERAND_VALUE); } /* Setup width (access granularity) fields */ obj_desc->common_field.access_byte_width = (u8) ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */ /* * base_byte_offset is the address of the start of the field within the * region. It is the byte address of the first *datum* (field-width data * unit) of the field. (i.e., the first datum that contains at least the * first *bit* of the field.) * * Note: byte_alignment is always either equal to the access_bit_width or 8 * (Byte access), and it defines the addressing granularity of the parent * region or buffer. */ nearest_byte_address = ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position); obj_desc->common_field.base_byte_offset = ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment); /* * start_field_bit_offset is the offset of the first bit of the field within * a field datum. */ obj_desc->common_field.start_field_bit_offset = (u8) (field_bit_position - ACPI_MUL_8 (obj_desc->common_field.base_byte_offset)); /* * Valid bits -- the number of bits that compose a partial datum, * 1) At the end of the field within the region (arbitrary starting bit * offset) * 2) At the end of a buffer used to contain the field (starting offset * always zero) */ obj_desc->common_field.end_field_valid_bits = (u8) ((obj_desc->common_field.start_field_bit_offset + field_bit_length) % access_bit_width); /* start_buffer_bit_offset always = 0 */ obj_desc->common_field.end_buffer_valid_bits = (u8) (field_bit_length % access_bit_width); /* * datum_valid_bits is the number of valid field bits in the first * field datum. */ obj_desc->common_field.datum_valid_bits = (u8) (access_bit_width - obj_desc->common_field.start_field_bit_offset); /* * Does the entire field fit within a single field access element? (datum) * (i.e., without crossing a datum boundary) */ if ((obj_desc->common_field.start_field_bit_offset + field_bit_length) <= (u16) access_bit_width) { obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM; } return_ACPI_STATUS (AE_OK); }