mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
517 lines
9.0 KiB
517 lines
9.0 KiB
/*++
|
|
|
|
Copyright (c) 1992, 1993 Digital Equipment Corporation
|
|
|
|
Module Name:
|
|
|
|
eisaprof.c
|
|
|
|
Abstract:
|
|
|
|
This module handles the Profile Counter and all Profile counter functions
|
|
for the standard EISA interval timer.
|
|
|
|
Author:
|
|
|
|
Jeff McLeman (mcleman) 05-June-1992
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
Rod Gamache [DEC] 9-Mar-1993
|
|
Fix profile clock.
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "eisa.h"
|
|
#include "halprof.h"
|
|
|
|
//
|
|
// Define global data.
|
|
//
|
|
|
|
//
|
|
// Values used for Profile Clock
|
|
//
|
|
|
|
// Convert the interval to rollover count for 8254 timer. Since
|
|
// the 8254 counts down a 16 bit value at the clock rate of 1.193 MHZ,
|
|
// the computation is:
|
|
//
|
|
// RolloverCount = (Interval * 0.0000001) * (1193 * 1000000)
|
|
// = Interval * .1193
|
|
// = Interval * 1193 / 10000
|
|
|
|
#define PROFILE_INTERVAL 1193
|
|
#define PROFILE_INTERVALS_PER_100NS 10000/1193
|
|
#define MIN_PROFILE_TICKS 4
|
|
#define MAX_PROFILE_TICKS 0x10000 // 16 bit counter (zero is max)
|
|
|
|
//
|
|
// Since the profile timer interrupts at a frequency of 1.193 MHZ, we
|
|
// have .1193 intervals each 100ns. So we need a more reasonable value.
|
|
// If we compute the timer based on 1600ns intervals, we get 16 * .1193 or
|
|
// about 1.9 ticks per 16 intervals.
|
|
//
|
|
// We round this to 2 ticks per 1600ns intervals.
|
|
//
|
|
|
|
#define PROFILE_TIMER_1600NS_TICKS 2
|
|
|
|
//
|
|
// Default Profile Interval to be about 1ms.
|
|
//
|
|
|
|
ULONG HalpProfileInterval = PROFILE_TIMER_1600NS_TICKS * PROFILE_INTERVALS_PER_100NS * 10000 / 16; // ~1ms
|
|
|
|
//
|
|
// Default Number of Profile Clock Ticks per sample
|
|
//
|
|
|
|
ULONG HalpNumberOfTicks = 1;
|
|
|
|
//
|
|
// Define the profile interrupt object.
|
|
//
|
|
|
|
PKINTERRUPT HalpProfileInterruptObject;
|
|
|
|
//
|
|
// Declare profile interrupt handler.
|
|
//
|
|
|
|
BOOLEAN
|
|
HalpProfileInterrupt(
|
|
PKSERVICE_ROUTINE InterruptRoutine,
|
|
PVOID ServiceContext,
|
|
PKTRAP_FRAME TrapFrame
|
|
);
|
|
|
|
//
|
|
// Function prototypes.
|
|
//
|
|
|
|
BOOLEAN
|
|
HalQueryProfileInterval(
|
|
IN KPROFILE_SOURCE Source
|
|
);
|
|
|
|
NTSTATUS
|
|
HalSetProfileSourceInterval(
|
|
IN KPROFILE_SOURCE ProfileSource,
|
|
IN OUT ULONG *Interval
|
|
);
|
|
|
|
//
|
|
// Function definitions.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
HalpProfileSourceInformation (
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG ReturnedLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
|
|
|
|
Arguments:
|
|
|
|
Buffer - output buffer
|
|
BufferLength - length of buffer on input
|
|
ReturnedLength - The length of data returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
|
|
currently needed.
|
|
|
|
--*/
|
|
{
|
|
PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
|
|
NTSTATUS Status;
|
|
|
|
|
|
if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
return Status;
|
|
}
|
|
|
|
SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
|
|
SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
|
|
|
|
if (SourceInfo->Supported) {
|
|
SourceInfo->Interval = HalpProfileInterval * HalpNumberOfTicks;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HalpProfileSourceInterval (
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
|
|
|
|
Arguments:
|
|
|
|
Buffer - output buffer
|
|
BufferLength - length of buffer on input
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
|
|
currently needed.
|
|
|
|
--*/
|
|
{
|
|
PHAL_PROFILE_SOURCE_INTERVAL Interval;
|
|
NTSTATUS Status;
|
|
|
|
|
|
if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
|
|
Status = STATUS_INFO_LENGTH_MISMATCH;
|
|
return Status;
|
|
}
|
|
|
|
Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
|
|
Status = HalSetProfileSourceInterval(Interval->Source,
|
|
&Interval->Interval);
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpInitializeProfiler(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the profiler by setting initial values and connecting
|
|
the profile interrupt.
|
|
|
|
Arguments:
|
|
|
|
InterfaceType - Supplies the interface type of the bus on which the
|
|
profiler will be connected.
|
|
|
|
BusNumber - Supplies the number of the bus on which the profiler will
|
|
be connected.
|
|
|
|
BusInterruptLevel - Supplies the bus interrupt level to connect the
|
|
profile interrupt.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KAFFINITY Affinity;
|
|
KIRQL Irql;
|
|
ULONG Vector;
|
|
|
|
//
|
|
// Get the interrupt vector and synchronization Irql.
|
|
//
|
|
|
|
Vector = HalGetInterruptVector( Eisa,
|
|
0,
|
|
0,
|
|
0,
|
|
&Irql,
|
|
&Affinity );
|
|
|
|
IoConnectInterrupt( &HalpProfileInterruptObject,
|
|
(PKSERVICE_ROUTINE)HalpProfileInterrupt,
|
|
NULL,
|
|
NULL,
|
|
Vector,
|
|
Irql,
|
|
Irql,
|
|
Latched,
|
|
FALSE,
|
|
Affinity,
|
|
FALSE );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
HalpProfileInterrupt(
|
|
PKSERVICE_ROUTINE InterruptRoutine,
|
|
PVOID ServiceContext,
|
|
PKTRAP_FRAME TrapFrame
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is entered as a result of an interrupt generated by
|
|
the profile timer. Its function is to acknowlege the interrupt and
|
|
transfer control to the standard system routine to update the
|
|
system profile time.
|
|
|
|
Arguments:
|
|
|
|
InterruptRoutine - not used.
|
|
|
|
ServiceContext - not used.
|
|
|
|
TrapFrame - Supplies a pointer to the trap frame for the profile interrupt.
|
|
|
|
Returned Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// See if profiling is active
|
|
//
|
|
|
|
if ( HAL_PCR->ProfileCount ) {
|
|
|
|
//
|
|
// Check to see if the interval has expired
|
|
// If it has then call the kernel routine for profile
|
|
// and reset the count, else return.
|
|
|
|
|
|
if ( !(--HAL_PCR->ProfileCount) ) {
|
|
|
|
KeProfileInterrupt( TrapFrame );
|
|
HAL_PCR->ProfileCount = HalpNumberOfTicks;
|
|
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
HalQueryProfileInterval(
|
|
IN KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a profile source, returns whether or not that source is
|
|
supported.
|
|
|
|
Arguments:
|
|
|
|
Source - Supplies the profile source
|
|
|
|
Return Value:
|
|
|
|
TRUE - Profile source is supported
|
|
|
|
FALSE - Profile source is not supported
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ProfileSource == ProfileTime)
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
HalSetProfileSourceInterval(
|
|
IN KPROFILE_SOURCE ProfileSource,
|
|
IN OUT ULONG *Interval
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the profile interval for a specified profile source
|
|
|
|
Arguments:
|
|
|
|
ProfileSource - Supplies the profile source
|
|
|
|
Interval - Supplies the specified profile interval
|
|
Returns the actual profile interval
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
if (ProfileSource != ProfileTime)
|
|
return(STATUS_NOT_IMPLEMENTED);
|
|
|
|
//
|
|
// Set the interval.
|
|
//
|
|
|
|
*Interval = HalSetProfileInterval(*Interval);
|
|
|
|
//
|
|
// We're done.
|
|
//
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HalpProfileInterval = (Interval/16) * PROFILE_TIMER_1600NS_TICKS;
|
|
|
|
HalpProfileInterval = ( HalpProfileInterval < MIN_PROFILE_TICKS ) ?
|
|
MIN_PROFILE_TICKS : HalpProfileInterval;
|
|
|
|
return HalpProfileInterval * PROFILE_INTERVALS_PER_100NS;
|
|
}
|
|
|
|
|
|
VOID
|
|
HalStartProfileInterrupt (
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine turns on the profile interrupt.
|
|
|
|
N.B. This routine must be called at PROCLK_LEVEL while holding the
|
|
profile lock.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (ProfileSource != ProfileTime)
|
|
return;
|
|
|
|
//
|
|
// Assume that we only need 1 clock tick before we collect data
|
|
//
|
|
|
|
HalpNumberOfTicks = 1;
|
|
|
|
if ( HalpProfileInterval > MAX_PROFILE_TICKS ) {
|
|
|
|
HalpNumberOfTicks = HalpProfileInterval / (MAX_PROFILE_TICKS / 4);
|
|
HalpNumberOfTicks = 4 * HalpNumberOfTicks;
|
|
HalpProfileInterval = MAX_PROFILE_TICKS / 4;
|
|
|
|
}
|
|
|
|
//
|
|
// Set current profile count and interval.
|
|
//
|
|
|
|
HAL_PCR->ProfileCount = HalpNumberOfTicks;
|
|
|
|
PIC_PROFILER_ON(HalpProfileInterval);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
HalStopProfileInterrupt (
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine turns off the profile interrupt.
|
|
|
|
N.B. This routine must be called at PROCLK_LEVEL while holding the
|
|
profile lock.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (ProfileSource != ProfileTime)
|
|
return;
|
|
|
|
//
|
|
// Clear the current profile count and turn off the profiler timer.
|
|
//
|
|
|
|
HAL_PCR->ProfileCount = 0;
|
|
|
|
PIC_PROFILER_OFF();
|
|
|
|
return;
|
|
}
|