1/** @file 2 Timer Library functions built upon ACPI on IA32/x64. 3 4 ACPI power management timer is a 24-bit or 32-bit fixed rate free running count-up 5 timer that runs off a 3.579545 MHz clock. 6 When startup, Duet will check the FADT to determine whether the PM timer is a 7 32-bit or 24-bit timer. 8 9 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> 10 This program and the accompanying materials 11 are licensed and made available under the terms and conditions of the BSD License 12 which accompanies this distribution. The full text of the license may be found at 13 http://opensource.org/licenses/bsd-license.php 14 15 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 16 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 17 18**/ 19 20#include <Base.h> 21#include <Library/TimerLib.h> 22#include <Library/BaseLib.h> 23#include <Library/DebugLib.h> 24#include <Library/HobLib.h> 25#include <Guid/AcpiDescription.h> 26#include <Library/IoLib.h> 27#include <Library/PciLib.h> 28 29EFI_ACPI_DESCRIPTION *gAcpiDesc = NULL; 30 31/** 32 Internal function to get Acpi information from HOB. 33 34 @return Pointer to ACPI description structure. 35**/ 36EFI_ACPI_DESCRIPTION* 37InternalGetApciDescrptionTable ( 38 VOID 39 ) 40{ 41 EFI_PEI_HOB_POINTERS GuidHob; 42 43 if (gAcpiDesc != NULL) { 44 return gAcpiDesc; 45 } 46 47 GuidHob.Raw = GetFirstGuidHob (&gEfiAcpiDescriptionGuid); 48 if (GuidHob.Raw != NULL) { 49 gAcpiDesc = GET_GUID_HOB_DATA (GuidHob.Guid); 50 DEBUG ((EFI_D_INFO, "ACPI Timer: PM_TMR_BLK.RegisterBitWidth = 0x%X\n", gAcpiDesc->PM_TMR_BLK.RegisterBitWidth)); 51 DEBUG ((EFI_D_INFO, "ACPI Timer: PM_TMR_BLK.Address = 0x%X\n", gAcpiDesc->PM_TMR_BLK.Address)); 52 return gAcpiDesc; 53 } else { 54 DEBUG ((EFI_D_ERROR, "Fail to get Acpi description table from hob\n")); 55 return NULL; 56 } 57} 58 59/** 60 Internal function to read the current tick counter of ACPI. 61 62 @return The tick counter read. 63 64**/ 65STATIC 66UINT32 67InternalAcpiGetTimerTick ( 68 VOID 69 ) 70{ 71 return IoRead32 ((UINTN)gAcpiDesc->PM_TMR_BLK.Address); 72} 73 74/** 75 Stalls the CPU for at least the given number of ticks. 76 77 Stalls the CPU for at least the given number of ticks. It's invoked by 78 MicroSecondDelay() and NanoSecondDelay(). 79 80 @param Delay A period of time to delay in ticks. 81 82**/ 83STATIC 84VOID 85InternalAcpiDelay ( 86 IN UINT32 Delay 87 ) 88{ 89 UINT32 Ticks; 90 UINT32 Times; 91 92 Times = Delay >> (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2); 93 Delay &= (1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2)) - 1; 94 do { 95 // 96 // The target timer count is calculated here 97 // 98 Ticks = InternalAcpiGetTimerTick () + Delay; 99 Delay = 1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 2); 100 // 101 // Wait until time out 102 // Delay >= 2^23 (if ACPI provide 24-bit timer) or Delay >= 2^31 (if ACPI 103 // provide 32-bit timer) could not be handled by this function 104 // Timer wrap-arounds are handled correctly by this function 105 // 106 while (((Ticks - InternalAcpiGetTimerTick ()) & (1 << (gAcpiDesc->PM_TMR_BLK.RegisterBitWidth - 1))) == 0) { 107 CpuPause (); 108 } 109 } while (Times-- > 0); 110} 111 112/** 113 Stalls the CPU for at least the given number of microseconds. 114 115 Stalls the CPU for the number of microseconds specified by MicroSeconds. 116 117 @param MicroSeconds The minimum number of microseconds to delay. 118 119 @return MicroSeconds 120 121**/ 122UINTN 123EFIAPI 124MicroSecondDelay ( 125 IN UINTN MicroSeconds 126 ) 127{ 128 129 if (InternalGetApciDescrptionTable() == NULL) { 130 return MicroSeconds; 131 } 132 133 InternalAcpiDelay ( 134 (UINT32)DivU64x32 ( 135 MultU64x32 ( 136 MicroSeconds, 137 3579545 138 ), 139 1000000u 140 ) 141 ); 142 return MicroSeconds; 143} 144 145/** 146 Stalls the CPU for at least the given number of nanoseconds. 147 148 Stalls the CPU for the number of nanoseconds specified by NanoSeconds. 149 150 @param NanoSeconds The minimum number of nanoseconds to delay. 151 152 @return NanoSeconds 153 154**/ 155UINTN 156EFIAPI 157NanoSecondDelay ( 158 IN UINTN NanoSeconds 159 ) 160{ 161 if (InternalGetApciDescrptionTable() == NULL) { 162 return NanoSeconds; 163 } 164 165 InternalAcpiDelay ( 166 (UINT32)DivU64x32 ( 167 MultU64x32 ( 168 NanoSeconds, 169 3579545 170 ), 171 1000000000u 172 ) 173 ); 174 return NanoSeconds; 175} 176 177/** 178 Retrieves the current value of a 64-bit free running performance counter. 179 180 Retrieves the current value of a 64-bit free running performance counter. The 181 counter can either count up by 1 or count down by 1. If the physical 182 performance counter counts by a larger increment, then the counter values 183 must be translated. The properties of the counter can be retrieved from 184 GetPerformanceCounterProperties(). 185 186 @return The current value of the free running performance counter. 187 188**/ 189UINT64 190EFIAPI 191GetPerformanceCounter ( 192 VOID 193 ) 194{ 195 if (InternalGetApciDescrptionTable() == NULL) { 196 return 0; 197 } 198 199 return (UINT64)InternalAcpiGetTimerTick (); 200} 201 202/** 203 Retrieves the 64-bit frequency in Hz and the range of performance counter 204 values. 205 206 If StartValue is not NULL, then the value that the performance counter starts 207 with immediately after is it rolls over is returned in StartValue. If 208 EndValue is not NULL, then the value that the performance counter end with 209 immediately before it rolls over is returned in EndValue. The 64-bit 210 frequency of the performance counter in Hz is always returned. If StartValue 211 is less than EndValue, then the performance counter counts up. If StartValue 212 is greater than EndValue, then the performance counter counts down. For 213 example, a 64-bit free running counter that counts up would have a StartValue 214 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter 215 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. 216 217 @param StartValue The value the performance counter starts with when it 218 rolls over. 219 @param EndValue The value that the performance counter ends with before 220 it rolls over. 221 222 @return The frequency in Hz. 223 224**/ 225UINT64 226EFIAPI 227GetPerformanceCounterProperties ( 228 OUT UINT64 *StartValue, OPTIONAL 229 OUT UINT64 *EndValue OPTIONAL 230 ) 231{ 232 if (InternalGetApciDescrptionTable() == NULL) { 233 return 0; 234 } 235 236 if (StartValue != NULL) { 237 *StartValue = 0; 238 } 239 240 if (EndValue != NULL) { 241 *EndValue = (1 << gAcpiDesc->PM_TMR_BLK.RegisterBitWidth) - 1; 242 } 243 244 return 3579545; 245} 246 247/** 248 Converts elapsed ticks of performance counter to time in nanoseconds. 249 250 This function converts the elapsed ticks of running performance counter to 251 time value in unit of nanoseconds. 252 253 @param Ticks The number of elapsed ticks of running performance counter. 254 255 @return The elapsed time in nanoseconds. 256 257**/ 258UINT64 259EFIAPI 260GetTimeInNanoSecond ( 261 IN UINT64 Ticks 262 ) 263{ 264 UINT64 NanoSeconds; 265 UINT32 Remainder; 266 267 // 268 // Ticks 269 // Time = --------- x 1,000,000,000 270 // Frequency 271 // 272 NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, 3579545, &Remainder), 1000000000u); 273 274 // 275 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000) 276 // will not overflow 64-bit. 277 // 278 NanoSeconds += DivU64x32 (MultU64x32 ((UINT64) Remainder, 1000000000u), 3579545); 279 280 return NanoSeconds; 281} 282