NT4/private/ntos/nthals/halalpha/eisaprof.c
2020-09-30 17:12:29 +02:00

518 lines
9.0 KiB
C
Raw 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) 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;
}