|
|
/*++
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
|