673 lines
15 KiB
C
673 lines
15 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
i64clock.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bernard Lint, M. Jayakumar
|
|||
|
Ron Mosgrove - Intel
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Based on halmps/mpclockc.c
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
|
|||
|
extern ULONG HalpNextRate;
|
|||
|
extern BOOLEAN HalpClockSetMSRate;
|
|||
|
int _fltused;
|
|||
|
|
|||
|
BOOLEAN ReadPerfMonCounter = FALSE;
|
|||
|
ULONG HalpCPUMHz;
|
|||
|
|
|||
|
#if defined(INSTRUMENT_CLOCK_DRIFT)
|
|||
|
ULONGLONG HalpITMSkew;
|
|||
|
ULONG HalpCountBadITMValues;
|
|||
|
ULONGLONG HalpMinITMMissed;
|
|||
|
ULONGLONG HalpMaxITMMissed;
|
|||
|
|
|||
|
ULONG HalpBreakMissedTickMin;
|
|||
|
ULONG HalpBreakMissedTickMax = ~0U;
|
|||
|
BOOLEAN HalpResetITMDebug;
|
|||
|
#endif
|
|||
|
|
|||
|
#if DBG
|
|||
|
// Thierry - until compiler supports the generation of enum types in pdbs...
|
|||
|
// At that time, we will be able the use the enums instead of globals.
|
|||
|
unsigned int HalpDpfltrMaxMask = HALIA64_DPFLTR_MAXMASK;
|
|||
|
#endif // DBG
|
|||
|
|
|||
|
|
|||
|
ULONGLONG HalpITCFrequency = 500000000; // 500MHz for default real hardware power on.
|
|||
|
ULONGLONG HalpProcessorFrequency = 500000000; // 500MHz CPU
|
|||
|
|
|||
|
ULONG HalpMissedTickCount[HAL_MAXIMUM_PROCESSOR];
|
|||
|
|
|||
|
//
|
|||
|
// Ticks per 100ns used to compute ITM update count
|
|||
|
//
|
|||
|
|
|||
|
double HalpITCTicksPer100ns;
|
|||
|
ULONGLONG HalpClockCount;
|
|||
|
|
|||
|
//
|
|||
|
// HalpSetNextClockInterrupt():
|
|||
|
// move to cr.itm latency (= 40 cycles) + 2 cycles from the itc read.
|
|||
|
//
|
|||
|
|
|||
|
ULONGLONG HalpITMUpdateLatency = 42;
|
|||
|
|
|||
|
//
|
|||
|
// All of these are in 100ns units
|
|||
|
//
|
|||
|
|
|||
|
ULONGLONG HalpCurrentTimeIncrement = DEFAULT_CLOCK_INTERVAL;
|
|||
|
ULONGLONG HalpNextTimeIncrement = DEFAULT_CLOCK_INTERVAL;
|
|||
|
ULONGLONG HalpNewTimeIncrement = DEFAULT_CLOCK_INTERVAL;
|
|||
|
|
|||
|
ULONG HalpProfileInterval = DEFAULT_PROFILE_INTERVAL;
|
|||
|
BOOLEAN HalpProfileStopped = TRUE;
|
|||
|
|
|||
|
ULONGLONG // = (current ITC - previous ITM)
|
|||
|
HalpSetNextClockInterrupt(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,HalpSetInitialClockRate)
|
|||
|
#pragma alloc_text(INIT,HalpInitializeTimerResolution)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpClearClock (
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Set clock to zero.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HalpWriteITC(0);
|
|||
|
HalpWriteITM(0);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeClock (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initialize system time clock (ITC and ITM) to generate an interrupt
|
|||
|
at every 10 ms interval at ITC_CLOCK_VECTOR.
|
|||
|
|
|||
|
Previously this routine initialize system time clock using 8254 timer1
|
|||
|
counter 0 to generate an interrupt at every 15ms interval at 8259 irq0.
|
|||
|
|
|||
|
See the definitions of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
|
|||
|
needs to be changed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HalpSetInitialClockRate();
|
|||
|
HalpClearClock();
|
|||
|
HalpWriteITM(PCR->HalReserved[CURRENT_ITM_VALUE_INDEX]);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeClockPn (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Assumes that only non-BSP processors call this routine.
|
|||
|
Initializes system time clock (ITC and ITM) to generate an interrupt
|
|||
|
at every 10 ms interval at ITC_CLOCK_VECTOR.
|
|||
|
|
|||
|
Previously this routine initialize system time clock using 8254 timer1
|
|||
|
counter 0 to generate an interrupt at every 15ms interval at 8259 irq0.
|
|||
|
|
|||
|
See the definitions of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
|
|||
|
needs to be changed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONGLONG itmValue;
|
|||
|
|
|||
|
itmValue = (ULONGLONG)(HalpITCTicksPer100ns * MAXIMUM_CLOCK_INTERVAL);
|
|||
|
PCR->HalReserved[CURRENT_ITM_VALUE_INDEX] = itmValue;
|
|||
|
HalpClearClock();
|
|||
|
HalpWriteITM( itmValue );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpSetInitialClockRate (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called to set the initial clock interrupt rate
|
|||
|
Assumes that only the BSP processor calls this routine.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// CPU Frequency in MHz = ticks per second / 10 ** 6
|
|||
|
//
|
|||
|
|
|||
|
HalpCPUMHz = (ULONG)((HalpProcessorFrequency + 500000) / 1000000);
|
|||
|
|
|||
|
//
|
|||
|
// Ticks per 100ns = ticks per second / 10 ** 7
|
|||
|
//
|
|||
|
|
|||
|
HalpITCTicksPer100ns = (double) HalpITCFrequency / (10000000.);
|
|||
|
if (HalpITCTicksPer100ns < 1) {
|
|||
|
HalpITCTicksPer100ns = 1;
|
|||
|
}
|
|||
|
HalpClockCount = (ULONGLONG)(HalpITCTicksPer100ns * MAXIMUM_CLOCK_INTERVAL);
|
|||
|
PCR->HalReserved[CURRENT_ITM_VALUE_INDEX] = HalpClockCount;
|
|||
|
KeSetTimeIncrement(MAXIMUM_CLOCK_INTERVAL, MINIMUM_CLOCK_INTERVAL);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpClockInterrupt (
|
|||
|
IN PKINTERRUPT_ROUTINE Interrupt,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
System Clock Interrupt Handler, for P0 processor only.
|
|||
|
|
|||
|
N.B. Assumptions: Comes with IRQL set to CLOCK_LEVEL to disable
|
|||
|
interrupts.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TrapFrame - Trap frame address.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONGLONG CurrentITC;
|
|||
|
ULONGLONG currentITCDelta;
|
|||
|
ULONGLONG elapsedTimeIn100ns, numberOfTicksElapsed;
|
|||
|
#if defined(INSTRUMENT_CLOCK_DRIFT)
|
|||
|
ULONGLONG originalITM, currentITM, excessITM;
|
|||
|
#endif
|
|||
|
LONG mcaNotification;
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if a clock interrupt is generated in a small latency window
|
|||
|
// in HalpSetNextClockInterrupt.
|
|||
|
//
|
|||
|
|
|||
|
CurrentITC = HalpReadITC();
|
|||
|
#ifndef DISABLE_ITC_WORKAROUND
|
|||
|
while ((CurrentITC & 0xFFFFFFFF) == 0xFFFFFFFF) {
|
|||
|
CurrentITC = HalpReadITC();
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if ((LONGLONG) (PCR->HalReserved[CURRENT_ITM_VALUE_INDEX] - CurrentITC) > 0)
|
|||
|
{
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// PerfMon: Per P0 clock interrupt PMD4 collection.
|
|||
|
//
|
|||
|
|
|||
|
if (ReadPerfMonCounter) {
|
|||
|
ULONGLONG currentPerfMonValue;
|
|||
|
|
|||
|
currentPerfMonValue = HalpReadPerfMonDataReg4();
|
|||
|
HalDebugPrint(( HAL_INFO, "\nHAL: HalpClockInterrupt - PMD4=%I64x\n", currentPerfMonValue ));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#if defined(INSTRUMENT_CLOCK_DRIFT)
|
|||
|
//
|
|||
|
// Time this interrupt was scheduled to occur
|
|||
|
//
|
|||
|
originalITM = (ULONGLONG)PCR->HalReserved[CURRENT_ITM_VALUE_INDEX];
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Set next clock interrupt, based on ITC and
|
|||
|
// increment ITM, accounting for interrupt latency.
|
|||
|
//
|
|||
|
|
|||
|
currentITCDelta = HalpSetNextClockInterrupt();
|
|||
|
|
|||
|
#if defined(INSTRUMENT_CLOCK_DRIFT)
|
|||
|
//
|
|||
|
// Time the next interrupt is scheduled to occur
|
|||
|
//
|
|||
|
currentITM = (ULONGLONG)PCR->HalReserved[CURRENT_ITM_VALUE_INDEX];
|
|||
|
|
|||
|
excessITM = (currentITM - originalITM) / HalpClockCount - 1;
|
|||
|
|
|||
|
if (excessITM != 0) {
|
|||
|
if (HalpMinITMMissed == 0 || excessITM < HalpMinITMMissed) {
|
|||
|
HalpMinITMMissed = excessITM;
|
|||
|
}
|
|||
|
if (excessITM > HalpMaxITMMissed) {
|
|||
|
HalpMaxITMMissed = excessITM;
|
|||
|
}
|
|||
|
|
|||
|
HalpCountBadITMValues++;
|
|||
|
HalpITMSkew += excessITM;
|
|||
|
|
|||
|
if (HalpBreakMissedTickMin != 0 &&
|
|||
|
HalpBreakMissedTickMin <= excessITM &&
|
|||
|
HalpBreakMissedTickMax >= excessITM &&
|
|||
|
!HalpResetITMDebug) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (HalpResetITMDebug) {
|
|||
|
HalpResetITMDebug = FALSE;
|
|||
|
HalpCountBadITMValues = 0;
|
|||
|
HalpITMSkew = 0;
|
|||
|
HalpMinITMMissed = 0;
|
|||
|
HalpMaxITMMissed = 0;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Call the kernel to update system time.
|
|||
|
// P0 updates System time and Run Time.
|
|||
|
//
|
|||
|
|
|||
|
elapsedTimeIn100ns = (ULONGLONG) (currentITCDelta/HalpITCTicksPer100ns);
|
|||
|
|
|||
|
elapsedTimeIn100ns += HalpCurrentTimeIncrement;
|
|||
|
if (elapsedTimeIn100ns >= MAXIMUM_CLOCK_INTERVAL) {
|
|||
|
|
|||
|
KeUpdateSystemTime( TrapFrame, MAXIMUM_CLOCK_INTERVAL );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
numberOfTicksElapsed = elapsedTimeIn100ns / HalpCurrentTimeIncrement;
|
|||
|
KeUpdateSystemTime( TrapFrame,
|
|||
|
(ULONG)(numberOfTicksElapsed * HalpCurrentTimeIncrement)
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
HalpCurrentTimeIncrement = HalpNextTimeIncrement;
|
|||
|
HalpNextTimeIncrement = HalpNewTimeIncrement;
|
|||
|
|
|||
|
//
|
|||
|
// If MCA notification was requested by MCA Handler, execute it.
|
|||
|
//
|
|||
|
|
|||
|
mcaNotification = InterlockedExchange( &HalpMcaInfo.DpcNotification, 0 );
|
|||
|
if ( mcaNotification ) {
|
|||
|
if ( HalpMcaInfo.KernelDelivery ) {
|
|||
|
if ( !HalpMcaInfo.KernelDelivery( HalpMcaInfo.KernelToken, NULL ) ) {
|
|||
|
InterlockedIncrement( &HalpMcaInfo.Stats.KernelDeliveryFails );
|
|||
|
}
|
|||
|
}
|
|||
|
if ( HalpMcaInfo.DriverInfo.DpcCallback ) {
|
|||
|
if ( !KeInsertQueueDpc( &HalpMcaInfo.DriverDpc, NULL, NULL ) ) {
|
|||
|
InterlockedIncrement( &HalpMcaInfo.Stats.DriverDpcQueueFails );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Poll for debugger breakin if enabled.
|
|||
|
//
|
|||
|
|
|||
|
if ( KdDebuggerEnabled && KdPollBreakIn() ) {
|
|||
|
KeBreakinBreakpoint();
|
|||
|
}
|
|||
|
|
|||
|
} // HalpClockInterrupt()
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpClockInterruptPn (
|
|||
|
IN PKINTERRUPT_ROUTINE Interrupt,
|
|||
|
IN PKTRAP_FRAME TrapFrame
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
System Clock Interrupt Handler, for processors other than P0.
|
|||
|
|
|||
|
N.B. Assumptions: Comes with IRQL set to CLOCK_LEVEL to disable
|
|||
|
interrupts.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
TrapFrame - Trap frame address.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Set next clock interrupt, based on ITC and
|
|||
|
// increment ITM, accounting for interrupt latency.
|
|||
|
//
|
|||
|
|
|||
|
(void)HalpSetNextClockInterrupt();
|
|||
|
|
|||
|
//
|
|||
|
// Call the kernel to update run time.
|
|||
|
// Pn updates only Run time.
|
|||
|
//
|
|||
|
|
|||
|
KeUpdateRunTime(TrapFrame);
|
|||
|
|
|||
|
// IA64 MCA Notification - 09/18/2000 - WARNING
|
|||
|
// If faster MCA notification was required, the BSP MCA notification checking
|
|||
|
// should be placed here.
|
|||
|
//
|
|||
|
|
|||
|
} // HalpClockInterruptPn()
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeClockInterrupts (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PKPRCB Prcb;
|
|||
|
UCHAR InterruptVector;
|
|||
|
ULONGLONG ITVData;
|
|||
|
|
|||
|
Prcb = PCR->Prcb;
|
|||
|
InterruptVector = CLOCK_LEVEL << VECTOR_IRQL_SHIFT;
|
|||
|
|
|||
|
if (Prcb -> Number == 0) {
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector(InterruptVector,HalpClockInterrupt);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Non-BSP processor
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector(InterruptVector, HalpClockInterruptPn);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ITVData = (ULONGLONG) InterruptVector;
|
|||
|
|
|||
|
HalpWriteITVector(ITVData);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ULONG
|
|||
|
HalSetTimeIncrement (
|
|||
|
IN ULONG DesiredIncrement
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called to set the clock interrupt rate to the frequency
|
|||
|
required by the specified time increment value.
|
|||
|
|
|||
|
N.B. This function is only executed on the processor that keeps the
|
|||
|
system time. Previously this was called HalpSetTimeIncrement. We
|
|||
|
have renamed it HalSetTimeIncrement.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DesiredIncrement - Supplies desired number of 100ns units between clock
|
|||
|
interrupts.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The actual time increment in 100ns units.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONGLONG NextIntervalCount;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
//
|
|||
|
// DesiredIncrement must map within the acceptable range.
|
|||
|
//
|
|||
|
|
|||
|
if (DesiredIncrement < MINIMUM_CLOCK_INTERVAL)
|
|||
|
DesiredIncrement = MINIMUM_CLOCK_INTERVAL;
|
|||
|
else if (DesiredIncrement > MAXIMUM_CLOCK_INTERVAL)
|
|||
|
DesiredIncrement = MAXIMUM_CLOCK_INTERVAL;
|
|||
|
|
|||
|
//
|
|||
|
// Raise IRQL to the highest level, set the new clock interrupt
|
|||
|
// parameters, lower IRQl, and return the new time increment value.
|
|||
|
//
|
|||
|
|
|||
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the actual 64 bit time value which forms the target interval.
|
|||
|
// The resulting value is added to the ITC to form the new ITM value.
|
|||
|
// HalpITCTicksPer100ns is the calibrated value for the ITC whose value
|
|||
|
// works out to be 100ns (or as close as we can come).
|
|||
|
// Previously HalpITCTicksPer100ns was called as HalpPerformanceFrequency
|
|||
|
//
|
|||
|
|
|||
|
NextIntervalCount = (ULONGLONG)(HalpITCTicksPer100ns * DesiredIncrement);
|
|||
|
|
|||
|
//
|
|||
|
// Calculate the number of 100ns units to report to the kernel every
|
|||
|
// time the ITM matches the ITC with this new period. Note, for small
|
|||
|
// values of DesiredIncrement (min being 10000, ie 1ms), truncation
|
|||
|
// in the above may result in a small decrement in the 5th decimal
|
|||
|
// place. As we are effectively dealing with a 4 digit number, eg
|
|||
|
// 10000 becomes 9999.something, we really can't do any better than
|
|||
|
// the following.
|
|||
|
//
|
|||
|
|
|||
|
HalpClockCount = NextIntervalCount;
|
|||
|
|
|||
|
HalpNewTimeIncrement = DesiredIncrement;
|
|||
|
|
|||
|
//
|
|||
|
// HalpClockSetMSRate = TRUE;
|
|||
|
//
|
|||
|
|
|||
|
KeLowerIrql(OldIrql);
|
|||
|
return DesiredIncrement;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
HalpQueryFrequency(
|
|||
|
PULONGLONG ITCFrequency,
|
|||
|
PULONGLONG ProcessorFrequency
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called to provide the ITC update rate.
|
|||
|
This value is computed by first getting the platform base frequency
|
|||
|
from the SAL_FREQ_BASE call. Then applying on the return value, the
|
|||
|
ITC ratios obtained from the PAL_FREQ_RATIOS call.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
ULONGLONG ITCFrequency - number of ITC updates per seconds
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
ULONG ITCRatioDenominator = 0;
|
|||
|
ULONG ITCRatioNumerator = 0;
|
|||
|
ULONG ProcessorRatioDenominator = 0;
|
|||
|
ULONG ProcessorRatioNumerator = 0;
|
|||
|
|
|||
|
SAL_PAL_RETURN_VALUES SalReturn = {0};
|
|||
|
SAL_PAL_RETURN_VALUES PalReturn = {0};
|
|||
|
|
|||
|
SAL_STATUS SalStatus;
|
|||
|
PAL_STATUS PalStatus;
|
|||
|
|
|||
|
SalStatus = HalpSalCall(SAL_FREQ_BASE,
|
|||
|
0 /* Platform base clock frequency is the clock input to the processor */,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
&SalReturn);
|
|||
|
if (SalStatus != 0) {
|
|||
|
HalDebugPrint(( HAL_ERROR,
|
|||
|
"HAL: HalInitSystem - Phase1 SAL_FREQ_BASE is returning error # %d\n",
|
|||
|
SalStatus ));
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
HalDebugPrint(( HAL_INFO, "HAL: HalInitSystem - Platform base clock Frequency is %I64u\n",SalReturn.ReturnValues[1] ));
|
|||
|
|
|||
|
PalStatus = HalpPalCall( PAL_FREQ_RATIOS,
|
|||
|
0,
|
|||
|
0,
|
|||
|
0,
|
|||
|
&PalReturn);
|
|||
|
if (PalStatus != 0) {
|
|||
|
HalDebugPrint(( HAL_ERROR,
|
|||
|
"HAL: HalInitSystem - Phase1 PAL_FREQ_RATIOS is returning error # %d\n",
|
|||
|
PalStatus ));
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
|
|||
|
ProcessorRatioNumerator = (ULONG)((PalReturn.ReturnValues[1]) >> 32);
|
|||
|
ProcessorRatioDenominator = (ULONG)( PalReturn.ReturnValues[1]);
|
|||
|
|
|||
|
HalDebugPrint(( HAL_INFO,
|
|||
|
"HAL: HalInitSystem - PAL returns Processor to Platform clock Frequency as %lu : %lu\n",
|
|||
|
ProcessorRatioNumerator,
|
|||
|
ProcessorRatioDenominator));
|
|||
|
|
|||
|
*ProcessorFrequency = SalReturn.ReturnValues[1] * ProcessorRatioNumerator / ProcessorRatioDenominator;
|
|||
|
|
|||
|
HalDebugPrint(( HAL_INFO,
|
|||
|
"HAL: HalInitSystem - Processor clock Frequency is %I64u \n",
|
|||
|
ProcessorFrequency ));
|
|||
|
|
|||
|
ITCRatioNumerator = (ULONG)((PalReturn.ReturnValues[3]) >> 32);
|
|||
|
ITCRatioDenominator = (ULONG)( PalReturn.ReturnValues[3]);
|
|||
|
|
|||
|
HalDebugPrint(( HAL_INFO,
|
|||
|
"HAL: HalInitSystem - PAL returns ITC to Platform clock Frequency as %lu : %lu\n",
|
|||
|
ITCRatioNumerator,
|
|||
|
ITCRatioDenominator));
|
|||
|
|
|||
|
*ITCFrequency = SalReturn.ReturnValues[1] * ITCRatioNumerator / ITCRatioDenominator;
|
|||
|
|
|||
|
HalDebugPrint(( HAL_INFO,
|
|||
|
"HAL: HalInitSystem - ITC clock Frequency is %I64u \n",
|
|||
|
ITCFrequency ));
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|