]> git.proxmox.com Git - mirror_edk2.git/blobdiff - PcAtChipsetPkg/HpetTimerDxe/HpetTimer.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / PcAtChipsetPkg / HpetTimerDxe / HpetTimer.c
index b38963157cc1267569c0a9558ee3c1dd96c68ed5..427572c2ff6da4609d9ccd0b14aa59aa1ffdef16 100644 (file)
@@ -1,14 +1,8 @@
 /** @file\r
-  Timer Architectural Protocol module using High Precesion Event Timer (HPET)\r
+  Timer Architectural Protocol module using High Precision Event Timer (HPET)\r
 \r
-  Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
   is returned.\r
 \r
   @param  This            The EFI_TIMER_ARCH_PROTOCOL instance.\r
-  @param  NotifyFunction  The function to call when a timer interrupt fires.  \r
-                          This function executes at TPL_HIGH_LEVEL.  The DXE \r
-                          Core will register a handler for the timer interrupt, \r
-                          so it can know how much time has passed.  This \r
-                          information is used to signal timer based events.  \r
+  @param  NotifyFunction  The function to call when a timer interrupt fires.\r
+                          This function executes at TPL_HIGH_LEVEL.  The DXE\r
+                          Core will register a handler for the timer interrupt,\r
+                          so it can know how much time has passed.  This\r
+                          information is used to signal timer based events.\r
                           NULL will unregister the handler.\r
 \r
   @retval  EFI_SUCCESS            The timer handler was registered.\r
@@ -90,11 +84,11 @@ TimerDriverRegisterHandler (
 \r
   @param  This         The EFI_TIMER_ARCH_PROTOCOL instance.\r
   @param  TimerPeriod  The rate to program the timer interrupt in 100 nS units.\r
-                       If the timer hardware is not programmable, then \r
-                       EFI_UNSUPPORTED is returned.  If the timer is programmable, \r
-                       then the timer period will be rounded up to the nearest \r
-                       timer period that is supported by the timer hardware.  \r
-                       If TimerPeriod is set to 0, then the timer interrupts \r
+                       If the timer hardware is not programmable, then\r
+                       EFI_UNSUPPORTED is returned.  If the timer is programmable,\r
+                       then the timer period will be rounded up to the nearest\r
+                       timer period that is supported by the timer hardware.\r
+                       If TimerPeriod is set to 0, then the timer interrupts\r
                        will be disabled.\r
 \r
   @retval  EFI_SUCCESS       The timer period was changed.\r
@@ -126,8 +120,8 @@ TimerDriverSetTimerPeriod (
 EFI_STATUS\r
 EFIAPI\r
 TimerDriverGetTimerPeriod (\r
-  IN EFI_TIMER_ARCH_PROTOCOL   *This,\r
-  OUT UINT64                   *TimerPeriod\r
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,\r
+  OUT UINT64                  *TimerPeriod\r
   );\r
 \r
 /**\r
@@ -142,7 +136,7 @@ TimerDriverGetTimerPeriod (
   @param  This  The EFI_TIMER_ARCH_PROTOCOL instance.\r
 \r
   @retval  EFI_SUCCESS       The soft timer interrupt was generated.\r
-  @retval  EFI_UNSUPPORTEDT  The platform does not support the generation of soft \r
+  @retval  EFI_UNSUPPORTED   The platform does not support the generation of soft\r
                              timer interrupts.\r
 \r
 **/\r
@@ -151,11 +145,11 @@ EFIAPI
 TimerDriverGenerateSoftInterrupt (\r
   IN EFI_TIMER_ARCH_PROTOCOL  *This\r
   );\r
-  \r
+\r
 ///\r
 /// The handle onto which the Timer Architectural Protocol will be installed.\r
 ///\r
-EFI_HANDLE   mTimerHandle = NULL;\r
+EFI_HANDLE  mTimerHandle = NULL;\r
 \r
 ///\r
 /// The Timer Architectural Protocol that this driver produces.\r
@@ -183,11 +177,21 @@ EFI_TIMER_NOTIFY  mTimerNotifyFunction = NULL;
 UINT64  mTimerPeriod = 0;\r
 \r
 ///\r
-/// Accumulates HPET timer ticks to account for time passed when the \r
-/// HPET timer is disabled or when there is no timer notification function\r
-/// registered.\r
+/// The number of HPET timer ticks required for the current HPET rate specified by mTimerPeriod.\r
+///\r
+UINT64  mTimerCount;\r
+\r
+///\r
+/// Mask used for counter and comparator calculations to adjust for a 32-bit or 64-bit counter.\r
+///\r
+UINT64  mCounterMask;\r
+\r
+///\r
+/// The HPET main counter value from the most recent HPET timer interrupt.\r
 ///\r
-volatile UINT64  mTimerAccumulator = 0;\r
+volatile UINT64  mPreviousMainCounter;\r
+\r
+volatile UINT64  mPreviousComparator;\r
 \r
 ///\r
 /// The index of the HPET timer being managed by this driver.\r
