Add accurate TSC frequency calculation support
Current SBL code uses MSR(0xce) to calculate the CPU TSC frequency. However, it is not very accurate. A better way is to use CPUID to calculate the TSC frequency. This patch added new API to get accurate TSC frequency. It also added APIs to allow conversion between time and TSC ticks. Signed-off-by: Maurice Ma <maurice.ma@intel.com>
This commit is contained in:
parent
4d45a48ac0
commit
8c85533285
|
@ -1,6 +1,6 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
@ -32,4 +32,47 @@ GetTimeStampFrequency (
|
|||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Get timestamp accurate frequency in HZ by CPUID.
|
||||
|
||||
The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
|
||||
In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
|
||||
|
||||
@retval The number of TSC counts per second.
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
GetTimeStampAccurateFrequency (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Convert timestamp ticks to microseconds.
|
||||
|
||||
@param[in] Ticks The number of timestamp ticks to convert.
|
||||
|
||||
@retval MicroSeconds
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
TimeStampTickToMicroSecond (
|
||||
IN UINT64 Ticks
|
||||
);
|
||||
|
||||
/**
|
||||
Convert microseconds to timestamp ticks.
|
||||
|
||||
@param[in] MicroSeconds The number of microseconds to convert.
|
||||
|
||||
@retval Timestamp ticks
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
MicroSecondToTimeStampTick (
|
||||
IN UINT64 MicroSeconds
|
||||
);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/** @file
|
||||
|
||||
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
|
||||
**/
|
||||
|
||||
#include <Register/Intel/Cpuid.h>
|
||||
#include <Library/BaseLib.h>
|
||||
|
||||
/**
|
||||
|
@ -44,3 +45,85 @@ GetTimeStampFrequency (
|
|||
// Ratio * 100000
|
||||
return (UINT32)(Ratio * 100000);
|
||||
}
|
||||
|
||||
/**
|
||||
Get timestamp accurate frequency in HZ by CPUID.
|
||||
|
||||
The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
|
||||
In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
|
||||
|
||||
@retval The number of TSC counts per second.
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
GetTimeStampAccurateFrequency (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINT64 TscFrequency;
|
||||
UINT32 RegEax;
|
||||
UINT32 RegEbx;
|
||||
UINT32 RegEcx;
|
||||
|
||||
// Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
|
||||
// EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
|
||||
// TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
|
||||
AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
|
||||
|
||||
// If EAX, EBX or ECX returns 0, the XTAL ratio is not enumerated.
|
||||
if ((RegEax == 0) || (RegEbx == 0 ) || (RegEcx == 0)) {
|
||||
// Fallback to use GetTimeStampFrequency() instead
|
||||
TscFrequency = MultU64x32 (GetTimeStampFrequency(), 1000);
|
||||
} else {
|
||||
// Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
|
||||
TscFrequency = DivU64x32 (MultU64x32 (RegEcx, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
|
||||
}
|
||||
|
||||
return TscFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert microseconds to timestamp ticks.
|
||||
|
||||
@param[in] MicroSeconds The number of microseconds to convert.
|
||||
|
||||
@retval Timestamp ticks
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
MicroSecondToTimeStampTick (
|
||||
IN UINT64 MicroSeconds
|
||||
)
|
||||
{
|
||||
return DivU64x32 (
|
||||
MultU64x64 (
|
||||
GetTimeStampAccurateFrequency (),
|
||||
MicroSeconds
|
||||
),
|
||||
1000000u
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
Convert timestamp ticks to microseconds.
|
||||
|
||||
@param[in] Ticks The number of timestamp ticks to convert.
|
||||
|
||||
@retval MicroSeconds
|
||||
|
||||
**/
|
||||
UINT64
|
||||
EFIAPI
|
||||
TimeStampTickToMicroSecond (
|
||||
IN UINT64 Ticks
|
||||
)
|
||||
{
|
||||
return DivU64x64Remainder (
|
||||
MultU64x32 (Ticks, 1000000u),
|
||||
GetTimeStampAccurateFrequency (),
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## @file
|
||||
#
|
||||
# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
|
||||
# Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
|
||||
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#
|
||||
##
|
||||
|
@ -24,6 +24,7 @@
|
|||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
BootloaderCommonPkg/BootloaderCommonPkg.dec
|
||||
|
||||
[Pcd]
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ GpioDebugPortWriteByte (
|
|||
UINT64 Ts1;
|
||||
|
||||
Baud = PcdGet32 (PcdGpioDebugPortBaudRate);
|
||||
Freq = GetTimeStampFrequency ();
|
||||
Freq = GetTimeStampAccurateFrequency ();
|
||||
|
||||
// Prepare 10 bits, 1 start bit, 8 data bits, 1 stop bits
|
||||
Word = (Value << 1) | BIT9;
|
||||
|
@ -56,7 +56,7 @@ GpioDebugPortWriteByte (
|
|||
for (Idx = 0; Idx < 10; Idx++) {
|
||||
SetGpioTxPin (Word & (1 << Idx));
|
||||
// Wait for 1 bit calculated by current baud rate
|
||||
Ts1 = Ts0 + DivU64x32 (MultU64x32(Freq, (Idx + 1) * 1000), Baud);
|
||||
Ts1 = Ts0 + DivU64x32 (MultU64x32(Freq, Idx + 1), Baud);
|
||||
while (ReadTimeStamp () < Ts1) {
|
||||
CpuPause ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue