ACPI 4.0: Interpreter support for IPMI.

Adds support for IPMI which is similar to SMBus and uses a bi-directional
data buffer. ACPICA BZ 773. Lin Ming.
This commit is contained in:
Robert Moore 2009-06-19 09:17:58 -07:00
parent 17e7c9672f
commit 64a735c120
5 changed files with 100 additions and 39 deletions

View File

@ -151,6 +151,7 @@ AcpiExReadDataFromField (
ACPI_OPERAND_OBJECT *BufferDesc;
ACPI_SIZE Length;
void *Buffer;
UINT32 Function;
ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
@ -183,13 +184,27 @@ AcpiExReadDataFromField (
}
}
else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS))
(ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
{
/*
* This is an SMBus read. We must create a buffer to hold the data
* and directly access the region handler.
* This is an SMBus or IPMI read. We must create a buffer to hold
* the data and then directly access the region handler.
*
* Note: Smbus protocol value is passed in upper 16-bits of Function
*/
BufferDesc = AcpiUtCreateBufferObject (ACPI_SMBUS_BUFFER_SIZE);
if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
{
Length = ACPI_SMBUS_BUFFER_SIZE;
Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
}
else /* IPMI */
{
Length = ACPI_IPMI_BUFFER_SIZE;
Function = ACPI_READ;
}
BufferDesc = AcpiUtCreateBufferObject (Length);
if (!BufferDesc)
{
return_ACPI_STATUS (AE_NO_MEMORY);
@ -199,13 +214,11 @@ AcpiExReadDataFromField (
AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
/*
* Perform the read.
* Note: Smbus protocol value is passed in upper 16-bits of Function
*/
/* Call the region handler for the read */
Status = AcpiExAccessRegion (ObjDesc, 0,
ACPI_CAST_PTR (ACPI_INTEGER, BufferDesc->Buffer.Pointer),
ACPI_READ | (ObjDesc->Field.Attribute << 16));
Function);
AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
goto Exit;
}
@ -304,6 +317,7 @@ AcpiExWriteDataToField (
UINT32 Length;
void *Buffer;
ACPI_OPERAND_OBJECT *BufferDesc;
UINT32 Function;
ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
@ -332,40 +346,59 @@ AcpiExWriteDataToField (
}
}
else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
(ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS))
(ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
{
/*
* This is an SMBus write. We will bypass the entire field mechanism
* and handoff the buffer directly to the handler.
* This is an SMBus or IPMI write. We will bypass the entire field
* mechanism and handoff the buffer directly to the handler. For
* these address spaces, the buffer is bi-directional; on a write,
* return data is returned in the same buffer.
*
* Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE).
* Source must be a buffer of sufficient size:
* ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE.
*
* Note: SMBus protocol type is passed in upper 16-bits of Function
*/
if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
{
ACPI_ERROR ((AE_INFO, "SMBus write requires Buffer, found type %s",
ACPI_ERROR ((AE_INFO,
"SMBus or IPMI write requires Buffer, found type %s",
AcpiUtGetObjectTypeName (SourceDesc)));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
if (SourceDesc->Buffer.Length < ACPI_SMBUS_BUFFER_SIZE)
if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
{
Length = ACPI_SMBUS_BUFFER_SIZE;
Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
}
else /* IPMI */
{
Length = ACPI_IPMI_BUFFER_SIZE;
Function = ACPI_WRITE;
}
if (SourceDesc->Buffer.Length < Length)
{
ACPI_ERROR ((AE_INFO,
"SMBus write requires Buffer of length %X, found length %X",
ACPI_SMBUS_BUFFER_SIZE, SourceDesc->Buffer.Length));
"SMBus or IPMI write requires Buffer of length %X, found length %X",
Length, SourceDesc->Buffer.Length));
return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
}
BufferDesc = AcpiUtCreateBufferObject (ACPI_SMBUS_BUFFER_SIZE);
/* Create the bi-directional buffer */
BufferDesc = AcpiUtCreateBufferObject (Length);
if (!BufferDesc)
{
return_ACPI_STATUS (AE_NO_MEMORY);
}
Buffer = BufferDesc->Buffer.Pointer;
ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer,
ACPI_SMBUS_BUFFER_SIZE);
ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
/* Lock entire transaction if requested */
@ -374,11 +407,9 @@ AcpiExWriteDataToField (
/*
* Perform the write (returns status and perhaps data in the
* same buffer)
* Note: SMBus protocol type is passed in upper 16-bits of Function.
*/
Status = AcpiExAccessRegion (ObjDesc, 0,
(ACPI_INTEGER *) Buffer,
ACPI_WRITE | (ObjDesc->Field.Attribute << 16));
(ACPI_INTEGER *) Buffer, Function);
AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
*ResultDesc = BufferDesc;

View File

@ -202,12 +202,13 @@ AcpiExSetupRegion (
}
/*
* Exit now for SMBus address space, it has a non-linear address space
* 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)
if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI)
{
/* SMBus has a non-linear address space */
/* SMBus or IPMI has a non-linear address space */
return_ACPI_STATUS (AE_OK);
}

View File

@ -252,9 +252,10 @@
#define ACPI_RSDP_CHECKSUM_LENGTH 20
#define ACPI_RSDP_XCHECKSUM_LENGTH 36
/* SMBus bidirectional buffer size */
/* SMBus and IPMI bidirectional buffer size */
#define ACPI_SMBUS_BUFFER_SIZE 34
#define ACPI_IPMI_BUFFER_SIZE 66
/* _SxD and _SxW control methods */

View File

@ -816,7 +816,8 @@ typedef UINT8 ACPI_ADR_SPACE_TYPE;
#define ACPI_ADR_SPACE_SMBUS (ACPI_ADR_SPACE_TYPE) 4
#define ACPI_ADR_SPACE_CMOS (ACPI_ADR_SPACE_TYPE) 5
#define ACPI_ADR_SPACE_PCI_BAR_TARGET (ACPI_ADR_SPACE_TYPE) 6
#define ACPI_ADR_SPACE_DATA_TABLE (ACPI_ADR_SPACE_TYPE) 7
#define ACPI_ADR_SPACE_IPMI (ACPI_ADR_SPACE_TYPE) 7
#define ACPI_ADR_SPACE_DATA_TABLE (ACPI_ADR_SPACE_TYPE) 8
#define ACPI_ADR_SPACE_FIXED_HARDWARE (ACPI_ADR_SPACE_TYPE) 127

View File

@ -493,8 +493,8 @@ AeRegionInit (
*
*****************************************************************************/
ACPI_ADR_SPACE_TYPE SpaceId[] = {0, 1, 2, 3, 4, 5, 6, 0x80};
#define AEXEC_NUM_REGIONS 8
ACPI_ADR_SPACE_TYPE SpaceId[] = {0, 1, 2, 3, 4, 5, 6, 7, 0x80};
#define AEXEC_NUM_REGIONS 9
ACPI_STATUS
AeInstallHandlers (void)
@ -630,7 +630,8 @@ AeRegionHandler (
void *RegionContext)
{
ACPI_OPERAND_OBJECT *RegionObject = (ACPI_OPERAND_OBJECT*) RegionContext;
ACPI_OPERAND_OBJECT *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext);
UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Value);
ACPI_PHYSICAL_ADDRESS BaseAddress;
ACPI_SIZE Length;
BOOLEAN BufferExists;
@ -681,8 +682,9 @@ AeRegionHandler (
AcpiUtGetRegionName (RegionObject->Region.SpaceId),
(UINT32) Address));
if (SpaceId == ACPI_ADR_SPACE_SYSTEM_IO)
switch (SpaceId)
{
case ACPI_ADR_SPACE_SYSTEM_IO:
/*
* For I/O space, exercise the port validation
*/
@ -707,10 +709,11 @@ AeRegionHandler (
}
/* Now go ahead and simulate the hardware */
}
break;
case ACPI_ADR_SPACE_SMBUS:
else if (SpaceId == ACPI_ADR_SPACE_SMBUS)
{
Length = 0;
switch (Function & ACPI_IO_MASK)
@ -769,13 +772,37 @@ AeRegionHandler (
for (i = 0; i < Length; i++)
{
((UINT8 *) Value)[i+2] = (UINT8) (0xA0 + i);
Buffer[i+2] = (UINT8) (0xA0 + i);
}
((UINT8 *) Value)[0] = 0x7A;
((UINT8 *) Value)[1] = (UINT8) Length;
Buffer[0] = 0x7A;
Buffer[1] = (UINT8) Length;
return (AE_OK);
return AE_OK;
case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */
AcpiOsPrintf ("AcpiExec: Received IPMI request: "
"Address %X BaseAddress %X Length %X Width %X BufferLength %u\n",
(UINT32) Address, (UINT32) BaseAddress,
Length, BitWidth, Buffer[1]);
/*
* Regardless of a READ or WRITE, this handler is passed a 66-byte
* buffer in which to return the IPMI status/length/data.
*
* Return some example data to show use of the bidirectional buffer
*/
Buffer[0] = 0; /* Status byte */
Buffer[1] = 64; /* Return buffer data length */
Buffer[2] = 0; /* Completion code */
Buffer[3] = 0x34; /* Power measurement */
Buffer[4] = 0x12; /* Power measurement */
Buffer[65] = 0xEE; /* last buffer byte */
return (AE_OK);
default:
break;
}
/*