518 lines
9.0 KiB
C
518 lines
9.0 KiB
C
/*++
|
||
|
||
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;
|
||
}
|