windows-nt/Source/XPSP1/NT/base/hals/processor/amdk7/amdk7.c
2020-09-26 16:20:57 +08:00

857 lines
17 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
amdk7.c
Abstract:
This module implements code specific to the AMDK7 processor
Author:
Todd Carpenter (1/30/01) - create file
Environment:
Kernel mode
Notes:
DeviceInst = "ACPI\AuthenticAMD_-_x86_Family_6_Model_6"
ServiceName = "amdk7"
Revision History:
--*/
#include "..\lib\processor.h"
#include "amdk7.h"
#if DBG
PUCHAR DebugName = "AmdK7.sys";
#endif
PFDO_DATA DeviceExtensions[MAX_SUPPORTED_PROCESSORS];
UCHAR DevExtIndex;
ULONG AmdK7HackFlags;
extern GLOBALS Globals;
#ifdef ALLOC_PRAGMA
#pragma alloc_text (PAGE, InitializeDriver)
#pragma alloc_text (PAGE, GetProcessorBrandString)
#pragma alloc_text (PAGE, InitializeAcpi2PStates)
#pragma alloc_text (PAGE, InitializeAcpi2Cstates)
#pragma alloc_text (PAGE, MergePerformanceStates)
#endif
NTSTATUS
InitializeDriver(
PUNICODE_STRING ServiceKeyRegPath
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
//
// Get AmdK7 Hack Flags
//
GetRegistryDwordValue((PWCHAR) AMDK7_PARAMETERS_KEY,
L"HackFlags",
&AmdK7HackFlags);
return STATUS_SUCCESS;
}
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];
//
// This driver only supports FFH addresses, but SetPerfLevelGeneric
// only finds the correct state, it will then call Acpi2PerfStateTransition
//
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];
//
// This driver supports Acpi 1.0b style of throttling, use
// generic function
//
return SetThrottleLevelGeneric(Throttle, DeviceExtension);
}
NTSTATUS
GetProcessorBrandString (
PUCHAR BrandString,
PULONG Size
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
//
// This processor supports the CpuId based brand string
//
return GetCPUIDProcessorBrandString(BrandString, Size);
}
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((WARN, "ONLY Acpi 2.0 FFH 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
//
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.
--*/
{
NTSTATUS status;
NTSTATUS findStatus;
ULONG pssState = 0xdeadbeef;
DebugEnter();
//
// This function just merges available _PSS and stop clock throttle states
//
status = MergePerformanceStatesGeneric(DeviceExtension);
//
// With amdk7.sys, the order of transition execution differs if going from a
// higher state to a lower state when compared to going from a lower state to
// a higher state... Therefore, it is important that we set the current state
// before registering new performance states with the kernel.
//
// NOTE: MergePerformanceStatesGeneric() will invalidate CurrentPerfState,
// so it must be set here.
//
if (NT_SUCCESS(status)) {
findStatus = FindCurrentPssPerfState(DeviceExtension->PssPackage, &pssState);
if (NT_SUCCESS(findStatus)) {
DebugAssert(pssState < DeviceExtension->PssPackage->NumPStates);
DeviceExtension->CurrentPerfState = pssState;
}
}
return status;
}
NTSTATUS
Acpi2PerfStateTransition(
IN PFDO_DATA DeviceExtension,
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
--*/
{
NTSTATUS status = STATUS_SUCCESS;
ULONG transitionStatus;
ULONG pssControl;
ULONG64 fidControl;
ULONG64 vidControl;
ULONG64 fidVidStatus;
DebugEnter();
DebugAssert(DeviceExtension->PssPackage)
DebugAssert(NewState >= DeviceExtension->PpcResult);
DebugAssert(NewState < DeviceExtension->PssPackage->NumPStates);
DebugAssert(DeviceExtension->PssPackage->State[NewState].Control);
if (DeviceExtension->PctPackage.Control.AddressSpaceID != AcpiGenericSpaceFixedFunction) {
DebugAssert(!"Acpi2PerfStateTransition ONLY understands FFH addresses");
status = STATUS_UNSUCCESSFUL;
goto Acpi2PerfStateTransitionExit;
}
if (NewState == DeviceExtension->CurrentPssState) {
DebugPrint((WARN, "Acpi2PerfStateTransition() CurrentState == TargetState, exiting...\n"));
goto Acpi2PerfStateTransitionExit;
}
//
// Transitioning the Mobile Athlon Processor requires two steps:
//
// If transitioning from a higher state to a lower state, then:
// 1) core frequency transition
// 2) core voltage transition
//
// If transitioning from a lower state to a higher state, then:
// 1) core voltage transition
// 2) core frequency transition
//
//
// Get Frequency and Voltage value to write to MSR
//
pssControl = DeviceExtension->PssPackage->State[NewState].Control;
fidControl = ConvertPssControlToFidVidControl(pssControl, TRUE);
vidControl = ConvertPssControlToFidVidControl(pssControl, FALSE);
if (NewState > DeviceExtension->CurrentPssState) {
//
// High -> Low
//
DebugPrint((TRACE, "Perf Transition: state %u -> state %u\n", DeviceExtension->CurrentPssState, NewState));
DebugPrint((TRACE, "FidControl = 0x%I64x, VidControl = 0x%I64x\n", fidControl, vidControl));
AmdK7FidVidTransition(fidControl);
AmdK7FidVidTransition(vidControl);
} else {
//
// Low -> High
//
DebugPrint((TRACE, "Perf Transition: state %u -> state %u\n", DeviceExtension->CurrentPssState, NewState));
DebugPrint((TRACE, "VidControl = 0x%I64x, FidControl = 0x%I64x\n", vidControl, fidControl));
AmdK7FidVidTransition(vidControl);
AmdK7FidVidTransition(fidControl);
}
//
// check status
//
fidVidStatus = ReadMSR(AMDK7_FID_VID_STATUS_MSR);
transitionStatus = ConvertFidVidStatusToPssStatus(fidVidStatus);
if (transitionStatus == DeviceExtension->PssPackage->State[NewState].Status) {
DeviceExtension->CurrentPssState = NewState;
} else {
DebugPrint((ERROR, "ERROR! Expected 0x%x status value, recieved 0x%x\n",
DeviceExtension->PssPackage->State[NewState].Status,
transitionStatus));
DebugPrint((ERROR, "_PSS[%u]->Status:\n", NewState));
DumpPssStatus(DeviceExtension->PssPackage->State[NewState].Status);
DebugPrint((ERROR, "FidVidStatus MSR:\n", fidVidStatus));
DumpFidVidStatus(fidVidStatus);
status = STATUS_UNSUCCESSFUL;
}
Acpi2PerfStateTransitionExit:
DebugExitStatus(status);
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 previous state, transition to lowest non-throttled perf state
//
return SaveCurrentStateGoToLowVolts(DeviceExtension);
}
ULONG64
ConvertPssControlToFidVidControl(
ULONG PssControlValue,
BOOLEAN Fid
)
/*++
Routine Description:
Arguments:
Return Value:
NOTES:
_PSS Control field:
Bit Name
---- ----
4:0 FID
9:5 VID
29:10 SGTC
31:30 Reserved
FidVidCtl:
Bit Name Function
---- ---- --------
4:0 FID[4:0] New 5-bit FID to transition to
7:5 reserved
12:8 VID[4:0] New 5-bit VID to transition to
15:13 reserved
16 FIDC FID Control bit
17 VIDC VID Control bit
19:18 reserved
20 FidChgRatio Fid Change Ratio (always set to 1)
31:21 reserved
51:32 SGTC[19:0] Stop-Grant Timeout Count (write only)
63:52 reserved
--*/
{
FID_VID_CONTROL fidVidControl = {0};
PSS_CONTROL pssControl;
//DebugEnter();
DebugAssert(PssControlValue);
pssControl.AsDWord = PssControlValue;
fidVidControl.Fid = pssControl.Fid;
fidVidControl.Vid = pssControl.Vid;
fidVidControl.FidChngRatio = 1;
//
// The timeout needed for the Frequency Transion (FID) is exactly half that
// needed by the Voltage Transion (VID). We do this because of the latency
// savings
//
if (Fid) {
fidVidControl.SGTC = pssControl.SGTC / 2;
fidVidControl.FidControl = 1;
} else {
fidVidControl.SGTC = pssControl.SGTC;
fidVidControl.VidControl = 1;
}
return fidVidControl.AsQWord;
}
ULONG
ConvertFidVidStatusToPssStatus(
ULONG64 FidVidStatusValue
)
/*++
Routine Description:
Arguments:
Return Value:
NOTES:
FidVidStatus:
Bit Name Function
---- ---- --------
4:0 CFID[4:0] Current 5-bit FID
7:5 reserved
12:8 SFID[4:0] Startup 5-bit FID
15:13 reserved
20:16 MFID[4:0] Maximum 5-bit FID
31:21 reserved
36:32 CVID[4:0] Current 5-bit VID
39:37 reserved
44:40 SVID[4:0] Startup 5-bit VID
47:45 reserved
52:48 MVID[4:0] Maximum 5-bit VID
63:53 reserved
_PSS Status Field:
Bit Name
---- ----
4:0 FID current frequency
9:5 VID current voltage
31:10 reserved
--*/
{
PSS_STATUS pssStatus;
FID_VID_STATUS fidVidStatus;
//DebugEnter();
DebugAssert(FidVidStatusValue);
fidVidStatus.AsQWord = FidVidStatusValue;
pssStatus.Fid = fidVidStatus.CFid;
pssStatus.Vid = fidVidStatus.CVid;
pssStatus.Reserved = 0;
return pssStatus.AsDWord;
}
NTSTATUS
FindCurrentPssPerfState(
PACPI_PSS_PACKAGE PssPackage,
PULONG PssState
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
ULONG x;
ULONG transitionStatus;
ULONG64 fidVidStatus;
DebugEnter();
DebugAssert(PssPackage);
DebugAssert(PssState);
fidVidStatus = ReadMSR(AMDK7_FID_VID_STATUS_MSR);
transitionStatus = ConvertFidVidStatusToPssStatus(fidVidStatus);
for (x=0; x < PssPackage->NumPStates; x++) {
if (transitionStatus == PssPackage->State[x].Status) {
status = STATUS_SUCCESS;
*PssState = x;
break;
}
}
DebugExitStatus(status);
return status;
}
#if DBG
VOID
DumpFidVidStatus(
IN ULONG64 FidVidStatus
)
{
FID_VID_STATUS status;
status.AsQWord = FidVidStatus;
DebugPrint((MAXTRACE, " CFid: 0x%x\n", status.CFid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved1));
DebugPrint((MAXTRACE, " SFid: 0x%x\n", status.SFid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved2));
DebugPrint((MAXTRACE, " MFid: 0x%x\n", status.MFid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved3));
DebugPrint((MAXTRACE, " CVid: 0x%x\n", status.CVid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved4));
DebugPrint((MAXTRACE, " SVid: 0x%x\n", status.SVid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved5));
DebugPrint((MAXTRACE, " MVid: 0x%x\n", status.MVid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved6));
DebugPrint((MAXTRACE, "\n"));
}
VOID
DumpFidVidControl(
IN ULONG64 FidVidControl
)
{
FID_VID_CONTROL control;
control.AsQWord = FidVidControl;
DebugPrint((MAXTRACE, " Fid: 0x%x\n", control.Fid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved1));
DebugPrint((MAXTRACE, " Vid: 0x%x\n", control.Vid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved2));
DebugPrint((MAXTRACE, " FidControl: 0x%x\n", control.FidControl));
DebugPrint((MAXTRACE, " VidControl: 0x%x\n", control.VidControl));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved3));
DebugPrint((MAXTRACE, " FidChngRatio: 0x%x\n", control.FidChngRatio));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved4));
DebugPrint((MAXTRACE, " SGTC: 0x%x\n", control.SGTC));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved5));
DebugPrint((MAXTRACE, "\n"));
}
VOID
DumpPssStatus(
IN ULONG PssStatus
)
{
PSS_STATUS status;
status.AsDWord = PssStatus;
DebugPrint((MAXTRACE, " Fid: 0x%x\n", status.Fid));
DebugPrint((MAXTRACE, " Vid: 0x%x\n", status.Vid));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", status.Reserved));
DebugPrint((MAXTRACE, "\n"));
}
VOID
DumpPssControl(
IN ULONG PssControl
)
{
PSS_CONTROL control;
control.AsDWord = PssControl;
DebugPrint((MAXTRACE, " Fid: 0x%x\n", control.Fid));
DebugPrint((MAXTRACE, " Vid: 0x%x\n", control.Vid));
DebugPrint((MAXTRACE, " SGTC: 0x%x\n", control.SGTC));
DebugPrint((MAXTRACE, " Reserved: 0x%x\n", control.Reserved));
DebugPrint((MAXTRACE, "\n"));
}
#endif