/*++ 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