Home | History | Annotate | Download | only in AcpiTimerLib
      1 /** @file
      2   ACPI Timer implements one instance of Timer Library.
      3 
      4   Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <Base.h>
     16 #include <Library/TimerLib.h>
     17 #include <Library/BaseLib.h>
     18 #include <Library/PcdLib.h>
     19 #include <Library/PciLib.h>
     20 #include <Library/IoLib.h>
     21 #include <Library/DebugLib.h>
     22 #include <IndustryStandard/Acpi.h>
     23 
     24 /**
     25   Internal function to retrieves the 64-bit frequency in Hz.
     26 
     27   Internal function to retrieves the 64-bit frequency in Hz.
     28 
     29   @return The frequency in Hz.
     30 
     31 **/
     32 UINT64
     33 InternalGetPerformanceCounterFrequency (
     34   VOID
     35   );
     36 
     37 /**
     38   The constructor function enables ACPI IO space.
     39 
     40   If ACPI I/O space not enabled, this function will enable it.
     41   It will always return RETURN_SUCCESS.
     42 
     43   @retval EFI_SUCCESS   The constructor always returns RETURN_SUCCESS.
     44 
     45 **/
     46 RETURN_STATUS
     47 EFIAPI
     48 AcpiTimerLibConstructor (
     49   VOID
     50   )
     51 {
     52   UINTN   Bus;
     53   UINTN   Device;
     54   UINTN   Function;
     55   UINTN   EnableRegister;
     56   UINT8   EnableMask;
     57 
     58   //
     59   // ASSERT for the invalid PCD values. They must be configured to the real value.
     60   //
     61   ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF);
     62   ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress)      != 0xFFFF);
     63 
     64   //
     65   // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then
     66   // no PCI register programming is required to enable access to the the ACPI registers
     67   // specified by PcdAcpiIoPortBaseAddress
     68   //
     69   if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) {
     70     return RETURN_SUCCESS;
     71   }
     72 
     73   //
     74   // ASSERT for the invalid PCD values. They must be configured to the real value.
     75   //
     76   ASSERT (PcdGet8  (PcdAcpiIoPciDeviceNumber)   != 0xFF);
     77   ASSERT (PcdGet8  (PcdAcpiIoPciFunctionNumber) != 0xFF);
     78   ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF);
     79 
     80   //
     81   // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address
     82   //
     83   Bus            = PcdGet8  (PcdAcpiIoPciBusNumber);
     84   Device         = PcdGet8  (PcdAcpiIoPciDeviceNumber);
     85   Function       = PcdGet8  (PcdAcpiIoPciFunctionNumber);
     86   EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset);
     87   EnableMask     = PcdGet8  (PcdAcpiIoBarEnableMask);
     88 
     89   //
     90   // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it.
     91   //
     92   if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister) & EnableMask) != EnableMask)) {
     93     PciWrite16 (
     94       PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)),
     95       PcdGet16 (PcdAcpiIoPortBaseAddress)
     96       );
     97     PciOr8 (
     98       PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister),
     99       EnableMask
    100       );
    101   }
    102 
    103   return RETURN_SUCCESS;
    104 }
    105 
    106 /**
    107   Internal function to retrieve the ACPI I/O Port Base Address.
    108 
    109   Internal function to retrieve the ACPI I/O Port Base Address.
    110 
    111   @return The 16-bit ACPI I/O Port Base Address.
    112 
    113 **/
    114 UINT16
    115 InternalAcpiGetAcpiTimerIoPort (
    116   VOID
    117   )
    118 {
    119   UINT16  Port;
    120 
    121   Port = PcdGet16 (PcdAcpiIoPortBaseAddress);
    122 
    123   //
    124   // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then
    125   // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a
    126   // value other than PcdAcpiIoPortBaseAddress
    127   //
    128   if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) {
    129     Port = PciRead16 (PCI_LIB_ADDRESS (
    130                         PcdGet8  (PcdAcpiIoPciBusNumber),
    131                         PcdGet8  (PcdAcpiIoPciDeviceNumber),
    132                         PcdGet8  (PcdAcpiIoPciFunctionNumber),
    133                         PcdGet16 (PcdAcpiIoPciBarRegisterOffset)
    134                         ));
    135   }
    136 
    137   return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset);
    138 }
    139 
    140 /**
    141   Stalls the CPU for at least the given number of ticks.
    142 
    143   Stalls the CPU for at least the given number of ticks. It's invoked by
    144   MicroSecondDelay() and NanoSecondDelay().
    145 
    146   @param  Delay     A period of time to delay in ticks.
    147 
    148 **/
    149 VOID
    150 InternalAcpiDelay (
    151   IN UINT32  Delay
    152   )
    153 {
    154   UINT16   Port;
    155   UINT32   Ticks;
    156   UINT32   Times;
    157 
    158   Port   = InternalAcpiGetAcpiTimerIoPort ();
    159   Times  = Delay >> 22;
    160   Delay &= BIT22 - 1;
    161   do {
    162     //
    163     // The target timer count is calculated here
    164     //
    165     Ticks = IoRead32 (Port) + Delay;
    166     Delay = BIT22;
    167     //
    168     // Wait until time out
    169     // Delay >= 2^23 could not be handled by this function
    170     // Timer wrap-arounds are handled correctly by this function
    171     //
    172     while (((Ticks - IoRead32 (Port)) & BIT23) == 0) {
    173       CpuPause ();
    174     }
    175   } while (Times-- > 0);
    176 }
    177 
    178 /**
    179   Stalls the CPU for at least the given number of microseconds.
    180 
    181   Stalls the CPU for the number of microseconds specified by MicroSeconds.
    182 
    183   @param  MicroSeconds  The minimum number of microseconds to delay.
    184 
    185   @return MicroSeconds
    186 
    187 **/
    188 UINTN
    189 EFIAPI
    190 MicroSecondDelay (
    191   IN UINTN  MicroSeconds
    192   )
    193 {
    194   InternalAcpiDelay (
    195     (UINT32)DivU64x32 (
    196               MultU64x32 (
    197                 MicroSeconds,
    198                 ACPI_TIMER_FREQUENCY
    199                 ),
    200               1000000u
    201               )
    202     );
    203   return MicroSeconds;
    204 }
    205 
    206 /**
    207   Stalls the CPU for at least the given number of nanoseconds.
    208 
    209   Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
    210 
    211   @param  NanoSeconds The minimum number of nanoseconds to delay.
    212 
    213   @return NanoSeconds
    214 
    215 **/
    216 UINTN
    217 EFIAPI
    218 NanoSecondDelay (
    219   IN UINTN  NanoSeconds
    220   )
    221 {
    222   InternalAcpiDelay (
    223     (UINT32)DivU64x32 (
    224               MultU64x32 (
    225                 NanoSeconds,
    226                 ACPI_TIMER_FREQUENCY
    227                 ),
    228               1000000000u
    229               )
    230     );
    231   return NanoSeconds;
    232 }
    233 
    234 /**
    235   Retrieves the current value of a 64-bit free running performance counter.
    236 
    237   Retrieves the current value of a 64-bit free running performance counter. The
    238   counter can either count up by 1 or count down by 1. If the physical
    239   performance counter counts by a larger increment, then the counter values
    240   must be translated. The properties of the counter can be retrieved from
    241   GetPerformanceCounterProperties().
    242 
    243   @return The current value of the free running performance counter.
    244 
    245 **/
    246 UINT64
    247 EFIAPI
    248 GetPerformanceCounter (
    249   VOID
    250   )
    251 {
    252   return AsmReadTsc ();
    253 }
    254 
    255 /**
    256   Retrieves the 64-bit frequency in Hz and the range of performance counter
    257   values.
    258 
    259   If StartValue is not NULL, then the value that the performance counter starts
    260   with immediately after is it rolls over is returned in StartValue. If
    261   EndValue is not NULL, then the value that the performance counter end with
    262   immediately before it rolls over is returned in EndValue. The 64-bit
    263   frequency of the performance counter in Hz is always returned. If StartValue
    264   is less than EndValue, then the performance counter counts up. If StartValue
    265   is greater than EndValue, then the performance counter counts down. For
    266   example, a 64-bit free running counter that counts up would have a StartValue
    267   of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
    268   that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
    269 
    270   @param  StartValue  The value the performance counter starts with when it
    271                       rolls over.
    272   @param  EndValue    The value that the performance counter ends with before
    273                       it rolls over.
    274 
    275   @return The frequency in Hz.
    276 
    277 **/
    278 UINT64
    279 EFIAPI
    280 GetPerformanceCounterProperties (
    281   OUT UINT64  *StartValue,  OPTIONAL
    282   OUT UINT64  *EndValue     OPTIONAL
    283   )
    284 {
    285   if (StartValue != NULL) {
    286     *StartValue = 0;
    287   }
    288 
    289   if (EndValue != NULL) {
    290     *EndValue = 0xffffffffffffffffULL;
    291   }
    292   return InternalGetPerformanceCounterFrequency ();
    293 }
    294 
    295 /**
    296   Converts elapsed ticks of performance counter to time in nanoseconds.
    297 
    298   This function converts the elapsed ticks of running performance counter to
    299   time value in unit of nanoseconds.
    300 
    301   @param  Ticks     The number of elapsed ticks of running performance counter.
    302 
    303   @return The elapsed time in nanoseconds.
    304 
    305 **/
    306 UINT64
    307 EFIAPI
    308 GetTimeInNanoSecond (
    309   IN UINT64  Ticks
    310   )
    311 {
    312   UINT64  Frequency;
    313   UINT64  NanoSeconds;
    314   UINT64  Remainder;
    315   INTN    Shift;
    316 
    317   Frequency = GetPerformanceCounterProperties (NULL, NULL);
    318 
    319   //
    320   //          Ticks
    321   // Time = --------- x 1,000,000,000
    322   //        Frequency
    323   //
    324   NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
    325 
    326   //
    327   // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
    328   // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
    329   // i.e. highest bit set in Remainder should <= 33.
    330   //
    331   Shift = MAX (0, HighBitSet64 (Remainder) - 33);
    332   Remainder = RShiftU64 (Remainder, (UINTN) Shift);
    333   Frequency = RShiftU64 (Frequency, (UINTN) Shift);
    334   NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
    335 
    336   return NanoSeconds;
    337 }
    338