269 lines
5.3 KiB
C
269 lines
5.3 KiB
C
|
||
/*****************************************************************************
|
||
|
||
Copyright (c) 1993 Motorola Inc.
|
||
Copyright 1994 MOTOROLA, INC. All Rights Reserved. This file
|
||
contains copyrighted material. Use of this file is restricted
|
||
by the provisions of a Motorola Software License Agreement.
|
||
|
||
Module Name:
|
||
|
||
PXPROF.C
|
||
|
||
Abstract:
|
||
|
||
This implements the HAL profile functions:
|
||
|
||
HalSetProfileInterval
|
||
HalStartProfileInterrupt
|
||
HalStopProfileInterrupt
|
||
HalCalibratePerformanceCounter
|
||
HalpProfileInterrupt
|
||
|
||
|
||
Author:
|
||
|
||
Steve Johns 11-Feb-1994
|
||
|
||
Revision History:
|
||
Changed from using the DECREMENTER to 8254 Timer 1 10-Feb-94
|
||
|
||
******************************************************************************/
|
||
|
||
#include "halp.h"
|
||
#include "eisa.h"
|
||
#include "pxsiosup.h"
|
||
|
||
#define TIMER ((PEISA_CONTROL)HalpIoControlBase)
|
||
#define TIMER0_COMMAND (COMMAND_8254_COUNTER0 + COMMAND_8254_RW_16BIT + COMMAND_8254_MODE2)
|
||
|
||
ULONG HalpMaxProfileInterval = 540000; // 54 ms maximum
|
||
ULONG HalpMinProfileInterval = 10000; // 1 ms minimum
|
||
ULONG HalpProfileCount;
|
||
BOOLEAN HalpProfilingActive = FALSE;
|
||
ULONG HalpProfileInts = 0;
|
||
|
||
|
||
VOID HalStartProfileInterrupt (
|
||
KPROFILE_SOURCE ProfileSource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine unmasks IRQ0 at the master interrupt controller,
|
||
enabling the profile interrupt.
|
||
|
||
|
||
N.B. This routine must be called at PROFILE_LEVEL while holding
|
||
the profile lock.
|
||
|
||
Arguments:
|
||
|
||
ProfileSource
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
if (ProfileSource == ProfileTime) {
|
||
HalpProfilingActive = TRUE;
|
||
//
|
||
// Unmasks IRQ 0 (Timer 1)
|
||
//
|
||
HalEnableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL, Latched);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
ULONG HalSetProfileInterval (
|
||
IN ULONG Interval
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the profile interrupt interval.
|
||
|
||
Arguments:
|
||
|
||
Interval - Supplies the desired profile interval in 100ns units.
|
||
|
||
Return Value:
|
||
|
||
The actual profile interval, rounded to the nearest 100ns units.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG ActualInterval;
|
||
LARGE_INTEGER BigNumber;
|
||
|
||
//
|
||
// Clamp the requested profile interval between the minimum and
|
||
// maximum supported values.
|
||
//
|
||
if (Interval < HalpMinProfileInterval)
|
||
Interval = HalpMinProfileInterval;
|
||
else
|
||
if (Interval > HalpMaxProfileInterval)
|
||
Interval = HalpMaxProfileInterval;
|
||
//
|
||
// Compute Timer 1 counts for requested interval.
|
||
//
|
||
BigNumber.QuadPart = Int32x32To64(Interval, TIMER_CLOCK_IN);
|
||
|
||
BigNumber = RtlExtendedLargeIntegerDivide(BigNumber, 10000000, NULL);
|
||
HalpProfileCount = BigNumber.LowPart;
|
||
|
||
//
|
||
// Program Timer 1 to Mode 2 & program the timer count register.
|
||
//
|
||
WRITE_REGISTER_UCHAR (&(TIMER->CommandMode1), TIMER0_COMMAND);
|
||
WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount & 0xff));
|
||
WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount >> 8));
|
||
//
|
||
// Compute actual interval.
|
||
//
|
||
BigNumber.QuadPart = Int32x32To64(HalpProfileCount, 10000000);
|
||
BigNumber = RtlExtendedLargeIntegerDivide(BigNumber,TIMER_CLOCK_IN, NULL);
|
||
ActualInterval = BigNumber.LowPart;
|
||
|
||
return (ActualInterval);
|
||
}
|
||
|
||
|
||
|
||
|
||
BOOLEAN HalpHandleProfileInterrupt(
|
||
IN PKINTERRUPT Interrupt,
|
||
IN PVOID ServiceContext,
|
||
IN PVOID TrapFrame
|
||
)
|
||
{
|
||
|
||
if (HalpProfilingActive)
|
||
KeProfileInterrupt(TrapFrame);
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
HalStopProfileInterrupt (
|
||
KPROFILE_SOURCE ProfileSource
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine masks IRQ 0 (Timer 1) at the interrupt controller, thereby
|
||
stopping profile interrupts.
|
||
|
||
N.B. This routine must be called at PROFILE_LEVEL while holding the
|
||
profile lock.
|
||
|
||
Arguments:
|
||
|
||
ProfileSource
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
if (ProfileSource == ProfileTime) {
|
||
HalpProfilingActive = FALSE;
|
||
|
||
//
|
||
// Program Timer 1 to Mode 2 & program the LSB of the timer.
|
||
// That should keep it from interrupting in case IRQ0 accidently
|
||
// gets enabled.
|
||
//
|
||
WRITE_REGISTER_UCHAR (&(TIMER->CommandMode1), TIMER0_COMMAND);
|
||
WRITE_REGISTER_UCHAR (&(TIMER->Timer1), (UCHAR)(HalpProfileCount & 0xff));
|
||
|
||
|
||
//
|
||
// Mask IRQ 0 (Timer 1)
|
||
//
|
||
HalDisableSystemInterrupt(PROFILE_VECTOR, PROFILE_LEVEL);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
VOID
|
||
HalCalibratePerformanceCounter (
|
||
IN volatile PLONG Number
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine resets the performance counter value for the current
|
||
processor to zero. The reset is done such that the resulting value
|
||
is closely synchronized with other processors in the configuration.
|
||
|
||
Arguments:
|
||
|
||
Number - Supplies a pointer to count of the number of processors in
|
||
the configuration.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
KSPIN_LOCK Lock;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Raise IRQL to HIGH_LEVEL, decrement the number of processors, and
|
||
// wait until the number is zero.
|
||
//
|
||
KeInitializeSpinLock(&Lock);
|
||
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
||
if (ExInterlockedDecrementLong(Number, &Lock) != RESULT_ZERO) {
|
||
do {
|
||
} while (*Number !=0);
|
||
}
|
||
|
||
//
|
||
// Zero the Time Base registers
|
||
//
|
||
|
||
HalpZeroPerformanceCounter();
|
||
|
||
//
|
||
// Restore IRQL to its previous value and return.
|
||
//
|
||
|
||
KeLowerIrql(OldIrql);
|
||
return;
|
||
}
|