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