Enable multi-byte EC transfers.

Previously, the maximum data size passed to the EC operation region
handler was a single byte. Since there are often larger datums that
need to be transfered, and the EC would like to lock these as a single
transaction, this change enables transfers larger than a single byte.
This may require changes to the host-OS Embedded Controller driver
to enable 16/32/64 bit tranfers in addition to 8-bit transfers.
Alexey Starikovskiy, Lin Ming
This commit is contained in:
Robert Moore 2010-05-26 13:01:18 -07:00
parent 14aafc8b1b
commit df3d422671
3 changed files with 113 additions and 69 deletions

View File

@ -202,8 +202,8 @@ AcpiExSetupRegion (
}
/*
* Exit now for SMBus or IPMI address space, it has a non-linear address space
* and the request cannot be directly validated
* Exit now for SMBus or IPMI address space, it has a non-linear
* address space and the request cannot be directly validated
*/
if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI)
@ -233,8 +233,7 @@ AcpiExSetupRegion (
* (Region length is specified in bytes)
*/
if (RgnDesc->Region.Length <
(ObjDesc->CommonField.BaseByteOffset +
FieldDatumByteOffset +
(ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
ObjDesc->CommonField.AccessByteWidth))
{
if (AcpiGbl_EnableInterpreterSlack)
@ -794,6 +793,7 @@ AcpiExExtractFromField (
UINT32 BufferTailBits;
UINT32 DatumCount;
UINT32 FieldDatumCount;
UINT32 AccessBitWidth;
UINT32 i;
@ -803,7 +803,7 @@ AcpiExExtractFromField (
/* Validate target buffer and clear it */
if (BufferLength <
ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
{
ACPI_ERROR ((AE_INFO,
"Field size %u (bits) is too large for buffer (%u)",
@ -811,17 +811,37 @@ AcpiExExtractFromField (
return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
}
ACPI_MEMSET (Buffer, 0, BufferLength);
AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
/* Handle the simple case here */
if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
(ObjDesc->CommonField.BitLength == AccessBitWidth))
{
Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
return_ACPI_STATUS (Status);
}
/* TBD: Move to common setup code */
/* Field algorithm is limited to sizeof(UINT64), truncate if needed */
if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
{
ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
AccessBitWidth = sizeof (UINT64) * 8;
}
/* Compute the number of datums (access width data items) */
DatumCount = ACPI_ROUND_UP_TO (
ObjDesc->CommonField.BitLength,
ObjDesc->CommonField.AccessBitWidth);
ObjDesc->CommonField.BitLength, AccessBitWidth);
FieldDatumCount = ACPI_ROUND_UP_TO (
ObjDesc->CommonField.BitLength +
ObjDesc->CommonField.StartFieldBitOffset,
ObjDesc->CommonField.AccessBitWidth);
ObjDesc->CommonField.BitLength +
ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
/* Priming read from the field */
@ -854,12 +874,11 @@ AcpiExExtractFromField (
* This avoids the differences in behavior between different compilers
* concerning shift values larger than the target data width.
*/
if ((ObjDesc->CommonField.AccessBitWidth -
ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE)
if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
ACPI_INTEGER_BIT_SIZE)
{
MergedDatum |= RawDatum <<
(ObjDesc->CommonField.AccessBitWidth -
ObjDesc->CommonField.StartFieldBitOffset);
(AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
}
if (i == DatumCount)
@ -879,8 +898,7 @@ AcpiExExtractFromField (
/* Mask off any extra bits in the last datum */
BufferTailBits = ObjDesc->CommonField.BitLength %
ObjDesc->CommonField.AccessBitWidth;
BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
if (BufferTailBits)
{
MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
@ -916,6 +934,7 @@ AcpiExInsertIntoField (
void *Buffer,
UINT32 BufferLength)
{
void *NewBuffer;
ACPI_STATUS Status;
UINT64 Mask;
UINT64 WidthMask;
@ -926,9 +945,9 @@ AcpiExInsertIntoField (
UINT32 BufferTailBits;
UINT32 DatumCount;
UINT32 FieldDatumCount;
UINT32 i;
UINT32 AccessBitWidth;
UINT32 RequiredLength;
void *NewBuffer;
UINT32 i;
ACPI_FUNCTION_TRACE (ExInsertIntoField);
@ -965,31 +984,41 @@ AcpiExInsertIntoField (
BufferLength = RequiredLength;
}
/* TBD: Move to common setup code */
/* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
{
ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
}
AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
/*
* Create the bitmasks used for bit insertion.
* Note: This if/else is used to bypass compiler differences with the
* shift operator
*/
if (ObjDesc->CommonField.AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
{
WidthMask = ACPI_UINT64_MAX;
}
else
{
WidthMask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.AccessBitWidth);
WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
}
Mask = WidthMask &
ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
/* Compute the number of datums (access width data items) */
DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
ObjDesc->CommonField.AccessBitWidth);
AccessBitWidth);
FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
ObjDesc->CommonField.StartFieldBitOffset,
ObjDesc->CommonField.AccessBitWidth);
ObjDesc->CommonField.StartFieldBitOffset,
AccessBitWidth);
/* Get initial Datum from the input buffer */
@ -1024,12 +1053,11 @@ AcpiExInsertIntoField (
* This avoids the differences in behavior between different compilers
* concerning shift values larger than the target data width.
*/
if ((ObjDesc->CommonField.AccessBitWidth -
ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE)
if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
ACPI_INTEGER_BIT_SIZE)
{
MergedDatum = RawDatum >>
(ObjDesc->CommonField.AccessBitWidth -
ObjDesc->CommonField.StartFieldBitOffset);
(AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
}
else
{
@ -1048,15 +1076,15 @@ AcpiExInsertIntoField (
BufferOffset += ObjDesc->CommonField.AccessByteWidth;
ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
BufferLength - BufferOffset));
BufferLength - BufferOffset));
MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
}
/* Mask off any extra bits in the last datum */
BufferTailBits = (ObjDesc->CommonField.BitLength +
ObjDesc->CommonField.StartFieldBitOffset) %
ObjDesc->CommonField.AccessBitWidth;
ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
if (BufferTailBits)
{
Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);

View File

@ -193,12 +193,12 @@ AcpiExGenerateAccess (
FieldByteLength = FieldByteEndOffset - FieldByteOffset;
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Bit length %u, Bit offset %u\n",
FieldBitLength, FieldBitOffset));
"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));
"Byte Length %u, Byte Offset %u, End Offset %u\n",
FieldByteLength, FieldByteOffset, FieldByteEndOffset));
/*
* Iterative search for the maximum access width that is both aligned
@ -228,11 +228,11 @@ AcpiExGenerateAccess (
Accesses = FieldEndOffset - FieldStartOffset;
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"AccessWidth %u end is within region\n", AccessByteWidth));
"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));
"Field Start %u, Field End %u -- requires %u accesses\n",
FieldStartOffset, FieldEndOffset, Accesses));
/* Single access is optimal */
@ -261,7 +261,7 @@ AcpiExGenerateAccess (
if (AccessByteWidth == 1)
{
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Field goes beyond end-of-region!\n"));
"Field goes beyond end-of-region!\n"));
/* Field does not fit in the region at all */
@ -273,8 +273,8 @@ AcpiExGenerateAccess (
* previous access
*/
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Backing off to previous optimal access width of %u\n",
MinimumAccessWidth));
"Backing off to previous optimal access width of %u\n",
MinimumAccessWidth));
return_VALUE (MinimumAccessWidth);
}
}
@ -284,7 +284,7 @@ AcpiExGenerateAccess (
* just use max access width
*/
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Cannot access field in one operation, using width 8\n"));
"Cannot access field in one operation, using width 8\n"));
return_VALUE (8);
}
#endif /* ACPI_UNDER_DEVELOPMENT */
@ -444,18 +444,16 @@ AcpiExPrepCommonFieldObject (
* the same (equivalent) as the ByteAlignment.
*/
AccessBitWidth = AcpiExDecodeFieldAccess (ObjDesc, FieldFlags,
&ByteAlignment);
&ByteAlignment);
if (!AccessBitWidth)
{
return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
}
/* Setup width (access granularity) fields */
/* Setup width (access granularity) fields (values are: 1, 2, 4, 8) */
ObjDesc->CommonField.AccessByteWidth = (UINT8)
ACPI_DIV_8 (AccessBitWidth); /* 1, 2, 4, 8 */
ObjDesc->CommonField.AccessBitWidth = (UINT8) AccessBitWidth;
ACPI_DIV_8 (AccessBitWidth);
/*
* BaseByteOffset is the address of the start of the field within the
@ -468,9 +466,9 @@ AcpiExPrepCommonFieldObject (
* region or buffer.
*/
NearestByteAddress =
ACPI_ROUND_BITS_DOWN_TO_BYTES (FieldBitPosition);
ACPI_ROUND_BITS_DOWN_TO_BYTES (FieldBitPosition);
ObjDesc->CommonField.BaseByteOffset = (UINT32)
ACPI_ROUND_DOWN (NearestByteAddress, ByteAlignment);
ACPI_ROUND_DOWN (NearestByteAddress, ByteAlignment);
/*
* StartFieldBitOffset is the offset of the first bit of the field within
@ -502,8 +500,9 @@ AcpiExPrepFieldValue (
{
ACPI_OPERAND_OBJECT *ObjDesc;
ACPI_OPERAND_OBJECT *SecondDesc = NULL;
UINT32 Type;
ACPI_STATUS Status;
UINT32 AccessByteWidth;
UINT32 Type;
ACPI_FUNCTION_TRACE (ExPrepFieldValue);
@ -522,8 +521,7 @@ AcpiExPrepFieldValue (
Type = AcpiNsGetType (Info->RegionNode);
if (Type != ACPI_TYPE_REGION)
{
ACPI_ERROR ((AE_INFO,
"Needed Region, found type 0x%X (%s)",
ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
Type, AcpiUtGetTypeName (Type)));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
@ -541,8 +539,9 @@ AcpiExPrepFieldValue (
/* 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);
Status = AcpiExPrepCommonFieldObject (ObjDesc,
Info->FieldFlags, Info->Attribute,
Info->FieldBitPosition, Info->FieldBitLength);
if (ACPI_FAILURE (Status))
{
AcpiUtDeleteObjectDesc (ObjDesc);
@ -557,6 +556,22 @@ AcpiExPrepFieldValue (
ObjDesc->Field.RegionObj = AcpiNsGetAttachedObject (Info->RegionNode);
/* 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);
@ -570,11 +585,11 @@ AcpiExPrepFieldValue (
case ACPI_TYPE_LOCAL_BANK_FIELD:
ObjDesc->BankField.Value = Info->BankValue;
ObjDesc->BankField.RegionObj = AcpiNsGetAttachedObject (
Info->RegionNode);
ObjDesc->BankField.BankObj = AcpiNsGetAttachedObject (
Info->RegisterNode);
ObjDesc->BankField.Value = Info->BankValue;
ObjDesc->BankField.RegionObj =
AcpiNsGetAttachedObject (Info->RegionNode);
ObjDesc->BankField.BankObj =
AcpiNsGetAttachedObject (Info->RegisterNode);
/* An additional reference for the attached objects */
@ -594,9 +609,11 @@ AcpiExPrepFieldValue (
* 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;
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;
@ -605,10 +622,10 @@ AcpiExPrepFieldValue (
/* Get the Index and Data registers */
ObjDesc->IndexField.IndexObj = AcpiNsGetAttachedObject (
Info->RegisterNode);
ObjDesc->IndexField.DataObj = AcpiNsGetAttachedObject (
Info->DataRegisterNode);
ObjDesc->IndexField.IndexObj =
AcpiNsGetAttachedObject (Info->RegisterNode);
ObjDesc->IndexField.DataObj =
AcpiNsGetAttachedObject (Info->DataRegisterNode);
if (!ObjDesc->IndexField.DataObj || !ObjDesc->IndexField.IndexObj)
{
@ -663,10 +680,10 @@ AcpiExPrepFieldValue (
* preserving the current type of that NamedObj.
*/
Status = AcpiNsAttachObject (Info->FieldNode, ObjDesc,
AcpiNsGetType (Info->FieldNode));
AcpiNsGetType (Info->FieldNode));
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set NamedObj %p [%4.4s], ObjDesc %p\n",
Info->FieldNode, AcpiUtGetNodeName (Info->FieldNode), ObjDesc));
Info->FieldNode, AcpiUtGetNodeName (Info->FieldNode), ObjDesc));
/* Remove local reference to the object */

View File

@ -386,7 +386,6 @@ typedef struct acpi_object_thermal_zone
UINT32 BaseByteOffset; /* Byte offset within containing object */\
UINT32 Value; /* Value to store into the Bank or Index register */\
UINT8 StartFieldBitOffset;/* Bit offset within first field datum (0-63) */\
UINT8 AccessBitWidth; /* Read/Write size in bits (8-64) */
typedef struct acpi_object_field_common /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */