718 lines
14 KiB
C
718 lines
14 KiB
C
/*++
|
||
|
||
Copyright (c) 2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
legacy.c
|
||
|
||
Abstract:
|
||
|
||
|
||
Author:
|
||
|
||
Todd Carpenter (1/30/01) - create file
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
#include "..\lib\processor.h"
|
||
#include "amdk7.h"
|
||
#include "legacy.h"
|
||
#include "fidvid.h"
|
||
|
||
PST_SIGNATURE SystemSignature;
|
||
PPST_BLOCK_HEADER PstBlockHeader;
|
||
|
||
extern ULONG AmdK7HackFlags;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text (PAGE, InitializeNonAcpiPerformanceStates)
|
||
#pragma alloc_text (PAGE, GetLegacyMaxProcFrequency)
|
||
#endif
|
||
|
||
//
|
||
// Legacy functions that must have a stub.
|
||
//
|
||
|
||
NTSTATUS
|
||
InitializeNonAcpiPerformanceStates(
|
||
IN PFDO_DATA DevExt
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The generic processor driver doesn't have non-ACPI performance states.
|
||
|
||
Arguments:
|
||
|
||
FdoData - pointer to the device extension
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PPST_ENTRY pstMatch;
|
||
|
||
DebugEnter();
|
||
|
||
//
|
||
// Check hack flags to see if we should use the Legacy interface.
|
||
//
|
||
|
||
if (!(AmdK7HackFlags & ENABLE_LEGACY_INTERFACE)) {
|
||
status = STATUS_NOT_SUPPORTED;
|
||
goto InitializeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Find the Perf States
|
||
//
|
||
|
||
status = FindPSTBlock(&PstBlockHeader);
|
||
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((ERROR, "ERROR!! PST Block Header NOT found\n"));
|
||
goto InitializeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
DumpPSTBlock(PstBlockHeader);
|
||
|
||
//
|
||
// Generate Signature to help find correct PST
|
||
//
|
||
|
||
status = CreateSystemSignature(&SystemSignature);
|
||
DebugPrint((TRACE, "Dumping System Signature...\n"));
|
||
DumpPSTSignature(&SystemSignature);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto InitializeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Walk through one or more PST entries to find the best match
|
||
//
|
||
|
||
status = FindMatchingPSTEntry(PstBlockHeader,
|
||
&SystemSignature,
|
||
&pstMatch);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((ERROR, "ERROR!! Couldn't find PST entry to match system signature\n"));
|
||
goto InitializeNonAcpiPerformanceStatesExit;
|
||
}
|
||
|
||
DebugPrint((TRACE, "Dumping Matching Signature...\n"));
|
||
DumpPSTEntry(pstMatch);
|
||
|
||
DevExt->LegacyInterface = TRUE;
|
||
|
||
//
|
||
// Set up _PCT
|
||
//
|
||
|
||
DevExt->PctPackage.Control.AddressSpaceID = AcpiGenericSpaceFixedFunction;
|
||
DevExt->PctPackage.Status.AddressSpaceID = AcpiGenericSpaceFixedFunction;
|
||
|
||
|
||
//
|
||
// Convert matching PST entry into _PSS package
|
||
//
|
||
|
||
status = ConvertPstToPss(DevExt, pstMatch, &DevExt->PssPackage);
|
||
|
||
|
||
|
||
InitializeNonAcpiPerformanceStatesExit:
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// undo what we have done
|
||
//
|
||
|
||
if (PstBlockHeader) {
|
||
ExFreePool(PstBlockHeader);
|
||
PstBlockHeader = NULL;
|
||
}
|
||
|
||
if (DevExt->PssPackage) {
|
||
ExFreePool(DevExt->PssPackage);
|
||
DevExt->PssPackage = NULL;
|
||
}
|
||
|
||
DevExt->LegacyInterface = FALSE;
|
||
|
||
}
|
||
|
||
DebugExitStatus(status);
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
AcpiLegacyPerfStateTransition(
|
||
IN PFDO_DATA DevExt,
|
||
IN ULONG State
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The generic processor driver doesn't have non-ACPI performance states.
|
||
|
||
Arguments:
|
||
|
||
State - Target State
|
||
|
||
Return Value:
|
||
|
||
NT Status
|
||
|
||
--*/
|
||
{
|
||
return Acpi2PerfStateTransition(DevExt, State + DevExt->PpcResult);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
GetLegacyMaxProcFrequency(
|
||
OUT PULONG CpuSpeed
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
FID_VID_STATUS fidVidStatus;
|
||
|
||
DebugAssert(CpuSpeed);
|
||
|
||
fidVidStatus.AsQWord = ReadMSR(AMDK7_FID_VID_STATUS_MSR);
|
||
*CpuSpeed = FSB100FidToCpuFreq[fidVidStatus.MFid];
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FindPSTBlock (
|
||
OUT PPPST_BLOCK_HEADER PstBlock
|
||
)
|
||
/*++
|
||
|
||
Description:
|
||
|
||
This routine looks in the BIOS memory area for the PST Block Header. The
|
||
signature will be located on a 16-byte bountry in the area from C0000h to FFFF0h.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
ULONG size = 0;
|
||
PVOID baseAddress;
|
||
ULONG_PTR address;
|
||
ULONG_PTR limit;
|
||
PHYSICAL_ADDRESS PhysAddress;
|
||
|
||
DebugEnter();
|
||
DebugAssert(PstBlock);
|
||
PAGED_CODE();
|
||
|
||
|
||
PhysAddress.HighPart = 0;
|
||
PhysAddress.LowPart = PST_SEARCH_RANGE_BEGIN;
|
||
|
||
|
||
//
|
||
// Map memory to search for PST Table
|
||
//
|
||
|
||
baseAddress = MmMapIoSpace(PhysAddress, PST_SEARCH_RANGE_LENGTH, 0);
|
||
|
||
if (!baseAddress) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto FindPSTBlockExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Compute limit for the for loop. Do not start a scan within 16 bytes of
|
||
// physical address 0xFFFFF
|
||
//
|
||
|
||
address = (ULONG_PTR) baseAddress;
|
||
limit = address + PST_SEARCH_RANGE_LENGTH - PST_SEARCH_INTERVAL;
|
||
|
||
for (; address <= limit; address += PST_SEARCH_INTERVAL) {
|
||
|
||
if (*(PULONG)address == PST_BLOCK_SIGNATURE &&
|
||
(!memcmp(((PPST_BLOCK_HEADER)address)->Signature,
|
||
PST_BLOCK_SIGNATURE_STRING,
|
||
PST_BLOCK_SIGNATURE_STRING_LEN))) {
|
||
|
||
DebugPrint((TRACE, "Found PST Header Block at %p\n", address));
|
||
|
||
//
|
||
// We found the PST Block Header, copy it.
|
||
//
|
||
|
||
size = GetPSTSize((PPST_BLOCK_HEADER)address);
|
||
|
||
*PstBlock = ExAllocatePoolWithTag(PagedPool,
|
||
size,
|
||
PROCESSOR_POOL_TAG);
|
||
|
||
if (!(*PstBlock)) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto FindPSTBlockExit;
|
||
}
|
||
|
||
RtlCopyMemory(*PstBlock, (PVOID)address, size);
|
||
status = STATUS_SUCCESS;
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
FindPSTBlockExit:
|
||
|
||
//
|
||
// Unmap mapped memory
|
||
//
|
||
|
||
if (baseAddress) {
|
||
MmUnmapIoSpace(baseAddress, PST_SEARCH_RANGE_LENGTH);
|
||
}
|
||
|
||
DebugExitStatus(status);
|
||
return status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FindMatchingPSTEntry(
|
||
IN PPST_BLOCK_HEADER PstBlock,
|
||
IN PPST_SIGNATURE Signature,
|
||
OUT PPPST_ENTRY PstStates
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
||
ULONG x, y;
|
||
PPST_ENTRY pstEntry;
|
||
|
||
//DebugEnter();
|
||
DebugAssert(PstBlock);
|
||
DebugAssert(Signature);
|
||
DebugAssert(PstStates);
|
||
|
||
//
|
||
// Walk PST Block looking for matching PST Signature.
|
||
//
|
||
|
||
//
|
||
// Get First PST Entry
|
||
//
|
||
|
||
pstEntry = &PstBlock->PstState;
|
||
|
||
for (x=0; x < PstBlock->NumPST; x++) {
|
||
|
||
if ((pstEntry->CpuId == Signature->CpuId) &&
|
||
(pstEntry->FSBSpeed == Signature->FSBSpeed) &&
|
||
(pstEntry->MaxFid == Signature->MaxFid) &&
|
||
(pstEntry->StartVid == Signature->StartVid)) {
|
||
|
||
//
|
||
// Found Match, we assume there should only be one match, but
|
||
// if there are more, we take the first one.
|
||
//
|
||
|
||
*PstStates = pstEntry;
|
||
status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
}
|
||
|
||
//
|
||
// Get Next PST State
|
||
//
|
||
|
||
pstEntry = (PPST_ENTRY)((PUCHAR)pstEntry + sizeof(PST_ENTRY) +
|
||
(sizeof(PST_DATA) * (pstEntry->NumPStates - 1)));
|
||
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CreateSystemSignature(
|
||
PPST_SIGNATURE Signature
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
ULONG junk;
|
||
FID_VID_STATUS fidVidStatus;
|
||
|
||
//DebugEnter();
|
||
DebugAssert(Signature);
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Gather info needed to select the correct PST for this processor.
|
||
//
|
||
|
||
//
|
||
// Get special CPUID using extended CPUID fuction 1
|
||
//
|
||
|
||
CPUID(0x80000001, &Signature->CpuId, &junk, &junk, &junk);
|
||
|
||
//
|
||
// Get MAX Fid & Startup VID
|
||
//
|
||
|
||
fidVidStatus.AsQWord = ReadMSR(AMDK7_FID_VID_STATUS_MSR);
|
||
Signature->MaxFid = (UCHAR) fidVidStatus.MFid;
|
||
Signature->StartVid = (UCHAR) fidVidStatus.SVid;
|
||
|
||
//
|
||
// Get Front Side Bus speed
|
||
//
|
||
|
||
Signature->FSBSpeed = GetFSBSpeed();
|
||
DebugAssert(Signature->FSBSpeed);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
UCHAR
|
||
GetFSBSpeed(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
UCHAR speed;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// FSB Speed == CPU frequency / FSB multiplier
|
||
//
|
||
|
||
// toddcar - 4/30/01 - ISSUE:
|
||
// Need to finish support for 133mhz
|
||
//
|
||
|
||
speed = 100;
|
||
return speed;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ConvertPstToPss (
|
||
IN PFDO_DATA DevExt,
|
||
IN PPST_ENTRY PstEntry,
|
||
OUT PACPI_PSS_PACKAGE *PssPackage
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
ULONG pssSize;
|
||
ULONG x;
|
||
ULONG currentState;
|
||
PACPI_PSS_PACKAGE tmpPss;
|
||
|
||
DebugEnter();
|
||
DebugAssert(PstEntry);
|
||
DebugAssert(PssPackage);
|
||
PAGED_CODE();
|
||
|
||
|
||
|
||
//
|
||
// Allocate a chunk for PssPackage
|
||
//
|
||
|
||
pssSize = (sizeof(ACPI_PSS_DESCRIPTOR) * (PstEntry->NumPStates - 1)) +
|
||
sizeof(ACPI_PSS_PACKAGE);
|
||
|
||
|
||
tmpPss = ExAllocatePoolWithTag(NonPagedPool,
|
||
pssSize,
|
||
PROCESSOR_POOL_TAG);
|
||
|
||
|
||
if (!tmpPss) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto ConvertPstToPssExit;
|
||
}
|
||
|
||
RtlZeroMemory(tmpPss, pssSize);
|
||
tmpPss->NumPStates = PstEntry->NumPStates;
|
||
|
||
|
||
//
|
||
// Build a _PSS table
|
||
//
|
||
|
||
for (x = 0; x < PstEntry->NumPStates; x++) {
|
||
|
||
PSS_CONTROL pssControl = {0};
|
||
PSS_STATUS pssStatus = {0};
|
||
ULONG pssState = (PstEntry->NumPStates - 1) - x;
|
||
|
||
pssControl.Fid = pssStatus.Fid = PstEntry->States[x].Fid;
|
||
pssControl.Vid = pssStatus.Vid = PstEntry->States[x].Vid;
|
||
pssControl.SGTC = PstEntry->FSBSpeed * 100; // need to finish support for 133mhz bus
|
||
|
||
tmpPss->State[pssState].Control = pssControl.AsDWord;
|
||
tmpPss->State[pssState].Status = pssStatus.AsDWord;
|
||
|
||
DebugAssert(pssControl.Fid < INVALID_FID_VALUE);
|
||
tmpPss->State[pssState].CoreFrequency = FSB100FidToCpuFreq[pssControl.Fid];
|
||
|
||
DebugAssert(pssControl.Vid < INVALID_VID_VALUE);
|
||
tmpPss->State[pssState].Power = MobileVidToCpuVoltage[pssControl.Vid];
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Walk through each state collecting more information
|
||
//
|
||
|
||
status = FindCurrentPssPerfState(tmpPss, ¤tState);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto ConvertPstToPssExit;
|
||
}
|
||
|
||
DevExt->CurrentPssState = currentState;
|
||
DevExt->PssPackage = tmpPss;
|
||
|
||
|
||
//
|
||
// Set Latency Info
|
||
//
|
||
|
||
status = ValidatePssLatencyValues(DevExt);
|
||
|
||
|
||
//
|
||
// Restore saved state
|
||
//
|
||
|
||
if (DevExt->CurrentPssState != currentState) {
|
||
Acpi2PerfStateTransition(DevExt, currentState);
|
||
}
|
||
|
||
|
||
//
|
||
// Need to merge this new data with our perfstates
|
||
//
|
||
|
||
MergePerformanceStates(DevExt);
|
||
|
||
|
||
ConvertPstToPssExit:
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
if (DevExt->PssPackage) {
|
||
ExFreePool(DevExt->PssPackage);
|
||
DevExt->PssPackage = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
DebugExitStatus(status);
|
||
return status;
|
||
|
||
}
|
||
ULONG
|
||
GetPSTSize(
|
||
IN PPST_BLOCK_HEADER PstBlock
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
ULONG size;
|
||
ULONG x;
|
||
PPST_ENTRY pstEntry;
|
||
|
||
DebugAssert(PstBlock);
|
||
|
||
size = sizeof(PST_BLOCK_HEADER); // include block header, and one pst entry
|
||
size += sizeof(PST_ENTRY) * (PstBlock->NumPST - 1);
|
||
|
||
pstEntry = &PstBlock->PstState;
|
||
|
||
for (x=0; x < PstBlock->NumPST; x++) {
|
||
|
||
size += sizeof(PST_DATA) * (pstEntry->NumPStates-1);
|
||
|
||
pstEntry = (PPST_ENTRY)((PUCHAR)pstEntry + sizeof(PST_ENTRY) +
|
||
(sizeof(PST_DATA) * (pstEntry->NumPStates - 1)));
|
||
|
||
}
|
||
|
||
return size;
|
||
|
||
}
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
DumpPSTBlock(
|
||
PPST_BLOCK_HEADER PstBlock
|
||
)
|
||
{
|
||
|
||
ULONG x, y;
|
||
PPST_ENTRY pstEntry;
|
||
|
||
DebugAssert(PstBlock);
|
||
|
||
DebugPrint((TRACE, "\n"));
|
||
DebugPrint((TRACE, "PstBlock:\n"));
|
||
DebugPrint((TRACE, " Signature: %.10s\n", PstBlock->Signature));
|
||
DebugPrint((TRACE, " TableVersion: %u\n", PstBlock->TableVersion));
|
||
DebugPrint((TRACE, " Flags: 0x%x\n", PstBlock->Flags));
|
||
DebugPrint((TRACE, " SettlingTime: %u us\n", PstBlock->SettlingTime));
|
||
DebugPrint((TRACE, " Reserved1: 0x0\n", PstBlock->Reserved1));
|
||
DebugPrint((TRACE, " NumPST: %u\n", PstBlock->NumPST));
|
||
DebugPrint((TRACE, "\n"));
|
||
|
||
//
|
||
// Get First PST Entry
|
||
//
|
||
|
||
pstEntry = &PstBlock->PstState;
|
||
|
||
for (x=0; x < PstBlock->NumPST; x++) {
|
||
|
||
DumpPSTEntry(pstEntry);
|
||
|
||
//
|
||
// Get Next PST State
|
||
//
|
||
|
||
pstEntry = (PPST_ENTRY)((PUCHAR)pstEntry + sizeof(PST_ENTRY) +
|
||
(sizeof(PST_DATA) * (pstEntry->NumPStates - 1)));
|
||
|
||
}
|
||
}
|
||
|
||
|
||
VOID
|
||
DumpPSTEntry(
|
||
PPST_ENTRY PstEntry
|
||
)
|
||
{
|
||
ULONG y;
|
||
|
||
DebugPrint((TRACE, "PST Entry:\n"));
|
||
DebugPrint((TRACE, " CpuId: 0x%x\n", PstEntry->CpuId));
|
||
DebugPrint((TRACE, " FSBSpeed: %u mhz\n", PstEntry->FSBSpeed));
|
||
DebugPrint((TRACE, " MaxFid: 0x%x\n", PstEntry->MaxFid));
|
||
DebugPrint((TRACE, " StartVid: 0x%x\n", PstEntry->StartVid));
|
||
DebugPrint((TRACE, " NumPStates %u\n", PstEntry->NumPStates));
|
||
|
||
for (y=0; y < PstEntry->NumPStates; y++) {
|
||
|
||
DebugPrint((TRACE, " State #%u (Fid: 0x%x, Vid: 0x%x)\n",
|
||
y,
|
||
PstEntry->States[y].Fid,
|
||
PstEntry->States[y].Vid));
|
||
}
|
||
|
||
DebugPrint((TRACE, "\n"));
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
DumpPSTSignature(
|
||
PPST_SIGNATURE PstSig
|
||
)
|
||
{
|
||
|
||
DebugPrint((TRACE, "PST Signature:\n"));
|
||
DebugPrint((TRACE, " CpuId: 0x%x\n", PstSig->CpuId));
|
||
DebugPrint((TRACE, " FSBSpeed: %u mhz\n", PstSig->FSBSpeed));
|
||
DebugPrint((TRACE, " MaxFid: 0x%x\n", PstSig->MaxFid));
|
||
DebugPrint((TRACE, " StartVid: 0x%x\n", PstSig->StartVid));
|
||
DebugPrint((TRACE, "\n"));
|
||
|
||
}
|
||
#endif
|