EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

PcAtChipsetPkg/8254TimerDxe/Timer.c

Go to the documentation of this file.
00001 
00015 #include "Timer.h"
00016 
00017 //
00018 // The handle onto which the Timer Architectural Protocol will be installed
00019 //
00020 EFI_HANDLE                mTimerHandle = NULL;
00021 
00022 //
00023 // The Timer Architectural Protocol that this driver produces
00024 //
00025 EFI_TIMER_ARCH_PROTOCOL   mTimer = {
00026   TimerDriverRegisterHandler,
00027   TimerDriverSetTimerPeriod,
00028   TimerDriverGetTimerPeriod,
00029   TimerDriverGenerateSoftInterrupt
00030 };
00031 
00032 //
00033 // Pointer to the CPU Architectural Protocol instance
00034 //
00035 EFI_CPU_ARCH_PROTOCOL     *mCpu;
00036 
00037 //
00038 // Pointer to the Legacy 8259 Protocol instance
00039 //
00040 EFI_LEGACY_8259_PROTOCOL  *mLegacy8259;
00041 
00042 //
00043 // The notification function to call on every timer interrupt.
00044 // A bug in the compiler prevents us from initializing this here.
00045 //
00046 EFI_TIMER_NOTIFY mTimerNotifyFunction;
00047 
00048 //
00049 // The current period of the timer interrupt
00050 //
00051 volatile UINT64           mTimerPeriod = 0;
00052 
00053 //
00054 // Worker Functions
00055 //
00061 VOID
00062 SetPitCount (
00063   IN UINT16  Count
00064   )
00065 {
00066   IoWrite8 (TIMER_CONTROL_PORT, 0x36);
00067   IoWrite8 (TIMER0_COUNT_PORT, (UINT8)(Count & 0xff));
00068   IoWrite8 (TIMER0_COUNT_PORT, (UINT8)((Count >> 8) & 0xff));
00069 }
00070 
00077 VOID
00078 EFIAPI
00079 TimerInterruptHandler (
00080   IN EFI_EXCEPTION_TYPE   InterruptType,
00081   IN EFI_SYSTEM_CONTEXT   SystemContext
00082   )
00083 {
00084   EFI_TPL OriginalTPL;
00085 
00086   OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
00087 
00088   mLegacy8259->EndOfInterrupt (mLegacy8259, Efi8259Irq0);
00089 
00090   if (mTimerNotifyFunction != NULL) {
00091     //
00092     // @bug : This does not handle missed timer interrupts
00093     //
00094     mTimerNotifyFunction (mTimerPeriod);
00095   }
00096 
00097   gBS->RestoreTPL (OriginalTPL);
00098 }
00099 
00131 EFI_STATUS
00132 EFIAPI
00133 TimerDriverRegisterHandler (
00134   IN EFI_TIMER_ARCH_PROTOCOL  *This,
00135   IN EFI_TIMER_NOTIFY         NotifyFunction
00136   )
00137 {
00138   //
00139   // Check for invalid parameters
00140   //
00141   if (NotifyFunction == NULL && mTimerNotifyFunction == NULL) {
00142     return EFI_INVALID_PARAMETER;
00143   }
00144 
00145   if (NotifyFunction != NULL && mTimerNotifyFunction != NULL) {
00146     return EFI_ALREADY_STARTED;
00147   }
00148 
00149   mTimerNotifyFunction = NotifyFunction;
00150 
00151   return EFI_SUCCESS;
00152 }
00153 
00182 EFI_STATUS
00183 EFIAPI
00184 TimerDriverSetTimerPeriod (
00185   IN EFI_TIMER_ARCH_PROTOCOL  *This,
00186   IN UINT64                   TimerPeriod
00187   )
00188 {
00189   UINT64  TimerCount;
00190 
00191   //
00192   //  The basic clock is 1.19318 MHz or 0.119318 ticks per 100 ns.
00193   //  TimerPeriod * 0.119318 = 8254 timer divisor. Using integer arithmetic
00194   //  TimerCount = (TimerPeriod * 119318)/1000000.
00195   //
00196   //  Round up to next highest integer. This guarantees that the timer is
00197   //  equal to or slightly longer than the requested time.
00198   //  TimerCount = ((TimerPeriod * 119318) + 500000)/1000000
00199   //
00200   // Note that a TimerCount of 0 is equivalent to a count of 65,536
00201   //
00202   // Since TimerCount is limited to 16 bits for IA32, TimerPeriod is limited
00203   // to 20 bits.
00204   //
00205   if (TimerPeriod == 0) {
00206     //
00207     // Disable timer interrupt for a TimerPeriod of 0
00208     //
00209     mLegacy8259->DisableIrq (mLegacy8259, Efi8259Irq0);
00210   } else {
00211 
00212     //
00213     // Convert TimerPeriod into 8254 counts
00214     //
00215     TimerCount = DivU64x32 (MultU64x32 (119318, (UINT32) TimerPeriod) + 500000, 1000000);
00216 
00217     //
00218     // Check for overflow
00219     //
00220     if (TimerCount >= 65536) {
00221       TimerCount = 0;
00222       if (TimerPeriod >= DEFAULT_TIMER_TICK_DURATION) {
00223         TimerPeriod = DEFAULT_TIMER_TICK_DURATION;
00224       }
00225     }
00226     //
00227     // Program the 8254 timer with the new count value
00228     //
00229     SetPitCount ((UINT16) TimerCount);
00230 
00231     //
00232     // Enable timer interrupt
00233     //
00234     mLegacy8259->EnableIrq (mLegacy8259, Efi8259Irq0, FALSE);
00235   }
00236   //
00237   // Save the new timer period
00238   //
00239   mTimerPeriod = TimerPeriod;
00240 
00241   return EFI_SUCCESS;
00242 }
00243 
00260 EFI_STATUS
00261 EFIAPI
00262 TimerDriverGetTimerPeriod (
00263   IN EFI_TIMER_ARCH_PROTOCOL   *This,
00264   OUT UINT64                   *TimerPeriod
00265   )
00266 {
00267   if (TimerPeriod == NULL) {
00268     return EFI_INVALID_PARAMETER;
00269   }
00270 
00271   *TimerPeriod = mTimerPeriod;
00272 
00273   return EFI_SUCCESS;
00274 }
00275 
00293 EFI_STATUS
00294 EFIAPI
00295 TimerDriverGenerateSoftInterrupt (
00296   IN EFI_TIMER_ARCH_PROTOCOL  *This
00297   )
00298 {
00299   EFI_STATUS  Status;
00300   UINT16      IRQMask;
00301   EFI_TPL     OriginalTPL;
00302   
00303   //
00304   // If the timer interrupt is enabled, then the registered handler will be invoked.
00305   //
00306   Status = mLegacy8259->GetMask (mLegacy8259, NULL, NULL, &IRQMask, NULL);
00307   ASSERT_EFI_ERROR (Status);
00308   if ((IRQMask & 0x1) == 0) {
00309     //
00310     // Invoke the registered handler
00311     //
00312     OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
00313 
00314     if (mTimerNotifyFunction != NULL) {
00315       //
00316       // @bug : This does not handle missed timer interrupts
00317       //
00318       mTimerNotifyFunction (mTimerPeriod);
00319     }
00320    
00321     gBS->RestoreTPL (OriginalTPL);
00322   } else {
00323     return EFI_UNSUPPORTED;
00324   }
00325 
00326   return EFI_SUCCESS;
00327 }
00328 
00340 EFI_STATUS
00341 EFIAPI
00342 TimerDriverInitialize (
00343   IN EFI_HANDLE        ImageHandle,
00344   IN EFI_SYSTEM_TABLE  *SystemTable
00345   )
00346 {
00347   EFI_STATUS  Status;
00348   UINT32      TimerVector;
00349 
00350   //
00351   // Initialize the pointer to our notify function.
00352   //
00353   mTimerNotifyFunction = NULL;
00354 
00355   //
00356   // Make sure the Timer Architectural Protocol is not already installed in the system
00357   //
00358   ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiTimerArchProtocolGuid);
00359 
00360   //
00361   // Find the CPU architectural protocol.
00362   //
00363   Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &mCpu);
00364   ASSERT_EFI_ERROR (Status);
00365 
00366   //
00367   // Find the Legacy8259 protocol.
00368   //
00369   Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &mLegacy8259);
00370   ASSERT_EFI_ERROR (Status);
00371 
00372   //
00373   // Force the timer to be disabled
00374   //
00375   Status = TimerDriverSetTimerPeriod (&mTimer, 0);
00376   ASSERT_EFI_ERROR (Status);
00377 
00378   //
00379   // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver
00380   //
00381   TimerVector = 0;
00382   Status      = mLegacy8259->GetVector (mLegacy8259, Efi8259Irq0, (UINT8 *) &TimerVector);
00383   ASSERT_EFI_ERROR (Status);
00384 
00385   //
00386   // Install interrupt handler for 8254 Timer #0 (ISA IRQ0)
00387   //
00388   Status = mCpu->RegisterInterruptHandler (mCpu, TimerVector, TimerInterruptHandler);
00389   ASSERT_EFI_ERROR (Status);
00390 
00391   //
00392   // Force the timer to be enabled at its default period
00393   //
00394   Status = TimerDriverSetTimerPeriod (&mTimer, DEFAULT_TIMER_TICK_DURATION);
00395   ASSERT_EFI_ERROR (Status);
00396 
00397   //
00398   // Install the Timer Architectural Protocol onto a new handle
00399   //
00400   Status = gBS->InstallMultipleProtocolInterfaces (
00401                   &mTimerHandle,
00402                   &gEfiTimerArchProtocolGuid, &mTimer,
00403                   NULL
00404                   );
00405   ASSERT_EFI_ERROR (Status);
00406 
00407   return Status;
00408 }
00409 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines