820 lines
15 KiB
C
820 lines
15 KiB
C
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
longrun.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the Crusoe LongRun Adaptive Power Control interface
|
|
|
|
Author:
|
|
|
|
Todd Carpenter (10/31/00) - create file
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include <ntddk.h>
|
|
#include <ntacpi.h>
|
|
#include "crusoe.h"
|
|
|
|
LONGRUN_STATES LongRunStates;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (PAGE, InitializeLegacyInterface)
|
|
#pragma alloc_text (PAGE, GetCurrentCpuSpeed)
|
|
#pragma alloc_text (PAGE, GetMaxCpuSpeed)
|
|
#endif
|
|
|
|
NTSTATUS
|
|
InitializeLegacyInterface(
|
|
IN PFDO_DATA DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG flags;
|
|
|
|
DebugEnter();
|
|
PAGED_CODE();
|
|
|
|
|
|
//
|
|
// Check Processor Feature Flags
|
|
//
|
|
|
|
GetProcessorFeatureFlags(&flags);
|
|
|
|
if (flags & FEATURE_LONGRUN_ENALBED) {
|
|
|
|
//
|
|
// If the CMS4.2 Interface is present use it, else use CMS4.1
|
|
//
|
|
|
|
if (flags & FEATURE_LRTI_ENABLED) {
|
|
|
|
DebugPrint((ERROR, "Using LongRun CMS 4.2 Interface\n"));
|
|
BuildLongRunPerfStatesCMS42(&DeviceExtension->PssPackage);
|
|
|
|
} else {
|
|
|
|
DebugPrint((ERROR, "Using LongRun CMS 4.1 Interface\n"));
|
|
BuildLongRunPerfStatesCMS41(&DeviceExtension->PssPackage);
|
|
|
|
}
|
|
|
|
DeviceExtension->PctPackage.Control.AddressSpaceID = AcpiGenericSpaceFixedFunction;
|
|
DeviceExtension->PctPackage.Status.AddressSpaceID = AcpiGenericSpaceFixedFunction;
|
|
|
|
//
|
|
// Walk through _PSS states to calculate latency values
|
|
//
|
|
|
|
ValidatePssLatencyValues(DeviceExtension);
|
|
|
|
} else {
|
|
|
|
//
|
|
// LongRun Interface is not present
|
|
//
|
|
|
|
DebugAssert(!"LongRun Interface is NOT enabled!\n");
|
|
status = STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
DebugExitStatus(status)
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SetCurrentStateMSR(
|
|
IN ULONG State,
|
|
IN BOOLEAN InitPhase
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG index, longRunMax, longRunMin = 0;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULARGE_INTEGER longRunStatus;
|
|
|
|
//
|
|
// Convert our Perf State Value to LongRun value.
|
|
// NOTE: LongRun states are stored in Ascending order.
|
|
//
|
|
|
|
index = (LongRunStates.MaxState - 1) - State;
|
|
longRunMax = LongRunStates.States[index].LongRunValue;
|
|
|
|
if (InitPhase) {
|
|
longRunMin = longRunMax;
|
|
}
|
|
|
|
DebugPrint((ERROR, "Setting Long Run Range: l=0x%x, u=0x%x\n", longRunMin, longRunMax));
|
|
SetCurrentPerformanceRange(longRunMin, longRunMax);
|
|
longRunStatus.QuadPart = GetCurrentPerformanceRange();
|
|
|
|
if ((longRunStatus.HighPart != longRunMax) ||
|
|
(longRunStatus.LowPart != longRunMin)) {
|
|
|
|
DebugPrint((ERROR, "ERROR! Expected: l=0x%x, h=0x%x Recieved: l=0x%x, h=0x%x\n",
|
|
longRunMin,
|
|
longRunMax,
|
|
longRunStatus.LowPart,
|
|
longRunStatus.HighPart));
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ConvertLongRunValueToPerfState(
|
|
IN PLONGRUN_STATES PerfStates,
|
|
IN ULONG LongRunValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG x;
|
|
|
|
//
|
|
// Convert Transemta state values in Perf state values.
|
|
//
|
|
|
|
for (x = 0; x < PerfStates->MaxState; x++) {
|
|
|
|
if (PerfStates->States[x].LongRunValue == LongRunValue) {
|
|
return x;
|
|
}
|
|
}
|
|
|
|
return INVALID_LONGRUN_STATE;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetCurrentCpuSpeed(
|
|
OUT PULONG CpuSpeed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
STATE_INFO stateInfo;
|
|
|
|
DebugAssert(CpuSpeed);
|
|
|
|
status = GetCurrentStateInfo(&stateInfo);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
*CpuSpeed = stateInfo.CpuSpeed;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetMaxCpuSpeed(
|
|
OUT PULONG CpuSpeed
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG junk;
|
|
|
|
DebugAssert(CpuSpeed);
|
|
PAGED_CODE();
|
|
|
|
CPUID(LONGRUN_CPUID_PROCESSOR_INFO,
|
|
&junk,
|
|
&junk,
|
|
CpuSpeed,
|
|
&junk);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
GetProcessorFeatureFlags(
|
|
OUT PULONG Flags
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG junk;
|
|
|
|
DebugAssert(Flags);
|
|
PAGED_CODE();
|
|
|
|
CPUID(LONGRUN_CPUID_PROCESSOR_INFO,
|
|
&junk,
|
|
&junk,
|
|
&junk,
|
|
Flags);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetCurrentStateInfo(
|
|
OUT PSTATE_INFO StateInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG junk;
|
|
|
|
DebugAssert(StateInfo);
|
|
|
|
CPUID(LONGRUN_CPUID_GETSTATE,
|
|
&StateInfo->CpuSpeed,
|
|
&StateInfo->Voltage,
|
|
&StateInfo->LongRunValue,
|
|
&junk);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
GetCurrentPerformanceRange(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
return ReadMSR(LONGRUN_CONTROL_STATUS_MSR);
|
|
}
|
|
|
|
|
|
VOID
|
|
SetCurrentPerformanceRange(
|
|
IN ULONG Min,
|
|
IN ULONG Max
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msrInfo;
|
|
|
|
msrInfo.LowPart = Min;
|
|
msrInfo.HighPart = Max;
|
|
|
|
WriteMSR(LONGRUN_CONTROL_STATUS_MSR, msrInfo.QuadPart);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CalculateLongRunPerfStates(
|
|
IN PLONGRUN_STATES PerfStates
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
STATE_INFO stateInfo;
|
|
ULONG x, currentPerfState = 0;
|
|
ULONG currentLongRunValue = INVALID_LONGRUN_STATE;
|
|
|
|
DebugAssert(PerfStates);
|
|
|
|
PerfStates->MaxState = MAX_LONGRUN_STATES;
|
|
|
|
//
|
|
// step through each state from 0 - 100, recording
|
|
// unique performance states
|
|
//
|
|
|
|
for (x = 0; x <= MAX_LONGRUN_VALUE; x++) {
|
|
|
|
//DebugPrint((ERROR, "Transition to state %u\n", x));
|
|
SetCurrentPerformanceRange(x, x);
|
|
GetCurrentStateInfo(&stateInfo);
|
|
//DisplayStateInfo(&stateInfo);
|
|
|
|
//
|
|
// If this is a new state, record it.
|
|
//
|
|
// NOTE: we are ASSUMING that all states with identical LongRun
|
|
// state values are contigous AND that the LongRun values
|
|
// are increasing in value. Here is an example of what we
|
|
// expect to find.
|
|
//
|
|
// LongRun States (0-100) unique LongRun value
|
|
//
|
|
// 0-25 0
|
|
// 26-50 40
|
|
// 51-75 71
|
|
// 76-100 100
|
|
//
|
|
|
|
if (stateInfo.LongRunValue != currentLongRunValue) {
|
|
|
|
DebugAssert(currentPerfState < PerfStates->MaxState);
|
|
DebugAssert(stateInfo.LongRunValue <= MAX_LONGRUN_VALUE);
|
|
|
|
currentLongRunValue = stateInfo.LongRunValue;
|
|
|
|
RtlCopyMemory(&PerfStates->States[currentPerfState++],
|
|
&stateInfo,
|
|
sizeof(STATE_INFO));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BuildAcpi2PerformanceStates(
|
|
IN PACPI_PSS_PACKAGE PerfStates
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BuildLongRunPerfStatesCMS41(
|
|
OUT PACPI_PSS_PACKAGE *PssPackage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG x;
|
|
ULONG pssSize;
|
|
ULONG currentPerfState = 0;
|
|
ULONG currentLongRunValue = INVALID_LONGRUN_STATE;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
STATE_INFO stateInfo;
|
|
PACPI_PSS_PACKAGE tmpPss;
|
|
|
|
DebugEnter();
|
|
DebugAssert(PssPackage);
|
|
|
|
|
|
pssSize = sizeof(ACPI_PSS_PACKAGE) +
|
|
((MAX_LONGRUN_STATES-1) * sizeof(ACPI_PSS_DESCRIPTOR));
|
|
|
|
tmpPss = ExAllocatePoolWithTag(NonPagedPool,
|
|
pssSize,
|
|
PROCESSOR_POOL_TAG);
|
|
|
|
|
|
if (!tmpPss) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto BuildLongRunPerfStatesCMS41Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Iterate through each level collecting data.
|
|
//
|
|
|
|
tmpPss->NumPStates = MAX_LONGRUN_STATES;
|
|
|
|
for (x = 0; x <= MAX_LONGRUN_VALUE; x += 5) {
|
|
|
|
SetCurrentPerformanceRange(x, x);
|
|
GetCurrentStateInfo(&stateInfo);
|
|
|
|
|
|
//
|
|
// If this is a new state, record it.
|
|
//
|
|
// NOTE: we are ASSUMING that all states with identical LongRun
|
|
// state values are contigous AND that the LongRun values
|
|
// are increasing in value. Here is an example of what we
|
|
// expect to find.
|
|
//
|
|
// LongRun States (0-100) unique LongRun value
|
|
//
|
|
// 0-25 0
|
|
// 26-50 40
|
|
// 51-75 71
|
|
// 76-100 100
|
|
//
|
|
|
|
if (stateInfo.LongRunValue != currentLongRunValue) {
|
|
|
|
PACPI_PSS_DESCRIPTOR state;
|
|
CRUSOE_PSS_VALUE longRunState = {0};
|
|
|
|
DebugAssert(currentPerfState < MAX_LONGRUN_STATES);
|
|
DebugAssert(stateInfo.LongRunValue <= MAX_LONGRUN_VALUE);
|
|
|
|
state = &tmpPss->State[(MAX_LONGRUN_STATES-1) - currentPerfState];
|
|
|
|
state->CoreFrequency = stateInfo.CpuSpeed;
|
|
|
|
DebugAssert(stateInfo.Voltage < MAXUSHORT);
|
|
state->Power = stateInfo.Voltage;
|
|
state->Latency = CRUSOE_TRANSITION_LATENCY;
|
|
|
|
longRunState.Max = stateInfo.LongRunValue;
|
|
state->Control = longRunState.AsDWord;
|
|
state->Status = longRunState.AsDWord;
|
|
|
|
state->BmLatency = 0;
|
|
|
|
//
|
|
// If we have found all of the states, bail
|
|
//
|
|
|
|
if (currentPerfState == (MAX_LONGRUN_STATES-1)) {
|
|
break;
|
|
} else {
|
|
currentLongRunValue = stateInfo.LongRunValue;
|
|
currentPerfState++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*PssPackage = tmpPss;
|
|
|
|
BuildLongRunPerfStatesCMS41Exit:
|
|
|
|
DebugExitStatus(status);
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
BuildLongRunPerfStatesCMS42(
|
|
OUT PACPI_PSS_PACKAGE *PssPackage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULONG maxLevel;
|
|
ULONG pssSize;
|
|
ULONG x;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PACPI_PSS_PACKAGE tmpPss;
|
|
|
|
DebugEnter();
|
|
DebugAssert(PssPackage);
|
|
|
|
|
|
//
|
|
// Get max LongRun Level
|
|
//
|
|
|
|
maxLevel = LRTI_GetMaxSupportedLevel();
|
|
|
|
pssSize = sizeof(ACPI_PSS_PACKAGE) + (maxLevel * sizeof(ACPI_PSS_DESCRIPTOR));
|
|
tmpPss = ExAllocatePoolWithTag(NonPagedPool,
|
|
pssSize,
|
|
PROCESSOR_POOL_TAG);
|
|
|
|
|
|
if (!tmpPss) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto BuildLongRunPerfStatesCMS42Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Iterate through each level collecting data.
|
|
//
|
|
|
|
DebugAssert(maxLevel < MAXUCHAR);
|
|
tmpPss->NumPStates = (UCHAR) maxLevel+1;
|
|
|
|
for (x=0; x <= maxLevel; x++) {
|
|
|
|
PACPI_PSS_DESCRIPTOR state = &tmpPss->State[x];
|
|
CRUSOE_PSS_VALUE longRunState;
|
|
ULONG voltage;
|
|
|
|
LRTI_SetCurrentLevel(x);
|
|
|
|
state->CoreFrequency = LRTI_GetFrequency();
|
|
|
|
voltage = LRTI_GetVoltage();
|
|
|
|
DebugAssert(voltage < MAXUSHORT);
|
|
state->Power = voltage;
|
|
|
|
state->Latency = CRUSOE_TRANSITION_LATENCY;
|
|
|
|
longRunState.Max = LRTI_GetPerformanceIndex();
|
|
longRunState.Min = 0;
|
|
|
|
state->Control = longRunState.AsDWord;
|
|
state->Status = longRunState.AsDWord;
|
|
|
|
state->BmLatency = 0;
|
|
|
|
}
|
|
|
|
|
|
*PssPackage = tmpPss;
|
|
|
|
|
|
BuildLongRunPerfStatesCMS42Exit:
|
|
|
|
DebugExitStatus(status);
|
|
return status;
|
|
}
|
|
|
|
|
|
ULONG
|
|
LRTI_GetMaxSupportedLevel(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER results;
|
|
|
|
results.QuadPart = ReadMSR(LONGRUN_TI_READOUT_MSR);
|
|
return results.HighPart;
|
|
}
|
|
|
|
|
|
VOID
|
|
LRTI_SetCurrentLevel (
|
|
ULONG LongRunLevel
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr;
|
|
|
|
msr.LowPart = LongRunLevel;
|
|
msr.HighPart = 0;
|
|
|
|
WriteMSR(LONGRUN_TI_READOUT_MSR, msr.QuadPart);
|
|
}
|
|
|
|
|
|
ULONG
|
|
LRTI_GetPerformanceIndex (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr;
|
|
|
|
msr.QuadPart = ReadMSR(LONGRUN_TI_PERFORMANCE_INDEX_MSR);
|
|
return msr.LowPart;
|
|
}
|
|
|
|
|
|
ULONG
|
|
LRTI_GetVoltage (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr;
|
|
|
|
msr.QuadPart = ReadMSR(LONGRUN_TI_VOLTAGE_FREQUENCY_MSR);
|
|
return msr.HighPart;
|
|
}
|
|
|
|
|
|
ULONG
|
|
LRTI_GetFrequency (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr;
|
|
|
|
msr.QuadPart = ReadMSR(LONGRUN_TI_VOLTAGE_FREQUENCY_MSR);
|
|
return msr.LowPart;
|
|
}
|
|
|
|
|
|
ULONG
|
|
GetLongRunFlagsRegister (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr;
|
|
|
|
msr.QuadPart = ReadMSR(LONGRUN_FLAGS_REGISTER_MSR);
|
|
return msr.LowPart;
|
|
}
|
|
|
|
|
|
VOID
|
|
SetLongRunEconomyMode (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr = {0};
|
|
|
|
WriteMSR(LONGRUN_FLAGS_REGISTER_MSR, msr.QuadPart);
|
|
}
|
|
|
|
|
|
VOID
|
|
SetLongRunPerformanceMode (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
ULARGE_INTEGER msr = {0};
|
|
|
|
msr.LowPart |= 0x1;
|
|
WriteMSR(LONGRUN_FLAGS_REGISTER_MSR, msr.QuadPart);
|
|
}
|
|
|
|
|
|
#if DBG
|
|
VOID
|
|
DisplayStateInfo(
|
|
IN PSTATE_INFO State
|
|
)
|
|
{
|
|
DebugPrint((MAXTRACE, "State Info:\n"));
|
|
DebugPrint((MAXTRACE, " Processor Clock Frequency: %u Mhz\n", State->CpuSpeed));
|
|
DebugPrint((MAXTRACE, " Processor Core Voltage: %u millivolts\n", State->Voltage));
|
|
DebugPrint((MAXTRACE, " LongRun Value [0-100]: %u\n", State->LongRunValue));
|
|
DebugPrint((MAXTRACE, " Performance State: %u\n", ConvertLongRunValueToPerfState(
|
|
&LongRunStates,
|
|
State->LongRunValue)));
|
|
DebugPrint((MAXTRACE, "\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayLongRunStates(
|
|
IN PLONGRUN_STATES States
|
|
)
|
|
{
|
|
ULONG x;
|
|
|
|
DebugPrint((MAXTRACE, "LongRun Performance Levels:\n"));
|
|
|
|
for (x = 0; x < States->MaxState; x++) {
|
|
|
|
DebugPrint((ERROR, "State %u:\n", x));
|
|
DisplayStateInfo(&States->States[x]);
|
|
}
|
|
|
|
}
|
|
#endif
|