1 /** @file
2 ACPI Timer implements one instance of Timer Library.
3
4 Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are
6 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 <PiPei.h>
16 #include <Library/TimerLib.h>
17 #include <Library/BaseLib.h>
18 #include <Library/IoLib.h>
19 #include <Library/HobLib.h>
20 #include <Library/DebugLib.h>
21
22 #include <Guid/AcpiBoardInfoGuid.h>
23 #include <IndustryStandard/Acpi.h>
24
25 #define ACPI_TIMER_COUNT_SIZE BIT24
26
27 UINTN mPmTimerReg = 0;
28
29 /**
30 The constructor function enables ACPI IO space.
31
32 If ACPI I/O space not enabled, this function will enable it.
33 It will always return RETURN_SUCCESS.
34
35 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
36
37 **/
38 RETURN_STATUS
39 EFIAPI
AcpiTimerLibConstructor(VOID)40 AcpiTimerLibConstructor (
41 VOID
42 )
43 {
44 EFI_HOB_GUID_TYPE *GuidHob;
45 ACPI_BOARD_INFO *pAcpiBoardInfo;
46
47 //
48 // Find the acpi board information guid hob
49 //
50 GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);
51 ASSERT (GuidHob != NULL);
52
53 pAcpiBoardInfo = (ACPI_BOARD_INFO *)GET_GUID_HOB_DATA (GuidHob);
54
55 mPmTimerReg = (UINTN)pAcpiBoardInfo->PmTimerRegBase;
56
57 return EFI_SUCCESS;
58 }
59
60 /**
61 Internal function to read the current tick counter of ACPI.
62
63 Internal function to read the current tick counter of ACPI.
64
65 @return The tick counter read.
66
67 **/
68 UINT32
InternalAcpiGetTimerTick(VOID)69 InternalAcpiGetTimerTick (
70 VOID
71 )
72 {
73 if (mPmTimerReg == 0)
74 AcpiTimerLibConstructor ();
75
76 return IoRead32 (mPmTimerReg);
77 }
78
79 /**
80 Stalls the CPU for at least the given number of ticks.
81
82 Stalls the CPU for at least the given number of ticks. It's invoked by
83 MicroSecondDelay() and NanoSecondDelay().
84
85 @param Delay A period of time to delay in ticks.
86
87 **/
88 VOID
InternalAcpiDelay(IN UINT32 Delay)89 InternalAcpiDelay (
90 IN UINT32 Delay
91 )
92 {
93 UINT32 Ticks;
94 UINT32 Times;
95
96 Times = Delay >> 22;
97 Delay &= BIT22 - 1;
98 do {
99 //
100 // The target timer count is calculated here
101 //
102 Ticks = InternalAcpiGetTimerTick () + Delay;
103 Delay = BIT22;
104 //
105 // Wait until time out
106 // Delay >= 2^23 could not be handled by this function
107 // Timer wrap-arounds are handled correctly by this function
108 //
109 while (((Ticks - InternalAcpiGetTimerTick ()) & BIT23) == 0) {
110 CpuPause ();
111 }
112 } while (Times-- > 0);
113 }
114
115 /**
116 Stalls the CPU for at least the given number of microseconds.
117
118 Stalls the CPU for the number of microseconds specified by MicroSeconds.
119
120 @param MicroSeconds The minimum number of microseconds to delay.
121
122 @return MicroSeconds
123
124 **/
125 UINTN
126 EFIAPI
MicroSecondDelay(IN UINTN MicroSeconds)127 MicroSecondDelay (
128 IN UINTN MicroSeconds
129 )
130 {
131 InternalAcpiDelay (
132 (UINT32)DivU64x32 (
133 MultU64x32 (
134 MicroSeconds,
135 ACPI_TIMER_FREQUENCY
136 ),
137 1000000u
138 )
139 );
140 return MicroSeconds;
141 }
142
143 /**
144 Stalls the CPU for at least the given number of nanoseconds.
145
146 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
147
148 @param NanoSeconds The minimum number of nanoseconds to delay.
149
150 @return NanoSeconds
151
152 **/
153 UINTN
154 EFIAPI
NanoSecondDelay(IN UINTN NanoSeconds)155 NanoSecondDelay (
156 IN UINTN NanoSeconds
157 )
158 {
159 InternalAcpiDelay (
160 (UINT32)DivU64x32 (
161 MultU64x32 (
162 NanoSeconds,
163 ACPI_TIMER_FREQUENCY
164 ),
165 1000000000u
166 )
167 );
168 return NanoSeconds;
169 }
170
171 /**
172 Retrieves the current value of a 64-bit free running performance counter.
173
174 Retrieves the current value of a 64-bit free running performance counter. The
175 counter can either count up by 1 or count down by 1. If the physical
176 performance counter counts by a larger increment, then the counter values
177 must be translated. The properties of the counter can be retrieved from
178 GetPerformanceCounterProperties().
179
180 @return The current value of the free running performance counter.
181
182 **/
183 UINT64
184 EFIAPI
GetPerformanceCounter(VOID)185 GetPerformanceCounter (
186 VOID
187 )
188 {
189 return (UINT64)InternalAcpiGetTimerTick ();
190 }
191
192 /**
193 Retrieves the 64-bit frequency in Hz and the range of performance counter
194 values.
195
196 If StartValue is not NULL, then the value that the performance counter starts
197 with immediately after is it rolls over is returned in StartValue. If
198 EndValue is not NULL, then the value that the performance counter end with
199 immediately before it rolls over is returned in EndValue. The 64-bit
200 frequency of the performance counter in Hz is always returned. If StartValue
201 is less than EndValue, then the performance counter counts up. If StartValue
202 is greater than EndValue, then the performance counter counts down. For
203 example, a 64-bit free running counter that counts up would have a StartValue
204 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
205 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
206
207 @param StartValue The value the performance counter starts with when it
208 rolls over.
209 @param EndValue The value that the performance counter ends with before
210 it rolls over.
211
212 @return The frequency in Hz.
213
214 **/
215 UINT64
216 EFIAPI
GetPerformanceCounterProperties(OUT UINT64 * StartValue,OPTIONAL OUT UINT64 * EndValue OPTIONAL)217 GetPerformanceCounterProperties (
218 OUT UINT64 *StartValue, OPTIONAL
219 OUT UINT64 *EndValue OPTIONAL
220 )
221 {
222 if (StartValue != NULL) {
223 *StartValue = 0;
224 }
225
226 if (EndValue != NULL) {
227 *EndValue = ACPI_TIMER_COUNT_SIZE - 1;
228 }
229
230 return ACPI_TIMER_FREQUENCY;
231 }
232
233 /**
234 Converts elapsed ticks of performance counter to time in nanoseconds.
235
236 This function converts the elapsed ticks of running performance counter to
237 time value in unit of nanoseconds.
238
239 @param Ticks The number of elapsed ticks of running performance counter.
240
241 @return The elapsed time in nanoseconds.
242
243 **/
244 UINT64
245 EFIAPI
GetTimeInNanoSecond(IN UINT64 Ticks)246 GetTimeInNanoSecond (
247 IN UINT64 Ticks
248 )
249 {
250 UINT64 Frequency;
251 UINT64 NanoSeconds;
252 UINT64 Remainder;
253 INTN Shift;
254
255 Frequency = GetPerformanceCounterProperties (NULL, NULL);
256
257 //
258 // Ticks
259 // Time = --------- x 1,000,000,000
260 // Frequency
261 //
262 NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
263
264 //
265 // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
266 // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
267 // i.e. highest bit set in Remainder should <= 33.
268 //
269 Shift = MAX (0, HighBitSet64 (Remainder) - 33);
270 Remainder = RShiftU64 (Remainder, (UINTN) Shift);
271 Frequency = RShiftU64 (Frequency, (UINTN) Shift);
272 NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
273
274 return NanoSeconds;
275 }
276
277