提交 d7662157 编写于 作者: V vit9696

OcTimerLib: Support AMD ACPI PowerManagement timer

closes acidanthera/bugtracker#353
上级 f82cb159
......@@ -12,8 +12,8 @@
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef CPUID_H_
#define CPUID_H_
#ifndef CPUID_H
#define CPUID_H
#include <Register/Cpuid.h>
......@@ -212,4 +212,7 @@ enum {
CpuIdCachePrefetch128 = 0xF1, ///< 128-Byte Prefetching
};
#endif // CPUID_H_
#define CPUID_VENDOR_INTEL 0x756E6547
#define CPUID_VENDOR_AMD 0x68747541
#endif // CPUID_H
......@@ -12,8 +12,8 @@
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef GENERIC_ICH_H_
#define GENERIC_ICH_H_
#ifndef GENERIC_ICH_H
#define GENERIC_ICH_H
// GenericIchDefs Generic ICH Definitions.
//
......@@ -50,6 +50,11 @@
#define R_ICH_SMBUS_ACPI_CNT R_ICH_ACPI_CNT
#define B_ICH_SMBUS_ACPI_CNT_ACPI_EN B_ICH_ACPI_CNT_ACPI_EN
// AMD Bolton (AMD Bolton Register Reference Guide 3.03)
#define R_AMD_ACPI_MMIO_BASE 0xFED80000 ///< AcpiMMioAddr (3-268)
#define R_AMD_ACPI_MMIO_PMIO_BASE 0x300 ///< PMIO (3-268)
#define R_AMD_ACPI_PM_TMR_BLOCK 0x64 ///< AcpiPmTmrBlk (3-289)
// IchAcpiTimer The ICH's ACPI Timer.
......@@ -67,4 +72,4 @@
#define PCI_ICH_SMBUS_ADDRESS(Register) \
((UINTN)(PCI_LIB_ADDRESS (PCI_BUS_NUMBER_ICH, PCI_DEVICE_NUMBER_ICH, PCI_FUNCTION_NUMBER_ICH_SMBUS, (Register))))
#endif // GENERIC_ICH_H_
#endif // GENERIC_ICH_H
......@@ -12,11 +12,8 @@
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#ifndef OC_PROCESSOR_INFO_H_
#define OC_PROCESSOR_INFO_H_
#define CPUID_VENDOR_INTEL 0x756E6547
#define CPUID_VENDOR_AMD 0x68747541
#ifndef OC_PROCESSOR_INFO_H
#define OC_PROCESSOR_INFO_H
// SandyBridge/IvyBridge bus clock is fixed at 100MHz
......@@ -207,4 +204,4 @@ typedef enum {
CpuPStateCoordinationHardwareAll = 0xFE
} CPU_P_STATE_COORDINATION;
#endif // OC_PROCESSOR_INFO_H_
#endif // OC_PROCESSOR_INFO_H
......@@ -16,6 +16,7 @@
#include <IndustryStandard/GenericIch.h>
#include <IndustryStandard/Pci.h>
#include <IndustryStandard/CpuId.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
......@@ -37,6 +38,7 @@ RecalculateTSC (
)
{
UINT32 TimerAddr;
UINT32 CpuVendor;
UINT64 Tsc0;
UINT64 Tsc1;
UINT32 AcpiTick0;
......@@ -46,6 +48,8 @@ RecalculateTSC (
UINT32 TimerResolution;
EFI_TPL PrevTpl;
TimerAddr = 0;
//
// Intel timer support.
//
......@@ -72,82 +76,99 @@ RecalculateTSC (
DEBUG ((DEBUG_VERBOSE, "Acpi Timer Addr 0x%0x (SMB)\n", TimerAddr));
}
}
}
//
// AMD timer support.
//
if (TimerAddr == 0) {
//
// In an ideal world I believe we should detect AMD SMBus controller...
//
CpuVendor = 0;
AsmCpuid (CPUID_SIGNATURE, NULL, &CpuVendor, NULL, NULL);
if (CpuVendor == CPUID_VENDOR_AMD) {
TimerAddr = IoRead32 (
R_AMD_ACPI_MMIO_BASE + R_AMD_ACPI_MMIO_PMIO_BASE + R_AMD_ACPI_PM_TMR_BLOCK
);
}
}
if (TimerAddr != 0) {
mPerformanceCounterFrequency = 0;
if (TimerAddr != 0) {
mPerformanceCounterFrequency = 0;
//
// Check that timer is advancing (it does not on some virtual machines).
//
AcpiTick0 = IoRead32 (TimerAddr);
gBS->Stall (500);
AcpiTick1 = IoRead32 (TimerAddr);
if (AcpiTick0 != AcpiTick1) {
//
// ACPI PM timers are usually of 24-bit length, but there are some less common cases of 32-bit length also.
// When the maximal number is reached, it overflows.
// The code below can handle overflow with AcpiTicksTarget of up to 24-bit size,
// on both available sizes of ACPI PM Timers (24-bit and 32-bit).
//
// Check that timer is advancing (it does not on some virtual machines).
// 357954 clocks of ACPI timer (100ms)
//
AcpiTicksTarget = V_ACPI_TMR_FREQUENCY / TimerResolution;
//
// Disable all events to ensure that nobody interrupts us.
//
PrevTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
AcpiTick0 = IoRead32 (TimerAddr);
gBS->Stall (500);
AcpiTick1 = IoRead32 (TimerAddr);
Tsc0 = AsmReadTsc ();
if (AcpiTick0 != AcpiTick1) {
//
// ACPI PM timers are usually of 24-bit length, but there are some less common cases of 32-bit length also.
// When the maximal number is reached, it overflows.
// The code below can handle overflow with AcpiTicksTarget of up to 24-bit size,
// on both available sizes of ACPI PM Timers (24-bit and 32-bit).
//
// 357954 clocks of ACPI timer (100ms)
//
AcpiTicksTarget = V_ACPI_TMR_FREQUENCY / TimerResolution;
do {
CpuPause ();
//
// Disable all events to ensure that nobody interrupts us.
// Check how many AcpiTicks have passed since we started.
//
PrevTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
AcpiTick0 = IoRead32 (TimerAddr);
Tsc0 = AsmReadTsc ();
do {
CpuPause ();
AcpiTick1 = IoRead32 (TimerAddr);
if (AcpiTick0 <= AcpiTick1) {
//
// Check how many AcpiTicks have passed since we started.
// No overflow.
//
AcpiTick1 = IoRead32 (TimerAddr);
if (AcpiTick0 <= AcpiTick1) {
//
// No overflow.
//
AcpiTicksDelta = AcpiTick1 - AcpiTick0;
} else if (AcpiTick0 - AcpiTick1 <= 0x00FFFFFF) {
//
// Overflow, 24-bit timer.
//
AcpiTicksDelta = 0x00FFFFFF - AcpiTick0 + AcpiTick1;
} else {
//
// Overflow, 32-bit timer.
//
AcpiTicksDelta = MAX_UINT32 - AcpiTick0 + AcpiTick1;
}
AcpiTicksDelta = AcpiTick1 - AcpiTick0;
} else if (AcpiTick0 - AcpiTick1 <= 0x00FFFFFF) {
//
// Keep checking AcpiTicks until target is reached.
// Overflow, 24-bit timer.
//
} while (AcpiTicksDelta < AcpiTicksTarget);
Tsc1 = AsmReadTsc ();
AcpiTicksDelta = 0x00FFFFFF - AcpiTick0 + AcpiTick1;
} else {
//
// Overflow, 32-bit timer.
//
AcpiTicksDelta = MAX_UINT32 - AcpiTick0 + AcpiTick1;
}
//
// On some systems we may end up waiting for notably longer than 100ms,
// despite disabling all events. Divide by actual time passed as suggested
// by asava's Clover patch r2668.
// Keep checking AcpiTicks until target is reached.
//
mPerformanceCounterFrequency = DivU64x32 (
MultU64x32 (Tsc1 - Tsc0, V_ACPI_TMR_FREQUENCY), AcpiTicksDelta
);
} while (AcpiTicksDelta < AcpiTicksTarget);
//
// Restore to normal TPL.
//
gBS->RestoreTPL (PrevTpl);
}
Tsc1 = AsmReadTsc ();
//
// On some systems we may end up waiting for notably longer than 100ms,
// despite disabling all events. Divide by actual time passed as suggested
// by asava's Clover patch r2668.
//
mPerformanceCounterFrequency = DivU64x32 (
MultU64x32 (Tsc1 - Tsc0, V_ACPI_TMR_FREQUENCY), AcpiTicksDelta
);
//
// Restore to normal TPL.
//
gBS->RestoreTPL (PrevTpl);
}
}
......
......@@ -37,6 +37,7 @@
[Packages]
OcSupportPkg/OcSupportPkg.dec
MdePkg/MdePkg.dec
UefiCpuPkg/UefiCpuPkg.dec
[LibraryClasses]
PciLib
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册