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.
529 lines
13 KiB
529 lines
13 KiB
/*++
|
|
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ixpciint.c
|
|
|
|
Abstract:
|
|
|
|
All PCI bus interrupt mapping is in this module, so that a real
|
|
system which doesn't have all the limitations which PC PCI
|
|
systems have can replaced this code easly.
|
|
(bus memory & i/o address mappings can also be fix here)
|
|
|
|
Author:
|
|
|
|
Ken Reneris
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "pci.h"
|
|
#include "pcip.h"
|
|
#include "pcmp_nt.inc"
|
|
|
|
volatile ULONG PCIType2Stall;
|
|
extern struct HalpMpInfo HalpMpInfoTable;
|
|
extern BOOLEAN HalpHackNoPciMotion;
|
|
extern BOOLEAN HalpDoingCrashDump;
|
|
|
|
|
|
ULONG
|
|
HalpGetSystemInterruptVector(
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG InterruptLevel,
|
|
IN ULONG InterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
);
|
|
|
|
|
|
VOID
|
|
HalpPCIPin2MPSLine (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
);
|
|
|
|
VOID
|
|
HalpPCIBridgedPin2Line (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
);
|
|
|
|
VOID
|
|
HalpPCIMPSLine2Pin (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciNewData,
|
|
IN PPCI_COMMON_CONFIG PciOldData
|
|
);
|
|
|
|
NTSTATUS
|
|
HalpGetFixedPCIMPSLine (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER PciSlot,
|
|
OUT PSUPPORTED_RANGE *Interrupt
|
|
);
|
|
|
|
PSUPPORTED_RANGES
|
|
HalpAllocateNewRangeList (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpFreeRangeList (
|
|
PSUPPORTED_RANGES Ranges
|
|
);
|
|
|
|
VOID
|
|
HalpMPSPCIChildren (
|
|
VOID
|
|
);
|
|
|
|
ULONG
|
|
HalpGetPCIBridgedInterruptVector (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG InterruptLevel,
|
|
IN ULONG InterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT,HalpSubclassPCISupport)
|
|
#pragma alloc_text(INIT,HalpMPSPCIChildren)
|
|
#pragma alloc_text(PAGE,HalpGetFixedPCIMPSLine)
|
|
#pragma alloc_text(PAGE,HalpGetPCIBridgedInterruptVector)
|
|
#endif
|
|
|
|
|
|
//
|
|
// Turn PCI pin to inti via the MPS spec
|
|
// (note: pin must be non-zero)
|
|
//
|
|
|
|
#define PCIPin2Int(Slot,Pin) (Slot.u.bits.DeviceNumber << 2) | (Pin-1);
|
|
|
|
|
|
|
|
VOID
|
|
HalpSubclassPCISupport (
|
|
PBUS_HANDLER Handler,
|
|
ULONG HwType
|
|
)
|
|
{
|
|
ULONG d, i, MaxDeviceFound;
|
|
PPCIPBUSDATA BusData;
|
|
PCI_SLOT_NUMBER SlotNumber;
|
|
|
|
|
|
BusData = (PPCIPBUSDATA) Handler->BusData;
|
|
SlotNumber.u.bits.Reserved = 0;
|
|
MaxDeviceFound = 0;
|
|
|
|
#ifdef P6_WORKAROUNDS
|
|
BusData->MaxDevice = 0x10;
|
|
#endif
|
|
|
|
//
|
|
// Find any PCI bus which has MPS inti information, and provide
|
|
// MPS handlers for dealing with it.
|
|
//
|
|
// Note: we assume that any PCI bus with any MPS information
|
|
// is totally defined. (Ie, it's not possible to connect some PCI
|
|
// interrupts on a given PCI bus via the MPS table without connecting
|
|
// them all).
|
|
//
|
|
// Note2: we assume that PCI buses are listed in the MPS table in
|
|
// the same order the BUS declares them. (Ie, the first listed
|
|
// PCI bus in the MPS table is assumed to match physical PCI bus 0, etc).
|
|
//
|
|
//
|
|
|
|
for (d=0; d < PCI_MAX_DEVICES; d++) {
|
|
SlotNumber.u.bits.DeviceNumber = d;
|
|
SlotNumber.u.bits.FunctionNumber = 0;
|
|
|
|
i = PCIPin2Int (SlotNumber, 1);
|
|
if (HalpGetPcMpInterruptDesc(PCIBus, Handler->BusNumber, i, &i)) {
|
|
MaxDeviceFound = d;
|
|
}
|
|
}
|
|
|
|
if (MaxDeviceFound) {
|
|
//
|
|
// There are Inti mapping for interrupts on this PCI bus
|
|
// Change handlers for this bus to MPS versions
|
|
//
|
|
|
|
Handler->GetInterruptVector = HalpGetSystemInterruptVector;
|
|
BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2MPSLine;
|
|
BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIMPSLine2Pin;
|
|
BusData->GetIrqRange = HalpGetFixedPCIMPSLine;
|
|
|
|
if (BusData->MaxDevice < MaxDeviceFound) {
|
|
BusData->MaxDevice = MaxDeviceFound;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Not all PCI machines are eisa machine, since the PCI interrupts
|
|
// aren't coming into IoApics go check the Eisa ELCR for broken
|
|
// behaviour.
|
|
//
|
|
|
|
HalpCheckELCR ();
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpMPSPCIChildren (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Any PCI buses which don't have declared interrupt mappings and
|
|
are children of parent buses that have MPS interrupt mappings
|
|
need to inherit interrupts from parents via PCI barbar pole
|
|
algorithm
|
|
|
|
--*/
|
|
{
|
|
PBUS_HANDLER Handler, Parent;
|
|
PPCIPBUSDATA BusData, ParentData;
|
|
ULONG b, cnt, i, id;
|
|
PCI_SLOT_NUMBER SlotNumber;
|
|
struct {
|
|
union {
|
|
UCHAR map[4];
|
|
ULONG all;
|
|
} u;
|
|
} Interrupt, Hold;
|
|
|
|
//
|
|
// Lookup each PCI bus in the system
|
|
//
|
|
|
|
for (b=0; Handler = HaliHandlerForBus(PCIBus, b); b++) {
|
|
|
|
BusData = (PPCIPBUSDATA) Handler->BusData;
|
|
|
|
if (BusData->CommonData.Pin2Line == (PciPin2Line) HalpPCIPin2MPSLine) {
|
|
|
|
//
|
|
// This bus already has mappings
|
|
//
|
|
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if any parent has PCI MPS interrupt mappings
|
|
//
|
|
|
|
Interrupt.u.map[0] = 1;
|
|
Interrupt.u.map[1] = 2;
|
|
Interrupt.u.map[2] = 3;
|
|
Interrupt.u.map[3] = 4;
|
|
|
|
Parent = Handler;
|
|
SlotNumber = BusData->CommonData.ParentSlot;
|
|
|
|
while (Parent = Parent->ParentHandler) {
|
|
|
|
if (Parent->InterfaceType != PCIBus) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Check if parent has MPS interrupt mappings
|
|
//
|
|
|
|
ParentData = (PPCIPBUSDATA) Parent->BusData;
|
|
if (ParentData->CommonData.Pin2Line == (PciPin2Line) HalpPCIPin2MPSLine) {
|
|
|
|
//
|
|
// This parent has MPS interrupt mappings. Set the device
|
|
// to get its InterruptLine values from the buses SwizzleIn table
|
|
//
|
|
|
|
Handler->GetInterruptVector = HalpGetPCIBridgedInterruptVector;
|
|
BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIBridgedPin2Line;
|
|
BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIMPSLine2Pin;
|
|
|
|
for (i=0; i < 4; i++) {
|
|
id = PCIPin2Int (SlotNumber, Interrupt.u.map[i]);
|
|
BusData->SwizzleIn[i] = (UCHAR) id;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Apply interrupt mapping
|
|
//
|
|
|
|
i = SlotNumber.u.bits.DeviceNumber;
|
|
Hold.u.map[0] = Interrupt.u.map[(i + 0) & 3];
|
|
Hold.u.map[1] = Interrupt.u.map[(i + 1) & 3];
|
|
Hold.u.map[2] = Interrupt.u.map[(i + 2) & 3];
|
|
Hold.u.map[3] = Interrupt.u.map[(i + 3) & 3];
|
|
Interrupt.u.all = Hold.u.all;
|
|
|
|
SlotNumber = ParentData->CommonData.ParentSlot;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpPCIPin2MPSLine (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
)
|
|
/*++
|
|
--*/
|
|
{
|
|
if (!PciData->u.type0.InterruptPin) {
|
|
return ;
|
|
}
|
|
|
|
PciData->u.type0.InterruptLine = (UCHAR)
|
|
PCIPin2Int (SlotNumber, PciData->u.type0.InterruptPin);
|
|
}
|
|
|
|
VOID
|
|
HalpPCIBridgedPin2Line (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciData
|
|
)
|
|
/*++
|
|
|
|
This function maps the device's InterruptPin to an InterruptLine
|
|
value.
|
|
|
|
test function particular to dec pci-pci bridge card
|
|
|
|
--*/
|
|
{
|
|
PPCIPBUSDATA BusData;
|
|
ULONG i;
|
|
|
|
if (!PciData->u.type0.InterruptPin) {
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Convert slot Pin into Bus INTA-D.
|
|
//
|
|
|
|
BusData = (PPCIPBUSDATA) BusHandler->BusData;
|
|
|
|
i = (PciData->u.type0.InterruptPin +
|
|
SlotNumber.u.bits.DeviceNumber - 1) & 3;
|
|
|
|
PciData->u.type0.InterruptLine = BusData->SwizzleIn[i];
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpPCIMPSLine2Pin (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER SlotNumber,
|
|
IN PPCI_COMMON_CONFIG PciNewData,
|
|
IN PPCI_COMMON_CONFIG PciOldData
|
|
)
|
|
/*++
|
|
--*/
|
|
{
|
|
//
|
|
// PCI interrupts described in the MPS table are directly
|
|
// connected to APIC Inti pins.
|
|
// Do nothing...
|
|
//
|
|
}
|
|
|
|
ULONG
|
|
HalpGetPCIBridgedInterruptVector (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN ULONG InterruptLevel,
|
|
IN ULONG InterruptVector,
|
|
OUT PKIRQL Irql,
|
|
OUT PKAFFINITY Affinity
|
|
)
|
|
{
|
|
//
|
|
// Get parent's translation
|
|
//
|
|
|
|
return BusHandler->ParentHandler->GetInterruptVector (
|
|
BusHandler->ParentHandler,
|
|
BusHandler->ParentHandler,
|
|
InterruptLevel,
|
|
InterruptVector,
|
|
Irql,
|
|
Affinity
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
HalpGetFixedPCIMPSLine (
|
|
IN PBUS_HANDLER BusHandler,
|
|
IN PBUS_HANDLER RootHandler,
|
|
IN PCI_SLOT_NUMBER PciSlot,
|
|
OUT PSUPPORTED_RANGE *Interrupt
|
|
)
|
|
{
|
|
UCHAR buffer[PCI_COMMON_HDR_LENGTH];
|
|
PPCI_COMMON_CONFIG PciData;
|
|
|
|
PciData = (PPCI_COMMON_CONFIG) buffer;
|
|
HalGetBusData (
|
|
PCIConfiguration,
|
|
BusHandler->BusNumber,
|
|
PciSlot.u.AsULONG,
|
|
PciData,
|
|
PCI_COMMON_HDR_LENGTH
|
|
);
|
|
|
|
if (PciData->VendorID == PCI_INVALID_VENDORID ||
|
|
PCI_CONFIG_TYPE (PciData) != 0) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
*Interrupt = ExAllocatePool (PagedPool, sizeof (SUPPORTED_RANGE));
|
|
if (!*Interrupt) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory (*Interrupt, sizeof (SUPPORTED_RANGE));
|
|
(*Interrupt)->Base = 1; // base = 1, limit = 0
|
|
|
|
|
|
if (!PciData->u.type0.InterruptPin) {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
(*Interrupt)->Base = PciData->u.type0.InterruptLine;
|
|
(*Interrupt)->Limit = PciData->u.type0.InterruptLine;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
HalpPCIType2TruelyBogus (
|
|
ULONG Context
|
|
)
|
|
/*++
|
|
|
|
This is a piece of work.
|
|
|
|
Type 2 of the PCI configuration space is bad. Bad as in to
|
|
access it one needs to block out 4K of I/O space.
|
|
|
|
Video cards are bad. The only decode the bits in an I/O address
|
|
they feel like. Which means one can't block out a 4K range
|
|
or these video cards don't work.
|
|
|
|
Combinding all these bad things onto an MP machine is even
|
|
more (sic) bad. The I/O ports can't be mapped out unless
|
|
all processors stop accessing I/O space.
|
|
|
|
Allowing access to device specific PCI control space during
|
|
an interrupt isn't bad, (although accessing it on every interrupt
|
|
is stupid) but this cause the added grief that all processors
|
|
need to obtained at above all device interrupts.
|
|
|
|
And... naturally we have an MP machine with a wired down
|
|
bad video controller, stuck in the bad Type 2 configuration
|
|
space (when we told everyone about type 1!). So the "fix"
|
|
is to HALT ALL processors for the duration of reading/writing
|
|
ANY part of PCI configuration space such that we can be sure
|
|
no processor is touching the 4k I/O ports which get mapped out
|
|
of existance when type2 accesses occur.
|
|
|
|
----
|
|
|
|
While I'm flaming. Hooking PCI interrupts ontop of ISA interrupts
|
|
in a machine which has the potential to have 240+ interrupts
|
|
sources (read APIC) is bad ... and stupid.
|
|
|
|
--*/
|
|
{
|
|
// oh - let's just wait here and not pay attention to that other processor
|
|
// guy whom is punching holes into the I/O space
|
|
while (PCIType2Stall == Context) {
|
|
HalpPollForBroadcast ();
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpPCIAcquireType2Lock (
|
|
PKSPIN_LOCK SpinLock,
|
|
PKIRQL OldIrql
|
|
)
|
|
{
|
|
if (!HalpDoingCrashDump) {
|
|
*OldIrql = KfRaiseIrql (CLOCK2_LEVEL-1);
|
|
KiAcquireSpinLock (SpinLock);
|
|
|
|
//
|
|
// Interrupt all other processors and have them wait until the
|
|
// barrier is cleared. (HalpGenericCall waits until the target
|
|
// processors have been interrupted before returning)
|
|
//
|
|
|
|
HalpGenericCall (
|
|
HalpPCIType2TruelyBogus,
|
|
PCIType2Stall,
|
|
HalpActiveProcessors & ~KeGetCurrentPrcb()->SetMember
|
|
);
|
|
} else {
|
|
*OldIrql = HIGH_LEVEL;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpPCIReleaseType2Lock (
|
|
PKSPIN_LOCK SpinLock,
|
|
KIRQL Irql
|
|
)
|
|
{
|
|
if (!HalpDoingCrashDump) {
|
|
PCIType2Stall++; // clear barrier
|
|
KiReleaseSpinLock (SpinLock);
|
|
KfLowerIrql (Irql);
|
|
}
|
|
}
|