580 lines
12 KiB
C
580 lines
12 KiB
C
|
|
|||
|
//
|
|||
|
|
|||
|
/**
|
|||
|
*** Copyright (C) 1996-97 Intel Corporation. All rights reserved.
|
|||
|
***
|
|||
|
*** The information and source code contained herein is the exclusive
|
|||
|
*** property of Intel Corporation and may not be disclosed, examined
|
|||
|
*** or reproduced in whole or in part without explicit written authorization
|
|||
|
*** from the company.
|
|||
|
**/
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 Intel Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
i64sxint.c copied from simsxint.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the routines to manage the
|
|||
|
system interrupt and IRQL.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
William K. Cheung (wcheung) 14-Apr-1995
|
|||
|
Bernard Lint
|
|||
|
M. Jayakumar (Muthurajan.Jayakumar@intel.com)
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Todd Kjos (HP) (v-tkjos) 1-Jun-1998 : Added I/O Sapic support
|
|||
|
|
|||
|
Thierry Fevrier (HP) (v-thief) 8-Feb-2000 : Profiling support
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "halp.h"
|
|||
|
#include "iosapic.h"
|
|||
|
|
|||
|
VOID HalpInitLINT(VOID);
|
|||
|
|
|||
|
extern KSPIN_LOCK HalpIoSapicLock;
|
|||
|
extern PULONG_PTR *HalEOITable[];
|
|||
|
PULONG_PTR HalpEOITableP0[MAX_INTR_VECTOR];
|
|||
|
|
|||
|
ULONG HalpNodeAffinity[MAX_NODES];
|
|||
|
ULONG HalpMaxNode = 1;
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitializeInterrupts (
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function initializes interrupts for an IA64 system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Note:
|
|||
|
|
|||
|
In KiInitializeKernel(), PCR.InterruptRoutine[] entries have been first initialized
|
|||
|
with the Unexpected Interrupt code then entries index-0, APC_VECTOR, DISPATCH_VECTOR
|
|||
|
have been initialized with their respective interrupt handlers.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
//
|
|||
|
// Turn off LINT0 LINT1 (disable 8259)
|
|||
|
//
|
|||
|
|
|||
|
// __setReg(CV_IA64_SaLRR0, 0x10000);
|
|||
|
// __setReg(CV_IA64_SaLRR1, 0x10000);
|
|||
|
HalpInitLINT();
|
|||
|
__dsrlz();
|
|||
|
|
|||
|
//
|
|||
|
// interval timer interrupt; 10ms by default
|
|||
|
//
|
|||
|
|
|||
|
HalpInitializeClockInterrupts();
|
|||
|
|
|||
|
//
|
|||
|
// Initialize SpuriousInterrupt
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector
|
|||
|
(SAPIC_SPURIOUS_VECTOR, HalpSpuriousHandler);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Initialize CMCI Interrupt
|
|||
|
//
|
|||
|
// Note that it is possible that HAL_CMC_PRESENT is not set.
|
|||
|
// With the current implementation, we always connect the vector to the ISR.
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector
|
|||
|
(CMCI_VECTOR, HalpCMCIHandler);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize CPEI Interrupt
|
|||
|
//
|
|||
|
// Note that it is possible that HAL_CPE_PRESENT is not set.
|
|||
|
// With the current implementation, we always connect the vector to the ISR.
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector
|
|||
|
(CPEI_VECTOR, HalpCPEIHandler);
|
|||
|
|
|||
|
//
|
|||
|
// Initialiaze MC Rendezvous Interrupt
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector
|
|||
|
(MC_RZ_VECTOR, HalpMcRzHandler);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize MC Wakeup Interrupt
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector
|
|||
|
(MC_WKUP_VECTOR, HalpMcWkupHandler);
|
|||
|
|
|||
|
//
|
|||
|
// IPI Interrupt
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector(IPI_VECTOR, HalpIpiInterruptHandler);
|
|||
|
|
|||
|
//
|
|||
|
// profile timer interrupt; turned off initially
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector(PROFILE_VECTOR, HalpProfileInterrupt);
|
|||
|
|
|||
|
//
|
|||
|
// Performance monitor interrupt
|
|||
|
//
|
|||
|
|
|||
|
HalpSetHandlerAddressToVector(PERF_VECTOR, HalpPerfInterrupt);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // HalpInitializeInterrupts()
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitIntiInfo(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
USHORT Index;
|
|||
|
|
|||
|
// Initialize the vector to INTi table
|
|||
|
|
|||
|
for (Index=0; Index < ((1 + MAX_NODES)*256); Index++) {
|
|||
|
HalpVectorToINTI[Index] = (ULONG)-1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpInitEOITable(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
USHORT Index;
|
|||
|
ULONG ProcessorNumber;
|
|||
|
|
|||
|
// Allocate and Initialize EOI table on current processor
|
|||
|
|
|||
|
ProcessorNumber = PCR->Prcb->Number;
|
|||
|
|
|||
|
if (ProcessorNumber == 0) {
|
|||
|
HalEOITable[ProcessorNumber] = HalpEOITableP0;
|
|||
|
} else {
|
|||
|
HalEOITable[ProcessorNumber] = ExAllocatePool(NonPagedPool,
|
|||
|
MAX_INTR_VECTOR*sizeof(HalEOITable[0]));
|
|||
|
}
|
|||
|
|
|||
|
// For kernel access to eoi table
|
|||
|
|
|||
|
PCR->EOITable = HalEOITable[ProcessorNumber];
|
|||
|
|
|||
|
for (Index=0; Index < MAX_INTR_VECTOR; Index++) {
|
|||
|
HalEOITable[ProcessorNumber][Index] = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
HalpWriteEOITable(
|
|||
|
IN ULONG Vector,
|
|||
|
IN PULONG_PTR EoiAddress,
|
|||
|
IN ULONG Number
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine updates the EOI table for a processor
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Entry to update (IDT entry)
|
|||
|
|
|||
|
EoiAddress - Address to write (SAPIC address)
|
|||
|
|
|||
|
Number - Logical (NT) processor number
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
if (HalEOITable != NULL && HalEOITable[Number] != NULL) {
|
|||
|
HalEOITable[Number][Vector] = EoiAddress;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
HalEnableSystemInterrupt (
|
|||
|
IN ULONG Vector,
|
|||
|
IN KIRQL Irql,
|
|||
|
IN KINTERRUPT_MODE InterruptMode
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine enables the specified system interrupt.
|
|||
|
|
|||
|
N.B. This routine assumes that the caller has provided any required
|
|||
|
synchronization to enable a system interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Supplies the vector of the system interrupt that is enabled.
|
|||
|
|
|||
|
Irql - Supplies the IRQL of the interrupting source.
|
|||
|
|
|||
|
InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
|
|||
|
Latched.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if the system interrupt was enabled
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG Entry, Destination;
|
|||
|
ULONG OldLevel;
|
|||
|
ULONG Inti;
|
|||
|
ULONG LevelAndPolarity;
|
|||
|
USHORT ThisCpuApicID;
|
|||
|
ULONG InterruptType;
|
|||
|
BOOLEAN RetVal = TRUE;
|
|||
|
UCHAR IDTEntry;
|
|||
|
|
|||
|
ASSERT(Vector < (1+MAX_NODES)*0x100-1);
|
|||
|
ASSERT(Irql <= HIGH_LEVEL);
|
|||
|
|
|||
|
HalDebugPrint(( HAL_VERBOSE, "HAL: HalpEnableSystemInterrupt - INTI=0x%x Vector=0x%x IRQL=0x%x\n",
|
|||
|
HalpVectorToINTI[Vector],
|
|||
|
Vector,
|
|||
|
Irql ));
|
|||
|
|
|||
|
if ( (Inti = HalpVectorToINTI[Vector]) == (ULONG)-1 ) {
|
|||
|
//
|
|||
|
// There is no external device associated with this interrupt,
|
|||
|
// but it might be an internal interrupt i.e. one that never
|
|||
|
// involves the IOSAPIC.
|
|||
|
//
|
|||
|
return HalpIsInternalInterruptVector(Vector);
|
|||
|
}
|
|||
|
|
|||
|
// Make sure the passed-in level matches our settings...
|
|||
|
if ((InterruptMode == LevelSensitive && !HalpIsLevelTriggered(Inti)) ||
|
|||
|
(InterruptMode != LevelSensitive && HalpIsLevelTriggered(Inti)) ) {
|
|||
|
|
|||
|
// It doesn't match!
|
|||
|
HalDebugPrint(( HAL_INFO, "HAL: HalpEnableSystemInterrupt - Warning device interrupt mode overridden\n"));
|
|||
|
}
|
|||
|
|
|||
|
LevelAndPolarity =
|
|||
|
(HalpIsLevelTriggered(Inti) ? LEVEL_TRIGGERED : EDGE_TRIGGERED) |
|
|||
|
(HalpIsActiveLow(Inti) ? ACTIVE_LOW : ACTIVE_HIGH);
|
|||
|
|
|||
|
//
|
|||
|
// Block interrupts and synchronize until we're done
|
|||
|
//
|
|||
|
OldLevel = HalpAcquireHighLevelLock (&HalpIoSapicLock);
|
|||
|
|
|||
|
ThisCpuApicID = (USHORT)KeGetPcr()->HalReserved[PROCESSOR_ID_INDEX];
|
|||
|
|
|||
|
// Get Interrupt type
|
|||
|
HalpGetRedirEntry(Inti,&Entry,&Destination);
|
|||
|
|
|||
|
InterruptType = Entry & INT_TYPE_MASK;
|
|||
|
IDTEntry = HalVectorToIDTEntry(Vector);
|
|||
|
|
|||
|
switch (InterruptType) {
|
|||
|
case DELIVER_FIXED:
|
|||
|
case DELIVER_LOW_PRIORITY:
|
|||
|
//
|
|||
|
// Normal external interrupt...
|
|||
|
// Enable the interrupt in the I/O SAPIC redirection table
|
|||
|
//
|
|||
|
if (IDTEntry < 16) {
|
|||
|
// Reserved vectors: Extint, NMI, IntelReserved
|
|||
|
// No vectors in this range can be assigned
|
|||
|
ASSERT(0);
|
|||
|
RetVal = FALSE;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// All external interrupts are delivered as Fixed interrupts
|
|||
|
// without the "redirectable" bit set (aka Lowest Priority). This
|
|||
|
// disallows hardware to redirect the interrupts using the XTP mechanism.
|
|||
|
//
|
|||
|
|
|||
|
Entry = (ULONG)IDTEntry | LevelAndPolarity;
|
|||
|
|
|||
|
HalpSetRedirEntry ( Inti, Entry, ThisCpuApicID );
|
|||
|
break;
|
|||
|
|
|||
|
case DELIVER_EXTINT:
|
|||
|
//
|
|||
|
// This is an interrupt that uses the IO Sapic to route PIC
|
|||
|
// events. This configuration is not supported in IA64.
|
|||
|
//
|
|||
|
ASSERT(0);
|
|||
|
RetVal = FALSE;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
HalDebugPrint(( HAL_ERROR, "HAL: HalEnableSystemInterrupt - Unknown Interrupt Type: %d\n",
|
|||
|
InterruptType));
|
|||
|
RetVal = FALSE;
|
|||
|
break;
|
|||
|
} // switch (InterruptType)
|
|||
|
|
|||
|
HalpReleaseHighLevelLock (&HalpIoSapicLock, OldLevel);
|
|||
|
return(RetVal);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalDisableSystemInterrupt (
|
|||
|
IN ULONG Vector,
|
|||
|
IN KIRQL Irql
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine disables the specified system interrupt.
|
|||
|
|
|||
|
In the simulation environment, this function does nothing and returns.
|
|||
|
|
|||
|
N.B. This routine assumes that the caller has provided any required
|
|||
|
synchronization to disable a system interrupt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vector - Supplies the vector of the system interrupt that is disabled.
|
|||
|
|
|||
|
Irql - Supplies the IRQL of the interrupting source.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG Entry, Destination;
|
|||
|
ULONG OldLevel;
|
|||
|
ULONG Inti;
|
|||
|
ULONG LevelAndPolarity;
|
|||
|
ULONG ThisCpuApicID;
|
|||
|
ULONG InterruptType;
|
|||
|
|
|||
|
ASSERT(Vector < (1+MAX_NODES)*0x100-1);
|
|||
|
ASSERT(Irql <= HIGH_LEVEL);
|
|||
|
|
|||
|
HalDebugPrint(( HAL_INFO, "HAL: HalpDisableSystemInterrupt: INTI=%x Vector=%x IRQL=%x\n",
|
|||
|
HalpVectorToINTI[Vector],
|
|||
|
Vector,
|
|||
|
Irql));
|
|||
|
|
|||
|
if ( (Inti = HalpVectorToINTI[Vector]) == (ULONG)-1 ) {
|
|||
|
//
|
|||
|
// There is no external device associated with this interrupt
|
|||
|
//
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Block interrupts and synchronize until we're done
|
|||
|
//
|
|||
|
OldLevel = HalpAcquireHighLevelLock(&HalpIoSapicLock);
|
|||
|
|
|||
|
ThisCpuApicID = (USHORT)KeGetPcr()->HalReserved[PROCESSOR_ID_INDEX];
|
|||
|
|
|||
|
// Get Interrupt Type and Destination
|
|||
|
HalpGetRedirEntry(Inti, &Entry, &Destination);
|
|||
|
|
|||
|
if (ThisCpuApicID != Destination) {
|
|||
|
// The interrupt is not enabled on this Cpu
|
|||
|
HalpReleaseHighLevelLock (&HalpIoSapicLock, OldLevel);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InterruptType = Entry & INT_TYPE_MASK;
|
|||
|
|
|||
|
switch (InterruptType) {
|
|||
|
case DELIVER_FIXED:
|
|||
|
//
|
|||
|
// Normal external interrupt...
|
|||
|
// Disable the interrupt in the I/O SAPIC redirection table
|
|||
|
//
|
|||
|
if (Vector < 16) {
|
|||
|
// Reserved vectors: Extint, NMI, IntelReserved
|
|||
|
// No vectors in this range can be assigned
|
|||
|
ASSERT(0);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
HalpDisableRedirEntry (Inti);
|
|||
|
break;
|
|||
|
|
|||
|
case DELIVER_EXTINT:
|
|||
|
//
|
|||
|
// This is an interrupt that uses the IO Sapic to route PIC
|
|||
|
// events. This configuration is not supported in IA64.
|
|||
|
//
|
|||
|
ASSERT(0);
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
HalDebugPrint(( HAL_INFO, "HAL: HalDisableSystemInterrupt - Unknown Interrupt Type: %d\n",
|
|||
|
InterruptType ));
|
|||
|
break;
|
|||
|
} // switch (InterruptType)
|
|||
|
|
|||
|
HalpReleaseHighLevelLock (&HalpIoSapicLock, OldLevel);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
UCHAR
|
|||
|
HalpNodeNumber(
|
|||
|
ULONG Number
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine divines the Node number for the CPU Number.
|
|||
|
Node numbers start at 1, and represent the granularity of interrupt
|
|||
|
routing decisions.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Number - Processor number
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
if (HalpMaxProcsPerCluster != 0) {
|
|||
|
// One Node per Cluster.
|
|||
|
return (UCHAR)(Number/HalpMaxProcsPerCluster + 1);
|
|||
|
} else {
|
|||
|
// One Node per machine.
|
|||
|
return(1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
HalpAddNodeNumber(
|
|||
|
ULONG Number
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine adds the current processor to the Node tables.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG Node;
|
|||
|
//
|
|||
|
// Add the current processor to the Node tables.
|
|||
|
//
|
|||
|
Node = HalpNodeNumber(Number);
|
|||
|
|
|||
|
if (HalpMaxNode < Node) {
|
|||
|
HalpMaxNode = Node;
|
|||
|
}
|
|||
|
|
|||
|
HalpNodeAffinity[Node-1] |= 1 << Number;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
HalpGetProcessorNumberByApicId(
|
|||
|
USHORT ApicId
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the logical processor number for a given
|
|||
|
physical processor id (extended local sapic id)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ApicId -- Extended ID of processor (16 bit id)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Logical (NT) processor number
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG index;
|
|||
|
|
|||
|
for (index = 0; index < HalpMpInfo.ProcessorCount; index++) {
|
|||
|
|
|||
|
if (ApicId == HalpProcessorInfo[index].LocalApicID) {
|
|||
|
|
|||
|
return HalpProcessorInfo[index].NtProcessorNumber;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ASSERT (index < HalpMpInfo.ProcessorCount);
|
|||
|
|
|||
|
//
|
|||
|
// Note: The previous code returned an invalid index (HalpMpInfo.ProcessorCount
|
|||
|
// which is 1 greater than the number of processors) we should probably
|
|||
|
// just bugcheck here.
|
|||
|
//
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|