diff options
author | njl <njl@FreeBSD.org> | 2003-12-09 02:54:47 +0000 |
---|---|---|
committer | njl <njl@FreeBSD.org> | 2003-12-09 02:54:47 +0000 |
commit | 5171c4ac8892785ece7917adf7766e9d072d2b59 (patch) | |
tree | 5bd13c1163815f44a7f26ecb4905c82eef6807af /sys/contrib | |
parent | d7a7fb25fd69eef75ab6e2fe96f0b78607a05b4d (diff) | |
download | FreeBSD-src-5171c4ac8892785ece7917adf7766e9d072d2b59.zip FreeBSD-src-5171c4ac8892785ece7917adf7766e9d072d2b59.tar.gz |
Local change: Allow access to the field if it is within the region
size rounded up to a multiple of the access byte width. This overcomes
"off-by-one" programming errors in the AML often found in Toshiba
laptops.
Diffstat (limited to 'sys/contrib')
-rw-r--r-- | sys/contrib/dev/acpica/exfldio.c | 309 |
1 files changed, 174 insertions, 135 deletions
diff --git a/sys/contrib/dev/acpica/exfldio.c b/sys/contrib/dev/acpica/exfldio.c index 9994218..5994d7b 100644 --- a/sys/contrib/dev/acpica/exfldio.c +++ b/sys/contrib/dev/acpica/exfldio.c @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exfldio - Aml Field I/O - * $Revision: 96 $ + * $Revision: 100 $ * *****************************************************************************/ @@ -139,7 +139,8 @@ * RETURN: Status * * DESCRIPTION: Common processing for AcpiExExtractFromField and - * AcpiExInsertIntoField. Initialize the + * AcpiExInsertIntoField. Initialize the Region if necessary and + * validate the request. * ******************************************************************************/ @@ -172,7 +173,7 @@ AcpiExSetupRegion ( * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. */ - if (!(RgnDesc->Region.Flags & AOPOBJ_DATA_VALID)) + if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) { Status = AcpiDsGetRegionArguments (RgnDesc); if (ACPI_FAILURE (Status)) @@ -188,6 +189,20 @@ AcpiExSetupRegion ( return_ACPI_STATUS (AE_OK); } +#ifdef ACPI_UNDER_DEVELOPMENT + /* + * If the Field access is AnyAcc, we can now compute the optimal + * access (because we know know the length of the parent region) + */ + if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) + { + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + } +#endif + /* * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. @@ -206,8 +221,9 @@ AcpiExSetupRegion ( */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", - ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.AccessByteWidth, - RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length)); + AcpiUtGetNodeName (ObjDesc->CommonField.Node), + ObjDesc->CommonField.AccessByteWidth, + AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length)); } /* @@ -216,9 +232,10 @@ AcpiExSetupRegion ( */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", - ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.BaseByteOffset, + AcpiUtGetNodeName (ObjDesc->CommonField.Node), + ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, - RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length)); + AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length)); #ifndef ACPICA_PEDANTIC { @@ -311,13 +328,13 @@ AcpiExAccessRegion ( } ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, - " Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n", + " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", AcpiUtGetRegionName (RgnDesc->Region.SpaceId), RgnDesc->Region.SpaceId, ObjDesc->CommonField.AccessByteWidth, ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset, - ACPI_HIDWORD (Address), ACPI_LODWORD (Address))); + ACPI_FORMAT_UINT64 (Address))); /* Invoke the appropriate AddressSpace/OpRegion handler */ @@ -589,13 +606,15 @@ AcpiExFieldDatumIo ( { if (ReadWrite == ACPI_READ) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n", - ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value))); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*Value), + ObjDesc->CommonField.AccessByteWidth)); } else { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n", - ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value))); + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", + ACPI_FORMAT_UINT64 (*Value), + ObjDesc->CommonField.AccessByteWidth)); } } @@ -657,6 +676,11 @@ AcpiExWriteWithUpdateRule ( */ Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, &CurrentValue, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } + MergedValue |= (CurrentValue & ~Mask); } break; @@ -676,6 +700,7 @@ AcpiExWriteWithUpdateRule ( break; default: + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n", (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); @@ -683,18 +708,19 @@ AcpiExWriteWithUpdateRule ( } } + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", + ACPI_FORMAT_UINT64 (Mask), + FieldDatumByteOffset, + ObjDesc->CommonField.AccessByteWidth, + ACPI_FORMAT_UINT64 (FieldValue), + ACPI_FORMAT_UINT64 (MergedValue))); + /* Write the merged value */ Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, &MergedValue, ACPI_WRITE); - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", - ACPI_HIDWORD (Mask), ACPI_LODWORD (Mask), - FieldDatumByteOffset, - ACPI_HIDWORD (FieldValue), ACPI_LODWORD (FieldValue), - ACPI_HIDWORD (MergedValue),ACPI_LODWORD (MergedValue))); - return_ACPI_STATUS (Status); } @@ -728,7 +754,7 @@ AcpiExGetBufferDatum ( UINT32 Index; - ACPI_FUNCTION_ENTRY (); + ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity); /* Get proper index into buffer (handles big/little endian) */ @@ -763,6 +789,8 @@ AcpiExGetBufferDatum ( /* Should not get here */ break; } + + return_VOID; } @@ -794,7 +822,8 @@ AcpiExSetBufferDatum ( { UINT32 Index; - ACPI_FUNCTION_ENTRY (); + + ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity); /* Get proper index into buffer (handles big/little endian) */ @@ -829,6 +858,8 @@ AcpiExSetBufferDatum ( /* Should not get here */ break; } + + return_VOID; } @@ -853,12 +884,13 @@ AcpiExExtractFromField ( { ACPI_STATUS Status; UINT32 FieldDatumByteOffset; - UINT32 DatumOffset; - ACPI_INTEGER PreviousRawDatum; + UINT32 BufferDatumOffset; + ACPI_INTEGER PreviousRawDatum = 0; ACPI_INTEGER ThisRawDatum = 0; ACPI_INTEGER MergedDatum = 0; UINT32 ByteFieldLength; UINT32 DatumCount; + UINT32 i; ACPI_FUNCTION_TRACE ("ExExtractFromField"); @@ -882,83 +914,80 @@ AcpiExExtractFromField ( DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth); + /* + * If the field is not aligned on a datum boundary and does not + * fit within a single datum, we must read an extra datum. + * + * We could just split the aligned and non-aligned cases since the + * aligned case is so very simple, but this would require more code. + */ + if ((ObjDesc->CommonField.EndFieldValidBits != 0) && + (!(ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))) + { + DatumCount++; + } + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "ByteLen=%X, DatumLen=%X, ByteGran=%X\n", + "ByteLen %X, DatumLen %X, ByteGran %X\n", ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth)); /* * Clear the caller's buffer (the whole buffer length as given) - * This is very important, especially in the cases where a byte is read, - * but the buffer is really a UINT32 (4 bytes). + * This is very important, especially in the cases where the buffer + * is longer than the size of the field. */ ACPI_MEMSET (Buffer, 0, BufferLength); - /* Read the first raw datum to prime the loop */ - FieldDatumByteOffset = 0; - DatumOffset= 0; - - Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, - &PreviousRawDatum, ACPI_READ); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } + BufferDatumOffset= 0; + /* Read the entire field */ - /* We might actually be done if the request fits in one datum */ - - if ((DatumCount == 1) && - (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)) + for (i = 0; i < DatumCount; i++) { - /* 1) Shift the valid data bits down to start at bit 0 */ - - MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); + Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, + &ThisRawDatum, ACPI_READ); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); + } - /* 2) Mask off any upper unused bits (bits not part of the field) */ + /* We might actually be done if the request fits in one datum */ - if (ObjDesc->CommonField.EndBufferValidBits) + if ((DatumCount == 1) && + (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)) { - MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits); - } + /* 1) Shift the valid data bits down to start at bit 0 */ - /* Store the datum to the caller buffer */ + MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); - AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, DatumOffset); + /* 2) Mask off any upper unused bits (bits not part of the field) */ - return_ACPI_STATUS (AE_OK); - } + if (ObjDesc->CommonField.EndBufferValidBits) + { + MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits); + } + /* Store the datum to the caller buffer */ - /* We need to get more raw data to complete one or more field data */ + AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, + ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); - while (DatumOffset < DatumCount) - { - FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; + return_ACPI_STATUS (AE_OK); + } - /* - * If the field is aligned on a byte boundary, we don't want - * to perform a final read, since this would potentially read - * past the end of the region. - * - * We could just split the aligned and non-aligned cases since the - * aligned case is so very simple, but this would require more code. - */ - if ((ObjDesc->CommonField.StartFieldBitOffset != 0) || - ((ObjDesc->CommonField.StartFieldBitOffset == 0) && - (DatumOffset < (DatumCount -1)))) + /* Special handling for the last datum to ignore extra bits */ + + if ((i >= (DatumCount -1)) && + (ObjDesc->CommonField.EndFieldValidBits)) { /* - * Get the next raw datum, it contains some or all bits - * of the current field datum + * This is the last iteration of the loop. We need to clear + * any unused bits (bits that are not part of this field) before + * we store the final merged datum into the caller buffer. */ - Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, - &ThisRawDatum, ACPI_READ); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } + ThisRawDatum &= + ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); } /* @@ -968,51 +997,51 @@ AcpiExExtractFromField ( { /* Field is not skewed and we can just copy the datum */ - MergedDatum = PreviousRawDatum; + AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength, + ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); + BufferDatumOffset++; } else { - /* - * Put together the appropriate bits of the two raw data to make a - * single complete field datum - * - * 1) Normalize the first datum down to bit 0 - */ - MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); - - /* 2) Insert the second datum "above" the first datum */ + /* Not aligned -- on the first iteration, just save the datum */ - MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits); - - if ((DatumOffset >= (DatumCount -1))) + if (i != 0) { /* - * This is the last iteration of the loop. We need to clear - * any unused bits (bits that are not part of this field) that - * came from the last raw datum before we store the final - * merged datum into the caller buffer. + * Put together the appropriate bits of the two raw data to make a + * single complete field datum + * + * 1) Normalize the first datum down to bit 0 */ - if (ObjDesc->CommonField.EndBufferValidBits) - { - MergedDatum &= - ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits); - } + MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); + + /* 2) Insert the second datum "above" the first datum */ + + MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits); + + AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, + ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); + BufferDatumOffset++; } + + /* + * Save the raw datum that was just acquired since it may contain bits + * of the *next* field datum + */ + PreviousRawDatum = ThisRawDatum; } - /* - * Store the merged field datum in the caller's buffer, according to - * the granularity of the field (size of each datum). - */ - AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, - ObjDesc->CommonField.AccessByteWidth, DatumOffset); + FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; + } - /* - * Save the raw datum that was just acquired since it may contain bits - * of the *next* field datum. Update offsets - */ - PreviousRawDatum = ThisRawDatum; - DatumOffset++; + /* For non-aligned case, there is one last datum to insert */ + + if (ObjDesc->CommonField.StartFieldBitOffset != 0) + { + MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); + + AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, + ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); } return_ACPI_STATUS (AE_OK); @@ -1058,21 +1087,28 @@ AcpiExInsertIntoField ( * larger than the field, this typically happens when an integer is * written to a field that is actually smaller than an integer. */ - ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength); + ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->CommonField.BitLength); if (BufferLength < ByteFieldLength) { - ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n", + ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, + "Buffer length %X too small for field %X\n", BufferLength, ByteFieldLength)); return_ACPI_STATUS (AE_BUFFER_OVERFLOW); } + ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES ( + ObjDesc->CommonField.StartFieldBitOffset + + ObjDesc->CommonField.BitLength); + /* Convert byte count to datum count, round up if necessary */ - DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth); + DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, + ObjDesc->CommonField.AccessByteWidth); ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, - "ByteLen=%X, DatumLen=%X, ByteGran=%X\n", + "Bytes %X, Datums %X, ByteGran %X\n", ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth)); /* @@ -1125,6 +1161,10 @@ AcpiExInsertIntoField ( return_ACPI_STATUS (Status); } + /* We just wrote the first datum */ + + DatumOffset++; + /* If the entire field fits within one datum, we are done. */ if ((DatumCount == 1) && @@ -1146,7 +1186,6 @@ AcpiExInsertIntoField ( */ while (DatumOffset < DatumCount) { - DatumOffset++; FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; /* @@ -1180,37 +1219,37 @@ AcpiExInsertIntoField ( * a datum boundary. Update Rule must be applied to the bits outside * the field. */ - if (DatumOffset == DatumCount) + DatumOffset++; + if ((DatumOffset == DatumCount) && + (ObjDesc->CommonField.EndFieldValidBits)) { /* * If there are dangling non-aligned bits, perform one more merged write * Else - field is aligned at the end, no need for any more writes */ - if (ObjDesc->CommonField.EndFieldValidBits) - { - /* - * Part3: - * This is the last datum and the field does not end on a datum boundary. - * Build the partial datum and write with the update rule. - * - * Mask off the unused bits above (after) the end-of-field - */ - Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); - MergedDatum &= Mask; - /* Write the last datum with the update rule */ + /* + * Part3: + * This is the last datum and the field does not end on a datum boundary. + * Build the partial datum and write with the update rule. + * + * Mask off the unused bits above (after) the end-of-field + */ + Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); + MergedDatum &= Mask; - Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, - FieldDatumByteOffset); - if (ACPI_FAILURE (Status)) - { - return_ACPI_STATUS (Status); - } + /* Write the last datum with the update rule */ + + Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, + FieldDatumByteOffset); + if (ACPI_FAILURE (Status)) + { + return_ACPI_STATUS (Status); } } else { - /* Normal case -- write the completed datum */ + /* Normal (aligned) case -- write the completed datum */ Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, &MergedDatum, ACPI_WRITE); |