/** @file\r
Timer Architectural Protocol module using High Precesion Event Timer (HPET)\r
\r
- Copyright (c) 2011 - 2016, 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
\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
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
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
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
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
// Disable HPET timer when adjusting the COMPARATOR value to prevent a missed interrupt\r
//\r
HpetEnable (FALSE);\r
- \r
+\r
//\r
// Capture main counter value\r
//\r
// Enable the HPET counter once the new COMPARATOR value has been set.\r
//\r
HpetEnable (TRUE);\r
- \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
MultU64x32 (\r
Delta & mCounterMask,\r
mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
- ), \r
+ ),\r
100000000\r
);\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
//\r
// Save main counter value\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
\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
IN UINT64 TimerPeriod\r
)\r
{\r
+ EFI_TPL Tpl;\r
UINT64 MainCounter;\r
UINT64 Delta;\r
UINT64 CurrentComparator;\r
HPET_TIMER_MSI_ROUTE_REGISTER HpetTimerMsiRoute;\r
- \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
MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
if (MainCounter < mPreviousMainCounter) {\r
Delta = (mCounterMask - mPreviousMainCounter) + MainCounter;\r
- } else { \r
+ } else {\r
Delta = MainCounter - mPreviousMainCounter;\r
}\r
if ((Delta & mCounterMask) >= mTimerCount) {\r
//\r
// If TimerPeriod is 0, then mask HPET Timer interrupts\r
//\r
- \r
+\r
if (mTimerConfiguration.Bits.MsiInterruptCapablity != 0 && FeaturePcdGet (PcdHpetMsiEnable)) {\r
//\r
// Disable HPET MSI interrupt generation\r
//\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
+ //\r
mTimerCount = DivU64x32 (\r
MultU64x32 (TimerPeriod, 100000000),\r
mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
MainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
if (MainCounter > mPreviousMainCounter) {\r
Delta = MainCounter - mPreviousMainCounter;\r
- } else { \r
+ } else {\r
Delta = (mCounterMask - mPreviousMainCounter) + MainCounter;\r
}\r
if ((Delta & mCounterMask) >= mTimerCount) {\r
HpetWrite (HPET_TIMER_COMPARATOR_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, (MainCounter + 1) & mCounterMask);\r
- } else { \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
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
// 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
\r
//\r
// Disable interrupts\r
- // \r
+ //\r
Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
- \r
+\r
//\r
// Capture main counter value\r
//\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
MultU64x32 (\r
Delta & mCounterMask,\r
mHpetGeneralCapabilities.Bits.CounterClockPeriod\r
- ), \r
+ ),\r
100000000\r
);\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
// Save main counter value\r
//\r
mPreviousMainCounter = MainCounter;\r
- \r
+\r
//\r
// Restore interrupts\r
- // \r
+ //\r
gBS->RestoreTPL (Tpl);\r
- \r
+\r
return EFI_SUCCESS;\r
}\r
\r
\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
\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
\r
//\r
// Dump HPET Configuration Information\r
- // \r
+ //\r
DEBUG_CODE (\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_TIMER%d_MSI_ROUTE = 0x%016lx\n", TimerIndex, HpetRead (HPET_TIMER_MSI_ROUTE_OFFSET + TimerIndex * HPET_TIMER_STRIDE)));\r
}\r
);\r
- \r
+\r
//\r
// Capture the current HPET main counter value.\r
//\r
mPreviousMainCounter = HpetRead (HPET_MAIN_COUNTER_OFFSET);\r
- \r
+\r
//\r
- // Determine the interrupt mode to use for the HPET Timer. \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
// 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
//\r
MsiTimerIndex = TimerIndex;\r
}\r
}\r
- \r
+\r
//\r
// Check to see if this HPET Timer supports I/O APIC interrupts\r
//\r
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
\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 = 1;\r
HpetWrite (HPET_TIMER_CONFIGURATION_OFFSET + mTimerIndex * HPET_TIMER_STRIDE, mTimerConfiguration.Uint64);\r
- \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
} 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
\r
//\r
// Wait for a few timer interrupts to fire before continuing\r
- // \r
+ //\r
while (mNumTicks < 10);\r
);\r
- \r
+\r
//\r
// Install the Timer Architectural Protocol onto a new handle\r
//\r