Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

722 lines
17 KiB

/*++
Copyright (c) 1990 Microsoft Corporation
Copyright (c) 1992,1993,1994,1995,1996 Digital Equipment Corporation
Module Name:
smir.c
Abstract:
The module provides the interrupt support for Lego's
Server Management and Watchdog timer functions.
Author:
Gene Morgan (Digital) 3-Nov-1995
Revision History:
Gene Morgan (Digital) 3-Nov-1995
Initial version for Lego. Adapted from Mikasa/Noritake.
Gene Morgan 15-Apr-1996
Service Watchdog Timer.
--*/
#include "halp.h"
//
// Define external function prototypes
//
UCHAR
HalpAcknowledgeServerMgmtInterrupt(
PVOID ServiceContext
);
VOID
LegoServerMgmtReportWarningCondition(
BOOLEAN ReportWatchdog,
USHORT SmRegAll,
USHORT WdRegAll
);
BOOLEAN
HalpLegoShutdownWatchdog(
VOID
);
//
// Save area for interrupt mask register.
//
USHORT HalpLegoServerMgmtInterruptMask;
//
// Server management and watchdog timer control.
// defined/setup in lgmapio.c
//
extern PVOID HalpLegoServerMgmtQva;
extern PVOID HalpLegoWatchdogQva;
//
// Globals for conveying Cpu and Backplane type
//
extern BOOLEAN HalpLegoCpu;
extern BOOLEAN HalpLegoBackplane;
extern ULONG HalpLegoCpuType;
extern ULONG HalpLegoBackplaneType;
extern UCHAR HalpLegoFeatureMask;
extern BOOLEAN HalpLegoServiceWatchdog;
//
// Track whether error logger is available
//
extern BOOLEAN HalpServerMgmtLoggingEnabled;
//
// True if someone has "enabled" interrupts
// for a particular server management event.
//
extern BOOLEAN HalpLegoDispatchWatchdog;
extern BOOLEAN HalpLegoDispatchNmi;
extern BOOLEAN HalpLegoDispatchInt;
extern BOOLEAN HalpLegoDispatchPsu;
extern BOOLEAN HalpLegoDispatchHalt;
VOID
HalpInitializeServerMgmtInterrupts(
VOID
)
/*++
Routine Description:
This routine initializes the Lego
Server Management and Watchdog Timer functions
Arguments:
None.
Return Value:
None.
Notes:
Goal is to set the Server Management and Watchdog
functions to a known state.
--*/
{
LEGO_SRV_MGMT SmRegister;
LEGO_WATCHDOG WdRegister;
//
// Initial state is error logger is not available
//
HalpServerMgmtLoggingEnabled = FALSE;
//
// Assume watchdog is idle.
// There's no interrupt mask bit, so no work needs to be done here.
//
if (HalpLegoFeatureMask & LEGO_FEATURE_WATCHDOG) {
//
// Do nothing until clock is started.
//
HalpLegoDispatchWatchdog = FALSE;
}
// Set the mask bits for all Server Management functions
// (i.e., block interrupts)
//
if (HalpLegoFeatureMask & LEGO_FEATURE_SERVER_MGMT) {
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.IntMask = 0;
SmRegister.NmiMask = 0;
SmRegister.PsuMask = 0; // not present on all platforms
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
HalpLegoDispatchNmi = FALSE;
HalpLegoDispatchInt = FALSE;
HalpLegoDispatchPsu = FALSE;
HalpLegoDispatchHalt = FALSE;
}
}
VOID
HalpDisableServerMgmtInterrupt(
IN ULONG Vector
)
/*++
Routine Description:
This function disables the Server Management
or Watchdog Timer interrupt specified by Vector.
Arguments:
Vector - Supplies the vector of the interrupt to disable.
Return Value:
None.
Notes:
An interrupt is masked by setting the appropriate mask bit to 1.
The halt button cannot be masked.
--*/
{
LEGO_SRV_MGMT SmRegister;
LEGO_WATCHDOG WdRegister;
// dispatch on vector to determine which interrupt mask to clear
//
switch (Vector) {
case WATCHDOG_VECTOR:
//
// Disable Watchdog timer interrupts (and the timer itself)
//
// If timer is running and timer 2 is active, timer 2
// must be stopped before the timer can be disabled.
//
HalpLegoShutdownWatchdog();
//
// Re-enable timer but stop performing secondary dispatch
//
WdRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva );
WdRegister.Enabled = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva, WdRegister.All );
HalpLegoDispatchWatchdog = FALSE;
break;
case SM_WARNING_VECTOR:
#if 0
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.IntMask = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
#endif
HalpLegoDispatchInt = FALSE;
break;
case SM_ERROR_VECTOR:
#if 0
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.NmiMask = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
#endif
HalpLegoDispatchNmi = FALSE;
break;
case SM_PSU_FAILURE_VECTOR:
#if 0
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.PsuMask = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
#endif
HalpLegoDispatchPsu = FALSE;
break;
case HALT_BUTTON_VECTOR:
//
// Halt button cannot be masked -- ignore
//
HalpLegoDispatchHalt = FALSE;
break;
default:
//
// Error - unrecognized vector
//
break;
}
}
VOID
HalpEnableServerMgmtInterrupt(
IN ULONG Vector,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This function enables the Server Management or
Watchdog Timer interrupt specified by Vector.
Arguments:
Vector - Supplies the vector of the interrupt to be enabled.
InterruptMode - Supplies the mode of the interrupt;
LevelSensitive or Latched //[wem] ??? check this ???
Return Value:
None.
Notes:
An interrupt is enabled by clearing the appropriate mask bit (i.e., set to 0).
The halt button cannot be masked.
--*/
{
LEGO_SRV_MGMT SmRegister;
LEGO_WATCHDOG WdRegister;
// dispatch on vector to determine which interrupt mask to clear
//
switch (Vector) {
case WATCHDOG_VECTOR:
//
// Enable Watchdog timer interrupts (and the timer itself)
// Assume all other aspects of the timer are correctly setup, but:
//
// If timer is already running and timer 2 is active, re-establish timer 1.
//
HalpLegoShutdownWatchdog();
WdRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva );
WdRegister.Enabled = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva, WdRegister.All );
//
// Watchdog is enabled and Timer 1 is now running
//
HalpLegoDispatchWatchdog = TRUE;
break;
case SM_WARNING_VECTOR:
#if 0
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.IntMask = 0;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
#endif
HalpLegoDispatchInt = TRUE;
break;
case SM_ERROR_VECTOR:
#if 0
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.NmiMask = 0;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
#endif
HalpLegoDispatchNmi = TRUE;
break;
case SM_PSU_FAILURE_VECTOR:
#if 0
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegister.PsuMask = 0;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
#endif
HalpLegoDispatchPsu = TRUE;
break;
case HALT_BUTTON_VECTOR:
//
// Halt button cannot be masked.
//
HalpLegoDispatchHalt = TRUE;
break;
default:
//
// Error - unrecognized vector
//
break;
}
}
UCHAR
HalpAcknowledgeServerMgmtInterrupt(
PVOID ServiceContext
)
/*++
Routine Description:
Acknowledge the Server Management interrupt. Return vector number of the
highest priority pending interrupt.
Arguments:
ServiceContext - Service context of the interrupt service - supplies
a QVA to Lego's Server Management interrupt register.
Return Value:
Return the value of the highest priority pending interrupt,
or 0xff if none.
--*/
{
LEGO_SRV_MGMT SmRegister;
LEGO_WATCHDOG WdRegister;
UCHAR Vector;
//
// Check the watchdog and server management registers to see which
// event occurred.
//
// Read watchdog first since it is most probable cause of interrupt
//
//
// Value to return if no match
//
Vector = 0xFF;
//
// Check Watchdog register's interrupt bit.
//
WdRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva );
#if DBG
DbgPrint(" <WdReg:%04x> ",WdRegister.All);
#endif
if (WdRegister.Interrupt==1) {
Vector = (WATCHDOG_VECTOR - SERVER_MGMT_VECTORS);
#if DBG
DbgPrint(" <WdReg:%04x> ",WdRegister.All);
#endif
}
else {
//
// Check Server Management register bits
//
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
#if DBG
DbgPrint(" <SmReg:%04x> ",SmRegister.All);
#endif
if (SmRegister.CpuTempFailure==1
|| SmRegister.CpuTempRestored==1
|| SmRegister.EnclFanFailure==1) {
Vector = (SM_WARNING_VECTOR - SERVER_MGMT_VECTORS);
}
else if (SmRegister.Psu1Failure==1
|| SmRegister.Psu2Failure) {
Vector = (SM_PSU_FAILURE_VECTOR - SERVER_MGMT_VECTORS);
}
}
return Vector;
}
BOOLEAN
HalpServerMgmtDispatch(
IN PKINTERRUPT Interrupt,
IN PVOID ServiceContext,
IN PKTRAP_FRAME TrapFrame
)
/*++
Routine Description:
This routine is entered as the result of an interrupt having been generated
via the vector connected to the Server Management device interrupt object.
Its function is to call the second-level interrupt dispatch routine.
If the second level dispatch doesn't handle, then this routine will perform
default handling.
This service routine could have been connected as follows, where the
ISR is the assembly wrapper that does the handoff to this function:
KeInitializeInterrupt( &Interrupt,
HalpServerMgmtInterruptHandler,
(PVOID) HalpLegoServerMgmtInterruptQva,
(PKSPIN_LOCK)NULL,
SERVER_MGMT_VECTOR,
SERVER_MGMT_DEVICE_LEVEL,
SERVER_MGMT_DEVICE_LEVEL,
LevelSensitive,
TRUE,
0,
FALSE);
KeConnectInterrupt(&Interrupt);
Arguments:
Interrupt - Supplies a pointer to the interrupt object.
ServiceContext - Supplies a pointer to the Server Management
interrupt register.
TrapFrame - Supplies a pointer to the trap frame for this interrupt.
Return Value:
Returns the value returned from the second level routine.
Notes:
Only the CPU IRQ5 interrupts come through here. Server management
NMIs are handled by HalpHandleNmi()
--*/
{
UCHAR SmVector;
BOOLEAN returnValue;
LEGO_SRV_MGMT SmRegister, SmRegisterLog;
LEGO_WATCHDOG WdRegister, WdRegisterLog;
BOOLEAN LogIt = FALSE;
BOOLEAN LogWatchdog = FALSE;
//
// [wem] DEBUG - count SM dispatch entries
//
static long IntCount = 0;
#if DBG //[wem]
IntCount++;
if (IntCount<5) {
DbgPrint("II<SM><");
}
if (IntCount % 1000 == 0) {
DbgPrint("II<SM><%08x><", IntCount);
}
#endif
//
// Acknowledge interrupt and receive the returned interrupt vector.
// If we got 0xff back, there were no enabled interrupts, so we
// signal that with a FALSE return, immediately.
//
SmVector = HalpAcknowledgeServerMgmtInterrupt(ServiceContext);
#if DBG
DbgPrint("<SmVector:%04x> ",SmVector);
#endif
if (SmVector == ((UCHAR)0xff)) {
#if DBG //[wem]
if (IntCount<5 || (IntCount % 1000)==0) {
DbgPrint("ff>.");
}
#endif
return( FALSE );
}
SmVector += SERVER_MGMT_VECTORS;
#if DBG
DbgPrint("<SmVector:%04x> ",SmVector);
#endif
switch (SmVector) {
case WATCHDOG_VECTOR:
if (HalpLegoDispatchWatchdog
&& ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SmVector])(
PCR->InterruptRoutine[SmVector],
TrapFrame)
) {
return TRUE;
}
WdRegisterLog.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva );
#if DBG
DbgPrint("<WdReg:%04x> ",WdRegisterLog.All);
#endif
if (HalpLegoServiceWatchdog) {
//
// Get control of the watchdog timer
//
HalpLegoShutdownWatchdog();
//
// Re-enable it
//
WdRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva );
WdRegister.Enabled = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva, WdRegister.All);
returnValue = TRUE;
}
else {
//
// Dismiss the interrupt -- but system is on the way down!
//
WdRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva );
WdRegister.Interrupt = 1;
WdRegister.Enabled = 1;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoWatchdogQva, WdRegister.All );
//
// Interrupt not serviced
//
returnValue = FALSE;
}
LogIt = TRUE;
LogWatchdog = TRUE;
break;
case SM_WARNING_VECTOR:
if (HalpLegoDispatchInt
&& ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SmVector])(
PCR->InterruptRoutine[SmVector],
TrapFrame)
) {
return TRUE;
}
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegisterLog.All = SmRegister.All;
// Handle any that were not handled by secondary dispatch
//
if (SmRegister.CpuTempRestored==1) {
HalDisplayString ("Server Management: CPU Temperature restored.\n");
}
if (SmRegister.CpuTempFailure==1) {
HalDisplayString ("Server Management: CPU Temperature warning.\n");
}
if (SmRegister.EnclFanFailure==1) {
HalDisplayString ("Server Management: System fan failure.\n");
}
// Any interrupts will be cleared
// Don't touch PSU interrupts
//
SmRegister.Psu1Failure = 0;
SmRegister.Psu2Failure = 0;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
LogIt = TRUE;
returnValue = TRUE;
break;
case SM_PSU_FAILURE_VECTOR:
if (HalpLegoDispatchPsu
&& ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[SmVector])(
PCR->InterruptRoutine[SmVector],
TrapFrame)
) {
return TRUE;
}
SmRegister.All = READ_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva );
SmRegisterLog.All = SmRegister.All;
//
// Handle any that were not handled by secondary dispatch
//
if (SmRegister.Psu1Failure==1) {
HalDisplayString ("Server Management: PSU 1 has failed.\n");
}
if (SmRegister.Psu2Failure==1) {
HalDisplayString ("Server Management: PSU 2 has failed.\n");
}
// Any interrupts will be cleared
// Don't touch fan/temperature interrupts
//
SmRegister.CpuTempRestored = 0;
SmRegister.CpuTempFailure = 0;
SmRegister.EnclFanFailure = 0;
WRITE_REGISTER_USHORT ((PUSHORT)HalpLegoServerMgmtQva, SmRegister.All );
LogIt = TRUE;
returnValue = TRUE;
break;
default:
returnValue = FALSE; //[wem] Error -- bugcheck?
}
#if DBG //[wem]
if (IntCount<5 || (IntCount % 1000)==0) {
DbgPrint("%02x>.", returnValue);
}
#endif
//
// Post "correctable" error record to error log.
//
if (LogIt) {
LegoServerMgmtReportWarningCondition(LogWatchdog, SmRegisterLog.All,WdRegisterLog.All);
}
return( returnValue );
}