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.
499 lines
12 KiB
499 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
|
|
|
|
Module Name:
|
|
|
|
pciir.c
|
|
|
|
Abstract:
|
|
|
|
The module provides the interrupt support for the Mikasa's PCI
|
|
interrupts.
|
|
|
|
Author:
|
|
|
|
James Livingston 2-May-1994
|
|
|
|
Revision History:
|
|
|
|
Janet Schneider (Digital) 27-July-1995
|
|
Added support for the Noritake.
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
|
|
//
|
|
// Define external function prototypes
|
|
//
|
|
|
|
UCHAR
|
|
HalpAcknowledgeMikasaPciInterrupt(
|
|
PVOID ServiceContext
|
|
);
|
|
|
|
UCHAR
|
|
HalpAcknowledgeNoritakePciInterrupt(
|
|
PVOID ServiceContext
|
|
);
|
|
|
|
//
|
|
// Import save area for PCI interrupt mask register.
|
|
//
|
|
|
|
USHORT HalpMikasaPciInterruptMask;
|
|
|
|
USHORT HalpNoritakePciInterrupt1Mask;
|
|
USHORT HalpNoritakePciInterrupt2Mask;
|
|
USHORT HalpNoritakePciInterrupt3Mask;
|
|
|
|
//
|
|
// Reference for globals defined in I/O mapping module.
|
|
//
|
|
extern PVOID HalpMikasaPciIrQva;
|
|
extern PVOID HalpMikasaPciImrQva;
|
|
|
|
extern PVOID HalpNoritakePciIr1Qva;
|
|
extern PVOID HalpNoritakePciIr2Qva;
|
|
extern PVOID HalpNoritakePciIr3Qva;
|
|
extern PVOID HalpNoritakePciImr1Qva;
|
|
extern PVOID HalpNoritakePciImr2Qva;
|
|
extern PVOID HalpNoritakePciImr3Qva;
|
|
|
|
//
|
|
// Define reference to platform identifier
|
|
//
|
|
|
|
extern BOOLEAN HalpNoritakePlatform;
|
|
|
|
|
|
VOID
|
|
HalpInitializeMikasaPciInterrupts(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the Mikasa PCI interrupts.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Initialize the Mikasa PCI interrupts. There is a single interrupt mask
|
|
// that permits individual interrupts to be enabled or disabled by
|
|
// setting the appropriate bit in the interrupt mask register. We
|
|
// initialize them all to "disabled".
|
|
//
|
|
|
|
HalpMikasaPciInterruptMask = 0;
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpMikasaPciImrQva,
|
|
HalpMikasaPciInterruptMask );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpInitializeNoritakePciInterrupts(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the Noritake PCI interrupts.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Initialize the Noritake PCI interrupts. There are three interrupt masks
|
|
// that permit individual interrupts to be enabled or disabled by
|
|
// setting the appropriate bit in the interrupt mask register. We
|
|
// initialize them all to "disabled", except for the SUM bits. (Bit 0
|
|
// in IR1, and bits 0 and 1 in IR2.)
|
|
//
|
|
|
|
HalpNoritakePciInterrupt1Mask = 0x1;
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr1Qva,
|
|
HalpNoritakePciInterrupt1Mask );
|
|
|
|
HalpNoritakePciInterrupt2Mask = 0x3;
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr2Qva,
|
|
HalpNoritakePciInterrupt2Mask );
|
|
|
|
HalpNoritakePciInterrupt3Mask = 0x0;
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr3Qva,
|
|
HalpNoritakePciInterrupt3Mask );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpDisableMikasaPciInterrupt(
|
|
IN ULONG Vector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables the PCI interrupt specified by Vector.
|
|
|
|
Arguments:
|
|
|
|
Vector - Supplies the vector of the PCI interrupt that is disabled.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Calculate the PCI interrupt vector, relative to 0, offset by one.
|
|
//
|
|
|
|
Vector -= PCI_VECTORS + 1;
|
|
|
|
//
|
|
// Get the current state of the interrupt mask register, then set
|
|
// the bit corresponding to the adjusted value of Vector to zero,
|
|
// to disable that PCI interrupt.
|
|
//
|
|
|
|
HalpMikasaPciInterruptMask =
|
|
READ_REGISTER_USHORT( (PUSHORT)HalpMikasaPciImrQva );
|
|
HalpMikasaPciInterruptMask &= (USHORT) ~(1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpMikasaPciImrQva,
|
|
HalpMikasaPciInterruptMask );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpDisableNoritakePciInterrupt(
|
|
IN ULONG Vector
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables the PCI interrupt specified by Vector.
|
|
|
|
Arguments:
|
|
|
|
Vector - Supplies the vector of the PCI interrupt that is disabled.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Calculate the PCI interrupt vector, relative to 0.
|
|
//
|
|
|
|
Vector -= PCI_VECTORS;
|
|
|
|
//
|
|
// First we must determine which interrupt register the interrupt is in.
|
|
// In each case, subtract the register offset to get the bit position in
|
|
// the interrupt register. Then, get the current state of the interrupt
|
|
// mask register. Finally, set the bit corresponding to the adjusted value
|
|
// of Vector to zero, to disable that PCI interrupt.
|
|
//
|
|
|
|
if( Vector >= REGISTER_2_VECTOR_OFFSET ) {
|
|
|
|
if( Vector >= REGISTER_3_VECTOR_OFFSET ) {
|
|
|
|
//
|
|
// The interrupt is in Interrupt Register 3.
|
|
//
|
|
|
|
Vector -= REGISTER_3_VECTOR_OFFSET;
|
|
|
|
HalpNoritakePciInterrupt3Mask = READ_REGISTER_USHORT(
|
|
(PUSHORT)HalpNoritakePciImr3Qva );
|
|
HalpNoritakePciInterrupt3Mask &= (USHORT) ~(1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr3Qva,
|
|
HalpNoritakePciInterrupt3Mask );
|
|
|
|
} else {
|
|
|
|
//
|
|
// The interrupt is in Interrupt Register 2.
|
|
//
|
|
|
|
Vector -= REGISTER_2_VECTOR_OFFSET;
|
|
|
|
HalpNoritakePciInterrupt2Mask = READ_REGISTER_USHORT(
|
|
(PUSHORT)HalpNoritakePciImr2Qva );
|
|
HalpNoritakePciInterrupt2Mask &= (USHORT) ~(1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr2Qva,
|
|
HalpNoritakePciInterrupt2Mask );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The interrupt is in Interrupt Register 1.
|
|
//
|
|
|
|
Vector -= REGISTER_1_VECTOR_OFFSET;
|
|
|
|
HalpNoritakePciInterrupt1Mask =
|
|
READ_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr1Qva );
|
|
HalpNoritakePciInterrupt1Mask &= (USHORT) ~(1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr1Qva,
|
|
HalpNoritakePciInterrupt1Mask );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpEnableMikasaPciInterrupt(
|
|
IN ULONG Vector,
|
|
IN KINTERRUPT_MODE InterruptMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the PCI interrupt specified by Vector.
|
|
Arguments:
|
|
|
|
Vector - Supplies the vector of the PCI interrupt that is enabled.
|
|
|
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|
Latched (ignored for Mikasa PCI interrupts; they're always levels).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Calculate the PCI interrupt vector, relative to 0, offset by one.
|
|
//
|
|
|
|
Vector -= PCI_VECTORS + 1;
|
|
|
|
//
|
|
// Get the current state of the interrupt mask register, then set
|
|
// the bit corresponding to the adjusted value of Vector to one,
|
|
// to enable that PCI interrupt.
|
|
//
|
|
|
|
HalpMikasaPciInterruptMask =
|
|
READ_REGISTER_USHORT( (PUSHORT)HalpMikasaPciImrQva );
|
|
HalpMikasaPciInterruptMask |= (USHORT) (1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpMikasaPciImrQva,
|
|
HalpMikasaPciInterruptMask );
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpEnableNoritakePciInterrupt(
|
|
IN ULONG Vector,
|
|
IN KINTERRUPT_MODE InterruptMode
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the PCI interrupt specified by Vector.
|
|
Arguments:
|
|
|
|
Vector - Supplies the vector of the PCI interrupt that is enabled.
|
|
|
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|
Latched (ignored for Mikasa PCI interrupts; they're always levels).
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// Calculate the PCI interrupt vector, relative to 0.
|
|
//
|
|
|
|
Vector -= PCI_VECTORS;
|
|
|
|
//
|
|
// First we must determine which interrupt register the interrupt is in.
|
|
// In each case, subtract the register offset to get the bit position in
|
|
// the interrupt register. Then, get the current state of the interrupt
|
|
// mask register. Finally, set the bit corresponding to the adjusted value
|
|
// of Vector to one, to enable that PCI interrupt.
|
|
//
|
|
|
|
if( Vector >= REGISTER_2_VECTOR_OFFSET ) {
|
|
|
|
if( Vector >= REGISTER_3_VECTOR_OFFSET ) {
|
|
|
|
//
|
|
// The interrupt is in Interrupt Register 3.
|
|
//
|
|
|
|
Vector -= REGISTER_3_VECTOR_OFFSET;
|
|
|
|
HalpNoritakePciInterrupt3Mask = READ_REGISTER_USHORT(
|
|
(PUSHORT)HalpNoritakePciImr3Qva );
|
|
HalpNoritakePciInterrupt3Mask |= (USHORT) (1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr3Qva,
|
|
HalpNoritakePciInterrupt3Mask );
|
|
|
|
} else {
|
|
|
|
//
|
|
// The interrupt is in Interrupt Register 2.
|
|
//
|
|
|
|
Vector -= REGISTER_2_VECTOR_OFFSET;
|
|
|
|
HalpNoritakePciInterrupt2Mask = READ_REGISTER_USHORT(
|
|
(PUSHORT)HalpNoritakePciImr2Qva );
|
|
HalpNoritakePciInterrupt2Mask |= (USHORT) (1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr2Qva,
|
|
HalpNoritakePciInterrupt2Mask );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// The interrupt is in Interrupt Register 1.
|
|
//
|
|
|
|
Vector -= REGISTER_1_VECTOR_OFFSET;
|
|
|
|
HalpNoritakePciInterrupt1Mask =
|
|
READ_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr1Qva );
|
|
HalpNoritakePciInterrupt1Mask |= (USHORT) (1 << Vector);
|
|
WRITE_REGISTER_USHORT( (PUSHORT)HalpNoritakePciImr1Qva,
|
|
HalpNoritakePciInterrupt1Mask );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
HalpPciDispatch(
|
|
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 PCI device interrupt object. Its function
|
|
is to call the second-level interrupt dispatch routine.
|
|
|
|
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,
|
|
HalpPciInterruptHandler,
|
|
(PVOID) HalpPciIrQva,
|
|
(PKSPIN_LOCK)NULL,
|
|
PCI_VECTOR,
|
|
PCI_DEVICE_LEVEL,
|
|
PCI_DEVICE_LEVEL,
|
|
LevelSensitive,
|
|
TRUE,
|
|
0,
|
|
FALSE);
|
|
|
|
KeConnectInterrupt(&Interrupt);
|
|
|
|
Arguments:
|
|
|
|
Interrupt - Supplies a pointer to the interrupt object.
|
|
|
|
ServiceContext - Supplies a pointer to the PCI interrupt register.
|
|
|
|
TrapFrame - Supplies a pointer to the trap frame for this interrupt.
|
|
|
|
Return Value:
|
|
|
|
Returns the value returned from the second level routine.
|
|
|
|
--*/
|
|
{
|
|
UCHAR PCIVector;
|
|
BOOLEAN returnValue;
|
|
USHORT PCRInOffset;
|
|
|
|
//
|
|
// Acknowledge interrupt and receive the returned interrupt vector.
|
|
// If we got zero back, there were no enabled interrupts, so we
|
|
// signal that with a FALSE return, immediately.
|
|
//
|
|
|
|
if( HalpNoritakePlatform ) {
|
|
|
|
PCIVector = HalpAcknowledgeNoritakePciInterrupt(ServiceContext);
|
|
|
|
} else {
|
|
|
|
PCIVector = HalpAcknowledgeMikasaPciInterrupt(ServiceContext);
|
|
|
|
}
|
|
|
|
if (PCIVector == 0) {
|
|
return( FALSE );
|
|
}
|
|
|
|
PCRInOffset = PCIVector + PCI_VECTORS;
|
|
|
|
returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])(
|
|
PCR->InterruptRoutine[PCRInOffset],
|
|
TrapFrame
|
|
);
|
|
|
|
return( returnValue );
|
|
}
|