ACPI: EC: Allow limited large burst reads
Subsystems (2)
RFC PATCH 1/1 ACPI: EC: Allow limited large burst reads
access_bit_width field is u8 in ACPICA, thus 256 value written to it becomes 0, causing divide by zero later.
Proper fix would be to remove access_bit_width at all, just because we already have access_byte_width, which is access_bit_width / 8. Limit access width to 64 bit for in general, but allow larger reads if they are aligned with access_byte_width.
Signed-off-by Alexey Starikovskiy <[email protected]>
---
drivers/acpi/acpica/acobject.h | 3 +-- drivers/acpi/acpica/exfldio.c | 24 ++++++++++++------------ drivers/acpi/acpica/exprep.c | 16 +++++----------- 3 files changed, 18 insertions(+), 25 deletions(-)
drivers/acpi/acpica/acobject.h +1 -2
@@ -243,12 +243,11 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO};u8 field_flags;/* Access, update, and lock bits */ \u8 attribute;/* From access_as keyword */ \u8 access_byte_width;/* Read/Write size in bytes */ \ +u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */ \struct acpi_namespace_node *node;/* Link back to parent node */ \u32 bit_length;/* Length of field in bits */ \u32 base_byte_offset;/* Byte offset within containing object */ \u32 value;/* Value to store into the Bank or Index register */ \ -u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */ \ -u8 access_bit_width;/* Read/Write size in bits (8-64) */ struct acpi_object_field_common {/* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */
drivers/acpi/acpica/exfldio.c +12 -12
@@ -699,12 +699,12 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,/* Compute the number of datums (access width data items) */ datum_count =ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length, - obj_desc->common_field.access_bit_width); + obj_desc->common_field.access_byte_width *8 ); field_datum_count =ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field. - access_bit_width); + access_byte_width *8 );/* Priming read from the field */
@@ -738,12 +738,12 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,* This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ -if ((obj_desc->common_field.access_bit_width - +if ((obj_desc->common_field.access_byte_width *8 - obj_desc->common_field.start_field_bit_offset) <ACPI_INTEGER_BIT_SIZE ) { merged_datum |= raw_datum << (obj_desc->common_field. - access_bit_width - + access_byte_width *8 - obj_desc->common_field. start_field_bit_offset); }
@@ -766,7 +766,7 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,/* Mask off any extra bits in the last datum */ buffer_tail_bits = obj_desc->common_field.bit_length % - obj_desc->common_field.access_bit_width; + (obj_desc->common_field.access_byte_width *8 );if (buffer_tail_bits) { merged_datum &=ACPI_MASK_BITS_ABOVE (buffer_tail_bits); }
@@ -849,12 +849,12 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,* Note: This if/else is used to bypass compiler differences with the * shift operator */ -if (obj_desc->common_field.access_bit_width ==ACPI_INTEGER_BIT_SIZE ) { +if (obj_desc->common_field.access_byte_width *8 ==ACPI_INTEGER_BIT_SIZE ) { width_mask =ACPI_UINT64_MAX ; }else { width_mask =ACPI_MASK_BITS_ABOVE (obj_desc->common_field. - access_bit_width); + access_byte_width *8 ); } mask = width_mask &
@@ -863,13 +863,13 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,/* Compute the number of datums (access width data items) */ datum_count =ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length, - obj_desc->common_field.access_bit_width); + obj_desc->common_field.access_byte_width *8 ); field_datum_count =ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length + obj_desc->common_field. start_field_bit_offset, obj_desc->common_field. - access_bit_width); + access_byte_width *8 );/* Get initial Datum from the input buffer */
@@ -905,12 +905,12 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,* This avoids the differences in behavior between different compilers * concerning shift values larger than the target data width. */ -if ((obj_desc->common_field.access_bit_width - +if ((obj_desc->common_field.access_byte_width *8 - obj_desc->common_field.start_field_bit_offset) <ACPI_INTEGER_BIT_SIZE ) { merged_datum = raw_datum >> (obj_desc->common_field. - access_bit_width - + access_byte_width *8 - obj_desc->common_field. start_field_bit_offset); }else {
@@ -937,7 +937,7 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, buffer_tail_bits = (obj_desc->common_field.bit_length + obj_desc->common_field.start_field_bit_offset) % - obj_desc->common_field.access_bit_width; + (obj_desc->common_field.access_byte_width *8 );if (buffer_tail_bits) { mask &=ACPI_MASK_BITS_ABOVE (buffer_tail_bits); }
drivers/acpi/acpica/exprep.c +5 -11
@@ -360,8 +360,6 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, 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
@@ -470,15 +468,11 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)/* 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 ) - obj_desc->common_field.access_bit_width = -ACPI_ROUND_UP (obj_desc->common_field. - bit_length,8 ); - obj_desc->common_field.access_byte_width = -ACPI_DIV_8 (obj_desc->common_field. - access_bit_width); - } +ACPI_ADR_SPACE_EC && + obj_desc->common_field.bit_length >8 ) + obj_desc->common_field.access_byte_width = +ACPI_ROUND_BITS_UP_TO_BYTES ( + obj_desc->common_field.bit_length); ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n",