@@ -212,7 +216,7 @@ HPET_GENERAL_CAPABILITIES_ID_REGISTER  mHpetGeneralCapabilities;
 HPET_GENERAL_CONFIGURATION_REGISTER  mHpetGeneralConfiguration;\r
 \r
 ///\r
-/// Cached state of the Configuration register for the HPET Timer managed by \r
+/// Cached state of the Configuration register for the HPET Timer managed by\r
 /// this driver.  Caching the state reduces the number of times the configuration\r
 /// register is read.\r
 ///\r
@@ -242,7 +246,7 @@ HpetRead (
 /**\r
   Write a 64-bit HPET register.\r
 \r
-  @param  Offset  Specifies the ofsfert of the HPET register to write.\r
+  @param  Offset  Specifies the offset of the HPET register to write.\r
   @param  Value   Specifies the value to write to the HPET register specified by Offset.\r
 \r
   @return  The 64-bit value written to HPET register specified by Offset.\r
@@ -267,7 +271,7 @@ HpetEnable (
   IN BOOLEAN  Enable\r
   )\r
 {\r
-  mHpetGeneralConfiguration.Bits.MainCounterEnable = Enable ? 1 : 0;  \r
+  mHpetGeneralConfiguration.Bits.MainCounterEnable = Enable ? 1 : 0;\r
   HpetWrite (HPET_GENERAL_CONFIGURATION_OFFSET, mHpetGeneralConfiguration.Uint64);\r
 }\r
 \r
@@ -276,24 +280,29 @@ HpetEnable (
   and computes the amount of time that has passed since the last HPET timer interrupt.\r
   If a notification function is registered, then the amount of time since the last\r
   HPET interrupt is passed to that notification function in 100 ns units.  The HPET\r
-  time is updated to generate another interrupt in the required time period. \r
+  time is updated to generate another interrupt in the required time period.\r
 \r
-  @param  InterruptType  The type of interrupt that occured.\r
-  @param  SystemContext  A pointer to the system context when the interrupt occured.\r
+  @param  InterruptType  The type of interrupt that occurred.\r
+  @param  SystemContext  A pointer to the system context when the interrupt occurred.\r
 **/\r
 VOID\r
 EFIAPI\r
 TimerInterruptHandler (\r
-  IN EFI_EXCEPTION_TYPE   InterruptType,\r
-  IN EFI_SYSTEM_CONTEXT   SystemContext\r
+  IN EFI_EXCEPTION_TYPE  InterruptType,\r
+  IN EFI_SYSTEM_CONTEXT  SystemContext\r
   )\r
 {\r
+  UINT64  MainCounter;\r
+  UINT64  Comparator;\r
   UINT64  TimerPeriod;\r
-  \r
+  UINT64  Delta;\r
+\r
   //\r
   // Count number of ticks\r
   //\r
-  DEBUG_CODE (mNumTicks++;);\r
+  DEBUG_CODE (\r
+    mNumTicks++;\r
+    );\r
 \r
   //\r
   // Clear HPET timer interrupt status\r
@@ -306,37 +315,89 @@ TimerInterruptHandler (
   SendApicEoi ();\r
 \r
   //\r
-  // Accumulate time from the HPET main counter value\r
+  // Disable HPET timer when adjusting the COMPARATOR value to prevent a missed interrupt\r
   //\r
-  mTimerAccumulator += HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
+  HpetEnable (FALSE);\r
 \r
   //\r
-  // Reset HPET main counter to 0\r
+  // Capture main counter value\r
   //\r
-  HpetWrite (HPET_MAIN_COUNTER_OFFSET, 0);\r
+  MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
+\r
+  //\r
+  // Get the previous comparator counter\r
+  //\r
+  mPreviousComparator = HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
+\r
+  //\r
+  // Set HPET COMPARATOR to the value required for the next timer tick\r
+  //\r
+  Comparator = (mPreviousComparator + mTimerCount) & mCounterMask;\r
+\r
+  if ((mPreviousMainCounter < MainCounter) && (mPreviousComparator > Comparator)) {\r
+    //\r
+    // When comparator overflows\r
+    //\r
+    HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, Comparator);\r
+  } else if ((mPreviousMainCounter > MainCounter) && (mPreviousComparator < Comparator)) {\r
+    //\r
+    // When main counter overflows\r
+    //\r
+    HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + mTimerCount) & mCounterMask);\r
+  } else {\r
+    //\r
+    // When both main counter and comparator do not overflow or both do overflow\r
+    //\r
+    if (Comparator > MainCounter) {\r
+      HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, Comparator);\r
+    } else {\r
+      HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + mTimerCount) & mCounterMask);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Enable the HPET counter once the new COMPARATOR value has been set.\r
+  //\r
+  HpetEnable (TRUE);\r
 \r
   //\r
   // Check to see if there is a registered notification function\r
   //\r
   if (mTimerNotifyFunction != NULL) {\r
     //\r
-    // Compute time since last notification in 100 ns units (10 ^ -7) \r
+    // Compute time since last notification in 100 ns units (10 ^ -7)\r
     //\r
+    if (MainCounter > mPreviousMainCounter) {\r
+      //\r
+      // Main counter does not overflow\r
+      //\r
+      Delta = MainCounter - mPreviousMainCounter;\r
+    } else {\r
+      //\r
+      // Main counter overflows, first usb, then add\r
+      //\r
+      Delta = (mCounterMask - mPreviousMainCounter) + MainCounter;\r
+    }\r
+\r
     TimerPeriod = DivU64x32 (\r
                     MultU64x32 (\r
-                      mTimerAccumulator, \r
+                      Delta & mCounterMask,\r
                       mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
-                      ), \r
+                      ),\r
                     100000000\r
                     );\r
