mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
672 lines
12 KiB
672 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
crusoe.c
|
|
|
|
Abstract:
|
|
|
|
This module implements code specific to the Crusoe processor
|
|
|
|
|
|
Author:
|
|
|
|
Todd Carpenter (10/31/00) - create file
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Notes:
|
|
|
|
DeviceInst = "ACPI\GenuineTMx86_-_x86_Family_5_Model_4"
|
|
ServiceName = "crusoe"
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
#include "crusoe.h"
|
|
#include "..\lib\processor.h"
|
|
|
|
#if DBG
|
|
PUCHAR DebugName = "Crusoe.sys";
|
|
#endif
|
|
|
|
PFDO_DATA DeviceExtensions[MAX_SUPPORTED_PROCESSORS];
|
|
UCHAR DevExtIndex;
|
|
|
|
extern GLOBALS Globals;
|
|
extern LONGRUN_STATES LongRunStates;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text (PAGE, InitializeDriver)
|
|
#pragma alloc_text (PAGE, InitializeNonAcpiPerformanceStates)
|
|
#pragma alloc_text (PAGE, InitializeAcpi2PStates)
|
|
#pragma alloc_text (PAGE, InitializeAcpi2Cstates)
|
|
#pragma alloc_text (PAGE, MergePerformanceStates)
|
|
#pragma alloc_text (PAGE, GetLegacyMaxProcFrequency)
|
|
#pragma alloc_text (PAGE, AdjustLegacyProcessorPerformanceStates)
|
|
#pragma alloc_text (PAGE, GetProcessorBrandString)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
InitializeDriver(
|
|
PUNICODE_STRING ServiceKeyRegPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
InitializeNonAcpiPerformanceStates(
|
|
IN PFDO_DATA DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
DebugEnter();
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// We automatically fail to use the Legacy Interface
|
|
//
|
|
|
|
if (Globals.HackFlags & DISABLE_LEGACY_INTERFACE_FLAG) {
|
|
DebugPrint((ERROR, " Legacy Interface Disabled\n"));
|
|
return STATUS_NOT_FOUND;
|
|
}
|
|
|
|
|
|
//
|
|
// Find and gather legacy interface info
|
|
//
|
|
|
|
status = InitializeLegacyInterface(DeviceExtension);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DebugExitStatus(status);
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Found Legacy Interface, and is available to use.
|
|
//
|
|
|
|
DeviceExtension->LegacyInterface = TRUE;
|
|
|
|
|
|
//
|
|
// Merge Perf states with other states we may have.
|
|
//
|
|
|
|
status = MergePerformanceStates(DeviceExtension);
|
|
DumpProcessorPerfStates(DeviceExtension->PerfStates);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
if (DeviceExtension->PerfStates) {
|
|
ExFreePool(DeviceExtension->PerfStates);
|
|
}
|
|
|
|
if (DeviceExtension->PssPackage) {
|
|
ExFreePool(DeviceExtension->PssPackage);
|
|
}
|
|
|
|
DeviceExtension->PerfStates = NULL;
|
|
DeviceExtension->LegacyInterface = FALSE;
|
|
}
|
|
|
|
|
|
DebugExitStatus(status);
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AcpiLegacyPerfStateTransition(
|
|
IN PFDO_DATA DevExt,
|
|
IN ULONG State
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
return Acpi2PerfStateTransition(DevExt, State);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
FASTCALL
|
|
SetPerfLevel(
|
|
IN UCHAR Throttle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PFDO_DATA DeviceExtension;
|
|
ULONG apicId;
|
|
ULONG index = 0;
|
|
|
|
DebugEnter();
|
|
|
|
|
|
//
|
|
// Get APIC Id and retrieve Device Extension index
|
|
//
|
|
|
|
if (!Globals.SingleProcessorProfile) {
|
|
apicId = GetApicId();
|
|
index = Globals.ProcInfo.ApicIdToDevExtIndex[apicId];
|
|
}
|
|
|
|
//
|
|
// Get the DeviceExtension.
|
|
//
|
|
|
|
DeviceExtension = DeviceExtensions[index];
|
|
|
|
//
|
|
// Since this driver does not support Functional Fixed Hardware, we
|
|
// use generic method.
|
|
//
|
|
|
|
return SetPerfLevelGeneric(Throttle, DeviceExtension);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
FASTCALL
|
|
SetThrottleLevel(
|
|
IN UCHAR Throttle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PFDO_DATA DeviceExtension;
|
|
ULONG apicId;
|
|
ULONG index = 0;
|
|
|
|
DebugEnter();
|
|
|
|
//
|
|
// Get APIC Id and retrieve Device Extension index
|
|
//
|
|
|
|
if (!Globals.SingleProcessorProfile) {
|
|
apicId = GetApicId();
|
|
index = Globals.ProcInfo.ApicIdToDevExtIndex[apicId];
|
|
}
|
|
|
|
|
|
//
|
|
// Get the DeviceExtension.
|
|
//
|
|
|
|
DeviceExtension = DeviceExtensions[index];
|
|
|
|
|
|
//
|
|
// Since this driver does not support Functional Fixed Hardware, we
|
|
// use generic method.
|
|
//
|
|
|
|
return SetThrottleLevelGeneric(Throttle, DeviceExtension);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
InitializeAcpi2PStates(
|
|
IN PFDO_DATA DevExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = InitializeAcpi2PStatesGeneric(DevExt);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
if ((DevExt->PctPackage.Control.AddressSpaceID != AcpiGenericSpaceFixedFunction) ||
|
|
(DevExt->PctPackage.Status.AddressSpaceID != AcpiGenericSpaceFixedFunction)) {
|
|
|
|
DebugPrint((ERROR, "This driver ONLY supports FFH addresses for Acpi 2.0\n"));
|
|
status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Walk through _PSS states to calculate latency values
|
|
//
|
|
|
|
ValidatePssLatencyValues(DevExt);
|
|
|
|
//
|
|
// Need to merge this new data with our perfstates
|
|
//
|
|
|
|
MergePerformanceStates(DevExt);
|
|
|
|
}
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
InitializeAcpi2Cstates(
|
|
PFDO_DATA DevExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function looks to see if there is an ACPI 2.0 _CST object in the
|
|
namespace, and, if there is, it replaces the functions found by
|
|
InitializeAcpi1Cstates.
|
|
|
|
Further note: This function leaves the filling in of throttling functions
|
|
to the InitializePerformanceStates functions.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension
|
|
|
|
Return Value:
|
|
|
|
A NTSTATUS code to indicate the result of the initialization.
|
|
|
|
--*/
|
|
{
|
|
ULONG apicId;
|
|
ULONG index = 0;
|
|
|
|
DebugEnter();
|
|
PAGED_CODE();
|
|
|
|
|
|
//
|
|
// Record the address of this processor's DeviceExtension, as the
|
|
// throttling API doesn't give it to us.
|
|
//
|
|
|
|
if (!Globals.SingleProcessorProfile) {
|
|
|
|
//
|
|
// save the index into the DeviceExtension[] for later retrieval based
|
|
// on APIC Id.
|
|
//
|
|
|
|
apicId = Globals.ProcInfo.ProcIdToApicId[DevExt->ProcObjInfo.PhysicalID];
|
|
Globals.ProcInfo.ApicIdToDevExtIndex[apicId] = DevExtIndex;
|
|
|
|
index = DevExtIndex++;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// save Device Extension pointer
|
|
//
|
|
|
|
DeviceExtensions[index] = DevExt;
|
|
|
|
|
|
//
|
|
// This processor driver only supports I/O Space based Cstates.
|
|
// InitializeAcpi2IoSpaceCstates() will fail if it finds Cstates with
|
|
// non AcpiGenericSpaceIO type addresses.
|
|
//
|
|
|
|
return InitializeAcpi2IoSpaceCstates(DevExt);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MergePerformanceStates (
|
|
IN PFDO_DATA DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine looks at the performance states stored in the device extension.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension
|
|
|
|
|
|
Return Value:
|
|
|
|
A NTSTATUS code to indicate the result of the initialization.
|
|
|
|
NOTE:
|
|
|
|
- The caller must hold PerfStateLock.
|
|
|
|
- This is called during START_DEVICE, and after recieving a Notify(0x80)
|
|
on the processor.
|
|
|
|
--*/
|
|
{
|
|
|
|
DebugEnter();
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Use the generic method to merge our perf states with stop clock states
|
|
//
|
|
|
|
return MergePerformanceStatesGeneric(DeviceExtension);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Acpi2PerfStateTransition(
|
|
IN PFDO_DATA DevExt,
|
|
IN ULONG NewState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine changes the performance state of the processor
|
|
based on ACPI 2.0 performance state objects.
|
|
|
|
Arguments:
|
|
|
|
State - Index into _PSS object
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
{
|
|
ULONG lowerBound;
|
|
ULONG uppperBound;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
STATE_INFO stateInfo;
|
|
CRUSOE_PSS_VALUE pssControl;
|
|
CRUSOE_PSS_VALUE pssStatus;
|
|
ULARGE_INTEGER longRunRange;
|
|
|
|
DebugEnter();
|
|
|
|
//
|
|
// The only type of Acpi 2.0 implementation this driver supports is FFH
|
|
//
|
|
|
|
DebugAssert(DevExt);
|
|
DebugAssert(DevExt->PctPackage.Control.AddressSpaceID == AcpiGenericSpaceFixedFunction);
|
|
DebugAssert(DevExt->PctPackage.Status.AddressSpaceID == AcpiGenericSpaceFixedFunction);
|
|
|
|
pssControl.AsDWord = DevExt->PssPackage->State[NewState].Control;
|
|
pssStatus.AsDWord = DevExt->PssPackage->State[NewState].Status;
|
|
|
|
//
|
|
// Sanity Check illeagal conditions
|
|
//
|
|
|
|
if (pssControl.Min > MAX_LONGRUN_VALUE) {
|
|
DebugPrint((ERROR, "ERROR: illegal LongRun value: Min=0x%x\n", pssControl.Min));
|
|
pssControl.Min = MAX_LONGRUN_VALUE;
|
|
}
|
|
|
|
if (pssControl.Max > MAX_LONGRUN_VALUE) {
|
|
DebugPrint((ERROR, "ERROR: illegal LongRun value: Max=0x%x\n", pssControl.Max));
|
|
pssControl.Max = MAX_LONGRUN_VALUE;
|
|
}
|
|
|
|
if (pssControl.Min > pssControl.Max) {
|
|
DebugPrint((ERROR, "ERROR: illegal LongRun Range: Min: 0x%x, Max: 0x%x\n",
|
|
pssControl.Min,
|
|
pssControl.Max));
|
|
|
|
pssControl.Min = pssControl.Max;
|
|
}
|
|
|
|
|
|
//
|
|
// Transition to new performance state
|
|
//
|
|
|
|
DebugPrint((ERROR, "Setting Long Run Range: l=0x%x, u=0x%x\n", pssControl.Min, pssControl.Max));
|
|
SetCurrentPerformanceRange(pssControl.Min, pssControl.Max);
|
|
|
|
|
|
//
|
|
// Check to see if the transition was successful
|
|
// NOTE: we have to check the LongRun Range rather than a specific state as
|
|
// there is no way to know which state within a given range the cpu
|
|
// will be in.
|
|
//
|
|
|
|
longRunRange.QuadPart = GetCurrentPerformanceRange();
|
|
|
|
|
|
if ((longRunRange.HighPart == pssStatus.Max) &&
|
|
(longRunRange.LowPart == pssStatus.Min)) {
|
|
|
|
DevExt->CurrentPssState = NewState;
|
|
|
|
} else {
|
|
|
|
DebugPrint((ERROR, "ERROR! Expected: l=0x%x, h=0x%x Recieved: l=0x%x, h=0x%x\n",
|
|
pssStatus.Min,
|
|
pssStatus.Max,
|
|
longRunRange.LowPart,
|
|
longRunRange.HighPart));
|
|
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ProcessResumeFromSleepState(
|
|
SYSTEM_POWER_STATE PreviousState,
|
|
PFDO_DATA DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DebugEnter();
|
|
|
|
//
|
|
// if we are resuming from Hibernate, and this is an Acpi 2.0 system,
|
|
// we must re-claim perf state and cstate control from the bios.
|
|
//
|
|
|
|
if (PreviousState == PowerSystemHibernate) {
|
|
|
|
if (DeviceExtension->PssPackage) {
|
|
AssumeProcessorPerformanceControl();
|
|
}
|
|
|
|
if (DeviceExtension->CstPresent) {
|
|
AssumeCStateControl();
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// restore previous state
|
|
//
|
|
|
|
return RestoreToSavedPerformanceState(DeviceExtension);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ProcessSuspendToSleepState(
|
|
SYSTEM_POWER_STATE TargetState,
|
|
PFDO_DATA DeviceExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
DebugEnter();
|
|
|
|
//
|
|
// save current state, transition to lowest non-throttled perf state
|
|
//
|
|
|
|
return SaveCurrentStateGoToLowVolts(DeviceExtension);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetLegacyMaxProcFrequency(
|
|
OUT PULONG CpuSpeed
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
return GetMaxCpuSpeed(CpuSpeed);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AdjustLegacyProcessorPerformanceStates(
|
|
IN OUT PPROCESSOR_PERFORMANCE_STATES PerfStates
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetProcessorBrandString (
|
|
PUCHAR BrandString,
|
|
PULONG Size
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
--*/
{
PAGED_CODE();
//
// This processor family supports CPUID Brand String
//
return GetCPUIDProcessorBrandString(BrandString, Size);
}
|