451 lines
10 KiB
C
451 lines
10 KiB
C
/*++
|
|
|
|
Copyright(c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
shared.c
|
|
|
|
Abstract:
|
|
|
|
routines shared outside of library
|
|
|
|
Author:
|
|
|
|
Todd Carpenter
|
|
|
|
Environment:
|
|
|
|
kernel mode
|
|
|
|
|
|
Revision History:
|
|
|
|
03-28-01 : created, toddcar
|
|
|
|
--*/
|
|
#include "processor.h"
|
|
|
|
|
|
NTSTATUS
|
|
ValidatePssLatencyValues (
|
|
IN PFDO_DATA DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG savedState = INVALID_PERF_STATE;
|
|
ULONG targetState;
|
|
ULONG x;
|
|
ULONG latency;
|
|
LARGE_INTEGER start;
|
|
LARGE_INTEGER end;
|
|
LARGE_INTEGER freq;
|
|
|
|
|
|
DebugEnter();
|
|
DebugAssert(DeviceExtension);
|
|
|
|
//
|
|
// Save current state, go to highest perfstate available
|
|
//
|
|
|
|
if (DeviceExtension->CurrentPerfState != INVALID_PERF_STATE) {
|
|
savedState = DeviceExtension->CurrentPerfState;
|
|
}
|
|
|
|
if (DeviceExtension->CurrentPerfState) {
|
|
Acpi2PerfStateTransition(DeviceExtension, DeviceExtension->PpcResult);
|
|
}
|
|
|
|
|
|
//
|
|
// Get Perf Counter Frequency
|
|
//
|
|
|
|
KeQueryPerformanceCounter(&freq);
|
|
|
|
|
|
//
|
|
// Walk though all available states, calulate transition latency
|
|
//
|
|
|
|
for (x = 0; x < DeviceExtension->PssPackage->NumPStates; x++) {
|
|
|
|
targetState = DeviceExtension->PssPackage->NumPStates - x - 1;
|
|
latency = 0;
|
|
|
|
//
|
|
// We should already be at PerfState == PpcResult,
|
|
// and we can't go to a higher state
|
|
//
|
|
|
|
if (targetState < DeviceExtension->PpcResult) {
|
|
continue;
|
|
}
|
|
|
|
start = KeQueryPerformanceCounter(NULL);
|
|
status = Acpi2PerfStateTransition(DeviceExtension, targetState);
|
|
end = KeQueryPerformanceCounter(NULL);
|
|
|
|
//
|
|
// Calculate transition latency.
|
|
//
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
latency = (ULONG)((end.QuadPart - start.QuadPart) * 1000000 / freq.QuadPart);
|
|
}
|
|
|
|
//
|
|
// Record new latency value in unused BmLatency field
|
|
//
|
|
|
|
DeviceExtension->PssPackage->State[targetState].Latency = latency;
|
|
}
|
|
|
|
|
|
//
|
|
// Restore saved Perf State
|
|
//
|
|
|
|
if (savedState != DeviceExtension->CurrentPerfState &&
|
|
savedState != INVALID_PERF_STATE) {
|
|
Acpi2PerfStateTransition(DeviceExtension, savedState);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ReadGenAddr(
|
|
IN PGEN_ADDR GenAddr
|
|
)
|
|
{
|
|
ULONG bitWidth;
|
|
ULONG mask = 0;
|
|
ULONG result = 0;
|
|
|
|
|
|
DebugAssert(GenAddr);
|
|
DebugAssert(GenAddr->BitWidth);
|
|
DebugAssert(GenAddr->BitWidth <= 32);
|
|
|
|
|
|
//
|
|
// Figure out how wide our target register is.
|
|
//
|
|
|
|
bitWidth = GenAddr->BitWidth + GenAddr->BitOffset;
|
|
|
|
|
|
if (bitWidth <= 8) {
|
|
bitWidth = 8;
|
|
} else if (bitWidth <= 16) {
|
|
bitWidth = 16;
|
|
} else {
|
|
bitWidth = 32;
|
|
}
|
|
|
|
switch (GenAddr->AddressSpaceID) {
|
|
|
|
case AcpiGenericSpaceIO:
|
|
|
|
DebugAssert(!(GenAddr->Address.LowPart & 0Xffff0000));
|
|
DebugAssert(GenAddr->Address.HighPart == 0);
|
|
|
|
switch (bitWidth) {
|
|
|
|
case 8:
|
|
|
|
result = READ_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart);
|
|
break;
|
|
|
|
case 16:
|
|
|
|
result = READ_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart);
|
|
break;
|
|
|
|
case 32:
|
|
|
|
result = READ_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart);
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case AcpiGenericSpaceMemory:
|
|
|
|
//
|
|
// This code path depends on the fact that the addresses
|
|
// in these structures have already been converted to
|
|
// virtual addresses.
|
|
//
|
|
|
|
switch (bitWidth) {
|
|
|
|
case 8:
|
|
|
|
result = READ_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart);
|
|
break;
|
|
|
|
case 16:
|
|
|
|
result = READ_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart);
|
|
break;
|
|
|
|
case 32:
|
|
|
|
result = READ_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart);
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return 0;
|
|
|
|
}
|
|
|
|
//
|
|
// If the register is not actually byte-aligned, correct for that.
|
|
//
|
|
|
|
if (result && (bitWidth != GenAddr->BitWidth)) {
|
|
|
|
result >>= GenAddr->BitOffset;
|
|
result &= ((0x1ul << GenAddr->BitWidth) - 1);
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
VOID
|
|
WriteGenAddr(
|
|
IN PGEN_ADDR GenAddr,
|
|
IN ULONG Value
|
|
)
|
|
{
|
|
ULONG bitWidth;
|
|
ULONG data = 0;
|
|
ULONG mask = 0;
|
|
|
|
DebugAssert(GenAddr);
|
|
DebugAssert(GenAddr->BitWidth);
|
|
DebugAssert(GenAddr->BitWidth <= 32);
|
|
|
|
|
|
//
|
|
// Figure out how wide our target register is.
|
|
//
|
|
|
|
bitWidth = GenAddr->BitWidth + GenAddr->BitOffset;
|
|
|
|
|
|
if (bitWidth <= 8) {
|
|
bitWidth = 8;
|
|
} else if (bitWidth <= 16) {
|
|
bitWidth = 16;
|
|
} else {
|
|
bitWidth = 32;
|
|
}
|
|
|
|
|
|
switch (GenAddr->AddressSpaceID) {
|
|
|
|
case AcpiGenericSpaceIO:
|
|
|
|
DebugAssert(!(GenAddr->Address.LowPart & 0Xffff0000));
|
|
DebugAssert(GenAddr->Address.HighPart == 0);
|
|
|
|
switch(bitWidth) {
|
|
|
|
case 8:
|
|
|
|
DebugAssert(!(Value & 0xffffff00));
|
|
|
|
if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) {
|
|
|
|
data = READ_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart);
|
|
mask = (UCHAR)~0 >> (8 - GenAddr->BitWidth);
|
|
mask = (UCHAR)~(mask << GenAddr->BitOffset);
|
|
data &= mask;
|
|
data |= (UCHAR)Value << GenAddr->BitOffset;
|
|
|
|
} else {
|
|
data = Value;
|
|
}
|
|
|
|
WRITE_PORT_UCHAR((PUCHAR)(UINT_PTR)GenAddr->Address.LowPart, (UCHAR)data);
|
|
break;
|
|
|
|
case 16:
|
|
|
|
DebugAssert(!(Value & 0xffff0000));
|
|
|
|
if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) {
|
|
|
|
data = READ_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart);
|
|
mask = (USHORT)~0 >> (16 - GenAddr->BitWidth);
|
|
mask = (USHORT)~(mask << GenAddr->BitOffset);
|
|
data &= mask;
|
|
data |= (USHORT)Value << GenAddr->BitOffset;
|
|
|
|
} else {
|
|
data = Value;
|
|
}
|
|
|
|
WRITE_PORT_USHORT((PUSHORT)(UINT_PTR)GenAddr->Address.LowPart, (USHORT)data);
|
|
break;
|
|
|
|
case 32:
|
|
|
|
if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) {
|
|
|
|
data = READ_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart);
|
|
mask = (ULONG)~0 >> (32 - GenAddr->BitWidth);
|
|
mask = ~(mask << GenAddr->BitOffset);
|
|
data &= mask;
|
|
data |= Value << GenAddr->BitOffset;
|
|
|
|
} else {
|
|
data = Value;
|
|
}
|
|
|
|
WRITE_PORT_ULONG((PULONG)(UINT_PTR)GenAddr->Address.LowPart, data);
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
break;
|
|
|
|
case AcpiGenericSpaceMemory:
|
|
|
|
//
|
|
// This code path depends on the fact that the addresses in these structures
|
|
// have already been converted to virtual addresses.
|
|
//
|
|
|
|
switch (bitWidth) {
|
|
|
|
case 8:
|
|
|
|
DebugAssert(!(Value & 0xffffff00));
|
|
|
|
if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) {
|
|
|
|
data = READ_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart);
|
|
mask = (UCHAR)~0 >> (8 - GenAddr->BitWidth);
|
|
mask = (UCHAR)~(mask << GenAddr->BitOffset);
|
|
data &= mask;
|
|
data |= (UCHAR)Value << GenAddr->BitOffset;
|
|
|
|
} else {
|
|
data = Value;
|
|
}
|
|
|
|
WRITE_REGISTER_UCHAR((PUCHAR)GenAddr->Address.QuadPart, (UCHAR)data);
|
|
break;
|
|
|
|
case 16:
|
|
|
|
DebugAssert(!(Value & 0xffff0000));
|
|
|
|
if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) {
|
|
|
|
data = READ_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart);
|
|
mask = (USHORT)~0 >> (16 - GenAddr->BitWidth);
|
|
mask = (USHORT)~(mask << GenAddr->BitOffset);
|
|
data &= mask;
|
|
data |= (USHORT)Value << GenAddr->BitOffset;
|
|
|
|
} else {
|
|
data = Value;
|
|
}
|
|
|
|
WRITE_REGISTER_USHORT((PUSHORT)GenAddr->Address.QuadPart, (USHORT)data);
|
|
break;
|
|
|
|
case 32:
|
|
|
|
if ((GenAddr->BitOffset != 0) || (GenAddr->BitWidth != bitWidth)) {
|
|
|
|
data = READ_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart);
|
|
mask = (ULONG)~0 >> (32 - GenAddr->BitWidth);
|
|
mask = ~(mask << GenAddr->BitOffset);
|
|
data &= mask;
|
|
data |= Value << GenAddr->BitOffset;
|
|
|
|
} else {
|
|
data = Value;
|
|
}
|
|
|
|
WRITE_REGISTER_ULONG((PULONG)GenAddr->Address.QuadPart, data);
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Misc Debug Routines
|
|
//
|
|
|
|
#if DBG
|
|
VOID
|
|
DumpPSS(
|
|
IN PACPI_PSS_PACKAGE PStates
|
|
)
|
|
{
|
|
ULONG x;
|
|
PACPI_PSS_DESCRIPTOR pState;
|
|
|
|
DebugAssert(PStates);
|
|
|
|
DebugPrint((TRACE, "\n"));
|
|
DebugPrint((TRACE, "_PSS:\n"));
|
|
|
|
for (x = 0; x < PStates->NumPStates; x++) {
|
|
|
|
pState = &PStates->State[x];
|
|
|
|
DebugPrint((TRACE, "State: #%u\n", x));
|
|
DebugPrint((TRACE, " Core Frequency %u mhz\n",pState->CoreFrequency));
|
|
DebugPrint((TRACE, " Power %u mW\n", pState->Power));
|
|
DebugPrint((TRACE, " Transition Latency %u us\n", pState->Latency));
|
|
DebugPrint((TRACE, " Bus Master Latency %u us\n", pState->BmLatency));
|
|
DebugPrint((TRACE, " Control value 0x%x\n", pState->Control));
|
|
DebugPrint((TRACE, " Status value 0x%x\n", pState->Status));
|
|
DebugPrint((TRACE, "\n"));
|
|
|
|
}
|
|
|
|
}
|
|
#endif
|