-    mTimerAccumulator = 0;\r
-                    \r
+\r
     //\r
     // Call registered notification function passing in the time since the last\r
     // interrupt in 100 ns units.\r
-    //    \r
+    //\r
     mTimerNotifyFunction (TimerPeriod);\r
   }\r
+\r
+  //\r
+  // Save main counter value\r
+  //\r
+  mPreviousMainCounter = MainCounter;\r
 }\r
 \r
 /**\r
@@ -353,11 +414,11 @@ TimerInterruptHandler (
   is returned.\r
 \r
   @param  This            The EFI_TIMER_ARCH_PROTOCOL instance.\r
-  @param  NotifyFunction  The function to call when a timer interrupt fires.  \r
-                          This function executes at TPL_HIGH_LEVEL.  The DXE \r
-                          Core will register a handler for the timer interrupt, \r
-                          so it can know how much time has passed.  This \r
-                          information is used to signal timer based events.  \r
+  @param  NotifyFunction  The function to call when a timer interrupt fires.\r
+                          This function executes at TPL_HIGH_LEVEL.  The DXE\r
+                          Core will register a handler for the timer interrupt,\r
+                          so it can know how much time has passed.  This\r
+                          information is used to signal timer based events.\r
                           NULL will unregister the handler.\r
 \r
   @retval  EFI_SUCCESS            The timer handler was registered.\r
@@ -379,10 +440,11 @@ TimerDriverRegisterHandler (
   //\r
   // Check for invalid parameters\r
   //\r
-  if (NotifyFunction == NULL && mTimerNotifyFunction == NULL) {\r
+  if ((NotifyFunction == NULL) && (mTimerNotifyFunction == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
-  if (NotifyFunction != NULL && mTimerNotifyFunction != NULL) {\r
+\r
+  if ((NotifyFunction != NULL) && (mTimerNotifyFunction != NULL)) {\r
     return EFI_ALREADY_STARTED;\r
   }\r
 \r
@@ -409,11 +471,11 @@ TimerDriverRegisterHandler (
 \r
   @param  This         The EFI_TIMER_ARCH_PROTOCOL instance.\r
   @param  TimerPeriod  The rate to program the timer interrupt in 100 nS units.\r
-                       If the timer hardware is not programmable, then \r
-                       EFI_UNSUPPORTED is returned.  If the timer is programmable, \r
-                       then the timer period will be rounded up to the nearest \r
-                       timer period that is supported by the timer hardware.  \r
-                       If TimerPeriod is set to 0, then the timer interrupts \r
+                       If the timer hardware is not programmable, then\r
+                       EFI_UNSUPPORTED is returned.  If the timer is programmable,\r
+                       then the timer period will be rounded up to the nearest\r
+                       timer period that is supported by the timer hardware.\r
+                       If TimerPeriod is set to 0, then the timer interrupts\r
                        will be disabled.\r
 \r
   @retval  EFI_SUCCESS       The timer period was changed.\r
@@ -428,19 +490,52 @@ TimerDriverSetTimerPeriod (
   IN UINT64                   TimerPeriod\r
   )\r
 {\r
-  UINT64  TimerCount;\r
+  EFI_TPL                        Tpl;\r
+  UINT64                         MainCounter;\r
+  UINT64                         Delta;\r
+  UINT64                         CurrentComparator;\r
+  HPET_TIMER_MSI_ROUTE_REGISTER  HpetTimerMsiRoute;\r
+\r
+  //\r
+  // Disable interrupts\r
+  //\r
+  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
 \r
   //\r
   // Disable HPET timer when adjusting the timer period\r
   //\r
   HpetEnable (FALSE);\r
-  \r
+\r
   if (TimerPeriod == 0) {\r
+    if (mTimerPeriod != 0) {\r
+      //\r
+      // Check if there is possibly a pending interrupt\r
+      //\r
+      MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
+      if (MainCounter < mPreviousMainCounter) {\r
+        Delta = (mCounterMask - mPreviousMainCounter) + MainCounter;\r
+      } else {\r
+        Delta = MainCounter - mPreviousMainCounter;\r
+      }\r
+\r
+      if ((Delta & mCounterMask) >= mTimerCount) {\r
+        //\r
+        // Interrupt still happens after disable HPET, wait to be processed\r
+        // Wait until interrupt is processed and comparator is increased\r
+        //\r
+        CurrentComparator = HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
+        while (CurrentComparator == mPreviousComparator) {\r
+          CurrentComparator = HpetRead (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
+          CpuPause ();\r
+        }\r
+      }\r
+    }\r
+\r
     //\r
     // If TimerPeriod is 0, then mask HPET Timer interrupts\r
     //\r
-    \r
-    if (mTimerConfiguration.Bits.MsiInterruptCapablity != 0 && FeaturePcdGet (PcdHpetMsiEnable)) {\r
+\r
+    if ((mTimerConfiguration.Bits.MsiInterruptCapability != 0) && FeaturePcdGet (PcdHpetMsiEnable)) {\r
       //\r
       // Disable HPET MSI interrupt generation\r
       //\r
@@ -451,54 +546,50 @@ TimerDriverSetTimerPeriod (
       //\r
       IoApicEnableInterrupt (mTimerIrq, FALSE);\r
     }\r
-    \r
+\r
     //\r
-    // Disable HPET timer interrupt \r
+    // Disable HPET timer interrupt\r
     //\r
     mTimerConfiguration.Bits.InterruptEnable = 0;\r
     HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64);\r
   } else {\r
     //\r
-    // Convert TimerPeriod to femtoseconds and divide by the number if femtoseconds \r
+    // Convert TimerPeriod to femtoseconds and divide by the number if femtoseconds\r
     // per tick of the HPET counter to determine the number of HPET counter ticks\r
     // in TimerPeriod 100 ns units.\r
-    // \r
-    TimerCount = DivU64x32 (\r
-                   MultU64x32 (TimerPeriod, 100000000),\r
-                   mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
-                   );\r
+    //\r
+    mTimerCount = DivU64x32 (\r
+                    MultU64x32 (TimerPeriod, 100000000),\r
+                    mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
+                    );\r
 \r
     //\r
     // Program the HPET Comparator with the number of ticks till the next interrupt\r
     //\r
-    HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, TimerCount);\r
+    MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
+    if (MainCounter > mPreviousMainCounter) {\r
+      Delta = MainCounter - mPreviousMainCounter;\r
+    } else {\r
+      Delta = (mCounterMask - mPreviousMainCounter) + MainCounter;\r
+    }\r
 \r
-    //\r
-    // Capture the number of ticks since the last HPET Timer interrupt before \r
-    // clearing the main counter.  This value will be used in the next HPET\r
-    // timer interrupt handler to compute the total amount of time since the\r
-    // last HPET timer interrupt\r
-    //    \r
-    mTimerAccumulator = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
-    \r
-    //\r
-    // If the number of ticks since the last timer interrupt is greater than the\r
-    // timer period, reduce the number of ticks till the next interrupt to 1, so \r
-    // a timer interrupt will be generated as soon as the HPET counter is enabled.\r
-    //    \r
-    if (mTimerAccumulator >= TimerCount) {\r
-      HpetWrite (HPET_MAIN_COUNTER_OFFSET, TimerCount - 1);\r
-      //\r
-      // Adjust the accumulator down by TimerCount ticks because TimerCount\r
-      // ticks will be added to the accumulator on the next interrupt\r
-      //\r
-      mTimerAccumulator -= TimerCount;\r
+    if ((Delta & mCounterMask) >= mTimerCount) {\r
+      HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + 1) & mCounterMask);\r
+    } else {\r
+      HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (mPreviousMainCounter + mTimerCount) & mCounterMask);\r
     }\r
-    \r
+\r
     //\r
     // Enable HPET Timer interrupt generation\r
     //\r
-    if (mTimerConfiguration.Bits.MsiInterruptCapablity != 0 && FeaturePcdGet (PcdHpetMsiEnable)) {\r
+    if ((mTimerConfiguration.Bits.MsiInterruptCapability != 0) && FeaturePcdGet (PcdHpetMsiEnable)) {\r
+      //\r
+      // Program MSI Address and MSI Data values in the selected HPET Timer\r
+      // Program HPET register with APIC ID of current BSP in case BSP has been switched\r
+      //\r
+      HpetTimerMsiRoute.Bits.Address = GetApicMsiAddress ();\r
+      HpetTimerMsiRoute.Bits.Value   = (UINT32)GetApicMsiValue (PcdGet8 (PcdHpetLocalApicVector), LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY, FALSE, FALSE);\r
+      HpetWrite (HPET_TIMER_MSI_ROUTE_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, HpetTimerMsiRoute.Uint64);\r
       //\r
       // Enable HPET MSI Interrupt\r
       //\r
@@ -506,7 +597,9 @@ TimerDriverSetTimerPeriod (
     } else {\r
       //\r
       // Enable timer interrupt through I/O APIC\r
+      // Program IOAPIC register with APIC ID of current BSP in case BSP has been switched\r
       //\r
+      IoApicConfigureInterrupt (mTimerIrq, PcdGet8 (PcdHpetLocalApicVector), IO_APIC_DELIVERY_MODE_LOWEST_PRIORITY, TRUE, FALSE);\r
       IoApicEnableInterrupt (mTimerIrq, TRUE);\r
     }\r
 \r
@@ -516,7 +609,7 @@ TimerDriverSetTimerPeriod (
     mTimerConfiguration.Bits.InterruptEnable = 1;\r
     HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64);\r
   }\r
-    \r
+\r
   //\r
   // Save the new timer period\r
   //\r
@@ -529,7 +622,12 @@ TimerDriverSetTimerPeriod (
   // is disabled.\r
   //\r
   HpetEnable (TRUE);\r
-  \r
+\r
+  //\r
+  // Restore interrupts\r
+  //\r
+  gBS->RestoreTPL (Tpl);\r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -550,8 +648,8 @@ TimerDriverSetTimerPeriod (
 EFI_STATUS\r
 EFIAPI\r
 TimerDriverGetTimerPeriod (\r
-  IN EFI_TIMER_ARCH_PROTOCOL   *This,\r
-  OUT UINT64                   *TimerPeriod\r
+  IN EFI_TIMER_ARCH_PROTOCOL  *This,\r
+  OUT UINT64                  *TimerPeriod\r
   )\r
 {\r
   if (TimerPeriod == NULL) {\r
@@ -575,7 +673,7 @@ TimerDriverGetTimerPeriod (
   @param  This  The EFI_TIMER_ARCH_PROTOCOL instance.\r
 \r
   @retval  EFI_SUCCESS       The soft timer interrupt was generated.\r
-  @retval  EFI_UNSUPPORTEDT  The platform does not support the generation of soft \r
+  @retval  EFI_UNSUPPORTED   The platform does not support the generation of soft\r
                              timer interrupts.\r
 \r
 **/\r
