summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halraw/alpha/rwintbal.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halraw/alpha/rwintbal.c')
-rw-r--r--private/ntos/nthals/halraw/alpha/rwintbal.c1762
1 files changed, 1762 insertions, 0 deletions
diff --git a/private/ntos/nthals/halraw/alpha/rwintbal.c b/private/ntos/nthals/halraw/alpha/rwintbal.c
new file mode 100644
index 000000000..f32f533b1
--- /dev/null
+++ b/private/ntos/nthals/halraw/alpha/rwintbal.c
@@ -0,0 +1,1762 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ rwintbal.c
+
+Abstract:
+
+ The module provides support for distributing interrupt load among
+ processors for Rawhide systems.
+
+Author:
+
+ Matthew Buchman (DEC) 29-November-1995
+
+Revision History:
+
+--*/
+
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+#include "rawhide.h"
+#include "pcrtc.h"
+
+//
+// The enable mask for all interrupts sourced from the IOD (all device
+// interrupts, and all from PCI). A "1" indicates the interrupt is enabled.
+//
+
+extern PULONG *HalpIodInterruptMask;
+
+//
+// Declare IOD and CPU affinity tables
+//
+
+LIST_ENTRY HalpIodVectorDataHead;
+LIST_ENTRY HalpCpuVectorDataHead;
+
+PIOD_VECTOR_DATA HalpIodVectorData;
+PCPU_VECTOR_DATA HalpCpuVectorData;
+
+
+//
+// The number of target CPUS, mainly for performance comparison of
+// one processor vs. distributed interrupt load
+//
+
+#if 1
+ULONG HalpNumberOfTargetCpus = IOD_MAX_INT_TARG;
+#else
+ULONG HalpNumberOfTargetCpus = 1;
+#endif
+
+
+
+PVOID
+HalpFindWeightedEntry(
+ PLIST_ENTRY ListHead,
+ WEIGHTED_SEARCH_CRITERIA SearchCriteria
+ )
+/*++
+
+Routine Description:
+
+ This routine searches a WEIGHTED list searching for the maximum
+ or minimum weight, depending on the SearchCriteria. A WEIGHTED
+ list entry overlays the generic LIST_ENTRY provided by NT. This
+ allows us to use the generic LIST_ENTRY routines for list
+ manipulation. To treat this as an ordered list, we must traverse
+ this list by hand to find the maximum element.
+
+ The entry matching the search criteria is removed from the list
+ as a side effect.
+
+Arguments:
+
+ ListHead - a pointer the list head.
+
+ SearchCriteria - either FindMaxEntry or FindMinEntry
+
+Return Value:
+
+ Return a pointer to the maximum element or NULL for
+ an empty list.
+
+--*/
+{
+ PLIST_ENTRY NextEntry;
+ PLIST_ENTRY CurrentMaxMinEntry;
+ PWEIGHTED_LIST_ENTRY WeightedEntry;
+ LONG CurrentMaxMinWeight;
+
+
+ //
+ // Handle the empty list case
+ //
+
+ if (IsListEmpty(ListHead)) {
+ return (NULL);
+ }
+
+ //
+ // Traverse this list looking for the maximum weight
+ //
+
+ for (
+ NextEntry = ListHead->Flink,
+ CurrentMaxMinEntry = NULL;
+
+ NextEntry != ListHead;
+
+ NextEntry = NextEntry->Flink
+
+ ) {
+
+ //
+ // The WEIGHTED_LIST_ENTRY overlays the LIST_ENTRY
+ //
+
+ WeightedEntry = (PWEIGHTED_LIST_ENTRY)NextEntry;
+
+ if (CurrentMaxMinEntry == NULL) {
+
+ CurrentMaxMinEntry = NextEntry;
+ CurrentMaxMinWeight = WeightedEntry->Weight;
+
+ } else {
+
+ if (SearchCriteria == FindMaxWeight) {
+
+ if (WeightedEntry->Weight > CurrentMaxMinWeight) {
+ CurrentMaxMinEntry = NextEntry;
+ CurrentMaxMinWeight = WeightedEntry->Weight;
+ }
+
+ } else {
+
+ if (WeightedEntry->Weight < CurrentMaxMinWeight) {
+ CurrentMaxMinEntry = NextEntry;
+ CurrentMaxMinWeight = WeightedEntry->Weight;
+ }
+
+ }
+ }
+ }
+
+ //
+ // Remove the maximum from the list
+ //
+
+ RemoveEntryList(CurrentMaxMinEntry);
+
+ return ((PVOID)CurrentMaxMinEntry);
+}
+
+// mdbfix - delete these routines later!
+#if 0
+
+//
+// Declare the lower-level routine used to read PCI config space
+//
+
+VOID
+HalpReadPCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+VOID
+HalpFindPciBusVectors(
+ IN PCONFIGURATION_COMPONENT Component,
+ IN PVOID ConfigurationData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds all device interrupt vectors for the PCI bus
+ handler obtained from the configuration tree and sets the
+ corresponding bits in the VectorPresent bitmap for the IOD.
+
+Arguments:
+
+ Component - The ARC configuration component for this bus.
+
+ ConfigurationData - The configuration data payload (or NULL).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_PCI_CONFIGURATION ArcPciConfiguration;
+ ULONG BusNumber;
+ ULONG HwBusNumber;
+ BOOLEAN BusIsAcrossPPB;
+ PBUS_HANDLER BusHandler;
+ PPCIPBUSDATA BusData;
+ PCIPBUSDATA BusContext;
+ RTL_BITMAP DevicePresent;
+ PCI_SLOT_NUMBER SlotNumber;
+ PIOD_VECTOR_DATA IodIoVectors;
+ ULONG DeviceNumber;
+ ULONG NextDevice;
+ ULONG FunctionNumber;
+ ULONG InterruptLine;
+ PCI_COMMON_CONFIG CommonConfig;
+
+ //
+ // Copy the configuration data from the component.
+ //
+
+ RtlCopyMemory(
+ &ArcPciConfiguration,
+ ConfigurationData,
+ sizeof (ARC_PCI_CONFIGURATION)
+ );
+
+ //
+ // Use the values provided.
+ //
+
+ BusNumber = ArcPciConfiguration.BusNumber;
+ HwBusNumber = ArcPciConfiguration.HwBusNumber;
+ BusIsAcrossPPB = ArcPciConfiguration.BusIsAcrossPPB;
+ IodIoVectors = HalpIodVectorData + HwBusNumber;
+
+ //
+ // Initialize the BusNumber for this IOD now.
+ // We might want to use it later to obtain the bus handler
+ //
+
+ IodIoVectors->BusNumber = BusNumber;
+
+ //
+ // Allocate and initialize the handler for this bus. N.B. device-present
+ // checking is disabled at this point. We will enable it below.
+ //
+
+ BusHandler = HaliHandlerForBus(
+ PCIBus,
+ BusNumber
+ );
+
+ //
+ // Get a pointer to the bus-specific data.
+ //
+
+ BusData = (PPCIPBUSDATA)BusHandler->BusData;
+
+ //
+ // Use the device-present bitmap for this bus to query configuration
+ // Space for InterruptLine values.
+ //
+
+ //
+ // Initialize the device-present bitmap for this bus.
+ //
+
+ HalpInitializeBitMap(
+ &BusContext.DevicePresent,
+ BusContext.DevicePresentBits,
+ PCI_MAX_DEVICES * PCI_MAX_FUNCTION
+ );
+
+ //
+ // Copy the bitmap from the bus handler.
+ //
+
+ RtlCopyMemory(
+ &BusContext.DevicePresentBits,
+ &BusData->DevicePresentBits,
+ sizeof (BusData->DevicePresentBits)
+ );
+
+
+ //
+ // Starting with device 0, scan the device present
+ // bitmap.
+ //
+
+ DeviceNumber = 0;
+
+ while ( (DeviceNumber =
+ HalpFindSetBitsAndClear(
+ &BusContext.DevicePresent,
+ 1,
+ DeviceNumber
+ ) ) != -1 ) {
+
+ //
+ // Initialize the slot number.
+ //
+
+ SlotNumber.u.AsULONG = 0;
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+
+ //
+ // Loop through each function number.
+ //
+
+ for (FunctionNumber = 0;
+ FunctionNumber < PCI_MAX_FUNCTION;
+ FunctionNumber++) {
+
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+ //
+ // Read the common configuration header.
+ //
+
+ HalpReadPCIConfig(
+ BusHandler,
+ SlotNumber,
+ &CommonConfig,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ //
+ // If the Vendor ID is invalid, then no device is present
+ // at this device/function number.
+ //
+
+ if (CommonConfig.VendorID == PCI_INVALID_VENDORID) {
+ if (FunctionNumber == 0) {
+ break;
+ }
+ continue;
+ }
+
+ //
+ // Obtain the vector assigned to this Device:Function
+ // during PCI configuration.
+ //
+
+ if (CommonConfig.u.type0.InterruptLine) {
+
+ //
+ // Obtain vector and normalize
+ //
+
+ InterruptLine =CommonConfig.u.type0.InterruptLine;
+ InterruptLine -= (RawhidePinToLineOffset + 1);
+
+ //
+ // Determine if this is a shared vector
+ //
+
+ if ( HalpAreBitsSet(
+ &IodIoVectors->VectorPresent[0],
+ InterruptLine,
+ 1
+ ) == TRUE ) {
+
+ //
+ // Indicate vector is shared in bitmap
+ //
+
+ HalpSetBits(
+ &IodIoVectors->SharedVector[0],
+ InterruptLine,
+ 1
+ );
+
+ HalpDumpBitMap(&IodIoVectors->SharedVector[0]);
+
+ } else {
+
+ //
+ // Indicate device is present in bitmap
+ //
+
+ HalpSetBits(
+ &IodIoVectors->VectorPresent[0],
+ InterruptLine,
+ 1
+ );
+
+ HalpDumpBitMap(&IodIoVectors->VectorPresent[0]);
+
+ }
+
+ //
+ // Increment the weight
+ //
+
+ IodIoVectors->ListEntry.Weight++;
+
+ } // if (CommonConfig.InterruptLine)
+
+ //
+ // If this is not a multi-function device, then terminate
+ // the function number loop.
+ //
+
+ if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) {
+ break;
+ }
+
+ } // for (FunctionNumber...)
+
+ } // while (DeviceNumber != -1)
+}
+
+
+VOID
+HalpFindAllPciVectors(
+ IN PCONFIGURATION_COMPONENT_DATA Root
+ )
+/*++
+
+Routine Description:
+
+ This function loops through each multi-function adapter component
+ in the ARC configuration tree and calls HalpFindPciBusVectors()
+ searching for device vectors.
+
+Arguments:
+
+ Root - The root of the ARC configuration tree.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Key;
+ PCONFIGURATION_COMPONENT_DATA Adapter;
+
+ //
+ // Loop through each multi-function adapter component in the ARC
+ // configuration tree.
+ //
+
+ for (Key = 0; TRUE; Key++) {
+
+ //
+ // Get a pointer to the component data.
+ //
+
+ Adapter = KeFindConfigurationEntry(
+ Root,
+ AdapterClass,
+ MultiFunctionAdapter,
+ &Key
+ );
+
+ //
+ // If there are no more multi-function adapters in the ARC
+ // configuration tree, then we're done.
+ //
+
+ if (Adapter == NULL) {
+ break;
+ }
+
+ //
+ // Ascertain whether this is a PCI multi-function adapter component.
+ // If so, find the device vectors.
+ //
+
+ if (stricmp(Adapter->ComponentEntry.Identifier, "PCI") == 0) {
+ HalpFindPciBusVectors(
+ &Adapter->ComponentEntry,
+ Adapter->ConfigurationData
+ );
+ }
+ }
+}
+
+
+VOID
+HalpBalanceVectorLoadForIod(
+ PIOD_VECTOR_DATA IodVectorData
+ )
+/*++
+
+Routine Description:
+
+ Balance the vector load for the given IOD among the
+ CPU pair. The basic algorithm is:
+
+ 1. Find a device present from the bitmap.
+ 2. Choose the CPUwith the minimum vector load.
+ 3. Assign the device vector from (1) to this CPU
+ and update the CPU's vector load (weight) by 1.
+ 4. If the vector is shared (multiple devices
+ connect), update the CPU's vector load by 1.
+ While this does not accurately reflect the
+ actual vector's sharing the device, it will
+ due for algorithmic simplicity.
+ 5. Update the CPU's IOD service mask.
+ 6. repeat for all vectors.
+
+
+Arguments:
+
+ IodListHead - head of temporary IOD vector info list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ RTL_BITMAP VectorPresent;
+ ULONG VectorPresentBits;
+ ULONG IRRBitNumber;
+ ULONG InterruptBit;
+
+ HalpInitializeBitMap(
+ &VectorPresent,
+ (PULONG)&VectorPresentBits,
+ 32
+ );
+
+ //
+ // Copy the device present bitmap from the IOD information.
+ //
+
+ RtlCopyMemory(
+ &VectorPresentBits,
+ &IodVectorData->VectorPresentBits[0],
+ sizeof (IodVectorData->VectorPresentBits[0])
+ );
+
+ //
+ // Now that we have a copy of all device vectors for this
+ // IOD, clear the device present bitmap for target 0.
+ // This was only being used as temporary storage.
+ //
+
+ HalpClearAllBits(&IodVectorData->VectorPresent[0]);
+
+ //
+ // Start with the first IRR bit.
+ //
+
+ IRRBitNumber = 0;
+
+ //
+ // Find the next Device present.
+ // Remember that this bitmap actually represents
+ // the interrupt vector assigned to devices.
+ //
+
+ while (( IRRBitNumber =
+ HalpFindSetBitsAndClear(
+ &VectorPresent,
+ 1,
+ IRRBitNumber) ) != -1 ) {
+
+ InterruptBit = (1 << IRRBitNumber);
+
+ //
+ // Assign the vector for this IOD
+ //
+
+ HalpAssignInterruptForIod(IodVectorData, InterruptBit);
+
+ }
+
+}
+
+
+VOID
+HalpBalanceIoVectorLoad(
+ PLIST_ENTRY IodListHead
+ )
+/*++
+
+Routine Description:
+
+ Balance the vector load among the set of processors.
+ The basic algorithm is:
+
+ 1. Find an IOD to process:
+
+ From the IOD set, find the IOD with the maximum
+ number of vectors, and permanantly remove this
+ IOD from the set.
+
+ 2. Find a CPU pair that will act as targets for
+ the selected IOD interrupts:
+
+ a. From the CPU set, find the first CPU with the
+ minimum number of vectors assigned and temporarily
+ remove this CPU from the CPU set.
+
+ b. From the CPU set, find the second CPU with the
+ minimum number of vectors assigned and temporarily
+ remove this CPU from the CPU set.
+
+ 3. Call HalpBalanceIodVectorLoad to divide the IOD
+ vectors among the two CPU's.
+
+ 5. Add the CPU's back the the CPU set. This makes them
+ available for selection during the next iteration.
+
+ 6. Repeat until the IOD set is empty.
+
+Arguments:
+
+ IodListHead - head of temporary IOD vector info list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIOD_VECTOR_DATA IodVectorData;
+
+ //
+ // Balance the vector load for each IOD,
+ // assigning vector affinity in the process
+ //
+
+ while (!IsListEmpty(IodListHead)) {
+
+ //
+ // Find the IOD with the maximum number of
+ // vectors. It is removed from the list as
+ // a side effect.
+ //
+
+ IodVectorData = (PIOD_VECTOR_DATA)
+ HalpFindWeightedEntry(IodListHead, FindMaxWeight);
+
+ //
+ // Assign the interrupt vector affinity for this IOD
+ //
+
+ HalpBalanceVectorLoadForIod(
+ IodVectorData
+ );
+
+ //
+ // Add this to the global list of IOD's.
+ // Use shortcut to obtain LIST_ENTRY.
+ //
+
+ InsertHeadList(
+ &HalpIodVectorDataHead,
+ &IodVectorData->ListEntry.ListEntry
+ );
+
+ }
+
+}
+
+
+VOID
+HalpInitializeIoVectorAffinity(
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ The IOD and CPU vector information tables are used balance the
+ interrupt load from all IOD's among the set of available CPU's.
+
+ Allocate and initialize the IOD and CPU vector information tables,
+ pre-assign vectors for EISA, I2c, SoftErr, and HardErr, and
+ call HalpIoVectorLoad() to assign IOD vectors to CPU's.
+
+Arguments:
+
+ LoaderParameterBlock - supplies a pointer to the loader block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MC_DEVICE_MASK IodMask = HalpIodMask;
+ MC_DEVICE_MASK CpuMask = HalpCpuMask;
+ PIOD_VECTOR_DATA IodVectorData;
+ PCPU_VECTOR_DATA CpuVectorData;
+ LIST_ENTRY IodListHead;
+ ULONG LogicalNumber;
+ ULONG Target;
+
+ //
+ // Allocate the IOD device affinity table.
+ //
+
+ HalpIodVectorData = (PIOD_VECTOR_DATA)
+ ExAllocatePool(
+ NonPagedPool,
+ sizeof(IOD_VECTOR_DATA)* HalpNumberOfIods
+ );
+
+ RtlZeroMemory(
+ HalpIodVectorData,
+ sizeof(IOD_VECTOR_DATA)*HalpNumberOfIods
+ );
+
+ //
+ // Initialize the IOD vector affinity list.
+ //
+
+ InitializeListHead(&HalpIodVectorDataHead);
+ InitializeListHead(&IodListHead);
+
+ for ( LogicalNumber = 0, IodVectorData = HalpIodVectorData;
+ LogicalNumber < HalpNumberOfIods;
+ LogicalNumber++, IodVectorData++ ) {
+
+
+ //
+ // Initialize bitmaps for each target.
+
+ for (Target = 0; Target < IOD_MAX_INT_TARG; Target++) {
+
+ //
+ // The VectorBitmap represents the devices on this IOD
+ // that been assigned vectors and to which target the
+ // vectors have been assigned.
+ //
+
+
+ HalpInitializeBitMap(
+ &IodVectorData->VectorPresent[Target] ,
+ (PULONG)&IodVectorData->VectorPresentBits[Target],
+ 32
+ );
+
+ //
+ // The SharedBitmap represents vectors that are shared
+ // by devices on this IOD. It is used to make decisions
+ // on which target to assign vectors.
+ //
+
+ HalpInitializeBitMap(
+ &IodVectorData->SharedVector[Target],
+ (PULONG)&IodVectorData->SharedVectorBits[Target],
+ 32
+ );
+
+ }
+
+ //
+ // Assign the device number. This cooresponds to the logical
+ // IOD number.
+ //
+
+ IodVectorData->HwBusNumber = LogicalNumber;
+
+ //
+ // Add this IOD to temporary list. The IOD will be added
+ // to permanent list after it is processed.
+ //
+
+ InsertTailList(
+ &IodListHead,
+ &IodVectorData->ListEntry.ListEntry
+ );
+
+ }
+
+ //
+ // Allocate the CPU IO device affinity table.
+ //
+
+ HalpCpuVectorData = (PCPU_VECTOR_DATA)
+ ExAllocatePool(
+ NonPagedPool,
+ sizeof(CPU_VECTOR_DATA) * HalpNumberOfCpus
+ );
+
+ RtlZeroMemory(
+ HalpCpuVectorData,
+ sizeof(CPU_VECTOR_DATA)*HalpNumberOfCpus
+ );
+
+ //
+ // Initialize the CPU vector affinity list.
+ //
+
+ InitializeListHead(&HalpCpuVectorDataHead);
+
+ for ( LogicalNumber = 0, CpuVectorData = HalpCpuVectorData;
+ LogicalNumber < HalpNumberOfCpus;
+ LogicalNumber++, CpuVectorData++ ) {
+
+ //
+ // Assign the device number. This cooresponds to the logical
+ // CPU number.
+ //
+
+ CpuVectorData->LogicalNumber = LogicalNumber;
+ CpuVectorData->McDeviceId.Gid = GidPrimary;
+
+ switch (LogicalNumber) {
+
+ case 0:
+
+ CpuVectorData->McDeviceId.Mid = MidCpu1;
+ break;
+
+ case 1:
+
+ CpuVectorData->McDeviceId.Mid = MidCpu1;
+ break;
+
+ case 2:
+
+ CpuVectorData->McDeviceId.Mid = MidCpu2;
+ break;
+
+ case 3:
+
+ CpuVectorData->McDeviceId.Mid = MidCpu3;
+ break;
+
+ }
+ //
+ // Insert this CPU into the list
+ //
+
+ InsertTailList(
+ &HalpCpuVectorDataHead,
+ &CpuVectorData->ListEntry.ListEntry
+ );
+
+ }
+
+ //
+ // Find all PCI Iod Vectors.
+ //
+
+ HalpFindAllPciVectors(LoaderBlock->ConfigurationRoot);
+
+ //
+ // Preassign error vectors for all IOD's as well as EISA, EISANMI
+ // and I2c vectors to the primary processor.
+ //
+
+ HalpAssignPrimaryProcessorVectors(&IodListHead);
+
+ //
+ // Balance the IO vector load among the CPU's
+ //
+
+ HalpBalanceIoVectorLoad(&IodListHead);
+
+#if HALDBG
+
+ HalpDumpIoVectorAffinity();
+
+#endif
+
+}
+
+
+VOID
+HalpAssignIodInterrupts(
+ MC_DEVICE_ID McDeviceId,
+ ULONG PciBusNumber,
+ va_list Arguments
+ )
+
+/*++
+
+Routine Description:
+
+ This enumeration routine assigns the Rawhide interrupts for the
+ corresponding IOD and sets up the target CPU's. The interrupts
+ are initialized with the values determined by
+ HalpInitializeIoVectorAffinity()
+
+ Interrupts were previously routed to the primary processor
+ by HalpInitializeIodInterrupts. Now that All processors are
+ started, we must reassign HardErr, Eisa, and EisaNMI interrupts.
+
+ The logical bus is assigned from the static variable PciBusNumber, which is
+ incremented with each invokation.
+
+Arguments:
+
+ McDeviceId - Supplies the MC Bus Device ID of the IOD to be intialized
+
+ PciBusNumber - Logical (Hardware) bus number.
+
+ Arguments - Variable Arguments. None for this routine.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIOD_VECTOR_DATA IodVectorData;
+ IOD_INT_MASK IntMask;
+ IOD_INT_TARGET_DEVICE IntTarg;
+ PVOID IntMaskQva;
+ ULONG Target;
+
+ IodVectorData = HalpIodVectorData + PciBusNumber;
+
+ //
+ // Disable MCI bus interrupts
+ //
+
+ WRITE_IOD_REGISTER_NEW(
+ McDeviceId,
+ &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl,
+ (IOD_INT_CTL_DISABLE_IO_INT | IOD_INT_CTL_DISABLE_VECT_WRITE)
+ );
+
+ //
+ // Initialize the target register base on assigned values
+ //
+
+ IntTarg.Int0TargDevId = (ULONG)IodVectorData->IntTarg[0].all;
+ IntTarg.Int1TargDevId = (ULONG)IodVectorData->IntTarg[1].all;
+
+ //
+ // Write the target register.
+ //
+
+ WRITE_IOD_REGISTER_NEW(
+ McDeviceId,
+ &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg,
+ IntTarg.all
+ );
+
+ //
+ // Write the mask bits for target 0 and 1
+ //
+
+ for (Target = 0; Target < IOD_MAX_INT_TARG; Target++) {
+
+ //
+ // Obtain the target IRR QVA
+ //
+
+ if (Target) {
+
+ IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask1;
+
+ } else {
+
+ IntMaskQva = (PVOID)&((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntMask0;
+
+ }
+ IntMask.all = IodVectorData->IntMask[Target].all;
+
+ WRITE_IOD_REGISTER_NEW(
+ McDeviceId,
+ IntMaskQva,
+ IntMask.all
+ );
+
+ }
+
+ //
+ // Enable Interrupts.
+ //
+
+ WRITE_IOD_REGISTER_NEW(
+ McDeviceId,
+ &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntCtrl,
+ IOD_INT_CTL_ENABLE_IO_INT
+ );
+
+}
+
+#endif // STATIC BALANCE
+
+
+VOID
+HalpInitializeVectorBalanceData(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ The IOD and CPU vector information tables are used balance the
+ interrupt load from all IOD's among the set of available CPU's.
+
+ Allocate and initialize the IOD and CPU vector information tables,
+ pre-assign vectors for EISA, I2c, SoftErr, and HardErr, and
+ call HalpIoVectorLoad() to assign IOD vectors to CPU's.
+
+Arguments:
+
+ LoaderParameterBlock - supplies a pointer to the loader block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MC_DEVICE_MASK IodMask = HalpIodMask;
+ MC_DEVICE_MASK CpuMask = HalpCpuMask;
+ PIOD_VECTOR_DATA IodVectorData;
+ ULONG LogicalNumber;
+ ULONG Target;
+
+ //
+ // Allocate the IOD device affinity table.
+ //
+
+ HalpIodVectorData = (PIOD_VECTOR_DATA)
+ ExAllocatePool(
+ NonPagedPool,
+ sizeof(IOD_VECTOR_DATA)* HalpNumberOfIods
+ );
+
+ RtlZeroMemory(
+ HalpIodVectorData,
+ sizeof(IOD_VECTOR_DATA)*HalpNumberOfIods
+ );
+
+ //
+ // Initialize the IOD vector affinity list.
+ //
+
+ InitializeListHead(&HalpIodVectorDataHead);
+
+ for ( LogicalNumber = 0, IodVectorData = HalpIodVectorData;
+ LogicalNumber < HalpNumberOfIods;
+ LogicalNumber++, IodVectorData++ ) {
+
+ //
+ // Assign the device number. This cooresponds to the logical
+ // IOD number.
+ //
+
+ IodVectorData->HwBusNumber = LogicalNumber;
+
+ //
+ // Add this IOD to temporary list. The IOD will be added
+ // to permanent list after it is processed.
+ //
+
+ InsertTailList(
+ &HalpIodVectorDataHead,
+ &IodVectorData->ListEntry.ListEntry
+ );
+
+ }
+
+ //
+ // Allocate the CPU vector data table for the maximum
+ // processor configuration.
+ //
+
+ HalpCpuVectorData = (PCPU_VECTOR_DATA)
+ ExAllocatePool(
+ NonPagedPool,
+ sizeof(CPU_VECTOR_DATA)*HalpNumberOfCpus
+ );
+
+ RtlZeroMemory(
+ HalpCpuVectorData,
+ sizeof(CPU_VECTOR_DATA)*HalpNumberOfCpus
+ );
+
+ //
+ // Initialize the CPU vector affinity list.
+ // CPU's will add their entry later.
+ //
+
+ InitializeListHead(&HalpCpuVectorDataHead);
+
+}
+
+
+VOID
+HalpInitializeCpuVectorData(
+ ULONG LogicalCpu
+ )
+/*++
+
+Routine Description:
+
+ Allocate and initialize the CPU vector entry for this logical
+ CPU and add it to the global list,
+
+Arguments:
+
+ LogicalCpu - Logical CPU number assigned by HalStartNextProcessor().
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MC_DEVICE_MASK CpuMask = HalpCpuMask;
+ PCPU_VECTOR_DATA CpuVectorData;
+ ULONG Target;
+
+ //
+ // Use the logical processor number to offset into in the
+ // global CPU table.
+ //
+
+ CpuVectorData = HalpCpuVectorData + LogicalCpu;
+
+ //
+ // Initalize CPU vector data fields
+ //
+
+ CpuVectorData->LogicalNumber = LogicalCpu;
+
+ //
+ // Insert into global list
+ //
+
+ InsertTailList(
+ &HalpCpuVectorDataHead,
+ &CpuVectorData->ListEntry.ListEntry
+ );
+
+#if HALDBG
+ DbgPrint(
+ "Initialized vector data for CPU %d (%d, %d)\n",
+ CpuVectorData->LogicalNumber,
+ HalpLogicalToPhysicalProcessor[LogicalCpu].Gid,
+ HalpLogicalToPhysicalProcessor[LogicalCpu].Mid
+ );
+#endif
+
+}
+
+
+VOID
+HalpAssignPrimaryProcessorVectors(
+ PLIST_ENTRY IodListHead
+ )
+/*++
+
+Routine Description:
+
+ Assign primary processor vectors. This includes the following:
+
+ HardErr
+ SoftErr
+ Eisa
+ EisaNMI
+ I2cBus
+ I2cCtrl
+
+ By having the primary processor handle the error vectors, we
+ prevent hard errors from being serviced by multiple
+ processors.
+
+Arguments:
+
+ IodListHead - head of temporary IOD vector info list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PLIST_ENTRY ListEntry;
+ PIOD_VECTOR_DATA IodVectorData;
+ PCPU_VECTOR_DATA PrimaryCpuVectorData;
+ MC_DEVICE_ID McDeviceId;
+ ULONG Target;
+
+ //
+ // Obtain the vector data structure for the primary processor
+ //
+
+ PrimaryCpuVectorData = HalpCpuVectorData;
+
+ //
+ // Assign the hard and soft error interrupt for each IOD
+ // to the primary processor
+ //
+
+ for ( ListEntry = IodListHead->Flink;
+ ListEntry != IodListHead;
+ ListEntry = ListEntry->Flink ) {
+
+ //
+ // Obtain the IOD vector data.
+ //
+
+ IodVectorData = (PIOD_VECTOR_DATA)ListEntry;
+
+ McDeviceId = HalpIodLogicalToPhysical[IodVectorData->HwBusNumber];
+
+#if HALDBG
+ DbgPrint(
+ "Assign IOD (%d, %d) Target 0 to Primary Processor\n",
+ McDeviceId.Gid,
+ McDeviceId.Mid
+ );
+#endif
+
+ //
+ // Assign the Target 0 CPU for this IOD
+ //
+
+ IodVectorData->TargetCpu[0] = PrimaryCpuVectorData;
+
+ //
+ // Assign the SoftErr and HardErr interrupts to each IOD
+ //
+
+ IodVectorData->IntMask[0].all |= (1 << IodHardErrIrrBit);
+ IodVectorData->IntMask[0].all |= (1 << IodSoftErrIrrBit);
+
+
+#if HALDBG
+ DbgPrint(
+ "Assign IOD (%d, %d) HardError to Target 0, CPU 0\n",
+ McDeviceId.Gid,
+ McDeviceId.Mid
+ );
+#endif
+
+ //
+ // Assign the Eisa, EisaNMI, and I2C interrupts for PCI bus 0
+ // to the primary processor.
+ //
+
+ if (IodVectorData->HwBusNumber == 0) {
+
+ IodVectorData->IntMask[0].all |= (1 << IodEisaIrrBit);
+// mdbfix - I2c not enabled
+// IodVectorData->IntMask[0].all |= (1 << IodI2cBusIrrBit);
+// IodVectorData->IntMask[0].all |= (1 << IodI2cCtrlIrrBit);
+ IodVectorData->IntMask[0].all |= (1 << IodEisaNmiIrrBit);
+
+#if HALDBG
+ DbgPrint(
+ "Assign IOD (%d, %d) EISA & EISANMI to Target 0, CPU 0\n",
+ McDeviceId.Gid,
+ McDeviceId.Mid
+ );
+#endif
+
+// mdbfix -
+#if 0
+ //
+ // Weight this Processor for EISA vectors KBD, MOUSE, etc.
+ //
+
+ PrimaryCpuVectorData->ListEntry.Weight++;
+#endif
+ }
+
+ //
+ // Initialize the affinity mask, target, and CPU vector link
+ //
+
+ IodVectorData->Affinity[0] |= 1;
+
+ IodVectorData->IntTarg[0] =
+ HalpLogicalToPhysicalProcessor[HAL_PRIMARY_PROCESSOR];
+
+ IodVectorData->TargetCpu[0] = PrimaryCpuVectorData;
+
+ }
+
+}
+
+
+ULONG
+HalpAssignInterruptForIod(
+ PIOD_VECTOR_DATA IodVectorData,
+ ULONG InterruptBit
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ IodVectorData - IOD to assign interrupt
+
+ InterruptBit - Interrupt bit in the IRR to set
+
+Return Value:
+
+ Return the logical CPU number assigned the interrupt
+
+--*/
+
+{
+ PCPU_VECTOR_DATA TargetCpu;
+ MC_DEVICE_ID McDeviceId;
+ IOD_INT_TARGET_DEVICE IntTarg;
+ ULONG Target;
+ ULONG LogicalCpu;
+
+ McDeviceId = HalpIodLogicalToPhysical[IodVectorData->HwBusNumber];
+
+#if HALDBG
+
+ DbgPrint(
+ "Assigning IOD (%d, %d) Interrupt 0x%x\n",
+ McDeviceId.Gid,
+ McDeviceId.Mid,
+ InterruptBit
+ );
+#endif
+
+ //
+ // If both of the target CPU's have not been assigned,
+ // assign them now.
+ //
+
+ if ( !IodVectorData->TargetCpu[0] || !IodVectorData->TargetCpu[1] ) {
+
+
+ for (Target = 0; Target < HalpNumberOfTargetCpus; Target++) {
+
+ if ((TargetCpu = IodVectorData->TargetCpu[Target]) == NULL) {
+
+ TargetCpu = (PCPU_VECTOR_DATA)
+ HalpFindWeightedEntry(
+ &HalpCpuVectorDataHead,
+ FindMinWeight
+ );
+
+ //
+ // Handle for UP and second target not assigned
+ //
+
+ if (TargetCpu == NULL) {
+
+ break;
+
+ }
+
+#if HALDBG
+ DbgPrint(
+ "IOD (%d, %d) Target %d assigned to CPU %d\n",
+ McDeviceId.Gid,
+ McDeviceId.Mid,
+ Target,
+ TargetCpu->LogicalNumber
+ );
+#endif
+
+ LogicalCpu = TargetCpu->LogicalNumber;
+
+ //
+ // Initialize the affinity mask, target, and CPU vector link
+ //
+
+ IodVectorData->Affinity[Target] |= (1 << LogicalCpu);
+ IodVectorData->IntTarg[Target] =
+ HalpLogicalToPhysicalProcessor[LogicalCpu];
+ IodVectorData->TargetCpu[Target] = TargetCpu;
+
+ //
+ // Initialize the MC_DEVICE_ID for this target.
+ //
+
+
+ //
+ // Read the target register.
+ //
+
+ IntTarg.all = READ_IOD_REGISTER_NEW(
+ McDeviceId,
+ &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg
+ );
+
+
+ //
+ // Obtain the Target assigned by Vector Balancing
+ //
+
+ if (Target) {
+
+ IntTarg.Int1TargDevId = (ULONG)
+ IodVectorData->IntTarg[Target].all;
+
+ } else {
+
+ IntTarg.Int1TargDevId = (ULONG)
+ IodVectorData->IntTarg[Target].all;
+
+ }
+
+ //
+ // Write the target register.
+ //
+
+ WRITE_IOD_REGISTER_NEW(
+ McDeviceId,
+ &((PIOD_INT_CSRS)(IOD_INT_CSRS_QVA))->IntTarg,
+ IntTarg.all
+ );
+
+ } else {
+
+ //
+ // Remove this entry from the list before assigning
+ // the next CPU
+ //
+
+ RemoveEntryList(&TargetCpu->ListEntry.ListEntry);
+
+ }
+ }
+
+ //
+ // Add the CPU's back to the global list.
+ //
+
+ for (Target = 0; Target < HalpNumberOfTargetCpus; Target++) {
+
+ if (IodVectorData->TargetCpu[Target]) {
+
+ InsertTailList(
+ &HalpCpuVectorDataHead,
+ &IodVectorData->TargetCpu[Target]->ListEntry.ListEntry
+ );
+
+ }
+ }
+
+ }
+
+ //
+ // Determine if the vector has already been assigned a target.
+ // If so, return the target cpu that is was assigned to.
+ // If not Choose the CPU with the minimum weight. The weight
+ // is an indication of how many PCI vectors have already been
+ // assigned to a CPU.
+ //
+
+ if ( (IodVectorData->TargetCpu[0] != NULL) &&
+ (IodVectorData->IntMask[0].all & InterruptBit) ) {
+
+ Target = 0;
+
+ } else if ( (IodVectorData->TargetCpu[1] != NULL) &&
+ (IodVectorData->IntMask[1].all & InterruptBit) ) {
+
+ Target = 1;
+
+ } else if ( !IodVectorData->TargetCpu[1] ) {
+
+ //
+ // If the second target CPU was not assigned,
+ // this is a UP system so choose target 0.
+ //
+
+ Target = 0;
+
+ } else if ( IodVectorData->TargetCpu[0]->ListEntry.Weight <
+ IodVectorData->TargetCpu[1]->ListEntry.Weight ) {
+
+ //
+ // Target 0 currently has a lower interrupt load
+ //
+
+ Target = 0;
+
+ } else {
+
+ //
+ // Target 1 currently has a lower interrupt load
+ //
+
+ Target = 1;
+
+ }
+
+ TargetCpu = IodVectorData->TargetCpu[Target];
+ LogicalCpu = TargetCpu->LogicalNumber;
+
+#if HALDBG
+ DbgPrint(
+ "Assign IOD (%d, %d) Interrupt 0x%x to Target %d, CPU %d\n",
+ McDeviceId.Gid,
+ McDeviceId.Mid,
+ InterruptBit,
+ Target,
+ TargetCpu->LogicalNumber
+ );
+
+#endif
+
+ //
+ // Enable this vector in the IOD Interrupt Mask
+ // This value is written later to the IntReq register
+ //
+
+ IodVectorData->IntMask[Target].all |= InterruptBit;
+
+ //
+ // Update the weight of the target CPU.
+ //
+
+ TargetCpu->ListEntry.Weight++;
+
+ return (LogicalCpu);
+
+}
+
+#if HALDBG
+//
+// Declare the lower-level routine used to read PCI config space
+//
+
+VOID
+HalpReadPCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+VOID
+HalpDumpIoVectorAffinity(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Dump IO vector Affinity Assignment
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+
+ PIOD_VECTOR_DATA IodVectorData;
+ PCPU_VECTOR_DATA CpuVectorData;
+ MC_DEVICE_ID McDeviceId;
+ MC_ENUM_CONTEXT mcCtx;
+ PCI_COMMON_CONFIG CommonConfig;
+ PBUS_HANDLER BusHandler;
+ PPCIPBUSDATA BusData;
+ PCIPBUSDATA BusContext;
+ RTL_BITMAP DevicePresent;
+ PCI_SLOT_NUMBER SlotNumber;
+ PLIST_ENTRY NextEntry;
+ ULONG HwBusNumber;
+ ULONG BusNumber;
+ ULONG DeviceNumber;
+ ULONG FunctionNumber;
+ ULONG Target;
+
+
+ DbgPrint("Dump IOD VECTOR DATA\n\n");
+
+ //
+ // Traverse Iod Vector Data List
+ //
+
+ for (
+ NextEntry = HalpIodVectorDataHead.Flink;
+ NextEntry != &HalpIodVectorDataHead;
+ NextEntry = NextEntry->Flink
+ ) {
+
+
+ IodVectorData = (PIOD_VECTOR_DATA) NextEntry;
+ HwBusNumber = IodVectorData->HwBusNumber;
+ BusNumber = IodVectorData->BusNumber;
+ McDeviceId = HalpIodLogicalToPhysical[HwBusNumber];
+
+ DbgPrint(
+ "\n\nIod: Logical %d, Physical (%d, %d)\n\n",
+ HwBusNumber,
+ McDeviceId.Gid,
+ McDeviceId.Mid
+ );
+
+
+ BusHandler = HaliHandlerForBus(PCIBus,BusNumber);
+
+ //
+ // Get a pointer to the bus-specific data.
+ //
+
+ BusData = (PPCIPBUSDATA)BusHandler->BusData;
+
+ //
+ // Use the device-present bitmap for this bus to query configuration
+ // Space for InterruptLine values.
+ //
+
+ //
+ // Initialize the device-present bitmap for this bus.
+ //
+
+ HalpInitializeBitMap(
+ &BusContext.DevicePresent,
+ BusContext.DevicePresentBits,
+ PCI_MAX_DEVICES * PCI_MAX_FUNCTION
+ );
+
+ //
+ // Copy the bitmap from the bus handler.
+ //
+
+ RtlCopyMemory(
+ &BusContext.DevicePresentBits,
+ &BusData->DevicePresentBits,
+ sizeof (BusData->DevicePresentBits)
+ );
+
+
+ //
+ // Starting with device 0, scan the device present
+ // bitmap.
+ //
+
+ DeviceNumber = 0;
+
+ DbgPrint("Devices Present on Bus:\n\n");
+
+ while ( (DeviceNumber =
+ HalpFindSetBitsAndClear(
+ &BusContext.DevicePresent,
+ 1,
+ DeviceNumber
+ ) ) != -1 ) {
+
+ DbgPrint("Device Number %d\n", DeviceNumber);
+
+ //
+ // Initialize the slot number.
+ //
+
+ SlotNumber.u.AsULONG = 0;
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+
+ //
+ // Loop through each function number.
+ //
+
+ for (FunctionNumber = 0;
+ FunctionNumber < PCI_MAX_FUNCTION;
+ FunctionNumber++) {
+
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+ //
+ // Read the common configuration header.
+ //
+
+ HalpReadPCIConfig(
+ BusHandler,
+ SlotNumber,
+ &CommonConfig,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ //
+ // If the Vendor ID is invalid, then no device is present
+ // at this device/function number.
+ //
+
+ if (CommonConfig.VendorID == PCI_INVALID_VENDORID) {
+ if (FunctionNumber == 0) {
+ break;
+ }
+ continue;
+ }
+
+ DbgPrint(
+ "Device %d, Function %d\n",
+ DeviceNumber,
+ FunctionNumber
+ );
+
+ DbgPrint(
+ "VendorId 0x%x, InterruptLine 0x%x\n",
+ CommonConfig.VendorID,
+ CommonConfig.u.type0.InterruptLine
+ );
+
+ //
+ // If this is not a multi-function device, then terminate
+ // the function number loop.
+ //
+
+ if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) {
+ break;
+ }
+
+ } // for (FunctionNumber...)
+
+ } // while (DeviceNumber)
+
+
+ DbgPrint("\nIOD Targets:\n\n");
+
+ for (Target = 0; Target < IOD_MAX_INT_TARG; Target++) {
+
+ DbgPrint(
+ "DevId: (%d, %d), Mask: 0x%x\n",
+ IodVectorData->IntTarg[Target].Gid,
+ IodVectorData->IntTarg[Target].Mid,
+ IodVectorData->IntMask[Target].all
+ );
+
+ }
+
+ } //for (IodVectorData)
+
+ DbgPrint("\nDump CPU VECTOR DATA\n\n");
+
+ for (
+ NextEntry = HalpCpuVectorDataHead.Flink;
+ NextEntry != &HalpCpuVectorDataHead;
+ NextEntry = NextEntry->Flink
+ ) {
+
+
+ CpuVectorData = (PCPU_VECTOR_DATA) NextEntry;
+ McDeviceId =
+ HalpLogicalToPhysicalProcessor[CpuVectorData->LogicalNumber];
+
+ DbgPrint(
+ "Cpu: Logical %d Physical (%d,%d)\n",
+ CpuVectorData->LogicalNumber,
+ McDeviceId.Gid,
+ McDeviceId.Mid
+ );
+
+ }
+
+}
+
+#endif // HALDBG