1167 lines
22 KiB
C
1167 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
p3.c
|
||
|
||
Abstract:
|
||
|
||
This module implements code specific to the PentiumIII processor
|
||
|
||
Author:
|
||
|
||
Jake Oshins (3/21/00) - create file
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Notes:
|
||
|
||
DeviceInst = "ACPI\GenuineIntel_-_x86_Family_6_Model_8"
|
||
ServiceName = "P3"
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "p3.h"
|
||
#include "..\lib\processor.h"
|
||
|
||
#if DBG
|
||
PUCHAR DebugName = "P3.sys";
|
||
#endif
|
||
|
||
PFDO_DATA DeviceExtensions[MAX_SUPPORTED_PROCESSORS];
|
||
UCHAR DevExtIndex;
|
||
P3_GLOBALS P3_Globals;
|
||
|
||
extern ULONG HalpThrottleScale;
|
||
extern GLOBALS Globals;
|
||
extern LEGACY_GEYSERVILLE_INT15 LegacyInterface;
|
||
|
||
VOID
|
||
AcpiNotify80CallbackWorker(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PVOID Context
|
||
);
|
||
|
||
NTSTATUS
|
||
UpdateAcDcMaxLevel(
|
||
IN PVOID Context,
|
||
IN BOOLEAN AC
|
||
);
|
||
|
||
#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, AdjustLegacyProcessorPerformanceStates)
|
||
#pragma alloc_text (PAGE, GetProcessorBrandString)
|
||
#endif
|
||
NTSTATUS
|
||
InitializeDriver(
|
||
PUNICODE_STRING ServiceKeyRegPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
|
||
//
|
||
// Get P3 Hack Flags
|
||
//
|
||
|
||
GetRegistryDwordValue((PWCHAR) P3_PARAMETERS_KEY,
|
||
L"HackFlags",
|
||
&P3_Globals.HackFlags);
|
||
|
||
|
||
|
||
//
|
||
// Setup Timer Dpc Thread, this is not MP safe.
|
||
//
|
||
|
||
if (Globals.SingleProcessorProfile) {
|
||
|
||
LONG timeOutSeconds = 0;
|
||
|
||
//
|
||
// Initialize CustomTimerDpc
|
||
//
|
||
|
||
KeInitializeDpc(&P3_Globals.Dpc, P3TimerDpcHandler, NULL);
|
||
KeInitializeTimer(&P3_Globals.Timer);
|
||
|
||
|
||
//
|
||
// Get tranistion timeout value from Registry
|
||
//
|
||
|
||
GetRegistryDwordValue((PWCHAR) P3_PARAMETERS_KEY,
|
||
L"RetryTimeOut",
|
||
&timeOutSeconds);
|
||
|
||
|
||
if (timeOutSeconds) {
|
||
|
||
//
|
||
// Validate timeout values
|
||
//
|
||
|
||
timeOutSeconds = MIN(timeOutSeconds, MAX_RETRY_TIMEOUT);
|
||
timeOutSeconds = MAX(timeOutSeconds, MIN_RETRY_TIMEOUT);
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// Set default 1 minute timeout
|
||
//
|
||
|
||
timeOutSeconds = DEFAULT_RETRY_TIMEOUT;
|
||
|
||
}
|
||
|
||
|
||
P3_Globals.TimeOut.QuadPart = -(timeOutSeconds * SECOND);
|
||
|
||
|
||
// tmp debug
|
||
DebugPrint((ERROR, "Using TimeOutRetry value of %d minutes (%d seconds)\n",
|
||
timeOutSeconds/60,
|
||
timeOutSeconds));
|
||
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
NTSTATUS
|
||
InitializeNonAcpiPerformanceStates(
|
||
IN PFDO_DATA DevExt
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function tries to gather as much information as it can about what
|
||
states are available. It puts a table in the device extension that
|
||
describes the available states. Unfortunately, we might not have enough
|
||
information to fill in the state table, as the BIOS doesn't tell us much.
|
||
We try to run through all the states, figuring out what we can about them
|
||
as we pass through them. But some states may not be available at the
|
||
moment, particularly if we are running on DC power at the moment. So some
|
||
states may have zeros in the table.
|
||
|
||
Arguments:
|
||
|
||
FdoData - pointer to the device extension
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
|
||
--*/
|
||
{
|
||
LARGE_INTEGER startTime;
|
||
LARGE_INTEGER endTime;
|
||
LARGE_INTEGER perfFreq;
|
||
ULONG newState;
|
||
ULONG currentFreq;
|
||
ULONG pssSize;
|
||
ULONG latency;
|
||
NTSTATUS status;
|
||
PLEGACY_GEYSERVILLE_INTERFACE_INFO info = &P3_Globals.LegacyInterfaceInfo;
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
//
|
||
// Check hack flags to see if we should use the Legacy interface.
|
||
//
|
||
|
||
if (!(P3_Globals.HackFlags & ENABLE_LEGACY_SPEEDSTEP_INTERFACE)) {
|
||
status = STATUS_NOT_FOUND;
|
||
DebugPrint((WARN, " Legacy Interface NOT enabled in P3\\parameters\\HackFlags.\n"));
|
||
DebugExitStatus(status);
|
||
return status;
|
||
}
|
||
|
||
|
||
//
|
||
// Find and gather legacy interface info
|
||
//
|
||
|
||
status = InitializeLegacyInterface(info, DevExt);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugExitStatus(status);
|
||
return status;
|
||
}
|
||
|
||
|
||
if (!info->CurrentlyAvailableStates) {
|
||
|
||
status = STATUS_NOT_FOUND;
|
||
DebugPrint((ERROR, " Found Legacy Interface, but no perfstates.\n"));
|
||
DebugExitStatus(status);
|
||
return status;
|
||
|
||
} else if (info->CurrentlyAvailableStates > MAX_GEYSERVILLE_STATES) {
|
||
|
||
status = STATUS_NOT_FOUND;
|
||
DebugPrint((ERROR, " Found Legacy Interface. Error: %u PerfStates defined\n",
|
||
info->CurrentlyAvailableStates));
|
||
DebugExitStatus(status);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Found Legacy Interface, and is available to use.
|
||
//
|
||
|
||
DevExt->LegacyInterface = TRUE;
|
||
|
||
|
||
//
|
||
// Allocate enough space for 2 perf states.
|
||
//
|
||
|
||
pssSize = sizeof(ACPI_PSS_PACKAGE) + sizeof(ACPI_PSS_DESCRIPTOR);
|
||
DevExt->PssPackage = ExAllocatePoolWithTag(NonPagedPool,
|
||
pssSize,
|
||
PROCESSOR_POOL_TAG);
|
||
|
||
|
||
if (!DevExt->PssPackage) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto InitalizeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
RtlZeroMemory(DevExt->PssPackage, pssSize);
|
||
|
||
DevExt->PssPackage->NumPStates = MAX_GEYSERVILLE_STATES;
|
||
|
||
|
||
//
|
||
// Jump through each state so that we can figure out how to fill in
|
||
// the table. Start by jumping to the low state.
|
||
//
|
||
|
||
DebugPrint((INFO, "Perf States available: 0x%x Current State: 0x%x\n",
|
||
info->CurrentlyAvailableStates,
|
||
info->CurrentState));
|
||
|
||
|
||
//
|
||
// Get Perf Counter Frequency
|
||
//
|
||
|
||
KeQueryPerformanceCounter(&perfFreq);
|
||
|
||
|
||
//
|
||
// Fill out the _PSS for first state, opposite of the current state
|
||
//
|
||
|
||
newState = info->CurrentState ? 0 : 1;
|
||
|
||
startTime = KeQueryPerformanceCounter(NULL);
|
||
status = AcpiPerfStateTransition(DevExt, newState);
|
||
endTime = KeQueryPerformanceCounter(NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
QueueEventLogWrite(DevExt, PROCESSOR_INIT_TRANSITION_FAILURE, newState);
|
||
goto InitalizeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Calculate latency, speed, & power
|
||
//
|
||
|
||
latency = (ULONG)((endTime.QuadPart - startTime.QuadPart) * 1000000 / perfFreq.QuadPart);
|
||
DevExt->PssPackage->State[newState].Latency = latency;
|
||
|
||
GetCurrentProcFrequency(newState, ¤tFreq);
|
||
DevExt->PssPackage->State[newState].CoreFrequency = currentFreq;
|
||
DevExt->PssPackage->State[newState].Power = currentFreq * 16;
|
||
|
||
DebugPrint((INFO, "Jumped to state 0x%x in %d us\n", newState, latency));
|
||
|
||
|
||
//
|
||
// Jump back to orginal state
|
||
//
|
||
|
||
newState = info->CurrentState;
|
||
|
||
startTime = KeQueryPerformanceCounter(NULL);
|
||
status = AcpiPerfStateTransition(DevExt, newState);
|
||
endTime = KeQueryPerformanceCounter(NULL);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
QueueEventLogWrite(DevExt, PROCESSOR_INIT_TRANSITION_FAILURE, newState);
|
||
goto InitalizeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Calculate latency, speed, & power
|
||
//
|
||
|
||
latency = (ULONG)((endTime.QuadPart - startTime.QuadPart) * 1000000 / perfFreq.QuadPart);
|
||
DevExt->PssPackage->State[newState].Latency = latency;
|
||
|
||
GetCurrentProcFrequency(newState, ¤tFreq);
|
||
DevExt->PssPackage->State[newState].CoreFrequency = currentFreq;
|
||
DevExt->PssPackage->State[newState].Power = currentFreq * 16;
|
||
|
||
DebugPrint((INFO, "Jumped to state 0x%x in %d us\n", newState, latency));
|
||
|
||
|
||
//
|
||
// NOTE: This is a work around because the Policy Manager won't set our
|
||
// low perf state to POP_THROTTLE_NON_LINEAR if we use the above algothrim,
|
||
// because it makes each of our states very linear. In Acpi 2.0, this
|
||
// information is given to us in the _PSS, but for legacy perfstates, we
|
||
// have to make it up.
|
||
//
|
||
|
||
AdjustLegacyProcessorPerformanceStates(DevExt->PssPackage);
|
||
|
||
|
||
//
|
||
// Sanity Check the two states.
|
||
//
|
||
|
||
DebugAssert(DevExt->PssPackage->State[0].CoreFrequency >
|
||
DevExt->PssPackage->State[1].CoreFrequency);
|
||
|
||
|
||
//
|
||
// Merge Perf states with other states we may have.
|
||
//
|
||
|
||
status = MergePerformanceStates(DevExt);
|
||
|
||
if(!NT_SUCCESS(status)) {
|
||
goto InitalizeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
//
|
||
// Register for power state change notification so we can re-init the
|
||
// legacy interface when resuming from S4
|
||
//
|
||
|
||
status = PowerStateHandlerNotificationRegistration(ProcessSleepStateNotification,
|
||
NULL,
|
||
TRUE);
|
||
|
||
//
|
||
// If the max state avaiablable on Ac & Dc is different, then
|
||
// register for AC<->DC transition notification.
|
||
//
|
||
|
||
if (P3_Globals.MaxLevelAc != P3_Globals.MaxLevelDc) {
|
||
RegisterAcDcTransitionNotifyHandler(UpdateAcDcMaxLevel, (PVOID) DevExt);
|
||
}
|
||
|
||
|
||
InitalizeNonAcpiPerformanceStatesExit:
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
if (DevExt->PssPackage) {
|
||
ExFreePool(DevExt->PssPackage);
|
||
}
|
||
|
||
DevExt->PssPackage = NULL;
|
||
DevExt->LegacyInterface = FALSE;
|
||
}
|
||
|
||
DebugExitStatus(status);
|
||
return status;
|
||
}
|
||
NTSTATUS
|
||
AcpiLegacyPerfStateTransition(
|
||
IN PFDO_DATA DeviceExtension,
|
||
IN ULONG State
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
#define TRANSITION_RETRY_VALUE 1000
|
||
|
||
NTSTATUS status;
|
||
ULONG x;
|
||
|
||
//
|
||
// Performance Transitions are currently unavailable.
|
||
//
|
||
|
||
if (P3_Globals.TransitionsUnavailable) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
|
||
//
|
||
// Adjust the actual state value.
|
||
//
|
||
|
||
State += DeviceExtension->PpcResult;
|
||
|
||
|
||
//
|
||
// Attempt transition
|
||
//
|
||
|
||
|
||
for (x = 0; x < TRANSITION_RETRY_VALUE; x++) {
|
||
|
||
status = SetCurrentStateSmm(State);
|
||
|
||
|
||
if (NT_SUCCESS(status) || (status == STATUS_PERF_TRANSITIONS_UNAVAILABLE)) {
|
||
|
||
break;
|
||
|
||
} else if (status == STATUS_INVALID_DEVICE_STATE) {
|
||
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if (x) {
|
||
DebugPrint((WARN, "SetCurrentStateSmm() Failed %u of 1000 retries\n", x));
|
||
}
|
||
|
||
|
||
if (status == STATUS_PERF_TRANSITIONS_UNAVAILABLE) {
|
||
|
||
// tmp debug
|
||
DebugPrint((ERROR, "SetCurrentStateSmm() failed STATUS_PERF_TRANSITIONS_UNAVAILABLE\n"));
|
||
DebugPrint((ERROR, "*** Disabling Transitions\n"));
|
||
|
||
//
|
||
// Transitions are no longer available.
|
||
//
|
||
|
||
P3_Globals.TransitionsUnavailable = TRUE;
|
||
|
||
|
||
//
|
||
// Set timer to launch DPC thread
|
||
//
|
||
|
||
KeSetTimer(&P3_Globals.Timer, P3_Globals.TimeOut, &P3_Globals.Dpc);
|
||
|
||
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
|
||
return status;
|
||
}
|
||
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);
|
||
|
||
//
|
||
// Make sure we didn't find any NON I/O or MEM addresses
|
||
//
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
if (((DevExt->PctPackage.Control.AddressSpaceID != AcpiGenericSpaceIO) &&
|
||
(DevExt->PctPackage.Control.AddressSpaceID != AcpiGenericSpaceMemory)) ||
|
||
((DevExt->PctPackage.Status.AddressSpaceID != AcpiGenericSpaceIO) &&
|
||
(DevExt->PctPackage.Status.AddressSpaceID != AcpiGenericSpaceMemory))) {
|
||
|
||
DebugPrint((WARN, "ONLY Memory & I/O _PCT addresses are supported\n"));
|
||
DebugPrint((WARN, "NOT using Acpi 2.0 Performance States\n"));
|
||
|
||
//
|
||
// Undo what InitializeAcpi2PStatesGeneric() did
|
||
//
|
||
|
||
if (DevExt->PssPackage) {
|
||
ExFreePool(DevExt->PssPackage);
|
||
DevExt->PssPackage = NULL;
|
||
}
|
||
|
||
return STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// 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();
|
||
|
||
|
||
//
|
||
// 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
|
||
//
|
||
|
||
DebugAssert(DeviceExtensions[index] == 0);
|
||
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();
|
||
|
||
//
|
||
// Since this driver does not support Functional Fixed Hardware, we
|
||
// use generic method.
|
||
//
|
||
|
||
return MergePerformanceStatesGeneric(DeviceExtension);
|
||
|
||
}
|
||
NTSTATUS
|
||
Acpi2PerfStateTransition(
|
||
IN PFDO_DATA DeviceExtension,
|
||
IN ULONG State
|
||
)
|
||
/*++
|
||
|
||
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
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Since this driver does not support Functional Fixed Hardware, we
|
||
// use generic method.
|
||
//
|
||
|
||
return Acpi2PerfStateTransitionGeneric(DeviceExtension, State);
|
||
|
||
}
|
||
NTSTATUS
|
||
AdjustLegacyProcessorPerformanceStates(
|
||
IN OUT PACPI_PSS_PACKAGE PssPackage
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DebugAssert(PssPackage->NumPStates <= 2)
|
||
PssPackage->State[0].Power = PssPackage->State[0].CoreFrequency * 50;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
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
|
||
ProcessSleepStateNotification (
|
||
IN POWER_STATE_HANDLER_TYPE State,
|
||
IN PVOID Context,
|
||
IN BOOLEAN Entering
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PFDO_DATA DeviceExtension;
|
||
|
||
DebugEnter();
|
||
|
||
//
|
||
// Currently we only support this for single proc machines.
|
||
//
|
||
|
||
if (Globals.SingleProcessorProfile) {
|
||
|
||
//
|
||
// Get the DeviceExtension.
|
||
//
|
||
|
||
DeviceExtension = DeviceExtensions[0];
|
||
|
||
|
||
//
|
||
// if we are resuming from Hibernate on a system using the legacy Geyserville
|
||
// interface, we need to reinit the interface
|
||
//
|
||
|
||
if (!Entering && (State == PowerStateSleeping4)) {
|
||
|
||
//
|
||
// Initialize Throttle States to "Throttle off"
|
||
//
|
||
|
||
if (HalpThrottleScale) {
|
||
ProcessorThrottle((UCHAR)HalpThrottleScale);
|
||
}
|
||
|
||
|
||
if (DeviceExtension->LegacyInterface) {
|
||
|
||
status = InitializeSmmInterface();
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Log event
|
||
//
|
||
|
||
QueueEventLogWrite(DeviceExtension,
|
||
PROCESSOR_REINITIALIZATION_FAILURE,
|
||
0);
|
||
|
||
DebugPrint((ERROR, "ProcessSleepStateNotification: InitializeSmmInterface() Failed! rc=0x%x\n",
|
||
status));
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
NTSTATUS
|
||
GetProcessorBrandString (
|
||
PUCHAR BrandString,
|
||
PULONG Size
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
#define CPUID_BRAND_STRING_LENGTH 49
|
||
|
||
PUCHAR tmpPtr;
|
||
ULONG tmp;
|
||
ULONG brandIndex;
|
||
ULONG cpuId;
|
||
NTSTATUS status;
|
||
|
||
DebugAssert(Size);
|
||
PAGED_CODE();
|
||
|
||
|
||
//
|
||
// check incoming buffer size, the most we will need is CPUID_BRAND_STRING_LENGTH
|
||
//
|
||
|
||
if (!BrandString || (*Size < CPUID_BRAND_STRING_LENGTH)) {
|
||
|
||
*Size = CPUID_BRAND_STRING_LENGTH;
|
||
return STATUS_BUFFER_TOO_SMALL;
|
||
}
|
||
|
||
|
||
//
|
||
// First we will check to see if this processor supports
|
||
// brand strings
|
||
//
|
||
|
||
status = GetCPUIDProcessorBrandString(BrandString, Size);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
|
||
CPUID(1, &cpuId, &brandIndex, &tmp, &tmp);
|
||
brandIndex &= 0xf;
|
||
|
||
|
||
//
|
||
// NOTE: these strings CANNOT exceed CPUID_BRAND_STRING_LENGTH in size
|
||
// or the above code must change
|
||
//
|
||
|
||
switch (brandIndex) {
|
||
|
||
case 0x1:
|
||
tmpPtr = "Intel(r) Celeron(r) processor";
|
||
break;
|
||
|
||
case 0x2:
|
||
tmpPtr = "Intel(r) Pentium(r)III processor";
|
||
break;
|
||
|
||
case 0x3:
|
||
|
||
if (cpuId == 0x6B1) {
|
||
tmpPtr = "Intel(r) Celeron(r) processor";
|
||
} else {
|
||
tmpPtr = "Intel(r) Pentium(r)III Xeon(tm) processor";
|
||
}
|
||
break;
|
||
|
||
case 0x4:
|
||
tmpPtr = "Intel(r) Pentium(r)III processor";
|
||
break;
|
||
|
||
case 0x6:
|
||
tmpPtr = "Mobile Intel(r) Pentium(r)III Processor-M";
|
||
break;
|
||
|
||
case 0x7:
|
||
tmpPtr = "Mobile Intel(r) Celeron(r) processor";
|
||
break;
|
||
|
||
case 0x8:
|
||
|
||
if (cpuId >= 0xF20) {
|
||
tmpPtr = "Intel(r) Genuine processor";
|
||
} else {
|
||
tmpPtr = "Intel(r) Pentium(r)4 processor";
|
||
}
|
||
break;
|
||
|
||
case 0x9:
|
||
tmpPtr = "Intel(r) Pentium(r)4 processor";
|
||
break;
|
||
|
||
case 0xA:
|
||
tmpPtr = "Intel(r) Xeon(tm) processor";
|
||
break;
|
||
|
||
case 0xE:
|
||
tmpPtr = "Intel(r) Xeon(tm) processor";
|
||
break;
|
||
|
||
default:
|
||
return STATUS_NOT_SUPPORTED;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Copy string to buffer
|
||
//
|
||
|
||
strncpy(BrandString, tmpPtr, strlen(tmpPtr) + 1);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
NTSTATUS
|
||
UpdateAcDcMaxLevel(
|
||
IN PVOID Context,
|
||
IN BOOLEAN AC
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ULONG newPpc;
|
||
PFDO_DATA devExt = Context;
|
||
|
||
//
|
||
// We only do this when using the Legacy SpeedStep interface
|
||
//
|
||
|
||
if (devExt->LegacyInterface &&
|
||
devExt->PssPackage) {
|
||
|
||
newPpc = AC ? P3_Globals.MaxLevelAc : P3_Globals.MaxLevelDc;
|
||
|
||
//
|
||
// if the Max state currently available has changed, then
|
||
// we will rebuilt the states.
|
||
//
|
||
|
||
if (devExt->PpcResult != newPpc) {
|
||
|
||
DebugPrint((ERROR, "UpdateAcDcMaxLevel: New _PPC = %u\n", newPpc));
|
||
|
||
devExt->PpcResult = newPpc;
|
||
AcpiNotify80CallbackWorker(devExt->Self,
|
||
NULL);
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
VOID
|
||
P3TimerDpcHandler (
|
||
IN PKDPC Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemArgument1,
|
||
IN PVOID SystemArgument2
|
||
)
|
||
{
|
||
|
||
// tmp debug
|
||
DebugPrint((ERROR, "*** Re-enabling Transitions\n"));
|
||
|
||
//
|
||
// Re-enable transitions
|
||
//
|
||
|
||
P3_Globals.TransitionsUnavailable = FALSE;
|
||
|
||
}
|