@@ -585,52 +683,65 @@ TimerDriverGenerateSoftInterrupt (
   IN EFI_TIMER_ARCH_PROTOCOL  *This\r
   )\r
 {\r
+  UINT64   MainCounter;\r
   EFI_TPL  Tpl;\r
   UINT64   TimerPeriod;\r
+  UINT64   Delta;\r
 \r
   //\r
   // Disable interrupts\r
-  //  \r
-  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
-\r
   //\r
-  // Read the current HPET main counter value\r
-  //\r
-  mTimerAccumulator += HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
+  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
 \r
   //\r
-  // Reset HPET main counter to 0\r
+  // Capture main counter value\r
   //\r
-  HpetWrite (HPET_MAIN_COUNTER_OFFSET, 0);\r
+  MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
 \r
   //\r
   // Check to see if there is a registered notification function\r
   //\r
   if (mTimerNotifyFunction != NULL) {\r
     //\r
-    // Compute time since last interrupt in 100 ns units (10 ^ -7) \r
+    // Compute time since last interrupt in 100 ns units (10 ^ -7)\r
     //\r
+    if (MainCounter > mPreviousMainCounter) {\r
+      //\r
+      // Main counter does not overflow\r
+      //\r
+      Delta = MainCounter - mPreviousMainCounter;\r
+    } else {\r
+      //\r
+      // Main counter overflows, first usb, then add\r
+      //\r
+      Delta = (mCounterMask - mPreviousMainCounter) + MainCounter;\r
+    }\r
+\r
     TimerPeriod = DivU64x32 (\r
                     MultU64x32 (\r
-                      mTimerAccumulator, \r
+                      Delta & mCounterMask,\r
                       mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
-                      ), \r
+                      ),\r
                     100000000\r
                     );\r
-    mTimerAccumulator = 0;\r
-                    \r
+\r
     //\r
     // Call registered notification function passing in the time since the last\r
     // interrupt in 100 ns units.\r
-    //    \r
+    //\r
     mTimerNotifyFunction (TimerPeriod);\r
   }\r
 \r
