[edk2] [PATCH] UefiCpuPkg/SecPeiDxeTimerLibUefiCpu: Add GetIntendFsbFrequency()

Jeff Fan posted 1 patch 6 years, 9 months ago
Failed in applying to current master (apply log)
.../Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c | 114 ++++++++++++++++++++-
1 file changed, 111 insertions(+), 3 deletions(-)
[edk2] [PATCH] UefiCpuPkg/SecPeiDxeTimerLibUefiCpu: Add GetIntendFsbFrequency()
Posted by Jeff Fan 6 years, 9 months ago
The current implementation gets CPU FSB frequency by PcdFSBClock. However, IA32
SDM defined accurate FSB for some specific processors. Actually, we could try to
get FSB frequency by hardware instead of by PcdFSBClock. If FSB frequency is not
documented by IA32 SDM, we still could get it by PcdFSBClock.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
---
 .../Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c | 114 ++++++++++++++++++++-
 1 file changed, 111 insertions(+), 3 deletions(-)

diff --git a/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c b/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c
index f703d7e..606ad0a 100644
--- a/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c
+++ b/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c
@@ -3,7 +3,7 @@
 
   This library uses the local APIC library so that it supports x2APIC mode.
   
-  Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD License
   which accompanies this distribution.  The full text of the license may be found at
@@ -20,6 +20,108 @@
 #include <Library/PcdLib.h>
 #include <Library/DebugLib.h>
 #include <Library/LocalApicLib.h>
+#include <Register/Cpuid.h>
+#include <Register/Msr.h>
+
+//
+// The following array is FSB frequencies defined in Pentinum 4 family, Core, Core 2
+// and Atom CPUs, its value unit is HZ.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+CONST UINT32                          mPentinum4FSBFrequencies[] = {
+  266666667,
+  133333333,
+  200000000,
+  166666667,
+  333333333,
+  100000000,
+  400000000
+};
+
+//
+// The following array is FSB frequencies defined in SivlerMont, Airmont
+// CPUs, its value unit is HZ.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+CONST UINT32                          mSivlerMontFSBFrequencies[] = {
+   83333333,
+  100000000,
+  133333333,
+  116666667,
+   80000000,
+   93333333,
+   90000000,
+   88888889,
+   87500000
+};
+
+/**
+  The function to get CPU intended FSB frequency.
+
+  This function reads the type of CPU by CPUID and returns FSB frequecny,
+
+  @retval CPU intended FSB frequency.
+
+**/
+UINT32
+GetIntendFsbFrequency (
+  VOID
+  )
+{
+  CPUID_VERSION_INFO_EAX                   Eax;
+  CPUID_VERSION_INFO_ECX                   Ecx;
+  CPUID_VERSION_INFO_EDX                   Edx;
+  UINT32                                   DisplayedFamily;
+  UINT32                                   DisplayedModel;
+  MSR_PENTIUM_4_EBC_FREQUENCY_ID_REGISTER  Pentium4Msr;
+  MSR_CORE_FSB_FREQ_REGISTER               CoreMsr;
+  MSR_SILVERMONT_FSB_FREQ_REGISTER         SilvermontMsr;
+  UINT32                                   Freq;
+  UINTN                                    FrequencyIndex;
+
+  AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, &Ecx.Uint32, &Edx.Uint32);
+
+  DisplayedFamily = Eax.Bits.FamilyId;
+  if (Eax.Bits.FamilyId == 0x0F) {
+    DisplayedFamily |= (Eax.Bits.ExtendedFamilyId << 4);
+  }
+
+  DisplayedModel = Eax.Bits.Model;
+  if (Eax.Bits.FamilyId == 0x06 || Eax.Bits.FamilyId == 0x0f) {
+    DisplayedModel |= (Eax.Bits.ExtendedModelId << 4);
+  }
+
+  Freq = 0;
+  if (IS_PENTIUM_4_PROCESSOR (DisplayedFamily, DisplayedModel)) {
+    Pentium4Msr.Uint64 = AsmReadMsr64 (MSR_PENTIUM_4_EBC_FREQUENCY_ID);
+    FrequencyIndex = Pentium4Msr.Bits.ScalableBusSpeed;
+    if (FrequencyIndex == 0 && DisplayedModel == 0x02) {
+      //
+      // FrequencyIndex:000B DisplayedModel:2 is 100 MHz
+      //
+      Freq = 100000000;
+    }
+    ASSERT (FrequencyIndex < (sizeof (mPentinum4FSBFrequencies) / sizeof (UINT32)));
+    Freq = mPentinum4FSBFrequencies[FrequencyIndex];
+  } else if (IS_CORE_PROCESSOR  (DisplayedFamily, DisplayedModel) ||
+             IS_CORE2_PROCESSOR (DisplayedFamily, DisplayedModel) ||
+             IS_ATOM_PROCESSOR  (DisplayedFamily, DisplayedModel)) {
+    CoreMsr.Uint64 = AsmReadMsr64 (MSR_CORE_FSB_FREQ);
+    FrequencyIndex = CoreMsr.Bits.ScalableBusSpeed;
+    ASSERT (FrequencyIndex < (sizeof (mPentinum4FSBFrequencies) / sizeof (UINT32)));
+    Freq = mPentinum4FSBFrequencies[FrequencyIndex];
+  } else if (IS_SILVERMONT_PROCESSOR (DisplayedFamily, DisplayedModel)) {
+    SilvermontMsr.Uint64 = AsmReadMsr64 (MSR_SILVERMONT_FSB_FREQ);
+    FrequencyIndex = SilvermontMsr.Bits.ScalableBusSpeed;
+    ASSERT (FrequencyIndex < (sizeof (mSivlerMontFSBFrequencies) / sizeof (UINT32)));
+    Freq = mSivlerMontFSBFrequencies[FrequencyIndex];
+  }
+
+  //
+  // If processor is not in supported list, then 0 will be return
+  //
+  return Freq;
+}
 
 /**
   Internal function to return the frequency of the local APIC timer.
@@ -33,10 +135,16 @@ InternalX86GetTimerFrequency (
   VOID
   )
 {
-  UINTN Divisor;
+  UINT32 Freq;
+  UINTN  Divisor;
+
+  Freq = GetIntendFsbFrequency ();
+  if (Freq == 0) {
+    Freq = PcdGet32(PcdFSBClock);
+  }
 
   GetApicTimerState (&Divisor, NULL, NULL);
-  return PcdGet32(PcdFSBClock) / (UINT32)Divisor;
+  return Freq / (UINT32)Divisor;
 }
 
 /**
-- 
2.9.3.windows.2

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel