NT4/private/ntos/nthals/halsable/alpha/xiintsup.c
2020-09-30 17:12:29 +02:00

913 lines
20 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) 1995 Digital Equipment Corporation
Module Name:
xiintsup.c
Abstract:
This module provides interrupt support for the Sable/Gamma/Lynx
External I/O module.
Author:
Dave Richarda 1-June-1995
Revision History:
--*/
#ifdef XIO_PASS1
#include "halp.h"
#include "eisa.h"
#include "sableref.h"
#include "xiintsup.h"
//
// External I/O 8259 Mask registers.
//
UCHAR XioMasterInterruptMask;
UCHAR XioSlaveInterruptMask;
//
// Define the context structure for use by interrupt service routines.
//
typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
PKINTERRUPT InterruptObject
);
extern ULONG HalpProcessors;
ULONG
HalpGetXioInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
)
{
if( HalpXioPresent ){
switch( BusInterruptLevel ){
case XioPciSlot0AVector:
case XioPciSlot0BVector:
case XioPciSlot0CVector:
case XioPciSlot0DVector:
case XioPciSlot1AVector:
case XioPciSlot1BVector:
case XioPciSlot1CVector:
case XioPciSlot1DVector:
*Irql = PCI_DEVICE_LEVEL;
if( HalpProcessors > 1 ){
*Affinity = HAL_CPU1_MASK;
} else {
*Affinity = HAL_CPU0_MASK;
}
return( SABLE_VECTORS + BusInterruptLevel );
}
}
//
// The caller specified a bus level not support by this platform.
//
*Irql = 0;
*Affinity = 0;
return(0);
}
BOOLEAN
HalpInitializeXioInterrupts(
VOID
)
/*++
Routine Description:
This routine does the following:
(1) initializes the Xio 8259 interrupt registers
(2) initializes structures necessary for EISA operations
(3) connects the intermediate interrupt dispatcher.
(4) initializes the EISA interrupt controller.
Arguments:
None.
Return Value:
If the second level interrupt dispatcher is connected, then a value of
TRUE is returned. Otherwise, a value of FALSE is returned.
--*/
{
UCHAR DataByte;
//
// Initialize the Xio interrupt controllers. The interrupt structure
// is one master interrupt controller with 1 cascaded slave controller.
// Proceed through each control word programming each of the controllers.
//
//
// Write control word 1 for each of the controllers, indicate
// that initialization is in progress and the control word 4 will
// be used.
//
DataByte = 0;
((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
// ((PINITIALIZATION_COMMAND_1) &DataByte)->LevelTriggeredMode = 1;
DataByte |= 0x04;
((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterControl,
DataByte
);
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveControl,
DataByte
);
//
// Write control word 2 for each of the controllers, set the base
// interrupt vector for each controller.
//
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask,
XioMasterBaseVector
);
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask,
XioSlaveBaseVector
);
//
// The third initialization control word set the controls for slave mode.
// The master ICW3 uses bit position and the slave ICW3 uses a numeric.
//
DataByte = (1 << (XioSlaveCascadeVector & ~XioMasterBaseVector) );
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask,
DataByte
);
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask,
(XioSlaveCascadeVector & ~XioMasterBaseVector)
);
//
// The fourth initialization control word is used to specify normal
// end-of-interrupt mode and not special-fully-nested mode.
//
DataByte = 0;
((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1;
#ifdef XIO_AEOI
((PINITIALIZATION_COMMAND_4) &DataByte)->AutoEndOfInterruptMode = 1;
#endif
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask,
DataByte
);
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask,
DataByte
);
//
// Disable all of the interrupts except the slave interrupts to the
// master controller.
//
XioMasterInterruptMask =
(UCHAR)( ~(1 << (XioSlaveCascadeVector & ~XioMasterBaseVector)) );
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterMask,
XioMasterInterruptMask
);
XioSlaveInterruptMask = 0xFF;
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask,
XioSlaveInterruptMask
);
return TRUE;
}
BOOLEAN
HalpXioDispatch(
VOID
)
/*++
Routine Description:
This routine is entered as a result of an interrupt being generated
via the vector that is directly connected XIO device interrupt.
This routine is responsible for determining the
source of the interrupt, performing the secondary dispatch and
acknowledging the interrupt in the 8259 controllers.
N.B. This interrupt is directly connected and therefore, no argument
values are defined.
Arguments:
None.
Return Value:
Returns the value returned from the second level routine.
--*/
{
UCHAR interruptVector;
BOOLEAN returnValue;
USHORT IdtIndex;
UCHAR InService;
PULONG DispatchCode;
PKINTERRUPT InterruptObject;
//
// Acknowledge the Interrupt controller and receive the returned
// interrupt vector.
//
interruptVector = READ_REGISTER_UCHAR(
&((PXIO_INTERRUPT_CSRS)
XIO_INTERRUPT_CSRS_QVA)->InterruptAcknowledge
);
//
// If we get a passive release, send a non-specific end of interrupt
// command and return TRUE, indicating that we processed the interrupt.
//
switch( interruptVector ){
case XioMasterPassiveReleaseVector:
#ifdef XIO_AEOI
//
// If the passive release vector has not been enabled, then we can
// dismiss it now.
//
if( XioMasterInterruptMask & 0x80 ){
return TRUE;
}
#else // XIO_AEOI
//
// Read the "in-service" mask.
//
WRITE_PORT_UCHAR( &((PSABLE_INTERRUPT_CSRS)SABLE_INTERRUPT_CSRS_QVA)->MasterControl,
0x0B
);
InService = READ_PORT_UCHAR(
&((PSABLE_INTERRUPT_CSRS) SABLE_INTERRUPT_CSRS_QVA)->MasterControl
);
if( (InService & 0x80) == 0 ){
//
// Send end of interrupt to clear the passive release in the
// master controller.
//
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterControl,
NONSPECIFIC_END_OF_INTERRUPT
);
return TRUE;
}
#endif // XIO_AEOI
break;
case XioSlavePassiveReleaseVector:
#ifdef XIO_AEOI
//
// If the passive release vector has not been enabled, then we can
// dismiss it now.
//
if( XioSlaveInterruptMask & 0x80 ){
return TRUE;
}
#else // XIO_AEOI
//
// Read the "in-service" mask.
//
WRITE_PORT_UCHAR( &((PSABLE_INTERRUPT_CSRS)SABLE_INTERRUPT_CSRS_QVA)->SlaveControl,
0x0B
);
InService = READ_PORT_UCHAR(
&((PSABLE_INTERRUPT_CSRS) SABLE_INTERRUPT_CSRS_QVA)->SlaveControl
);
if( (InService & 0x80) == 0 ){
//
// Send end of interrupt to clear the passive release in the
// slave controller.
//
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveControl,
NONSPECIFIC_END_OF_INTERRUPT
);
return TRUE;
}
#endif // XIO_AEOI
break;
}
//
// Dispatch to the secondary interrupt service routine.
//
IdtIndex = interruptVector + SABLE_VECTORS;
DispatchCode = (PULONG)PCR->InterruptRoutine[IdtIndex];
InterruptObject = CONTAINING_RECORD(DispatchCode,
KINTERRUPT,
DispatchCode);
returnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject);
#ifndef XIO_AEOI
//
// Dismiss the interrupt in the 8259 interrupt controllers.
// If this is a cascaded interrupt then the interrupt must be dismissed in
// both controllers.
//
if( (interruptVector & XioSlaveBaseVector) == XioSlaveBaseVector ){
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveControl,
NONSPECIFIC_END_OF_INTERRUPT
);
}
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->MasterControl,
NONSPECIFIC_END_OF_INTERRUPT
);
#endif // XIO_AEOI
return(returnValue);
}
VOID
HalpDisableXioInterrupt(
IN ULONG Vector
)
/*++
Routine Description:
This function Disables the External IO specified interrupt.
Arguments:
Vector - Supplies the vector of the Xio interrupt that is Disabled.
Return Value:
None.
--*/
{
ULONG Interrupt;
if( (Vector >= SABLE_VECTORS + XioMasterBaseVector) &&
(Vector <= SABLE_VECTORS + XioSlavePassiveReleaseVector) ){
//
// Calculate the Xio relative interrupt vector.
//
Vector -= SABLE_VECTORS;
//
// Compute the interrupt within the interrupt controller.
//
Interrupt = Vector & 0x7;
//
// Enable the interrupt for the appropriate interrupt controller.
//
if( (Vector & XioSlaveBaseVector) == XioSlaveBaseVector ){
XioSlaveInterruptMask |= (UCHAR) (1 << Interrupt);
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask,
XioSlaveInterruptMask
);
}
}
}
BOOLEAN
HalpEnableXioInterrupt(
IN ULONG Vector,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This function enables the Xio specified interrupt in the
appropriate 8259 interrupt controllers. It also supports the
edge/level control for EISA bus interrupts. By default, all interrupts
are edge detected (and latched).
Arguments:
Vector - Supplies the vector of the Xio interrupt that is enabled.
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
Latched (Edge).
Return Value:
None.
--*/
{
ULONG Interrupt;
if( (Vector >= SABLE_VECTORS + XioMasterBaseVector) &&
(Vector <= SABLE_VECTORS + XioSlavePassiveReleaseVector) ){
//
// Calculate the Xio relative interrupt vector.
//
Vector -= SABLE_VECTORS;
//
// Compute the interrupt within the interrupt controller.
//
Interrupt = Vector & 0x7;
//
// Enable the interrupt for the appropriate interrupt controller.
//
if( (Vector & XioSlaveBaseVector) == XioSlaveBaseVector ){
XioSlaveInterruptMask &= (UCHAR) ~(1 << Interrupt);
WRITE_PORT_UCHAR(
&((PXIO_INTERRUPT_CSRS) XIO_INTERRUPT_CSRS_QVA)->SlaveMask,
XioSlaveInterruptMask
);
return TRUE;
}
}
return FALSE;
}
#endif // XIO_PASS1
#ifdef XIO_PASS2
#include "halp.h"
#include "t2.h"
#include "icic.h"
#include "xiintsup.h"
//
// Define the context structure for use by interrupt service routines.
//
typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
PKINTERRUPT InterruptObject
);
extern ULONG HalpProcessors;
//
// Cached copies of the corresponding ICIC register(s).
//
ICIC_MASK_REGISTER XioIcIcMaskRegister;
ULONG
HalpGetXioInterruptVector(
IN PBUS_HANDLER BusHandler,
IN PBUS_HANDLER RootHandler,
IN ULONG BusInterruptLevel,
IN ULONG BusInterruptVector,
OUT PKIRQL Irql,
OUT PKAFFINITY Affinity
)
{
if( HalpXioPresent ){
switch( BusInterruptLevel ){
//
// Handle Vectors for PCI devices.
//
case XioPciSlot0AVector:
case XioPciSlot0BVector:
case XioPciSlot0CVector:
case XioPciSlot0DVector:
case XioPciSlot1AVector:
case XioPciSlot1BVector:
case XioPciSlot1CVector:
case XioPciSlot1DVector:
case XioPciSlot2AVector:
case XioPciSlot2BVector:
case XioPciSlot2CVector:
case XioPciSlot2DVector:
case XioPciSlot3AVector:
case XioPciSlot3BVector:
case XioPciSlot3CVector:
case XioPciSlot3DVector:
case XioPciSlot4AVector:
case XioPciSlot4BVector:
case XioPciSlot4CVector:
case XioPciSlot4DVector:
case XioPciSlot5AVector:
case XioPciSlot5BVector:
case XioPciSlot5CVector:
case XioPciSlot5DVector:
case XioPciSlot6AVector:
case XioPciSlot6BVector:
case XioPciSlot6CVector:
case XioPciSlot6DVector:
case XioPciSlot7AVector:
case XioPciSlot7BVector:
case XioPciSlot7CVector:
case XioPciSlot7DVector:
*Irql = DEVICE_LEVEL;
if( HalpProcessors > 1 ){
*Affinity = HAL_CPU1_MASK;
} else {
*Affinity = HAL_CPU0_MASK;
}
return( BusInterruptLevel );
}
}
*Irql = 0;
*Affinity = 0;
return 0;
}
BOOLEAN
HalpInitializeXioInterrupts(
VOID
)
/*++
Routine Description:
This routine initializes the ICIC on the Standard I/O module.
Arguments:
None.
Return Value:
TRUE.
--*/
{
T2_ICE Ice;
ICIC_ELCR_REGISTER XioIcIcElcrRegister;
//
// Initialize the interface between the T3/T4 and the ICIC.
//
Ice.all = 0;
Ice.EisaFlushAddress = 0x542;
Ice.IcEnable = 1;
Ice.HalfSpeedEnable = 0;
WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Ice,
Ice.all );
//
// Initialize the ICIC Mask Register.
//
XioIcIcMaskRegister = (ULONGLONG)-1;
WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcMaskRegister,
XioIcIcMaskRegister );
//
// Initialize the ICIC Edge/Level Control Register.
//
XioIcIcElcrRegister =
((ICIC_ELCR_REGISTER)1 << (XioPciSlot4AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot4BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot4CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot4DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot5AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot5BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot5CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot5DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot6AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot6BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot6CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot6DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot7AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot7BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot7CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot7DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot7DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot0AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot0BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot0CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot0DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot1AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot1BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot1CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot1DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot2AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot2BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot2CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot2DVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot3AVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot3BVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot3CVector - XioBaseVector)) |
((ICIC_ELCR_REGISTER)1 << (XioPciSlot3DVector - XioBaseVector));
WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcElcrRegister,
XioIcIcElcrRegister );
//
// Initialize the ICIC EISA Register.
//
WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcEisaRegister, (ULONGLONG)0 );
//
// Initialize the ICIC Mode Register.
//
WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcModeRegister, (ULONGLONG)0 );
return TRUE;
}
BOOLEAN
HalpXioDispatch(
VOID
)
/*++
Routine Description:
This routine dispatches interrupts received by the External I/O
ICIC.
Arguments:
None.
Return Value:
A boolean value indicating whether the interrupt was handled by
the FLIH/SLIH.
--*/
{
T2_VAR Var;
PULONG DispatchCode;
PKINTERRUPT InterruptObject;
BOOLEAN ReturnValue;
//
// Get the interrupt vector.
//
Var.all = READ_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Var );
//
// If this is a passive release, ignore the interrupt.
//
if( Var.PassiveRelease == 1 ){
return(TRUE);
}
//
// Dispatch to the secondary interrupt service routine.
//
DispatchCode = (PULONG)PCR->InterruptRoutine[XioBaseVector + Var.Vector];
InterruptObject = CONTAINING_RECORD(DispatchCode,
KINTERRUPT,
DispatchCode);
ReturnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject);
//
// Send an SEOI.
//
WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Var, Var.Vector );
return(ReturnValue);
}
VOID
HalpDisableXioInterrupt(
IN ULONG Vector
)
/*++
Routine Description:
This routine disables interrupts associated with the External I/O
ICIC.
Arguments:
Vector - The vector of the interrupt to disable.
Return Value:
None.
--*/
{
ULONGLONG IrqMask;
if( (Vector >= XioBaseVector) &&
(Vector <= XioPciSlot3DVector) ){
//
// Compute the IRQ mask.
//
IrqMask = (ICIC_MASK_REGISTER)1 << (Vector - XioBaseVector);
//
// Mask the interrupt.
//
XioIcIcMaskRegister |= IrqMask;
//
// Update the ICIC Mask Register.
//
WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcMaskRegister,
XioIcIcMaskRegister );
}
}
BOOLEAN
HalpEnableXioInterrupt(
IN ULONG Vector,
IN KINTERRUPT_MODE InterruptMode
)
/*++
Routine Description:
This routine enables interrupts associated with the External I/O
ICIC.
Arguments:
Vector - The vector of the interrupt to enable.
InterruptMode - An indication of whether the interrupt should
be edge-triggered/level-sensitive. (Ignored)
Return Value:
None.
--*/
{
ULONGLONG IrqMask;
if( (Vector >= XioBaseVector) &&
(Vector <= XioPciSlot3DVector) ){
//
// Compute the IRQ mask.
//
IrqMask = (ICIC_MASK_REGISTER)1 << (Vector - XioBaseVector);
//
// Un-mask the interrupt.
//
XioIcIcMaskRegister &= ~IrqMask;
//
// Update the ICIC Mask Register.
//
WRITE_ICIC_REGISTER( T4_CSRS_QVA, IcIcMaskRegister,
XioIcIcMaskRegister );
return TRUE;
}
return FALSE;
}
#endif // XIO_PASS2