windows-nt/Source/XPSP1/NT/base/hals/processor/amdk7/legacy.c

718 lines
14 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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, &currentState);
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