]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Misc/Stall.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Misc / Stall.c
1 /** @file
2 UEFI Miscellaneous boot Services Stall service implementation
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 //
10 // Include statements
11 //
12
13 #include "DxeMain.h"
14
15 /**
16 Internal worker function to call the Metronome Architectural Protocol for
17 the number of ticks specified by the UINT64 Counter value. WaitForTick()
18 service of the Metronome Architectural Protocol uses a UINT32 for the number
19 of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
20
21 @param Counter Number of ticks to wait.
22
23 **/
24 VOID
25 CoreInternalWaitForTick (
26 IN UINT64 Counter
27 )
28 {
29 while (RShiftU64 (Counter, 32) > 0) {
30 gMetronome->WaitForTick (gMetronome, 0xffffffff);
31 Counter -= 0xffffffff;
32 }
33 gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
34 }
35
36 /**
37 Introduces a fine-grained stall.
38
39 @param Microseconds The number of microseconds to stall execution.
40
41 @retval EFI_SUCCESS Execution was stalled for at least the requested
42 amount of microseconds.
43 @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
44
45 **/
46 EFI_STATUS
47 EFIAPI
48 CoreStall (
49 IN UINTN Microseconds
50 )
51 {
52 UINT64 Counter;
53 UINT32 Remainder;
54 UINTN Index;
55
56 if (gMetronome == NULL) {
57 return EFI_NOT_AVAILABLE_YET;
58 }
59
60 //
61 // Counter = Microseconds * 10 / gMetronome->TickPeriod
62 // 0x1999999999999999 = (2^64 - 1) / 10
63 //
64 if ((UINT64) Microseconds > 0x1999999999999999ULL) {
65 //
66 // Microseconds is too large to multiple by 10 first. Perform the divide
67 // operation first and loop 10 times to avoid 64-bit math overflow.
68 //
69 Counter = DivU64x32Remainder (
70 Microseconds,
71 gMetronome->TickPeriod,
72 &Remainder
73 );
74 for (Index = 0; Index < 10; Index++) {
75 CoreInternalWaitForTick (Counter);
76 }
77
78 if (Remainder != 0) {
79 //
80 // If Remainder was not zero, then normally, Counter would be rounded
81 // up by 1 tick. In this case, since a loop for 10 counts was used
82 // to emulate the multiply by 10 operation, Counter needs to be rounded
83 // up by 10 counts.
84 //
85 CoreInternalWaitForTick (10);
86 }
87 } else {
88 //
89 // Calculate the number of ticks by dividing the number of microseconds by
90 // the TickPeriod. Calculation is based on 100ns unit.
91 //
92 Counter = DivU64x32Remainder (
93 MultU64x32 (Microseconds, 10),
94 gMetronome->TickPeriod,
95 &Remainder
96 );
97 if (Remainder != 0) {
98 //
99 // If Remainder is not zero, then round Counter up by one tick.
100 //
101 Counter++;
102 }
103 CoreInternalWaitForTick (Counter);
104 }
105
106 return EFI_SUCCESS;
107 }