summaryrefslogtreecommitdiffstats
path: root/sys/contrib
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2003-12-09 02:54:47 +0000
committernjl <njl@FreeBSD.org>2003-12-09 02:54:47 +0000
commit5171c4ac8892785ece7917adf7766e9d072d2b59 (patch)
tree5bd13c1163815f44a7f26ecb4905c82eef6807af /sys/contrib
parentd7a7fb25fd69eef75ab6e2fe96f0b78607a05b4d (diff)
downloadFreeBSD-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.c309
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);
OpenPOWER on IntegriCloud