1 /** @file 2 ACPI Timer implements one instance of Timer Library. 3 4 5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> 6 SPDX-License-Identifier: BSD-2-Clause-Patent 7 **/ 8 9 #include <Base.h> 10 #include <Library/TimerLib.h> 11 #include <Library/BaseLib.h> 12 #include <Library/PcdLib.h> 13 #include <Library/PciLib.h> 14 #include <Library/IoLib.h> 15 #include <Library/DebugLib.h> 16 #include <IndustryStandard/Acpi.h> 17 // 18 // OVERRIDE: OverrideBegin 19 // 20 #include <Register/Cpuid.h> 21 // 22 // OVERRIDE: OverrideEnd 23 // 24 25 26 /** 27 Internal function to retrieves the 64-bit frequency in Hz. 28 29 Internal function to retrieves the 64-bit frequency in Hz. 30 31 @return The frequency in Hz. 32 33 **/ 34 UINT64 35 InternalGetPerformanceCounterFrequency ( 36 VOID 37 ); 38 39 /** 40 The constructor function enables ACPI IO space. 41 42 If ACPI I/O space not enabled, this function will enable it. 43 It will always return RETURN_SUCCESS. 44 45 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS. 46 47 **/ 48 RETURN_STATUS 49 EFIAPI 50 AcpiTimerLibConstructor ( 51 VOID 52 ) 53 { 54 UINTN Bus; 55 UINTN Device; 56 UINTN Function; 57 UINTN EnableRegister; 58 UINT8 EnableMask; 59 60 // 61 // ASSERT for the invalid PCD values. They must be configured to the real value. 62 // 63 ASSERT (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0xFFFF); 64 ASSERT (PcdGet16 (PcdAcpiIoPortBaseAddress) != 0xFFFF); 65 66 // 67 // If the register offset to the BAR for the ACPI I/O Port Base Address is 0x0000, then 68 // no PCI register programming is required to enable access to the the ACPI registers 69 // specified by PcdAcpiIoPortBaseAddress 70 // 71 if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) == 0x0000) { 72 return RETURN_SUCCESS; 73 } 74 75 // 76 // ASSERT for the invalid PCD values. They must be configured to the real value. 77 // 78 ASSERT (PcdGet8 (PcdAcpiIoPciDeviceNumber) != 0xFF); 79 ASSERT (PcdGet8 (PcdAcpiIoPciFunctionNumber) != 0xFF); 80 ASSERT (PcdGet16 (PcdAcpiIoPciEnableRegisterOffset) != 0xFFFF); 81 82 // 83 // Retrieve the PCD values for the PCI configuration space required to program the ACPI I/O Port Base Address 84 // 85 Bus = PcdGet8 (PcdAcpiIoPciBusNumber); 86 Device = PcdGet8 (PcdAcpiIoPciDeviceNumber); 87 Function = PcdGet8 (PcdAcpiIoPciFunctionNumber); 88 EnableRegister = PcdGet16 (PcdAcpiIoPciEnableRegisterOffset); 89 EnableMask = PcdGet8 (PcdAcpiIoBarEnableMask); 90 91 // 92 // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. 93 // 94 if ((PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister)) & EnableMask) != EnableMask) { 95 PciWrite16 ( 96 PCI_LIB_ADDRESS (Bus, Device, Function, PcdGet16 (PcdAcpiIoPciBarRegisterOffset)), 97 PcdGet16 (PcdAcpiIoPortBaseAddress) 98 ); 99 PciOr8 ( 100 PCI_LIB_ADDRESS (Bus, Device, Function, EnableRegister), 101 EnableMask 102 ); 103 } 104 105 return RETURN_SUCCESS; 106 } 107 108 /** 109 Internal function to retrieve the ACPI I/O Port Base Address. 110 111 Internal function to retrieve the ACPI I/O Port Base Address. 112 113 @return The 16-bit ACPI I/O Port Base Address. 114 115 **/ 116 UINT16 117 InternalAcpiGetAcpiTimerIoPort ( 118 VOID 119 ) 120 { 121 UINT16 Port; 122 123 Port = PcdGet16 (PcdAcpiIoPortBaseAddress); 124 125 // 126 // If the register offset to the BAR for the ACPI I/O Port Base Address is not 0x0000, then 127 // read the PCI register for the ACPI BAR value in case the BAR has been programmed to a 128 // value other than PcdAcpiIoPortBaseAddress 129 // 130 if (PcdGet16 (PcdAcpiIoPciBarRegisterOffset) != 0x0000) { 131 Port = PciRead16 (PCI_LIB_ADDRESS ( 132 PcdGet8 (PcdAcpiIoPciBusNumber), 133 PcdGet8 (PcdAcpiIoPciDeviceNumber), 134 PcdGet8 (PcdAcpiIoPciFunctionNumber), 135 PcdGet16 (PcdAcpiIoPciBarRegisterOffset) 136 )); 137 } 138 139 return (Port & PcdGet16 (PcdAcpiIoPortBaseAddressMask)) + PcdGet16 (PcdAcpiPm1TmrOffset); 140 } 141 142 /** 143 Stalls the CPU for at least the given number of ticks. 144 145 Stalls the CPU for at least the given number of ticks. It's invoked by 146 MicroSecondDelay() and NanoSecondDelay(). 147 148 @param Delay A period of time to delay in ticks. 149 150 **/ 151 VOID 152 InternalAcpiDelay ( 153 IN UINT32 Delay 154 ) 155 { 156 UINT16 Port; 157 UINT32 Ticks; 158 UINT32 Times; 159 160 Port = InternalAcpiGetAcpiTimerIoPort (); 161 Times = Delay >> 22; 162 Delay &= BIT22 - 1; 163 do { 164 // 165 // The target timer count is calculated here 166 // 167 Ticks = IoBitFieldRead32 (Port, 0, 23) + Delay; 168 Delay = BIT22; 169 // 170 // Wait until time out 171 // Delay >= 2^23 could not be handled by this function 172 // Timer wrap-arounds are handled correctly by this function 173 // 174 while (((Ticks - IoBitFieldRead32 (Port, 0, 23)) & BIT23) == 0) { 175 CpuPause (); 176 } 177 } while (Times-- > 0); 178 } 179 180 /** 181 Stalls the CPU for at least the given number of microseconds. 182 183 Stalls the CPU for the number of microseconds specified by MicroSeconds. 184 185 @param MicroSeconds The minimum number of microseconds to delay. 186 187 @return MicroSeconds 188 189 **/ 190 UINTN 191 EFIAPI 192 MicroSecondDelay ( 193 IN UINTN MicroSeconds 194 ) 195 { 196 InternalAcpiDelay ( 197 (UINT32)DivU64x32 ( 198 MultU64x32 ( 199 MicroSeconds, 200 ACPI_TIMER_FREQUENCY 201 ), 202 1000000u 203 ) 204 ); 205 return MicroSeconds; 206 } 207 208 /** 209 Stalls the CPU for at least the given number of nanoseconds. 210 211 Stalls the CPU for the number of nanoseconds specified by NanoSeconds. 212 213 @param NanoSeconds The minimum number of nanoseconds to delay. 214 215 @return NanoSeconds 216 217 **/ 218 UINTN 219 EFIAPI 220 NanoSecondDelay ( 221 IN UINTN NanoSeconds 222 ) 223 { 224 InternalAcpiDelay ( 225 (UINT32)DivU64x32 ( 226 MultU64x32 ( 227 NanoSeconds, 228 ACPI_TIMER_FREQUENCY 229 ), 230 1000000000u 231 ) 232 ); 233 return NanoSeconds; 234 } 235 236 /** 237 Retrieves the current value of a 64-bit free running performance counter. 238 239 Retrieves the current value of a 64-bit free running performance counter. The 240 counter can either count up by 1 or count down by 1. If the physical 241 performance counter counts by a larger increment, then the counter values 242 must be translated. The properties of the counter can be retrieved from 243 GetPerformanceCounterProperties(). 244 245 @return The current value of the free running performance counter. 246 247 **/ 248 UINT64 249 EFIAPI 250 GetPerformanceCounter ( 251 VOID 252 ) 253 { 254 return AsmReadTsc (); 255 } 256 257 /** 258 Retrieves the 64-bit frequency in Hz and the range of performance counter 259 values. 260 261 If StartValue is not NULL, then the value that the performance counter starts 262 with immediately after is it rolls over is returned in StartValue. If 263 EndValue is not NULL, then the value that the performance counter end with 264 immediately before it rolls over is returned in EndValue. The 64-bit 265 frequency of the performance counter in Hz is always returned. If StartValue 266 is less than EndValue, then the performance counter counts up. If StartValue 267 is greater than EndValue, then the performance counter counts down. For 268 example, a 64-bit free running counter that counts up would have a StartValue 269 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter 270 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0. 271 272 @param StartValue The value the performance counter starts with when it 273 rolls over. 274 @param EndValue The value that the performance counter ends with before 275 it rolls over. 276 277 @return The frequency in Hz. 278 279 **/ 280 UINT64 281 EFIAPI 282 GetPerformanceCounterProperties ( 283 OUT UINT64 *StartValue, OPTIONAL 284 OUT UINT64 *EndValue OPTIONAL 285 ) 286 { 287 if (StartValue != NULL) { 288 *StartValue = 0; 289 } 290 291 if (EndValue != NULL) { 292 *EndValue = 0xffffffffffffffffULL; 293 } 294 return InternalGetPerformanceCounterFrequency (); 295 } 296 297 /** 298 Converts elapsed ticks of performance counter to time in nanoseconds. 299 300 This function converts the elapsed ticks of running performance counter to 301 time value in unit of nanoseconds. 302 303 @param Ticks The number of elapsed ticks of running performance counter. 304 305 @return The elapsed time in nanoseconds. 306 307 **/ 308 UINT64 309 EFIAPI 310 GetTimeInNanoSecond ( 311 IN UINT64 Ticks 312 ) 313 { 314 UINT64 Frequency; 315 UINT64 NanoSeconds; 316 UINT64 Remainder; 317 INTN Shift; 318 Frequency = GetPerformanceCounterProperties (NULL, NULL); 319 320 // 321 // Ticks 322 // Time = --------- x 1,000,000,000 323 // Frequency 324 // 325 NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u); 326 327 // 328 // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit. 329 // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34, 330 // i.e. highest bit set in Remainder should <= 33. 331 // 332 Shift = MAX (0, HighBitSet64 (Remainder) - 33); 333 Remainder = RShiftU64 (Remainder, (UINTN) Shift); 334 Frequency = RShiftU64 (Frequency, (UINTN) Shift); 335 NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL); 336 337 return NanoSeconds; 338 } 339 340 // 341 // OVERRIDE: OverrideBegin 342 // 343 /** 344 Calculate TSC frequency. 345 346 The TSC counting frequency is determined by using CPUID leaf 0x15 that is the preferred 347 method for Skylake and beyond. Frequency in MHz = Core XTAL frequency * EBX/EAX. 348 In newer flavors of the CPU, core xtal frequency is returned in ECX (or 0 if not 349 supported). If ECX is 0, 24MHz is assumed. 350 @return The number of TSC counts per second. 351 352 **/ 353 UINT64 354 InternalCalculateTscFrequency ( 355 VOID 356 ) 357 { 358 UINT64 TscFrequency; 359 UINT64 CoreXtalFrequency; 360 UINT32 RegEax; 361 UINT32 RegEbx; 362 UINT32 RegEcx; 363 364 // 365 // Use CPUID leaf 0x15. 366 // TSC frequency = (Core Xtal Frequency) * EBX/EAX. EBX returns 0 if not 367 // supported. ECX, if non zero, provides Core Xtal Frequency in hertz 368 // (SDM Dec 2016). 369 // 370 AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL); 371 ASSERT (RegEbx != 0); 372 373 // 374 // If core xtal frequency (ECX) returns 0, it is safe to use 24MHz for post 375 // Skylake client CPU's. 376 // 377 if (RegEcx == 0) { 378 CoreXtalFrequency = 24000000ul; 379 } else { 380 CoreXtalFrequency = (UINT64)RegEcx; 381 } 382 383 // 384 // Calculate frequency. For integer division, round up/down result 385 // correctly by adding denominator/2 to the numerator prior to division. 386 // 387 TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax); 388 389 return TscFrequency; 390 } 391 // 392 // OVERRIDE: OverrideEnd 393 // 394 395