VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/Library/AcpiTimerLib/AcpiTimerLib.c@ 78403

Last change on this file since 78403 was 58466, checked in by vboxsync, 9 years ago

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

  • Property svn:eol-style set to native
File size: 10.8 KB
Line 
1/** @file
2 ACPI Timer implements one instance of Timer Library.
3
4 Copyright (c) 2008 - 2012, Intel Corporation. All rights reserved.<BR>
5 Copyright (c) 2011, Andrei Warkentin <[email protected]>
6
7 This program and the accompanying materials are
8 licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15**/
16
17#include <Base.h>
18#include <Library/TimerLib.h>
19#include <Library/BaseLib.h>
20#include <Library/IoLib.h>
21#include <Library/PciLib.h>
22#include <Library/DebugLib.h>
23#include <Library/PcdLib.h>
24#include <IndustryStandard/Pci22.h>
25#include <IndustryStandard/Acpi.h>
26
27//
28// PCI Location of PIIX4 Power Management PCI Configuration Registers
29//
30#define PIIX4_POWER_MANAGEMENT_BUS 0x00
31#define PIIX4_POWER_MANAGEMENT_DEVICE 0x01
32#define PIIX4_POWER_MANAGEMENT_FUNCTION 0x03
33
34//
35// Macro to access PIIX4 Power Management PCI Configuration Registers
36//
37#define PIIX4_PCI_POWER_MANAGEMENT_REGISTER(Register) \
38 PCI_LIB_ADDRESS ( \
39 PIIX4_POWER_MANAGEMENT_BUS, \
40 PIIX4_POWER_MANAGEMENT_DEVICE, \
41 PIIX4_POWER_MANAGEMENT_FUNCTION, \
42 Register \
43 )
44
45//
46// PCI Location of Q35 Power Management PCI Configuration Registers
47//
48#define Q35_POWER_MANAGEMENT_BUS 0x00
49#define Q35_POWER_MANAGEMENT_DEVICE 0x1f
50#define Q35_POWER_MANAGEMENT_FUNCTION 0x00
51
52//
53// Macro to access Q35 Power Management PCI Configuration Registers
54//
55#define Q35_PCI_POWER_MANAGEMENT_REGISTER(Register) \
56 PCI_LIB_ADDRESS ( \
57 Q35_POWER_MANAGEMENT_BUS, \
58 Q35_POWER_MANAGEMENT_DEVICE, \
59 Q35_POWER_MANAGEMENT_FUNCTION, \
60 Register \
61 )
62
63//
64// PCI Location of Host Bridge PCI Configuration Registers
65//
66#define HOST_BRIDGE_BUS 0x00
67#define HOST_BRIDGE_DEVICE 0x00
68#define HOST_BRIDGE_FUNCTION 0x00
69
70//
71// Macro to access Host Bridge Configuration Registers
72//
73#define HOST_BRIDGE_REGISTER(Register) \
74 PCI_LIB_ADDRESS ( \
75 HOST_BRIDGE_BUS, \
76 HOST_BRIDGE_DEVICE, \
77 HOST_BRIDGE_FUNCTION, \
78 Register \
79 )
80
81//
82// Host Bridge Device ID (DID) Register
83//
84#define HOST_BRIDGE_DID HOST_BRIDGE_REGISTER (0x02)
85
86//
87// Host Bridge DID Register values
88//
89#define PCI_DEVICE_ID_INTEL_82441 0x1237 // DID value for PIIX4
90#define PCI_DEVICE_ID_INTEL_Q35_MCH 0x29C0 // DID value for Q35
91
92//
93// Access Power Management PCI Config Regs based on Host Bridge type
94//
95#define PCI_POWER_MANAGEMENT_REGISTER(Register) \
96 ((PciRead16 (HOST_BRIDGE_DID) == PCI_DEVICE_ID_INTEL_Q35_MCH) ? \
97 Q35_PCI_POWER_MANAGEMENT_REGISTER (Register) : \
98 PIIX4_PCI_POWER_MANAGEMENT_REGISTER (Register))
99
100//
101// Power Management PCI Configuration Registers
102//
103#define PMBA PCI_POWER_MANAGEMENT_REGISTER (0x40)
104#define PMBA_RTE BIT0
105#define PMREGMISC PCI_POWER_MANAGEMENT_REGISTER (0x80)
106#define PMIOSE BIT0
107
108//
109// The ACPI Time is a 24-bit counter
110//
111#define ACPI_TIMER_COUNT_SIZE BIT24
112
113//
114// Offset in the Power Management Base Address to the ACPI Timer
115//
116#define ACPI_TIMER_OFFSET 0x8
117
118#ifdef VBOX
119UINT32 mPmba = 0x4000;
120
121#define PCI_BAR_IO 0x1
122#endif
123
124/**
125 The constructor function enables ACPI IO space.
126
127 If ACPI I/O space not enabled, this function will enable it.
128 It will always return RETURN_SUCCESS.
129
130 @retval EFI_SUCCESS The constructor always returns RETURN_SUCCESS.
131
132**/
133#ifndef VBOX
134RETURN_STATUS
135EFIAPI
136AcpiTimerLibConstructor (
137 VOID
138 )
139{
140 //
141 // Check to see if the Power Management Base Address is already enabled
142 //
143 if ((PciRead8 (PMREGMISC) & PMIOSE) == 0) {
144 //
145 // If the Power Management Base Address is not programmed,
146 // then program the Power Management Base Address from a PCD.
147 //
148 PciAndThenOr32 (PMBA, (UINT32)(~0x0000FFC0), PcdGet16 (PcdAcpiPmBaseAddress));
149
150 //
151 // Enable PMBA I/O port decodes in PMREGMISC
152 //
153 PciOr8 (PMREGMISC, PMIOSE);
154 }
155
156 return RETURN_SUCCESS;
157}
158#else
159RETURN_STATUS
160EFIAPI
161AcpiTimerLibConstructor (
162 VOID
163 )
164{
165 UINT8 u8Device = 7;
166 UINT16 u16VendorID = 0;
167 UINT16 u16DeviceID = 0;
168 u16VendorID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 0));
169 u16DeviceID = PciRead16(PCI_LIB_ADDRESS(0, u8Device, 0, 2));
170 if ( u16VendorID != 0x8086
171 || u16DeviceID != 0x7113)
172 return RETURN_ABORTED;
173
174 if (PciRead8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80)) & 1) {
175 mPmba = PciRead32 (PCI_LIB_ADDRESS (0, u8Device, 0, 0x40));
176 ASSERT (mPmba & PCI_BAR_IO);
177 DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba));
178 mPmba &= ~PCI_BAR_IO;
179 DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba));
180 } else {
181 PciAndThenOr32 (PCI_LIB_ADDRESS (0,u8Device,0,0x40),
182 (UINT32) ~0xfc0, mPmba);
183 PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x04), 0x01);
184 DEBUG((DEBUG_INFO, "%a:%d mPmba:%x\n", __FUNCTION__, __LINE__, mPmba));
185 }
186
187 //
188 // ACPI Timer enable is in Bus 0, Device ?, Function 3
189 //
190 PciOr8 (PCI_LIB_ADDRESS (0,u8Device,0,0x80), 0x01);
191 return RETURN_SUCCESS;
192}
193#endif
194
195/**
196 Internal function to read the current tick counter of ACPI.
197
198 Internal function to read the current tick counter of ACPI.
199
200 @return The tick counter read.
201
202**/
203UINT32
204InternalAcpiGetTimerTick (
205 VOID
206 )
207{
208 //
209 // Read PMBA to read and return the current ACPI timer value.
210 //
211#ifndef VBOX
212 return IoRead32 ((PciRead32 (PMBA) & ~PMBA_RTE) + ACPI_TIMER_OFFSET);
213#else
214 return IoRead32 (mPmba + ACPI_TIMER_OFFSET);
215#endif
216}
217
218/**
219 Stalls the CPU for at least the given number of ticks.
220
221 Stalls the CPU for at least the given number of ticks. It's invoked by
222 MicroSecondDelay() and NanoSecondDelay().
223
224 @param Delay A period of time to delay in ticks.
225
226**/
227VOID
228InternalAcpiDelay (
229 IN UINT32 Delay
230 )
231{
232 UINT32 Ticks;
233 UINT32 Times;
234
235 Times = Delay >> 22;
236 Delay &= BIT22 - 1;
237 do {
238 //
239 // The target timer count is calculated here
240 //
241 Ticks = InternalAcpiGetTimerTick () + Delay;
242 Delay = BIT22;
243 //
244 // Wait until time out
245 // Delay >= 2^23 could not be handled by this function
246 // Timer wrap-arounds are handled correctly by this function
247 //
248 while (((Ticks - InternalAcpiGetTimerTick ()) & BIT23) == 0) {
249 CpuPause ();
250 }
251 } while (Times-- > 0);
252}
253
254/**
255 Stalls the CPU for at least the given number of microseconds.
256
257 Stalls the CPU for the number of microseconds specified by MicroSeconds.
258
259 @param MicroSeconds The minimum number of microseconds to delay.
260
261 @return MicroSeconds
262
263**/
264UINTN
265EFIAPI
266MicroSecondDelay (
267 IN UINTN MicroSeconds
268 )
269{
270 InternalAcpiDelay (
271 (UINT32)DivU64x32 (
272 MultU64x32 (
273 MicroSeconds,
274 ACPI_TIMER_FREQUENCY
275 ),
276 1000000u
277 )
278 );
279 return MicroSeconds;
280}
281
282/**
283 Stalls the CPU for at least the given number of nanoseconds.
284
285 Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
286
287 @param NanoSeconds The minimum number of nanoseconds to delay.
288
289 @return NanoSeconds
290
291**/
292UINTN
293EFIAPI
294NanoSecondDelay (
295 IN UINTN NanoSeconds
296 )
297{
298 InternalAcpiDelay (
299 (UINT32)DivU64x32 (
300 MultU64x32 (
301 NanoSeconds,
302 ACPI_TIMER_FREQUENCY
303 ),
304 1000000000u
305 )
306 );
307 return NanoSeconds;
308}
309
310/**
311 Retrieves the current value of a 64-bit free running performance counter.
312
313 Retrieves the current value of a 64-bit free running performance counter. The
314 counter can either count up by 1 or count down by 1. If the physical
315 performance counter counts by a larger increment, then the counter values
316 must be translated. The properties of the counter can be retrieved from
317 GetPerformanceCounterProperties().
318
319 @return The current value of the free running performance counter.
320
321**/
322UINT64
323EFIAPI
324GetPerformanceCounter (
325 VOID
326 )
327{
328 return (UINT64)InternalAcpiGetTimerTick ();
329}
330
331/**
332 Retrieves the 64-bit frequency in Hz and the range of performance counter
333 values.
334
335 If StartValue is not NULL, then the value that the performance counter starts
336 with immediately after is it rolls over is returned in StartValue. If
337 EndValue is not NULL, then the value that the performance counter end with
338 immediately before it rolls over is returned in EndValue. The 64-bit
339 frequency of the performance counter in Hz is always returned. If StartValue
340 is less than EndValue, then the performance counter counts up. If StartValue
341 is greater than EndValue, then the performance counter counts down. For
342 example, a 64-bit free running counter that counts up would have a StartValue
343 of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
344 that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
345
346 @param StartValue The value the performance counter starts with when it
347 rolls over.
348 @param EndValue The value that the performance counter ends with before
349 it rolls over.
350
351 @return The frequency in Hz.
352
353**/
354UINT64
355EFIAPI
356GetPerformanceCounterProperties (
357 OUT UINT64 *StartValue, OPTIONAL
358 OUT UINT64 *EndValue OPTIONAL
359 )
360{
361 if (StartValue != NULL) {
362 *StartValue = 0;
363 }
364
365 if (EndValue != NULL) {
366 *EndValue = ACPI_TIMER_COUNT_SIZE - 1;
367 }
368
369 return ACPI_TIMER_FREQUENCY;
370}
371
372/**
373 Converts elapsed ticks of performance counter to time in nanoseconds.
374
375 This function converts the elapsed ticks of running performance counter to
376 time value in unit of nanoseconds.
377
378 @param Ticks The number of elapsed ticks of running performance counter.
379
380 @return The elapsed time in nanoseconds.
381
382**/
383UINT64
384EFIAPI
385GetTimeInNanoSecond (
386 IN UINT64 Ticks
387 )
388{
389 UINT64 NanoSeconds;
390 UINT32 Remainder;
391
392 //
393 // Ticks
394 // Time = --------- x 1,000,000,000
395 // Frequency
396 //
397 NanoSeconds = MultU64x32 (DivU64x32Remainder (Ticks, ACPI_TIMER_FREQUENCY, &Remainder), 1000000000u);
398
399 //
400 // Frequency < 0x100000000, so Remainder < 0x100000000, then (Remainder * 1,000,000,000)
401 // will not overflow 64-bit.
402 //
403 NanoSeconds += DivU64x32 (MultU64x32 ((UINT64) Remainder, 1000000000u), ACPI_TIMER_FREQUENCY);
404
405 return NanoSeconds;
406}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette