1 /** @file
2   Timer Library functions built upon ITC on IPF.
3 
4   Copyright (c) 2006 - 2011, 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/PalLib.h>
19 
20 
21 /**
22   Performs a delay measured as number of ticks.
23 
24   An internal function to perform a delay measured as number of ticks. It's
25   invoked by MicroSecondDelay() and NanoSecondDelay().
26 
27   @param  Delay The number of ticks to delay.
28 
29 **/
30 VOID
31 EFIAPI
InternalIpfDelay(IN INT64 Delay)32 InternalIpfDelay (
33   IN      INT64                     Delay
34   )
35 {
36   INT64                             Ticks;
37 
38   //
39   // The target timer count is calculated here
40   //
41   Ticks = (INT64)AsmReadItc () + Delay;
42 
43   //
44   // Wait until time out
45   // Delay > 2^63 could not be handled by this function
46   // Timer wrap-arounds are handled correctly by this function
47   //
48   while (Ticks - (INT64)AsmReadItc() >= 0);
49 }
50 
51 /**
52   Stalls the CPU for at least the given number of microseconds.
53 
54   Stalls the CPU for the number of microseconds specified by MicroSeconds.
55 
56   @param  MicroSeconds  The minimum number of microseconds to delay.
57 
58   @return The value of MicroSeconds inputted.
59 
60 **/
61 UINTN
62 EFIAPI
MicroSecondDelay(IN UINTN MicroSeconds)63 MicroSecondDelay (
64   IN      UINTN                     MicroSeconds
65   )
66 {
67   InternalIpfDelay (
68     GetPerformanceCounterProperties (NULL, NULL) *
69     MicroSeconds /
70     1000000
71     );
72   return MicroSeconds;
73 }
74 
75 /**
76   Stalls the CPU for at least the given number of nanoseconds.
77 
78   Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
79 
80   @param  NanoSeconds The minimum number of nanoseconds to delay.
81 
82   @return The value of NanoSeconds inputted.
83 
84 **/
85 UINTN
86 EFIAPI
NanoSecondDelay(IN UINTN NanoSeconds)87 NanoSecondDelay (
88   IN      UINTN                     NanoSeconds
89   )
90 {
91   InternalIpfDelay (
92     GetPerformanceCounterProperties (NULL, NULL) *
93     NanoSeconds /
94     1000000000
95     );
96   return NanoSeconds;
97 }
98 
99 /**
100   Retrieves the current value of a 64-bit free running performance counter.
101 
102   The counter can either count up by 1 or count down by 1. If the physical
103   performance counter counts by a larger increment, then the counter values
104   must be translated. The properties of the counter can be retrieved from
105   GetPerformanceCounterProperties().
106 
107   @return The current value of the free running performance counter.
108 
109 **/
110 UINT64
111 EFIAPI
GetPerformanceCounter(VOID)112 GetPerformanceCounter (
113   VOID
114   )
115 {
116   return AsmReadItc ();
117 }
118 
119 /**
120   Retrieves the 64-bit frequency in Hz and the range of performance counter
121   values.
122 
123   If StartValue is not NULL, then the value that the performance counter starts
124   with immediately after is it rolls over is returned in StartValue. If
125   EndValue is not NULL, then the value that the performance counter end with
126   immediately before it rolls over is returned in EndValue. The 64-bit
127   frequency of the performance counter in Hz is always returned. If StartValue
128   is less than EndValue, then the performance counter counts up. If StartValue
129   is greater than EndValue, then the performance counter counts down. For
130   example, a 64-bit free running counter that counts up would have a StartValue
131   of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
132   that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
133 
134   @param  StartValue  The value the performance counter starts with when it
135                       rolls over.
136   @param  EndValue    The value that the performance counter ends with before
137                       it rolls over.
138 
139   @return The frequency in Hz.
140 
141 **/
142 UINT64
143 EFIAPI
GetPerformanceCounterProperties(OUT UINT64 * StartValue,OPTIONAL OUT UINT64 * EndValue OPTIONAL)144 GetPerformanceCounterProperties (
145   OUT      UINT64                    *StartValue,  OPTIONAL
146   OUT      UINT64                    *EndValue     OPTIONAL
147   )
148 {
149   PAL_CALL_RETURN                   PalRet;
150   UINT64                            BaseFrequence;
151 
152   if (StartValue != NULL) {
153     *StartValue = 0;
154   }
155 
156   if (EndValue != NULL) {
157     *EndValue = (UINT64)(-1);
158   }
159 
160   PalRet = PalCall (PAL_FREQ_BASE, 0, 0, 0);
161   if (PalRet.Status != 0) {
162     return 1000000;
163   }
164   BaseFrequence = PalRet.r9;
165 
166   PalRet = PalCall (PAL_FREQ_RATIOS, 0, 0, 0);
167   if (PalRet.Status != 0) {
168     return 1000000;
169   }
170 
171   return BaseFrequence * (PalRet.r11 >> 32) / (UINT32)PalRet.r11;
172 }
173 
174 /**
175   Converts elapsed ticks of performance counter to time in nanoseconds.
176 
177   This function converts the elapsed ticks of running performance counter to
178   time value in unit of nanoseconds.
179 
180   @param  Ticks     The number of elapsed ticks of running performance counter.
181 
182   @return The elapsed time in nanoseconds.
183 
184 **/
185 UINT64
186 EFIAPI
GetTimeInNanoSecond(IN UINT64 Ticks)187 GetTimeInNanoSecond (
188   IN      UINT64                     Ticks
189   )
190 {
191   UINT64  Frequency;
192   UINT64  NanoSeconds;
193   UINT64  Remainder;
194   INTN    Shift;
195 
196   Frequency = GetPerformanceCounterProperties (NULL, NULL);
197 
198   //
199   //          Ticks
200   // Time = --------- x 1,000,000,000
201   //        Frequency
202   //
203   NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
204 
205   //
206   // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
207   // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
208   // i.e. highest bit set in Remainder should <= 33.
209   //
210   Shift = MAX (0, HighBitSet64 (Remainder) - 33);
211   Remainder = RShiftU64 (Remainder, (UINTN) Shift);
212   Frequency = RShiftU64 (Frequency, (UINTN) Shift);
213   NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
214 
215   return NanoSeconds;
216 }
217