+  //\r
+  // Save main counter value\r
+  //\r
+  mPreviousMainCounter = MainCounter;\r
+\r
   //\r
   // Restore interrupts\r
-  //  \r
+  //\r
   gBS->RestoreTPL (Tpl);\r
-  \r
+\r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -642,7 +753,7 @@ TimerDriverGenerateSoftInterrupt (
 \r
   @retval  EFI_SUCCESS           Timer Architectural Protocol created\r
   @retval  EFI_OUT_OF_RESOURCES  Not enough resources available to initialize driver.\r
-  @retval  EFI_DEVICE_ERROR      A device error occured attempting to initialize the driver.\r
+  @retval  EFI_DEVICE_ERROR      A device error occurred attempting to initialize the driver.\r
 \r
 **/\r
 EFI_STATUS\r
@@ -652,10 +763,10 @@ TimerDriverInitialize (
   IN EFI_SYSTEM_TABLE  *SystemTable\r
   )\r
 {\r
-  EFI_STATUS                             Status;\r
-  UINTN                                  TimerIndex;\r
-  UINTN                                  MsiTimerIndex;\r
-  HPET_TIMER_MSI_ROUTE_REGISTER          HpetTimerMsiRoute;\r
+  EFI_STATUS                     Status;\r
+  UINTN                          TimerIndex;\r
+  UINTN                          MsiTimerIndex;\r
+  HPET_TIMER_MSI_ROUTE_REGISTER  HpetTimerMsiRoute;\r
 \r
   DEBUG ((DEBUG_INFO, "Init HPET Timer Driver\n"));\r
 \r
@@ -667,22 +778,22 @@ TimerDriverInitialize (
   //\r
   // Find the CPU architectural protocol.\r
   //\r
-  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mCpu);\r
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&mCpu);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   //\r
   // Retrieve HPET Capabilities and Configuration Information\r
-  //  \r
+  //\r
   mHpetGeneralCapabilities.Uint64  = HpetRead (HPET_GENERAL_CAPABILITIES_ID_OFFSET);\r
   mHpetGeneralConfiguration.Uint64 = HpetRead (HPET_GENERAL_CONFIGURATION_OFFSET);\r
\r
+\r
   //\r
-  // If Revision is not valid, then ASSERT() and unload the driver because the HPET \r
+  // If Revision is not valid, then ASSERT() and unload the driver because the HPET\r
   // device is not present.\r
-  //  \r
+  //\r
   ASSERT (mHpetGeneralCapabilities.Uint64 != 0);\r
   ASSERT (mHpetGeneralCapabilities.Uint64 != 0xFFFFFFFFFFFFFFFFULL);\r
-  if (mHpetGeneralCapabilities.Uint64 == 0 || mHpetGeneralCapabilities.Uint64 == 0xFFFFFFFFFFFFFFFFULL) {\r
+  if ((mHpetGeneralCapabilities.Uint64 == 0) || (mHpetGeneralCapabilities.Uint64 == 0xFFFFFFFFFFFFFFFFULL)) {\r
     DEBUG ((DEBUG_ERROR, "HPET device is not present.  Unload HPET driver.\n"));\r
     return EFI_DEVICE_ERROR;\r
   }\r
@@ -694,25 +805,31 @@ TimerDriverInitialize (
 \r
   //\r
   // Dump HPET Configuration Information\r
-  //  \r
-  DEBUG_CODE (\r
-    DEBUG ((DEBUG_INFO, "HPET Base Address = %08x\n", PcdGet32 (PcdHpetBaseAddress)));\r
-    DEBUG ((DEBUG_INFO, "  HPET_GENERAL_CAPABILITIES_ID  = %016lx\n", mHpetGeneralCapabilities));\r
-    DEBUG ((DEBUG_INFO, "  HPET_GENERAL_CONFIGURATION    = %016lx\n", mHpetGeneralConfiguration.Uint64));\r
-    DEBUG ((DEBUG_INFO, "  HPET_GENERAL_INTERRUPT_STATUS = %016lx\n", HpetRead (HPET_GENERAL_INTERRUPT_STATUS_OFFSET)));\r
-    DEBUG ((DEBUG_INFO, "  HPET_MAIN_COUNTER             = %016lx\n", HpetRead (HPET_MAIN_COUNTER_OFFSET)));\r
-    DEBUG ((DEBUG_INFO, "  HPET Main Counter Period      = %d (fs)\n", mHpetGeneralCapabilities.Bits.CounterClockPeriod));\r
-    for (TimerIndex = 0; TimerIndex <= mHpetGeneralCapabilities.Bits.NumberOfTimers; TimerIndex++) {\r
-      DEBUG ((DEBUG_INFO, "  HPET_TIMER%d_CONFIGURATION     = %016lx\n", TimerIndex, HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + TimerIndex * HPET_TIMER_STRIDE)));\r
-      DEBUG ((DEBUG_INFO, "  HPET_TIMER%d_COMPARATOR        = %016lx\n", TimerIndex, HpetRead (HPET_TIMER_COMPARATOR_OFFSET    + TimerIndex * HPET_TIMER_STRIDE)));\r
-      DEBUG ((DEBUG_INFO, "  HPET_TIMER%d_MSI_ROUTE         = %016lx\n", TimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET     + TimerIndex * HPET_TIMER_STRIDE)));\r
-    }\r
-  );\r
-  \r
   //\r
-  // Determine the interrupt mode to use for the HPET Timer.  \r
+  DEBUG_CODE_BEGIN ();\r
+  DEBUG ((DEBUG_INFO, "HPET Base Address = 0x%08x\n", PcdGet32 (PcdHpetBaseAddress)));\r
+  DEBUG ((DEBUG_INFO, "  HPET_GENERAL_CAPABILITIES_ID  = 0x%016lx\n", mHpetGeneralCapabilities));\r
+  DEBUG ((DEBUG_INFO, "  HPET_GENERAL_CONFIGURATION    = 0x%016lx\n", mHpetGeneralConfiguration.Uint64));\r
+  DEBUG ((DEBUG_INFO, "  HPET_GENERAL_INTERRUPT_STATUS = 0x%016lx\n", HpetRead (HPET_GENERAL_INTERRUPT_STATUS_OFFSET)));\r
+  DEBUG ((DEBUG_INFO, "  HPET_MAIN_COUNTER             = 0x%016lx\n", HpetRead (HPET_MAIN_COUNTER_OFFSET)));\r
+  DEBUG ((DEBUG_INFO, "  HPET Main Counter Period      = %d (fs)\n", mHpetGeneralCapabilities.Bits.CounterClockPeriod));\r
+  for (TimerIndex = 0; TimerIndex <= mHpetGeneralCapabilities.Bits.NumberOfTimers; TimerIndex++) {\r
+    DEBUG ((DEBUG_INFO, "  HPET_TIMER%d_CONFIGURATION     = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + TimerIndex * HPET_TIMER_STRIDE)));\r
+    DEBUG ((DEBUG_INFO, "  HPET_TIMER%d_COMPARATOR        = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_COMPARATOR_OFFSET    + TimerIndex * HPET_TIMER_STRIDE)));\r
+    DEBUG ((DEBUG_INFO, "  HPET_TIMER%d_MSI_ROUTE         = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET     + TimerIndex * HPET_TIMER_STRIDE)));\r
+  }\r
+\r
+  DEBUG_CODE_END ();\r
+\r
+  //\r
+  // Capture the current HPET main counter value.\r
+  //\r
+  mPreviousMainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
+\r
+  //\r
+  // Determine the interrupt mode to use for the HPET Timer.\r
   // Look for MSI first, then unused PIC mode interrupt, then I/O APIC mode interrupt\r
-  //  \r
+  //\r
   MsiTimerIndex = HPET_INVALID_TIMER_INDEX;\r
   mTimerIndex   = HPET_INVALID_TIMER_INDEX;\r
   for (TimerIndex = 0; TimerIndex <= mHpetGeneralCapabilities.Bits.NumberOfTimers; TimerIndex++) {\r
@@ -720,11 +837,11 @@ TimerDriverInitialize (
     // Read the HPET Timer Capabilities and Configuration register\r
     //\r
     mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + TimerIndex * HPET_TIMER_STRIDE);\r
-    \r
+\r
     //\r
-    // Check to see if this HPET Timer supports MSI \r
+    // Check to see if this HPET Timer supports MSI\r
     //\r
-    if (mTimerConfiguration.Bits.MsiInterruptCapablity != 0) {\r
+    if (mTimerConfiguration.Bits.MsiInterruptCapability != 0) {\r
       //\r
       // Save the index of the first HPET Timer that supports MSI interrupts\r
       //\r
@@ -732,7 +849,7 @@ TimerDriverInitialize (
         MsiTimerIndex = TimerIndex;\r
       }\r
     }\r
-    \r
+\r
     //\r
     // Check to see if this HPET Timer supports I/O APIC interrupts\r
     //\r
@@ -747,11 +864,11 @@ TimerDriverInitialize (
     }\r
   }\r
 \r
-  if (FeaturePcdGet (PcdHpetMsiEnable) && MsiTimerIndex != HPET_INVALID_TIMER_INDEX) {\r
+  if (FeaturePcdGet (PcdHpetMsiEnable) && (MsiTimerIndex != HPET_INVALID_TIMER_INDEX)) {\r
     //\r
     // Use MSI interrupt if supported\r
     //\r
-    mTimerIndex  = MsiTimerIndex;\r
+    mTimerIndex = MsiTimerIndex;\r
 \r
     //\r
     // Program MSI Address and MSI Data values in the selected HPET Timer\r
@@ -764,7 +881,7 @@ TimerDriverInitialize (
     // Read the HPET Timer Capabilities and Configuration register and initialize for MSI mode\r
     //   Clear LevelTriggeredInterrupt to use edge triggered interrupts when in MSI mode\r
     //\r
-    mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
+    mTimerConfiguration.Uint64                       = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
     mTimerConfiguration.Bits.LevelTriggeredInterrupt = 0;\r
   } else {\r
     //\r
@@ -775,7 +892,7 @@ TimerDriverInitialize (
       DEBUG ((DEBUG_ERROR, "No HPET timers support MSI or I/O APIC mode.  Unload HPET driver.\n"));\r
       return EFI_DEVICE_ERROR;\r
     }\r
-    \r
+\r
     //\r
     // Initialize I/O APIC entry for HPET Timer Interrupt\r
     //   Fixed Delivery Mode, Level Triggered, Asserted Low\r
@@ -788,22 +905,43 @@ TimerDriverInitialize (
     //   Set LevelTriggeredInterrupt to use level triggered interrupts when in I/O APIC mode\r
     //   Set InterruptRoute field based in mTimerIrq\r
     //\r
-    mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
+    mTimerConfiguration.Uint64                       = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
     mTimerConfiguration.Bits.LevelTriggeredInterrupt = 1;\r
     mTimerConfiguration.Bits.InterruptRoute          = mTimerIrq;\r
   }\r
 \r
   //\r
   // Configure the selected HPET Timer with settings common to both MSI mode and I/O APIC mode\r
-  //   Clear InterruptEnable to keep interrupts disabled until full init is complete \r
-  //   Clear PeriodicInterruptEnable to use one-shot mode \r
-  //   Configure as a 32-bit counter  \r
+  //   Clear InterruptEnable to keep interrupts disabled until full init is complete\r
+  //   Clear PeriodicInterruptEnable to use one-shot mode\r
+  //   Configure as a 32-bit counter\r
   //\r
   mTimerConfiguration.Bits.InterruptEnable         = 0;\r
   mTimerConfiguration.Bits.PeriodicInterruptEnable = 0;\r
-  mTimerConfiguration.Bits.CounterSizeEnable       = 0;\r
+  mTimerConfiguration.Bits.CounterSizeEnable       = 1;\r
   HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64);\r
 \r
+  //\r
+  // Read the HPET Timer Capabilities and Configuration register back again.\r
+  // CounterSizeEnable will be read back as a 0 if it is a 32-bit only timer\r
+  //\r
+  mTimerConfiguration.Uint64 = HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE);\r
+  if ((mTimerConfiguration.Bits.CounterSizeEnable == 1) && (sizeof (UINTN) == sizeof (UINT64))) {\r
+    DEBUG ((DEBUG_INFO, "Choose 64-bit HPET timer.\n"));\r
+    //\r
+    // 64-bit BIOS can use 64-bit HPET timer\r
+    //\r
+    mCounterMask = 0xffffffffffffffffULL;\r
+    //\r
+    // Set timer back to 64-bit\r
+    //\r
+    mTimerConfiguration.Bits.CounterSizeEnable = 0;\r
+    HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64);\r
+  } else {\r
+    DEBUG ((DEBUG_INFO, "Choose 32-bit HPET timer.\n"));\r
+    mCounterMask = 0x00000000ffffffffULL;\r
+  }\r
+\r
   //\r
   // Install interrupt handler for selected HPET Timer\r
   //\r
@@ -827,30 +965,37 @@ TimerDriverInitialize (
   //\r
   // Show state of enabled HPET timer\r
   //\r
-  DEBUG_CODE (\r
-    if (mTimerConfiguration.Bits.MsiInterruptCapablity != 0 && FeaturePcdGet (PcdHpetMsiEnable)) {\r
-      DEBUG ((DEBUG_INFO, "HPET Interrupt Mode MSI\n"));\r
-    } else {\r
-      DEBUG ((DEBUG_INFO, "HPET Interrupt Mode I/O APIC\n"));\r
-      DEBUG ((DEBUG_INFO, "HPET I/O APIC IRQ         = %02x\n",   mTimerIrq));\r
-    }  \r
-    DEBUG ((DEBUG_INFO, "HPET Interrupt Vector     = %02x\n",   PcdGet8 (PcdHpetLocalApicVector)));\r
-    DEBUG ((DEBUG_INFO, "HPET_TIMER%d_CONFIGURATION = %016lx\n", mTimerIndex, HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE)));\r
-    DEBUG ((DEBUG_INFO, "HPET_TIMER%d_COMPARATOR    = %016lx\n", mTimerIndex, HpetRead (HPET_TIMER_COMPARATOR_OFFSET    + mTimerIndex * HPET_TIMER_STRIDE)));\r
-    DEBUG ((DEBUG_INFO, "HPET_TIMER%d_MSI_ROUTE     = %016lx\n", mTimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET     + mTimerIndex * HPET_TIMER_STRIDE)));\r
-\r
-    //\r
-    // Wait for a few timer interrupts to fire before continuing\r
-    // \r
-    while (mNumTicks < 10);\r
-  );\r
\r
+  DEBUG_CODE_BEGIN ();\r
+  if ((mTimerConfiguration.Bits.MsiInterruptCapability != 0) && FeaturePcdGet (PcdHpetMsiEnable)) {\r
+    DEBUG ((DEBUG_INFO, "HPET Interrupt Mode MSI\n"));\r
+  } else {\r
+    DEBUG ((DEBUG_INFO, "HPET Interrupt Mode I/O APIC\n"));\r
+    DEBUG ((DEBUG_INFO, "HPET I/O APIC IRQ         = 0x%02x\n", mTimerIrq));\r
+  }\r
+\r
+  DEBUG ((DEBUG_INFO, "HPET Interrupt Vector     = 0x%02x\n", PcdGet8 (PcdHpetLocalApicVector)));\r
+  DEBUG ((DEBUG_INFO, "HPET Counter Mask         = 0x%016lx\n", mCounterMask));\r
+  DEBUG ((DEBUG_INFO, "HPET Timer Period         = %d\n", mTimerPeriod));\r
+  DEBUG ((DEBUG_INFO, "HPET Timer Count          = 0x%016lx\n", mTimerCount));\r
+  DEBUG ((DEBUG_INFO, "HPET_TIMER%d_CONFIGURATION = 0x%016lx\n", mTimerIndex, HpetRead (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE)));\r
+  DEBUG ((DEBUG_INFO, "HPET_TIMER%d_COMPARATOR    = 0x%016lx\n", mTimerIndex, HpetRead (HPET_TIMER_COMPARATOR_OFFSET    + mTimerIndex * HPET_TIMER_STRIDE)));\r
+  DEBUG ((DEBUG_INFO, "HPET_TIMER%d_MSI_ROUTE     = 0x%016lx\n", mTimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET     + mTimerIndex * HPET_TIMER_STRIDE)));\r
+\r
+  //\r
+  // Wait for a few timer interrupts to fire before continuing\r
+  //\r
+  while (mNumTicks < 10) {\r
+  }\r
+\r
+  DEBUG_CODE_END ();\r
+\r
   //\r
   // Install the Timer Architectural Protocol onto a new handle\r
   //\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &mTimerHandle,\r
-                  &gEfiTimerArchProtocolGuid, &mTimer,\r
+                  &gEfiTimerArchProtocolGuid,\r
+                  &mTimer,\r
                   NULL\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r