1. Updated declaration of timer functions according to latest MWG.
authorbxing <bxing@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 25 Jul 2006 07:33:02 +0000 (07:33 +0000)
committerbxing <bxing@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 25 Jul 2006 07:33:02 +0000 (07:33 +0000)
2. Updated coding style.
3. Updated the algorithm used in delay functions to handle timer counter wrap-around.

git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1089 6f19259b-4bc3-4df7-8a09-765794883524

MdePkg/Include/Library/TimerLib.h
MdePkg/Library/BaseTimerLibLocalApic/Ipf/IpfTimerLib.c
MdePkg/Library/BaseTimerLibLocalApic/Ipf/ReadItc.s
MdePkg/Library/BaseTimerLibLocalApic/x86TimerLib.c

index 4b12152..8523bd0 100644 (file)
@@ -24,7 +24,7 @@
 \r
   @param  MicroSeconds  The minimum number of microseconds to delay.\r
 \r
-  @return Return value depends on implementation.\r
+  @return MicroSeconds\r
 \r
 **/\r
 UINTN\r
@@ -40,7 +40,7 @@ MicroSecondDelay (
 \r
   @param  NanoSeconds The minimum number of nanoseconds to delay.\r
 \r
-  @return Return value depends on implementation.\r
+  @return NanoSeconds\r
 \r
 **/\r
 UINTN\r
index 3814534..800b525 100644 (file)
 \r
 **/\r
 \r
-UINT64\r
-ReadItc (\r
-  VOID\r
-  );\r
-\r
 typedef struct {\r
   UINT64                            Status;\r
   UINT64                            r9;\r
@@ -30,6 +25,21 @@ typedef struct {
   UINT64                            r11;\r
 } PAL_PROC_RETURN;\r
 \r
+/**\r
+  Performs a PAL call using static calling convention.\r
+\r
+  An internal function to perform a PAL call using static calling convention.\r
+\r
+  @param  PalEntryPoint The entry point address of PAL. The address in ar.kr5\r
+                        would be used if this parameter were NULL on input.\r
+  @param  Arg1          The first argument of a PAL call.\r
+  @param  Arg1          The second argument of a PAL call.\r
+  @param  Arg1          The third argument of a PAL call.\r
+  @param  Arg1          The fourth argument of a PAL call.\r
+\r
+  @return The values returned in r8, r9, r10 and r11.\r
+\r
+**/\r
 PAL_PROC_RETURN\r
 PalCallStatic (\r
   IN      CONST VOID                *PalEntryPoint,\r
@@ -39,6 +49,50 @@ PalCallStatic (
   IN      UINT64                    Arg4\r
   );\r
 \r
+/**\r
+  Returns the current value of ar.itc.\r
+\r
+  An internal function to return the current value of ar.itc, which is the\r
+  timer tick on IPF.\r
+\r
+  @return The currect value of ar.itc\r
+\r
+**/\r
+INT64\r
+InternalIpfReadItc (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Performs a delay measured as number of ticks.\r
+\r
+  An internal function to perform a delay measured as number of ticks. It's\r
+  invoked by MicroSecondDelay() and NanoSecondDelay().\r
+\r
+  @param  Delay Number of ticks to delay.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+InternalIpfDelay (\r
+  IN      INT64                     Delay\r
+  )\r
+{\r
+  INT64                             Ticks;\r
+\r
+  //\r
+  // The target timer count is calculated here\r
+  //\r
+  Ticks = InternalIpfReadItc () + Delay;\r
+\r
+  //\r
+  // Wait until time out\r
+  // Delay > 2^63 could not be handled by this function\r
+  // Timer wrap-arounds are handled correctly by this function\r
+  //\r
+  while (Ticks - InternalIpfReadItc () >= 0);\r
+}\r
+\r
 /**\r
   Stalls the CPU for at least the given number of microseconds.\r
 \r
@@ -46,7 +100,7 @@ PalCallStatic (
 \r
   @param  MicroSeconds  The minimum number of microseconds to delay.\r
 \r
-  @return The ticks delayed actually.\r
+  @return MicroSeconds\r
 \r
 **/\r
 UINTN\r
@@ -55,13 +109,12 @@ MicroSecondDelay (
   IN      UINTN                     MicroSeconds\r
   )\r
 {\r
-  UINT64                            Ticks;\r
-  UINT64                            Delay;\r
-\r
-  Ticks = GetPerformanceCounter ();\r
-  Delay = GetPerformanceCounterProperties (NULL, NULL) * MicroSeconds / 1000000;\r
-  while (Ticks + Delay >= GetPerformanceCounter ());\r
-  return (UINTN)Delay;\r
+  InternalIpfDelay (\r
+    GetPerformanceCounterProperties (NULL, NULL) *\r
+    MicroSeconds /\r
+    1000000\r
+    );\r
+  return MicroSeconds;\r
 }\r
 \r
 /**\r
@@ -71,7 +124,7 @@ MicroSecondDelay (
 \r
   @param  NanoSeconds The minimum number of nanoseconds to delay.\r
 \r
-  @return The ticks delayed actually.\r
+  @return NanoSeconds\r
 \r
 **/\r
 UINTN\r
@@ -80,13 +133,12 @@ NanoSecondDelay (
   IN      UINTN                     NanoSeconds\r
   )\r
 {\r
-  UINT64                            Ticks;\r
-  UINT64                            Delay;\r
-\r
-  Ticks = GetPerformanceCounter ();\r
-  Delay = GetPerformanceCounterProperties (NULL, NULL) * NanoSeconds / 1000000000;\r
-  while (Ticks + Delay >= GetPerformanceCounter ());\r
-  return (UINTN)Delay;\r
+  InternalIpfDelay (\r
+    GetPerformanceCounterProperties (NULL, NULL) *\r
+    NanoSeconds /\r
+    1000000000\r
+    );\r
+  return NanoSeconds;\r
 }\r
 \r
 /**\r
@@ -107,7 +159,7 @@ GetPerformanceCounter (
   VOID\r
   )\r
 {\r
-  return ReadItc ();\r
+  return InternalIpfReadItc ();\r
 }\r
 \r
 /**\r
@@ -150,7 +202,13 @@ GetPerformanceCounterProperties (
   PalRet = PalCallStatic (NULL, 14, 0, 0, 0);\r
   ASSERT (PalRet.Status == 0);\r
 \r
-  *StartValue = 0;\r
-  *EndValue = (UINT64)(-1);\r
+  if (StartValue != NULL) {\r
+    *StartValue = 0;\r
+  }\r
+\r
+  if (EndValue != NULL) {\r
+    *EndValue = (UINT64)(-1);\r
+  }\r
+\r
   return BaseFrequence * (PalRet.r11 >> 32) / (UINT32)PalRet.r11;\r
 }\r
index 383bb24..ea94b67 100644 (file)
@@ -1,5 +1,6 @@
 /// @file\r
-///   Contains an implementation of ReadItc on Itanium-based architecture.\r
+///   Contains an implementation of InternalIpfReadItc () on Itanium-based\r
+///   architecture.\r
 ///\r
 /// Copyright (c) 2006, Intel Corporation\r
 /// All rights reserved. This program and the accompanying materials\r
@@ -17,9 +18,9 @@
 .auto\r
 .text\r
 \r
-.proc   ReadItc\r
-.type   ReadItc, @function\r
-ReadItc::\r
+.proc   InternalIpfReadItc\r
+.type   InternalIpfReadItc, @function\r
+InternalIpfReadItc::\r
         mov                 r8  = ar.itc\r
         br.ret.sptk.many    b0\r
-.endp   ReadItc
\ No newline at end of file
+.endp   InternalIpfReadItc\r
index 9c69cdf..e3af546 100644 (file)
 \r
 **/\r
 \r
-static\r
+//\r
+// The following 2 arrays are used in calculating the frequency of local APIC\r
+// timer. Refer to IA-32 developers' manual for more details.\r
+//\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+CONST UINT32                          mTimerLibLocalApicFrequencies[] = {\r
+  100000000,\r
+  133000000,\r
+  200000000,\r
+  166000000\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+CONST UINT8                           mTimerLibLocalApicDivisor[] = {\r
+  0x02, 0x04, 0x08, 0x10,\r
+  0x02, 0x04, 0x08, 0x10,\r
+  0x20, 0x40, 0x80, 0x01,\r
+  0x20, 0x40, 0x80, 0x01\r
+};\r
+\r
+/**\r
+  Internal function to retrieve the base address of local APIC.\r
+\r
+  Internal function to retrieve the base address of local APIC.\r
+\r
+  @return The base address of local APIC\r
+\r
+**/\r
+STATIC\r
 UINTN\r
-EFIAPI\r
-DelayWorker (\r
-  IN      UINT64                    NDelay\r
+InternalX86GetApicBase (\r
+  VOID\r
+  )\r
+{\r
+  return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;\r
+}\r
+\r
+/**\r
+  Internal function to return the frequency of the local APIC timer.\r
+\r
+  Internal function to return the frequency of the local APIC timer.\r
+\r
+  @param  ApicBase  The base address of memory mapped registers of local APIC.\r
+\r
+  @return The frequency of the timer in Hz.\r
+\r
+**/\r
+STATIC\r
+UINT32\r
+InternalX86GetTimerFrequency (\r
+  IN      UINTN                     ApicBase\r
+  )\r
+{\r
+  return\r
+    mTimerLibLocalApicFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /\r
+    mTimerLibLocalApicDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];\r
+}\r
+\r
+/**\r
+  Internal function to read the current tick counter of local APIC.\r
+\r
+  Internal function to read the current tick counter of local APIC.\r
+\r
+  @param  ApicBase  The base address of memory mapped registers of local APIC.\r
+\r
+  @return The tick counter read.\r
+\r
+**/\r
+STATIC\r
+INT32\r
+InternalX86GetTimerTick (\r
+  IN      UINTN                     ApicBase\r
   )\r
 {\r
-  UINT64                            Ticks;\r
-\r
-  Ticks = GetPerformanceCounter ();\r
-  Ticks -= DivU64x32 (\r
-             MultU64x64 (\r
-               GetPerformanceCounterProperties (NULL, NULL),\r
-               NDelay\r
-               ),\r
-             1000000000u\r
-             );\r
-  while (Ticks <= GetPerformanceCounter ());\r
-  return (UINTN)Ticks;\r
+  return MmioRead32 (ApicBase + 0x390);\r
+}\r
+\r
+/**\r
+  Stalls the CPU for at least the given number of ticks.\r
+\r
+  Stalls the CPU for at least the given number of ticks. It's invoked by\r
+  MicroSecondDelay() and NanoSecondDelay().\r
+\r
+  @param  ApicBase  The base address of memory mapped registers of local APIC.\r
+  @param  Delay     A period of time to delay in ticks.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+InternalX86Delay (\r
+  IN      UINTN                     ApicBase,\r
+  IN      UINT32                    Delay\r
+  )\r
+{\r
+  INT32                             Ticks;\r
+\r
+  ApicBase = InternalX86GetApicBase ();\r
+\r
+  //\r
+  // The target timer count is calculated here\r
+  //\r
+  Ticks = InternalX86GetTimerTick (ApicBase) - Delay;\r
+\r
+  //\r
+  // Wait until time out\r
+  // Delay > 2^31 could not be handled by this function\r
+  // Timer wrap-arounds are handled correctly by this function\r
+  //\r
+  while (InternalX86GetTimerTick (ApicBase) - Ticks >= 0);\r
 }\r
 \r
 /**\r
@@ -46,7 +137,7 @@ DelayWorker (
 \r
   @param  MicroSeconds  The minimum number of microseconds to delay.\r
 \r
-  @return Return value depends on implementation.\r
+  @return MicroSeconds\r
 \r
 **/\r
 UINTN\r
@@ -55,7 +146,20 @@ MicroSecondDelay (
   IN      UINTN                     MicroSeconds\r
   )\r
 {\r
-  return DelayWorker (MicroSeconds * 1000ull);\r
+  UINTN                             ApicBase;\r
+\r
+  ApicBase = InternalX86GetApicBase ();\r
+  InternalX86Delay (\r
+    ApicBase,\r
+    (UINT32)DivU64x32 (\r
+              MultU64x64 (\r
+                InternalX86GetTimerFrequency (ApicBase),\r
+                MicroSeconds\r
+                ),\r
+              1000000u\r
+              )\r
+    );\r
+  return MicroSeconds;\r
 }\r
 \r
 /**\r
@@ -65,7 +169,7 @@ MicroSecondDelay (
 \r
   @param  NanoSeconds The minimum number of nanoseconds to delay.\r
 \r
-  @return Return value depends on implementation.\r
+  @return NanoSeconds\r
 \r
 **/\r
 UINTN\r
@@ -74,17 +178,20 @@ NanoSecondDelay (
   IN      UINTN                     NanoSeconds\r
   )\r
 {\r
-  return DelayWorker (NanoSeconds);\r
-}\r
+  UINTN                             ApicBase;\r
 \r
-static\r
-UINTN\r
-EFIAPI\r
-GetApicBase (\r
-  VOID\r
-  )\r
-{\r
-  return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;\r
+  ApicBase = InternalX86GetApicBase ();\r
+  InternalX86Delay (\r
+    ApicBase,\r
+    (UINT32)DivU64x32 (\r
+              MultU64x64 (\r
+                InternalX86GetTimerFrequency (ApicBase),\r
+                NanoSeconds\r
+                ),\r
+              1000000000u\r
+              )\r
+    );\r
+  return NanoSeconds;\r
 }\r
 \r
 /**\r
@@ -105,7 +212,7 @@ GetPerformanceCounter (
   VOID\r
   )\r
 {\r
-  return MmioRead32 (GetApicBase () + 0x390);\r
+  return InternalX86GetTimerTick (InternalX86GetApicBase ());\r
 }\r
 \r
 /**\r
@@ -138,22 +245,9 @@ GetPerformanceCounterProperties (
   IN      UINT64                    *EndValue\r
   )\r
 {\r
-  static const UINT32               mFrequencies[] = {\r
-    100000000,\r
-    133000000,\r
-    200000000,\r
-    166000000\r
-  };\r
-  static const UINT8                mDivisor[] = {\r
-    0x02, 0x04, 0x08, 0x10,\r
-    0x02, 0x04, 0x08, 0x10,\r
-    0x20, 0x40, 0x80, 0x01,\r
-    0x20, 0x40, 0x80, 0x01\r
-  };\r
-\r
   UINTN                             ApicBase;\r
 \r
-  ApicBase = GetApicBase ();\r
+  ApicBase = InternalX86GetApicBase ();\r
 \r
   if (StartValue != NULL) {\r
     *StartValue = MmioRead32 (ApicBase + 0x380);\r
@@ -163,6 +257,5 @@ GetPerformanceCounterProperties (
     *EndValue = 0;\r
   }\r
 \r
-  return mFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /\r
-         mDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];\r
+  return InternalX86GetTimerFrequency (ApicBase);\r
 }\r