2020-09-30 17:12:29 +02:00

269 lines
5.3 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*****************************************************************************
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;
}