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
29 EFI_ACPI_DESCRIPTION *gAcpiDesc = NULL;
30
31 /**
32 Internal function to get Acpi information from HOB.
33
34 @return Pointer to ACPI description structure.
35 **/
36 EFI_ACPI_DESCRIPTION*
InternalGetApciDescrptionTable(VOID)37 InternalGetApciDescrptionTable (
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 **/
65 STATIC
66 UINT32
InternalAcpiGetTimerTick(VOID)67 InternalAcpiGetTimerTick (
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 **/
83 STATIC
84 VOID
InternalAcpiDelay(IN UINT32 Delay)85 InternalAcpiDelay (
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 **/
122 UINTN
123 EFIAPI
MicroSecondDelay(IN UINTN MicroSeconds)124 MicroSecondDelay (
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 **/
155 UINTN
156 EFIAPI
NanoSecondDelay(IN UINTN NanoSeconds)157 NanoSecondDelay (
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 **/
189 UINT64
190 EFIAPI
GetPerformanceCounter(VOID)191 GetPerformanceCounter (
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 **/
225 UINT64
226 EFIAPI
GetPerformanceCounterProperties(OUT UINT64 * StartValue,OPTIONAL OUT UINT64 * EndValue OPTIONAL)227 GetPerformanceCounterProperties (
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 **/
258 UINT64
259 EFIAPI
GetTimeInNanoSecond(IN UINT64 Ticks)260 GetTimeInNanoSecond (
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