1. Updated declaration of timer functions according to latest MWG.

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
This commit is contained in:
bxing 2006-07-25 07:33:02 +00:00
parent 26015d2294
commit ed384ef31c
4 changed files with 228 additions and 76 deletions

View File

@ -24,7 +24,7 @@
@param MicroSeconds The minimum number of microseconds to delay.
@return Return value depends on implementation.
@return MicroSeconds
**/
UINTN
@ -40,7 +40,7 @@ MicroSecondDelay (
@param NanoSeconds The minimum number of nanoseconds to delay.
@return Return value depends on implementation.
@return NanoSeconds
**/
UINTN

View File

@ -18,11 +18,6 @@
**/
UINT64
ReadItc (
VOID
);
typedef struct {
UINT64 Status;
UINT64 r9;
@ -30,6 +25,21 @@ typedef struct {
UINT64 r11;
} PAL_PROC_RETURN;
/**
Performs a PAL call using static calling convention.
An internal function to perform a PAL call using static calling convention.
@param PalEntryPoint The entry point address of PAL. The address in ar.kr5
would be used if this parameter were NULL on input.
@param Arg1 The first argument of a PAL call.
@param Arg1 The second argument of a PAL call.
@param Arg1 The third argument of a PAL call.
@param Arg1 The fourth argument of a PAL call.
@return The values returned in r8, r9, r10 and r11.
**/
PAL_PROC_RETURN
PalCallStatic (
IN CONST VOID *PalEntryPoint,
@ -39,6 +49,50 @@ PalCallStatic (
IN UINT64 Arg4
);
/**
Returns the current value of ar.itc.
An internal function to return the current value of ar.itc, which is the
timer tick on IPF.
@return The currect value of ar.itc
**/
INT64
InternalIpfReadItc (
VOID
);
/**
Performs a delay measured as number of ticks.
An internal function to perform a delay measured as number of ticks. It's
invoked by MicroSecondDelay() and NanoSecondDelay().
@param Delay Number of ticks to delay.
**/
STATIC
VOID
InternalIpfDelay (
IN INT64 Delay
)
{
INT64 Ticks;
//
// The target timer count is calculated here
//
Ticks = InternalIpfReadItc () + Delay;
//
// Wait until time out
// Delay > 2^63 could not be handled by this function
// Timer wrap-arounds are handled correctly by this function
//
while (Ticks - InternalIpfReadItc () >= 0);
}
/**
Stalls the CPU for at least the given number of microseconds.
@ -46,7 +100,7 @@ PalCallStatic (
@param MicroSeconds The minimum number of microseconds to delay.
@return The ticks delayed actually.
@return MicroSeconds
**/
UINTN
@ -55,13 +109,12 @@ MicroSecondDelay (
IN UINTN MicroSeconds
)
{
UINT64 Ticks;
UINT64 Delay;
Ticks = GetPerformanceCounter ();
Delay = GetPerformanceCounterProperties (NULL, NULL) * MicroSeconds / 1000000;
while (Ticks + Delay >= GetPerformanceCounter ());
return (UINTN)Delay;
InternalIpfDelay (
GetPerformanceCounterProperties (NULL, NULL) *
MicroSeconds /
1000000
);
return MicroSeconds;
}
/**
@ -71,7 +124,7 @@ MicroSecondDelay (
@param NanoSeconds The minimum number of nanoseconds to delay.
@return The ticks delayed actually.
@return NanoSeconds
**/
UINTN
@ -80,13 +133,12 @@ NanoSecondDelay (
IN UINTN NanoSeconds
)
{
UINT64 Ticks;
UINT64 Delay;
Ticks = GetPerformanceCounter ();
Delay = GetPerformanceCounterProperties (NULL, NULL) * NanoSeconds / 1000000000;
while (Ticks + Delay >= GetPerformanceCounter ());
return (UINTN)Delay;
InternalIpfDelay (
GetPerformanceCounterProperties (NULL, NULL) *
NanoSeconds /
1000000000
);
return NanoSeconds;
}
/**
@ -107,7 +159,7 @@ GetPerformanceCounter (
VOID
)
{
return ReadItc ();
return InternalIpfReadItc ();
}
/**
@ -150,7 +202,13 @@ GetPerformanceCounterProperties (
PalRet = PalCallStatic (NULL, 14, 0, 0, 0);
ASSERT (PalRet.Status == 0);
*StartValue = 0;
*EndValue = (UINT64)(-1);
if (StartValue != NULL) {
*StartValue = 0;
}
if (EndValue != NULL) {
*EndValue = (UINT64)(-1);
}
return BaseFrequence * (PalRet.r11 >> 32) / (UINT32)PalRet.r11;
}

View File

@ -1,5 +1,6 @@
/// @file
/// Contains an implementation of ReadItc on Itanium-based architecture.
/// Contains an implementation of InternalIpfReadItc () on Itanium-based
/// architecture.
///
/// Copyright (c) 2006, Intel Corporation
/// All rights reserved. This program and the accompanying materials
@ -17,9 +18,9 @@
.auto
.text
.proc ReadItc
.type ReadItc, @function
ReadItc::
.proc InternalIpfReadItc
.type InternalIpfReadItc, @function
InternalIpfReadItc::
mov r8 = ar.itc
br.ret.sptk.many b0
.endp ReadItc
.endp InternalIpfReadItc

View File

@ -18,25 +18,116 @@
**/
static
//
// The following 2 arrays are used in calculating the frequency of local APIC
// timer. Refer to IA-32 developers' manual for more details.
//
GLOBAL_REMOVE_IF_UNREFERENCED
CONST UINT32 mTimerLibLocalApicFrequencies[] = {
100000000,
133000000,
200000000,
166000000
};
GLOBAL_REMOVE_IF_UNREFERENCED
CONST UINT8 mTimerLibLocalApicDivisor[] = {
0x02, 0x04, 0x08, 0x10,
0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x01,
0x20, 0x40, 0x80, 0x01
};
/**
Internal function to retrieve the base address of local APIC.
Internal function to retrieve the base address of local APIC.
@return The base address of local APIC
**/
STATIC
UINTN
EFIAPI
DelayWorker (
IN UINT64 NDelay
InternalX86GetApicBase (
VOID
)
{
UINT64 Ticks;
return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;
}
Ticks = GetPerformanceCounter ();
Ticks -= DivU64x32 (
MultU64x64 (
GetPerformanceCounterProperties (NULL, NULL),
NDelay
),
1000000000u
);
while (Ticks <= GetPerformanceCounter ());
return (UINTN)Ticks;
/**
Internal function to return the frequency of the local APIC timer.
Internal function to return the frequency of the local APIC timer.
@param ApicBase The base address of memory mapped registers of local APIC.
@return The frequency of the timer in Hz.
**/
STATIC
UINT32
InternalX86GetTimerFrequency (
IN UINTN ApicBase
)
{
return
mTimerLibLocalApicFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /
mTimerLibLocalApicDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];
}
/**
Internal function to read the current tick counter of local APIC.
Internal function to read the current tick counter of local APIC.
@param ApicBase The base address of memory mapped registers of local APIC.
@return The tick counter read.
**/
STATIC
INT32
InternalX86GetTimerTick (
IN UINTN ApicBase
)
{
return MmioRead32 (ApicBase + 0x390);
}
/**
Stalls the CPU for at least the given number of ticks.
Stalls the CPU for at least the given number of ticks. It's invoked by
MicroSecondDelay() and NanoSecondDelay().
@param ApicBase The base address of memory mapped registers of local APIC.
@param Delay A period of time to delay in ticks.
**/
STATIC
VOID
InternalX86Delay (
IN UINTN ApicBase,
IN UINT32 Delay
)
{
INT32 Ticks;
ApicBase = InternalX86GetApicBase ();
//
// The target timer count is calculated here
//
Ticks = InternalX86GetTimerTick (ApicBase) - Delay;
//
// Wait until time out
// Delay > 2^31 could not be handled by this function
// Timer wrap-arounds are handled correctly by this function
//
while (InternalX86GetTimerTick (ApicBase) - Ticks >= 0);
}
/**
@ -46,7 +137,7 @@ DelayWorker (
@param MicroSeconds The minimum number of microseconds to delay.
@return Return value depends on implementation.
@return MicroSeconds
**/
UINTN
@ -55,7 +146,20 @@ MicroSecondDelay (
IN UINTN MicroSeconds
)
{
return DelayWorker (MicroSeconds * 1000ull);
UINTN ApicBase;
ApicBase = InternalX86GetApicBase ();
InternalX86Delay (
ApicBase,
(UINT32)DivU64x32 (
MultU64x64 (
InternalX86GetTimerFrequency (ApicBase),
MicroSeconds
),
1000000u
)
);
return MicroSeconds;
}
/**
@ -65,7 +169,7 @@ MicroSecondDelay (
@param NanoSeconds The minimum number of nanoseconds to delay.
@return Return value depends on implementation.
@return NanoSeconds
**/
UINTN
@ -74,17 +178,20 @@ NanoSecondDelay (
IN UINTN NanoSeconds
)
{
return DelayWorker (NanoSeconds);
}
UINTN ApicBase;
static
UINTN
EFIAPI
GetApicBase (
VOID
)
{
return (UINTN)AsmMsrBitFieldRead64 (27, 12, 35) << 12;
ApicBase = InternalX86GetApicBase ();
InternalX86Delay (
ApicBase,
(UINT32)DivU64x32 (
MultU64x64 (
InternalX86GetTimerFrequency (ApicBase),
NanoSeconds
),
1000000000u
)
);
return NanoSeconds;
}
/**
@ -105,7 +212,7 @@ GetPerformanceCounter (
VOID
)
{
return MmioRead32 (GetApicBase () + 0x390);
return InternalX86GetTimerTick (InternalX86GetApicBase ());
}
/**
@ -138,22 +245,9 @@ GetPerformanceCounterProperties (
IN UINT64 *EndValue
)
{
static const UINT32 mFrequencies[] = {
100000000,
133000000,
200000000,
166000000
};
static const UINT8 mDivisor[] = {
0x02, 0x04, 0x08, 0x10,
0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x80, 0x01,
0x20, 0x40, 0x80, 0x01
};
UINTN ApicBase;
ApicBase = GetApicBase ();
ApicBase = InternalX86GetApicBase ();
if (StartValue != NULL) {
*StartValue = MmioRead32 (ApicBase + 0x380);
@ -163,6 +257,5 @@ GetPerformanceCounterProperties (
*EndValue = 0;
}
return mFrequencies[AsmMsrBitFieldRead32 (44, 16, 18)] /
mDivisor[MmioBitFieldRead32 (ApicBase + 0x3e0, 0, 3)];
return InternalX86GetTimerFrequency (ApicBase);
}