1710 lines
45 KiB
C
1710 lines
45 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
ixirqarb.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements an arbiter for IRQs.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Santosh Jodh (santoshj) 22-June-1998
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
NT Kernel Model Driver only
|
||
|
|
||
|
--*/
|
||
|
#include <nthal.h>
|
||
|
#include <arbiter.h>
|
||
|
|
||
|
#ifndef _IN_KERNEL_
|
||
|
#define _IN_KERNEL_
|
||
|
#include <regstr.h>
|
||
|
#undef _IN_KERNEL_
|
||
|
#else
|
||
|
#include <regstr.h>
|
||
|
#endif
|
||
|
|
||
|
#if defined(NEC_98)
|
||
|
#include <pci.h>
|
||
|
#endif
|
||
|
#include "ixpciir.h"
|
||
|
|
||
|
#define ARBITER_CONTEXT_TO_INSTANCE(x) (x)
|
||
|
|
||
|
#define ARBITER_INTERRUPT_LEVEL 0x10
|
||
|
#define ARBITER_INTERRUPT_EDGE 0x20
|
||
|
#define ARBITER_INTERRUPT_BITS (ARBITER_INTERRUPT_LEVEL | ARBITER_INTERRUPT_EDGE)
|
||
|
|
||
|
#define NUM_IRQS 16
|
||
|
#if defined(NEC_98)
|
||
|
#define PIC_SLAVE_IRQ 7
|
||
|
#else
|
||
|
#define PIC_SLAVE_IRQ 2
|
||
|
#endif
|
||
|
|
||
|
extern ULONG HalDebug;
|
||
|
#if defined(NEC_98)
|
||
|
extern ULONG NEC98SpecialIRQMask;
|
||
|
#endif
|
||
|
|
||
|
#if DBG
|
||
|
#define DEBUG_PRINT(Level, Message) { \
|
||
|
if (HalDebug >= Level) { \
|
||
|
DbgPrint("HAL: "); \
|
||
|
DbgPrint Message; \
|
||
|
DbgPrint("\n"); \
|
||
|
} \
|
||
|
}
|
||
|
#else
|
||
|
#define DEBUG_PRINT(Level, Message)
|
||
|
#endif
|
||
|
|
||
|
typedef struct {
|
||
|
ARBITER_INSTANCE ArbiterState;
|
||
|
} HAL_ARBITER, *PHAL_ARBITER;
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpInitIrqArbiter (
|
||
|
IN PDEVICE_OBJECT HalFdo
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpFillInIrqArbiter (
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN LPCGUID InterfaceType,
|
||
|
IN USHORT Version,
|
||
|
IN PVOID InterfaceSpecificData,
|
||
|
IN ULONG InterfaceBufferSize,
|
||
|
IN OUT PINTERFACE Interface,
|
||
|
IN OUT PULONG Length
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbUnpackRequirement (
|
||
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor,
|
||
|
OUT PULONGLONG Minimum,
|
||
|
OUT PULONGLONG Maximum,
|
||
|
OUT PULONG Length,
|
||
|
OUT PULONG Alignment
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbPackResource (
|
||
|
IN PIO_RESOURCE_DESCRIPTOR Requirement,
|
||
|
IN ULONGLONG Start,
|
||
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbUnpackResource (
|
||
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||
|
OUT PULONGLONG Start,
|
||
|
OUT PULONG Length
|
||
|
);
|
||
|
|
||
|
LONG
|
||
|
HalpArbScoreRequirement (
|
||
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbTestAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PLIST_ENTRY ArbitrationList
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbRetestAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PLIST_ENTRY ArbitrationList
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbCommitAllocation(
|
||
|
IN PARBITER_INSTANCE Arbiter
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbRollbackAllocation (
|
||
|
PARBITER_INSTANCE Arbiter
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbPreprocessEntry(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN PARBITER_ALLOCATION_STATE State
|
||
|
);
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpArbFindSuitableRange (
|
||
|
PARBITER_INSTANCE Arbiter,
|
||
|
PARBITER_ALLOCATION_STATE State
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpArbAddAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN PARBITER_ALLOCATION_STATE State
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
HalpArbBacktrackAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN PARBITER_ALLOCATION_STATE State
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbBootAllocation(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PLIST_ENTRY ArbitrationList
|
||
|
);
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpArbGetNextAllocationRange(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PARBITER_ALLOCATION_STATE State
|
||
|
);
|
||
|
|
||
|
ULONG
|
||
|
HalpFindLinkInterrupt (
|
||
|
IN PRTL_RANGE_LIST RangeList,
|
||
|
IN ULONG Mask,
|
||
|
IN ULONG Start,
|
||
|
IN ULONG End,
|
||
|
IN ULONG Flags,
|
||
|
IN UCHAR UserFlags
|
||
|
);
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpArbQueryConflictCallback(
|
||
|
IN PVOID Context,
|
||
|
IN PRTL_RANGE Range
|
||
|
);
|
||
|
VOID
|
||
|
HalpIrqArbiterInterfaceReference(
|
||
|
IN PVOID Context
|
||
|
);
|
||
|
VOID
|
||
|
HalpIrqArbiterInterfaceDereference(
|
||
|
IN PVOID Context
|
||
|
);
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGE, HalpInitIrqArbiter)
|
||
|
#pragma alloc_text(PAGE, HalpFillInIrqArbiter)
|
||
|
#pragma alloc_text(PAGE, HalpArbUnpackRequirement)
|
||
|
#pragma alloc_text(PAGE, HalpArbPackResource)
|
||
|
#pragma alloc_text(PAGE, HalpArbUnpackResource)
|
||
|
#pragma alloc_text(PAGE, HalpArbScoreRequirement)
|
||
|
#pragma alloc_text(PAGE, HalpArbTestAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbRetestAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbCommitAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbRollbackAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbPreprocessEntry)
|
||
|
#pragma alloc_text(PAGE, HalpArbFindSuitableRange)
|
||
|
#pragma alloc_text(PAGE, HalpArbAddAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbBacktrackAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbBootAllocation)
|
||
|
#pragma alloc_text(PAGE, HalpArbGetNextAllocationRange)
|
||
|
#pragma alloc_text(PAGE, HalpFindLinkInterrupt)
|
||
|
#pragma alloc_text(PAGE, HalpArbQueryConflictCallback)
|
||
|
#pragma alloc_text(PAGE, HalpIrqArbiterInterfaceReference)
|
||
|
#pragma alloc_text(PAGE, HalpIrqArbiterInterfaceDereference)
|
||
|
#endif
|
||
|
|
||
|
HAL_ARBITER HalpArbiter = {{
|
||
|
0,//Signature
|
||
|
NULL,//MutexEvent
|
||
|
NULL,//Name
|
||
|
{0},//ResourceType
|
||
|
NULL,//Allocation
|
||
|
NULL,//PossibleAllocation
|
||
|
{0},//OrderingList
|
||
|
{0},//ReservedList
|
||
|
0,//ReferenceCount
|
||
|
NULL,//Interface
|
||
|
0,//AllocationStackMaxSize
|
||
|
NULL,//AllocationStack
|
||
|
HalpArbUnpackRequirement,//UnpackRequirement
|
||
|
HalpArbPackResource,//PackResource
|
||
|
HalpArbUnpackResource,//UnpackResource
|
||
|
HalpArbScoreRequirement,//ScoreRequirement
|
||
|
HalpArbTestAllocation,//TestAllocation
|
||
|
HalpArbRetestAllocation,//RetestAllocation
|
||
|
HalpArbCommitAllocation,//CommitAllocation
|
||
|
HalpArbRollbackAllocation,//RollbackAllocation
|
||
|
HalpArbBootAllocation,//BootAllocation
|
||
|
NULL,//QueryArbitrate
|
||
|
NULL,//QueryConflict
|
||
|
NULL,//AddReserved
|
||
|
NULL,//StartArbiter
|
||
|
HalpArbPreprocessEntry,//PreprocessEntry
|
||
|
NULL,//AllocateEntry
|
||
|
HalpArbGetNextAllocationRange,//GetNextAllocationRange
|
||
|
HalpArbFindSuitableRange,//FindSuitableRange
|
||
|
HalpArbAddAllocation,//AddAllocation
|
||
|
HalpArbBacktrackAllocation,//BacktrackAllocation
|
||
|
NULL,//OverrideConflict
|
||
|
FALSE,//TransactionInProgress
|
||
|
&HalpPciIrqRoutingInfo,//Extension
|
||
|
NULL,//BusDeviceObject
|
||
|
NULL,//ConflictCallbackContext
|
||
|
NULL,//ConflictCallback
|
||
|
}};
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpArbQueryConflictCallback(
|
||
|
IN PVOID Context,
|
||
|
IN PRTL_RANGE Range
|
||
|
)
|
||
|
{
|
||
|
if (Range->Attributes & ARBITER_INTERRUPT_LEVEL)
|
||
|
{
|
||
|
if(Range->Flags & RTL_RANGE_SHARED)
|
||
|
{
|
||
|
return (TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("Exclusive level interrupt %02x cannot be shared!", (ULONG)Context));
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DEBUG_PRINT(1, ("Refusing to share edge and level interrupts on %02x", (ULONG)Context));
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbPreprocessEntry(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN PARBITER_ALLOCATION_STATE State
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called from AllocateEntry to allow preprocessing of
|
||
|
entries
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Arbiter - The instance data of the arbiter who was called.
|
||
|
|
||
|
State - The state of the current arbitration.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
#define CM_RESOURE_INTERRUPT_LEVEL_LATCHED_BITS 0x0001
|
||
|
|
||
|
PARBITER_ALTERNATIVE current;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(State);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
//
|
||
|
// Check if this is a level (PCI) or latched (ISA (edge)) interrupt and set
|
||
|
// RangeAttributes accordingly so we set the appropriate flag when we add the
|
||
|
// range
|
||
|
//
|
||
|
|
||
|
if ((State->Alternatives[0].Descriptor->Flags
|
||
|
& CM_RESOURE_INTERRUPT_LEVEL_LATCHED_BITS)
|
||
|
== CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE)
|
||
|
{
|
||
|
|
||
|
State->RangeAttributes &= ~ARBITER_INTERRUPT_BITS;
|
||
|
State->RangeAttributes |= ARBITER_INTERRUPT_LEVEL;
|
||
|
|
||
|
} else
|
||
|
{
|
||
|
ASSERT(State->Alternatives[0].Descriptor->Flags
|
||
|
& CM_RESOURCE_INTERRUPT_LATCHED);
|
||
|
|
||
|
State->RangeAttributes &= ~ARBITER_INTERRUPT_BITS;
|
||
|
State->RangeAttributes |= ARBITER_INTERRUPT_EDGE;
|
||
|
}
|
||
|
|
||
|
return (STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpArbGetNextAllocationRange(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PARBITER_ALLOCATION_STATE State
|
||
|
)
|
||
|
{
|
||
|
//
|
||
|
// Default to having no next range.
|
||
|
//
|
||
|
|
||
|
BOOLEAN nextRange = FALSE;
|
||
|
|
||
|
//
|
||
|
// Try all possible interrupts on first call.
|
||
|
//
|
||
|
|
||
|
if (State->CurrentAlternative) {
|
||
|
|
||
|
if (++State->CurrentAlternative < &State->Alternatives[State->AlternativeCount]) {
|
||
|
|
||
|
DEBUG_PRINT(3, ("No next allocation range, exhausted all %08X alternatives", State->AlternativeCount));
|
||
|
nextRange = TRUE;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// First call, try the first alternative.
|
||
|
//
|
||
|
|
||
|
State->CurrentAlternative = &State->Alternatives[0];
|
||
|
nextRange = TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (nextRange) {
|
||
|
|
||
|
State->CurrentMinimum = State->CurrentAlternative->Minimum;
|
||
|
State->CurrentMaximum = State->CurrentAlternative->Maximum;
|
||
|
DEBUG_PRINT(3, ("Next allocation range 0x%I64x-0x%I64x", State->CurrentMinimum, State->CurrentMaximum));
|
||
|
|
||
|
}
|
||
|
|
||
|
return nextRange;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HalpFindLinkInterrupt (
|
||
|
IN PRTL_RANGE_LIST RangeList,
|
||
|
IN ULONG Mask,
|
||
|
IN ULONG Start,
|
||
|
IN ULONG End,
|
||
|
IN ULONG Flags,
|
||
|
IN UCHAR UserFlags
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine scans the mask from MSB to LSB for the first
|
||
|
value that is available in the range list.
|
||
|
|
||
|
Input Parameters:
|
||
|
|
||
|
RangeList - List to be searched.
|
||
|
|
||
|
Mask - Interrupt mask to be scanned.
|
||
|
|
||
|
Start - Start scan AFTER this interrupt.
|
||
|
|
||
|
Flags - Flags for the range list.
|
||
|
|
||
|
UserFlags - Special flags.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
First available interrupt from the mask iff successful. Else 0.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
ULONG interrupt;
|
||
|
ULONG test;
|
||
|
NTSTATUS status;
|
||
|
BOOLEAN available;
|
||
|
|
||
|
if (Start > 0x0F)
|
||
|
{
|
||
|
Start = 0x0F;
|
||
|
}
|
||
|
if (Start != 0 && Start >= End)
|
||
|
{
|
||
|
interrupt = Start;
|
||
|
test = 1 << interrupt;
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// If this interrupt is supported, see if it is free.
|
||
|
//
|
||
|
|
||
|
if (Mask & test)
|
||
|
{
|
||
|
available = FALSE;
|
||
|
status = RtlIsRangeAvailable( RangeList,
|
||
|
interrupt,
|
||
|
interrupt,
|
||
|
Flags,
|
||
|
UserFlags,
|
||
|
(PVOID)interrupt,
|
||
|
HalpArbQueryConflictCallback,
|
||
|
&available);
|
||
|
if (NT_SUCCESS(status) && available)
|
||
|
{
|
||
|
return (interrupt);
|
||
|
}
|
||
|
}
|
||
|
interrupt--;
|
||
|
test >>= 1;
|
||
|
}
|
||
|
while (interrupt > End);
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
BOOLEAN
|
||
|
HalpArbFindSuitableRange (
|
||
|
PARBITER_INSTANCE Arbiter,
|
||
|
PARBITER_ALLOCATION_STATE State
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This
|
||
|
Input Parameters:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
NTSTATUS status;
|
||
|
PLINK_NODE linkNode;
|
||
|
ULONG interrupt;
|
||
|
ULONG freeInterrupt;
|
||
|
PLINK_NODE current;
|
||
|
ULONG busNumber;
|
||
|
ULONG slotNumber;
|
||
|
#if defined(NEC_98)
|
||
|
PINT_ROUTE_INTERFACE_STANDARD pciInterface;
|
||
|
ULONG dummy;
|
||
|
UCHAR classCode;
|
||
|
UCHAR subClassCode;
|
||
|
ROUTING_TOKEN routingToken;
|
||
|
UCHAR pin;
|
||
|
#endif
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(State);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
if (State->Entry->InterfaceType == PCIBus)
|
||
|
{
|
||
|
#if defined(NEC_98)
|
||
|
pciInterface = pciIrqRoutingInfo->PciInterface;
|
||
|
|
||
|
//
|
||
|
// Call Pci driver to get info about the Pdo.
|
||
|
//
|
||
|
|
||
|
status = pciInterface->GetInterruptRouting( State->Entry->PhysicalDeviceObject,
|
||
|
&busNumber,
|
||
|
&slotNumber,
|
||
|
(PUCHAR)&dummy,
|
||
|
&pin,
|
||
|
&classCode,
|
||
|
&subClassCode,
|
||
|
(PDEVICE_OBJECT *)&dummy,
|
||
|
&routingToken,
|
||
|
(PUCHAR)&dummy);
|
||
|
|
||
|
//
|
||
|
// This means that it is not a Pci device.
|
||
|
//
|
||
|
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
busNumber = State->Entry->BusNumber;
|
||
|
slotNumber = State->Entry->SlotNumber;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
busNumber = (ULONG)-1;
|
||
|
slotNumber = (ULONG)-1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// See if there is link information for this device.
|
||
|
//
|
||
|
|
||
|
linkNode = NULL;
|
||
|
status = HalpFindLinkNode ( pciIrqRoutingInfo,
|
||
|
State->Entry->PhysicalDeviceObject,
|
||
|
busNumber,
|
||
|
slotNumber,
|
||
|
&linkNode);
|
||
|
switch (status)
|
||
|
{
|
||
|
case STATUS_SUCCESS:
|
||
|
|
||
|
if (linkNode == NULL)
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("Link does not exist for Pci PDO %08x. Hopefully, device can live without an interrupt!", State->Entry->PhysicalDeviceObject));
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If we have already decided an interrupt for this link,
|
||
|
// everyone using it gets the same interrupt.
|
||
|
//
|
||
|
|
||
|
if (linkNode->PossibleAllocation->RefCount > 0)
|
||
|
{
|
||
|
if ( State->CurrentMinimum <= linkNode->PossibleAllocation->Interrupt &&
|
||
|
linkNode->PossibleAllocation->Interrupt <= State->CurrentMaximum)
|
||
|
{
|
||
|
State->Start = linkNode->PossibleAllocation->Interrupt;
|
||
|
State->End = State->Start;
|
||
|
State->CurrentAlternative->Length = 1;
|
||
|
|
||
|
DEBUG_PRINT(2, ("Found Irq (%04x) for Pci PDO %08x using link %02x", (ULONG)State->Start, State->Entry->PhysicalDeviceObject, linkNode->Link));
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("Found Irq (%04x) for Pci PDO %08x using link %02x but is outside the range (%04x-%04x)!", (ULONG)State->Start, State->Entry->PhysicalDeviceObject, linkNode->Link, State->CurrentMinimum, State->CurrentMaximum));
|
||
|
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// We want to spread out the links as much as we can for
|
||
|
// performance.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// First see if this link is programmed for some IRQ.
|
||
|
//
|
||
|
|
||
|
interrupt = 0;
|
||
|
status = PciirqmpGetIrq((PUCHAR)&interrupt, (UCHAR)linkNode->Link);
|
||
|
|
||
|
if (NT_SUCCESS(status) && interrupt)
|
||
|
{
|
||
|
|
||
|
if (State->CurrentMinimum <= interrupt && interrupt <= State->CurrentMaximum)
|
||
|
{
|
||
|
//
|
||
|
// Make sure the BIOS did not mess up
|
||
|
//
|
||
|
|
||
|
freeInterrupt = HalpFindLinkInterrupt ( Arbiter->PossibleAllocation,
|
||
|
linkNode->InterruptMap,
|
||
|
interrupt,
|
||
|
interrupt,
|
||
|
0,
|
||
|
0);
|
||
|
if(freeInterrupt == 0)
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("BIOS failure. Assigned Irq (%02x) to link %02x which is unavailable or impossible according to mask %04x", interrupt, linkNode->Link, linkNode->InterruptMap));
|
||
|
}
|
||
|
interrupt = freeInterrupt;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("Found Irq (%04x) pre-programmedfor link %02x but is outside the range (%04x-%04x)!", interrupt, linkNode->Link, State->CurrentMinimum, State->CurrentMaximum));
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (interrupt == 0)
|
||
|
{
|
||
|
#if defined(NEC_98)
|
||
|
if (NEC98SpecialIRQMask){
|
||
|
linkNode->InterruptMap &= ~( 1 << NEC98SpecialIRQMask);
|
||
|
}
|
||
|
#endif
|
||
|
//
|
||
|
// Try to get an interrupt by itself for this link.
|
||
|
//
|
||
|
|
||
|
interrupt = HalpFindLinkInterrupt ( Arbiter->PossibleAllocation,
|
||
|
linkNode->InterruptMap,
|
||
|
(ULONG)State->CurrentMaximum,
|
||
|
(ULONG)State->CurrentMinimum,
|
||
|
0,
|
||
|
0);
|
||
|
#if defined(NEC_98)
|
||
|
//
|
||
|
// Force to share CardBus IRQ with another PCI Device
|
||
|
//
|
||
|
if ( interrupt &&
|
||
|
classCode == PCI_CLASS_BRIDGE_DEV &&
|
||
|
subClassCode == PCI_SUBCLASS_BR_CARDBUS )
|
||
|
{
|
||
|
//
|
||
|
// Remember this.
|
||
|
//
|
||
|
|
||
|
freeInterrupt = interrupt;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Is this being used by another link?
|
||
|
//
|
||
|
current = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
|
||
|
while ( current != NULL) {
|
||
|
|
||
|
if ( current->PossibleAllocation->Interrupt == interrupt )
|
||
|
{
|
||
|
//
|
||
|
// somebody use this. Cardbus controller use this, too.
|
||
|
//
|
||
|
interrupt = 0;
|
||
|
break;
|
||
|
}
|
||
|
current = current->Next;
|
||
|
}
|
||
|
|
||
|
if (interrupt){
|
||
|
interrupt = HalpFindLinkInterrupt ( Arbiter->PossibleAllocation,
|
||
|
linkNode->InterruptMap,
|
||
|
interrupt - 1,
|
||
|
(ULONG)State->CurrentMinimum,
|
||
|
0,
|
||
|
0);
|
||
|
if (interrupt) {
|
||
|
//
|
||
|
// Remember this, if find new interrupt.
|
||
|
//
|
||
|
|
||
|
freeInterrupt = interrupt;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
while (interrupt);
|
||
|
|
||
|
if (!interrupt)
|
||
|
{
|
||
|
interrupt = freeInterrupt;
|
||
|
}
|
||
|
|
||
|
} else if ( interrupt )
|
||
|
#else
|
||
|
if (interrupt)
|
||
|
#endif
|
||
|
{
|
||
|
//
|
||
|
// Remember this.
|
||
|
//
|
||
|
|
||
|
freeInterrupt = interrupt;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Is this being used by another link?
|
||
|
//
|
||
|
|
||
|
for ( current = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
current && current->PossibleAllocation->Interrupt != interrupt;
|
||
|
current = current->Next);
|
||
|
if (current == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
interrupt = HalpFindLinkInterrupt ( Arbiter->PossibleAllocation,
|
||
|
linkNode->InterruptMap,
|
||
|
interrupt - 1,
|
||
|
(ULONG)State->CurrentMinimum,
|
||
|
0,
|
||
|
0);
|
||
|
}
|
||
|
while (interrupt);
|
||
|
|
||
|
if (!interrupt)
|
||
|
{
|
||
|
if (!(pciIrqRoutingInfo->Parameters & PCIIR_FLAG_EXCLUSIVE)) {
|
||
|
interrupt = freeInterrupt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (interrupt)
|
||
|
{
|
||
|
State->Start = interrupt;
|
||
|
State->End = interrupt;
|
||
|
State->CurrentAlternative->Length = 1;
|
||
|
|
||
|
DEBUG_PRINT(2, ("Found Irq (%04x) for Pci PDO %08x using link %02x", (ULONG)State->Start, State->Entry->PhysicalDeviceObject, linkNode->Link));
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// There is no interrupt this link can use, too bad.
|
||
|
//
|
||
|
|
||
|
return (FALSE);
|
||
|
|
||
|
case STATUS_RESOURCE_REQUIREMENTS_CHANGED:
|
||
|
|
||
|
//
|
||
|
// Pci Ide device does not share Irqs.
|
||
|
//
|
||
|
|
||
|
if (State->CurrentAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_SHARED) {
|
||
|
|
||
|
State->CurrentAlternative->Flags &= ~ARBITER_ALTERNATIVE_FLAG_SHARED;
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
|
||
|
|
||
|
//
|
||
|
// Non Pci device.
|
||
|
//
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// HACKHACK: This is to allow boot conflict on IRQ 14 and 15.
|
||
|
// This is so that broken machines which report both PNP06xx and
|
||
|
// the PCI IDE controller work. One of them (no order guarantee)
|
||
|
// will come up with a conflict.
|
||
|
//
|
||
|
|
||
|
if (State->Entry->Flags & ARBITER_FLAG_BOOT_CONFIG) {
|
||
|
if ( State->CurrentMinimum == State->CurrentMaximum &&
|
||
|
(State->CurrentMinimum == 14 || State->CurrentMinimum == 15)) {
|
||
|
State->RangeAvailableAttributes |= ARBITER_RANGE_BOOT_ALLOCATED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (ArbFindSuitableRange(Arbiter, State));
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpArbAddAllocation(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN PARBITER_ALLOCATION_STATE State
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
NTSTATUS status;
|
||
|
PLINK_NODE linkNode;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(State);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
DEBUG_PRINT(3, ("Adding Irq (%04x) allocation for PDO %08x", (ULONG)State->Start, State->Entry->PhysicalDeviceObject));
|
||
|
|
||
|
linkNode = NULL;
|
||
|
status = HalpFindLinkNode ( pciIrqRoutingInfo,
|
||
|
State->Entry->PhysicalDeviceObject,
|
||
|
State->Entry->BusNumber,
|
||
|
State->Entry->SlotNumber,
|
||
|
&linkNode);
|
||
|
if (NT_SUCCESS(status) && status == STATUS_SUCCESS)
|
||
|
{
|
||
|
if (linkNode)
|
||
|
{
|
||
|
if (linkNode->PossibleAllocation->RefCount)
|
||
|
{
|
||
|
if (linkNode->PossibleAllocation->Interrupt != State->Start)
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("Two different interrupts (old = %08x, new = %08x) for the same link %08x!", linkNode->PossibleAllocation->Interrupt, State->Start, linkNode->Link));
|
||
|
ASSERT(linkNode->PossibleAllocation->Interrupt == State->Start);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(3, ("Adding new Irq (%04x) allocation for Pci PDO %08x using link %02x", (ULONG)State->Start, State->Entry->PhysicalDeviceObject, linkNode->Link));
|
||
|
|
||
|
linkNode->PossibleAllocation->Interrupt = (ULONG)State->Start;
|
||
|
}
|
||
|
|
||
|
linkNode->PossibleAllocation->RefCount++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("This should never happen!"));
|
||
|
ASSERT(linkNode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
status = RtlAddRange( Arbiter->PossibleAllocation,
|
||
|
State->Start,
|
||
|
State->End,
|
||
|
State->RangeAttributes,
|
||
|
RTL_RANGE_LIST_ADD_IF_CONFLICT +
|
||
|
((State->CurrentAlternative->Flags &
|
||
|
ARBITER_ALTERNATIVE_FLAG_SHARED)?
|
||
|
RTL_RANGE_LIST_ADD_SHARED : 0),
|
||
|
linkNode, // This line is different from the default function
|
||
|
State->Entry->PhysicalDeviceObject);
|
||
|
|
||
|
ASSERT(NT_SUCCESS(status));
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpArbBacktrackAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN PARBITER_ALLOCATION_STATE State
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
NTSTATUS status;
|
||
|
PLINK_NODE linkNode;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(State);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
DEBUG_PRINT(3, ("Backtracking Irq (%04x) allocation for PDO %08x", (ULONG)State->Start, State->Entry->PhysicalDeviceObject));
|
||
|
|
||
|
linkNode = NULL;
|
||
|
status = HalpFindLinkNode ( pciIrqRoutingInfo,
|
||
|
State->Entry->PhysicalDeviceObject,
|
||
|
State->Entry->BusNumber,
|
||
|
State->Entry->SlotNumber,
|
||
|
&linkNode);
|
||
|
if (NT_SUCCESS(status) && status == STATUS_SUCCESS)
|
||
|
{
|
||
|
if (linkNode)
|
||
|
{
|
||
|
if (linkNode->PossibleAllocation->RefCount == 0)
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("Negative ref count during backtracking!"));
|
||
|
ASSERT(linkNode->PossibleAllocation->RefCount);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(3, ("Backtracking Irq (%04x) allocation for Pci PDO %08x using link %02x", (ULONG)State->Start, State->Entry->PhysicalDeviceObject, linkNode->Link));
|
||
|
|
||
|
linkNode->PossibleAllocation->RefCount--;
|
||
|
if (linkNode->PossibleAllocation->RefCount == 0)
|
||
|
{
|
||
|
linkNode->PossibleAllocation->Interrupt = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DEBUG_PRINT(1, ("This should never happen!"));
|
||
|
ASSERT(linkNode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Let the default function do most of the work.
|
||
|
//
|
||
|
|
||
|
ArbBacktrackAllocation(Arbiter, State);
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbCommitAllocation(
|
||
|
IN PARBITER_INSTANCE Arbiter
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
RTL_RANGE_LIST_ITERATOR iterator;
|
||
|
PRTL_RANGE current;
|
||
|
PLINK_NODE linkNode;
|
||
|
NTSTATUS status;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
//
|
||
|
// Program the int line register for all Pci devices.
|
||
|
//
|
||
|
|
||
|
FOR_ALL_RANGES(Arbiter->PossibleAllocation, &iterator, current)
|
||
|
{
|
||
|
if (current->UserData)
|
||
|
{
|
||
|
HalpProgramInterruptLine ( pciIrqRoutingInfo,
|
||
|
current->Owner,
|
||
|
(ULONG)current->Start);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Program all links to their possible value if
|
||
|
// there is a reference to them.
|
||
|
//
|
||
|
|
||
|
for ( linkNode = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
linkNode;
|
||
|
linkNode = linkNode->Next)
|
||
|
{
|
||
|
status = HalpCommitLink(linkNode);
|
||
|
if (!NT_SUCCESS(status))
|
||
|
{
|
||
|
return (status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Let the default function do the rest of the work.
|
||
|
//
|
||
|
|
||
|
return (ArbCommitAllocation(Arbiter));
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbTestAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PLIST_ENTRY ArbitrationList
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
PLINK_NODE linkNode;
|
||
|
NTSTATUS status;
|
||
|
PARBITER_LIST_ENTRY current;
|
||
|
PDEVICE_OBJECT previousOwner;
|
||
|
PDEVICE_OBJECT currentOwner;
|
||
|
RTL_RANGE_LIST_ITERATOR iterator;
|
||
|
PRTL_RANGE currentRange;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(ArbitrationList);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
//
|
||
|
// Copy the allocation into the possible allocation for
|
||
|
// for links.
|
||
|
//
|
||
|
|
||
|
for ( linkNode = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
linkNode;
|
||
|
linkNode = linkNode->Next)
|
||
|
{
|
||
|
*linkNode->PossibleAllocation = *linkNode->Allocation;
|
||
|
}
|
||
|
|
||
|
previousOwner = NULL;
|
||
|
|
||
|
FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current)
|
||
|
{
|
||
|
currentOwner = current->PhysicalDeviceObject;
|
||
|
|
||
|
if (previousOwner != currentOwner) {
|
||
|
|
||
|
previousOwner = currentOwner;
|
||
|
FOR_ALL_RANGES(Arbiter->Allocation, &iterator, currentRange)
|
||
|
{
|
||
|
if (currentRange->Owner == currentOwner)
|
||
|
{
|
||
|
status = HalpFindLinkNode ( pciIrqRoutingInfo,
|
||
|
currentOwner,
|
||
|
current->BusNumber,
|
||
|
current->SlotNumber,
|
||
|
&linkNode);
|
||
|
if (NT_SUCCESS(status) && status == STATUS_SUCCESS)
|
||
|
{
|
||
|
if (linkNode)
|
||
|
{
|
||
|
if (linkNode->PossibleAllocation->RefCount > 0)
|
||
|
{
|
||
|
DEBUG_PRINT(3, ("Decrementing link (%02x) usage to %d during test allocation", linkNode->Link, linkNode->PossibleAllocation->RefCount - 1));
|
||
|
|
||
|
linkNode->PossibleAllocation->RefCount--;
|
||
|
if (linkNode->PossibleAllocation->RefCount == 0)
|
||
|
{
|
||
|
DEBUG_PRINT(3, ("Deleting Irq (%04x) allocation for link (%02x) during test allocation", linkNode->PossibleAllocation->Interrupt, linkNode->Link));
|
||
|
linkNode->PossibleAllocation->Interrupt = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Let the default function do most of the work.
|
||
|
//
|
||
|
|
||
|
return (ArbTestAllocation(Arbiter, ArbitrationList));
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbRetestAllocation (
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PLIST_ENTRY ArbitrationList
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
PLINK_NODE linkNode;
|
||
|
NTSTATUS status;
|
||
|
PARBITER_LIST_ENTRY current;
|
||
|
PDEVICE_OBJECT previousOwner;
|
||
|
PDEVICE_OBJECT currentOwner;
|
||
|
RTL_RANGE_LIST_ITERATOR iterator;
|
||
|
PRTL_RANGE currentRange;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(ArbitrationList);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
//
|
||
|
// Copy the allocation into the possible allocation for
|
||
|
// for links.
|
||
|
//
|
||
|
|
||
|
for ( linkNode = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
linkNode;
|
||
|
linkNode = linkNode->Next)
|
||
|
{
|
||
|
*linkNode->PossibleAllocation = *linkNode->Allocation;
|
||
|
}
|
||
|
|
||
|
previousOwner = NULL;
|
||
|
|
||
|
FOR_ALL_IN_LIST(ARBITER_LIST_ENTRY, ArbitrationList, current)
|
||
|
{
|
||
|
currentOwner = current->PhysicalDeviceObject;
|
||
|
|
||
|
if (previousOwner != currentOwner) {
|
||
|
|
||
|
previousOwner = currentOwner;
|
||
|
FOR_ALL_RANGES(Arbiter->Allocation, &iterator, currentRange)
|
||
|
{
|
||
|
if (currentRange->Owner == currentOwner)
|
||
|
{
|
||
|
status = HalpFindLinkNode ( pciIrqRoutingInfo,
|
||
|
currentOwner,
|
||
|
current->BusNumber,
|
||
|
current->SlotNumber,
|
||
|
&linkNode);
|
||
|
if (NT_SUCCESS(status) && status == STATUS_SUCCESS)
|
||
|
{
|
||
|
if (linkNode)
|
||
|
{
|
||
|
if (linkNode->PossibleAllocation->RefCount > 0)
|
||
|
{
|
||
|
DEBUG_PRINT(3, ("Decrementing link (%02x) usage to %d during retest allocation", linkNode->Link, linkNode->PossibleAllocation->RefCount - 1));
|
||
|
|
||
|
linkNode->PossibleAllocation->RefCount--;
|
||
|
if (linkNode->PossibleAllocation->RefCount == 0)
|
||
|
{
|
||
|
DEBUG_PRINT(3, ("Deleting Irq (%04x) allocation for link (%02x) during retest allocation", linkNode->PossibleAllocation->Interrupt, linkNode->Link));
|
||
|
linkNode->PossibleAllocation->Interrupt = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (ArbRetestAllocation(Arbiter, ArbitrationList));
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbBootAllocation(
|
||
|
IN PARBITER_INSTANCE Arbiter,
|
||
|
IN OUT PLIST_ENTRY ArbitrationList
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
PLINK_NODE linkNode;
|
||
|
NTSTATUS status;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
ASSERT(ArbitrationList);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
//
|
||
|
// Copy the allocation into the possible allocation for
|
||
|
// for links.
|
||
|
//
|
||
|
|
||
|
for ( linkNode = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
linkNode;
|
||
|
linkNode = linkNode->Next)
|
||
|
{
|
||
|
*linkNode->PossibleAllocation = *linkNode->Allocation;
|
||
|
}
|
||
|
|
||
|
status = ArbBootAllocation(Arbiter, ArbitrationList);
|
||
|
|
||
|
//
|
||
|
// Copy possible allocation back into allocation for links.
|
||
|
//
|
||
|
|
||
|
for ( linkNode = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
linkNode;
|
||
|
linkNode = linkNode->Next)
|
||
|
{
|
||
|
*linkNode->Allocation = *linkNode->PossibleAllocation;
|
||
|
}
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbRollbackAllocation (
|
||
|
PARBITER_INSTANCE Arbiter
|
||
|
)
|
||
|
{
|
||
|
PPCI_IRQ_ROUTING_INFO pciIrqRoutingInfo;
|
||
|
PLINK_NODE linkNode;
|
||
|
ULONG interrupt;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Arbiter);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
pciIrqRoutingInfo = Arbiter->Extension;
|
||
|
ASSERT(pciIrqRoutingInfo);
|
||
|
ASSERT(pciIrqRoutingInfo == &HalpPciIrqRoutingInfo);
|
||
|
|
||
|
//
|
||
|
// Clear the possible allocation.
|
||
|
//
|
||
|
|
||
|
for ( linkNode = pciIrqRoutingInfo->LinkNodeHead;
|
||
|
linkNode;
|
||
|
linkNode = linkNode->Next)
|
||
|
{
|
||
|
linkNode->PossibleAllocation->Interrupt = 0;
|
||
|
linkNode->PossibleAllocation->RefCount = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Let the default function do rest of the work.
|
||
|
//
|
||
|
|
||
|
return (ArbRollbackAllocation(Arbiter));
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbUnpackRequirement (
|
||
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor,
|
||
|
OUT PULONGLONG Minimum,
|
||
|
OUT PULONGLONG Maximum,
|
||
|
OUT PULONG Length,
|
||
|
OUT PULONG Alignment
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine unpacks the requirement descriptor into a minimum, maximum value
|
||
|
and the length and its alignment.
|
||
|
|
||
|
Input Parameters:
|
||
|
|
||
|
Descriptor - Requirement to be unpacked.
|
||
|
|
||
|
Minimum - Receives the minimum value for the requirement.
|
||
|
|
||
|
Maximum - Receives the maximum value for this requirement.
|
||
|
|
||
|
Length - Length of the requirement.
|
||
|
|
||
|
Alignment - Alignment of this requirement.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Standard NT status value.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Descriptor);
|
||
|
ASSERT(Minimum);
|
||
|
ASSERT(Maximum);
|
||
|
ASSERT(Length);
|
||
|
ASSERT(Alignment);
|
||
|
|
||
|
//
|
||
|
// Make sure we are dealing with the correct resource.
|
||
|
//
|
||
|
|
||
|
ASSERT(Descriptor->Type == CmResourceTypeInterrupt);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
//
|
||
|
// Do unpacking.
|
||
|
//
|
||
|
|
||
|
*Minimum = (ULONGLONG) Descriptor->u.Interrupt.MinimumVector;
|
||
|
*Maximum = (ULONGLONG) Descriptor->u.Interrupt.MaximumVector;
|
||
|
*Length = 1;
|
||
|
*Alignment = 1;
|
||
|
|
||
|
DEBUG_PRINT(3, ("Unpacking Irq requirement %p = 0x%04lx - 0x%04lx", Descriptor, *Minimum, *Maximum));
|
||
|
|
||
|
return (STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbPackResource (
|
||
|
IN PIO_RESOURCE_DESCRIPTOR Requirement,
|
||
|
IN ULONGLONG Start,
|
||
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine packs the resource descriptor from a starting value and the requirement.
|
||
|
|
||
|
Input Parameters:
|
||
|
|
||
|
Requirement - Resource requirement to be packed into the resource descriptor.
|
||
|
|
||
|
Start - Starting value for this resource.
|
||
|
|
||
|
Descriptor - Resource descriptor to be packed.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Requirement);
|
||
|
ASSERT(Start < (ULONG)-1);
|
||
|
ASSERT(Descriptor);
|
||
|
|
||
|
//
|
||
|
// Make sure we are dealing with the correct resource.
|
||
|
//
|
||
|
|
||
|
ASSERT(Requirement->Type == CmResourceTypeInterrupt);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
Descriptor->Type = CmResourceTypeInterrupt;
|
||
|
Descriptor->Flags = Requirement->Flags;
|
||
|
Descriptor->ShareDisposition = Requirement->ShareDisposition;
|
||
|
Descriptor->u.Interrupt.Vector = (ULONG) Start;
|
||
|
Descriptor->u.Interrupt.Level = (ULONG) Start;
|
||
|
Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
|
||
|
|
||
|
DEBUG_PRINT(3, ("Packing Irq resource %p = 0x%04lx", Descriptor, (ULONG)Start));
|
||
|
|
||
|
return (STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpArbUnpackResource (
|
||
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor,
|
||
|
OUT PULONGLONG Start,
|
||
|
OUT PULONG Length
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine unpacks the resource descriptor into a starting value and length.
|
||
|
|
||
|
Input Parameters:
|
||
|
|
||
|
Descriptor - Resource descriptor to be unpacked.
|
||
|
|
||
|
Start - Receives the starting value for this descriptor.
|
||
|
|
||
|
Length - Receives the length of this resource.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
STATUS_SUCCESS.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate arguments.
|
||
|
//
|
||
|
|
||
|
ASSERT(Descriptor);
|
||
|
ASSERT(Start);
|
||
|
ASSERT(Length);
|
||
|
|
||
|
//
|
||
|
// Make sure we are dealing with the correct resource.
|
||
|
//
|
||
|
|
||
|
ASSERT(Descriptor->Type == CmResourceTypeInterrupt);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
//
|
||
|
// Do unpacking.
|
||
|
//
|
||
|
|
||
|
*Start = Descriptor->u.Interrupt.Vector;
|
||
|
*Length = 1;
|
||
|
|
||
|
DEBUG_PRINT(3, ("Unpacking Irq resource %p = 0x%04lx", Descriptor, (ULONG)*Start));
|
||
|
|
||
|
return (STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
LONG
|
||
|
HalpArbScoreRequirement (
|
||
|
IN PIO_RESOURCE_DESCRIPTOR Descriptor
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine returns a score that indicates the flexibility of this
|
||
|
device's requirements. Less flexible devices get low scores so that
|
||
|
they get assigned resources before more flexible devices.
|
||
|
|
||
|
Input Parameters:
|
||
|
|
||
|
Descriptor - Resource descriptor to be scored.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Returns the score for the descriptor.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
LONG score;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Validate argument.
|
||
|
//
|
||
|
|
||
|
ASSERT(Descriptor);
|
||
|
|
||
|
//
|
||
|
// Make sure we are dealing with the correct resource.
|
||
|
//
|
||
|
|
||
|
ASSERT(Descriptor->Type == CmResourceTypeInterrupt);
|
||
|
|
||
|
//
|
||
|
// We should never be here if Pci Irq routing is not enabled.
|
||
|
//
|
||
|
|
||
|
ASSERT(IsPciIrqRoutingEnabled());
|
||
|
|
||
|
//
|
||
|
// Score is directly determined by number of irqs in the decriptor.
|
||
|
//
|
||
|
|
||
|
score = Descriptor->u.Interrupt.MaximumVector -
|
||
|
Descriptor->u.Interrupt.MinimumVector + 1;
|
||
|
|
||
|
DEBUG_PRINT(3, ("Scoring Irq resource %p = %i", Descriptor, score));
|
||
|
|
||
|
return (score);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpInitIrqArbiter (
|
||
|
IN PDEVICE_OBJECT HalFdo
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
|
||
|
if (HalpArbiter.ArbiterState.MutexEvent)
|
||
|
{
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
DEBUG_PRINT(3, ("Initialzing Irq arbiter!"));
|
||
|
|
||
|
status = ArbInitializeArbiterInstance( &HalpArbiter.ArbiterState,
|
||
|
HalFdo,
|
||
|
CmResourceTypeInterrupt,
|
||
|
L"HalIRQ",
|
||
|
L"Root",
|
||
|
NULL);
|
||
|
|
||
|
if (NT_SUCCESS(status))
|
||
|
{
|
||
|
//
|
||
|
// Make interrupts >= 16 unavailable.
|
||
|
//
|
||
|
|
||
|
status = RtlAddRange( HalpArbiter.ArbiterState.Allocation,
|
||
|
16,
|
||
|
MAXULONG,
|
||
|
0,
|
||
|
RTL_RANGE_LIST_ADD_IF_CONFLICT,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
status = RtlAddRange( HalpArbiter.ArbiterState.Allocation,
|
||
|
PIC_SLAVE_IRQ,
|
||
|
PIC_SLAVE_IRQ,
|
||
|
0,
|
||
|
RTL_RANGE_LIST_ADD_IF_CONFLICT,
|
||
|
NULL,
|
||
|
NULL);
|
||
|
|
||
|
DEBUG_PRINT(1, ("Irq arbiter successfully initialized!"));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Keep us "uninitialized"
|
||
|
//
|
||
|
HalpArbiter.ArbiterState.MutexEvent = NULL;
|
||
|
ASSERT(NT_SUCCESS(status));
|
||
|
}
|
||
|
|
||
|
return (status);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpIrqArbiterInterfaceReference(
|
||
|
IN PVOID Context
|
||
|
)
|
||
|
{
|
||
|
//HalPnpInterfaceReference
|
||
|
PAGED_CODE();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
HalpIrqArbiterInterfaceDereference(
|
||
|
IN PVOID Context
|
||
|
)
|
||
|
{
|
||
|
//HalPnpInterfaceDereference
|
||
|
PAGED_CODE();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
#ifdef ALLOC_DATA_PRAGMA
|
||
|
#pragma const_seg("PAGECONST")
|
||
|
#endif // ALLOC_DATA_PRAGMA
|
||
|
const ARBITER_INTERFACE ArbInterface = {
|
||
|
sizeof(ARBITER_INTERFACE),//Size
|
||
|
1,//Version
|
||
|
&HalpArbiter.ArbiterState,//Context
|
||
|
HalpIrqArbiterInterfaceReference,//InterfaceReference
|
||
|
HalpIrqArbiterInterfaceDereference,//InterfaceDereference
|
||
|
&ArbArbiterHandler,//ArbiterHandler
|
||
|
0//Flags -- Do not set ARBITER_PARTIAL here
|
||
|
};
|
||
|
#ifdef ALLOC_DATA_PRAGMA
|
||
|
#pragma const_seg()
|
||
|
#endif // ALLOC_DATA_PRAGMA
|
||
|
|
||
|
NTSTATUS
|
||
|
HalpFillInIrqArbiter (
|
||
|
IN PDEVICE_OBJECT DeviceObject,
|
||
|
IN LPCGUID InterfaceType,
|
||
|
IN USHORT Version,
|
||
|
IN PVOID InterfaceSpecificData,
|
||
|
IN ULONG InterfaceBufferSize,
|
||
|
IN OUT PINTERFACE Interface,
|
||
|
IN OUT PULONG Length
|
||
|
)
|
||
|
{
|
||
|
*Length = sizeof(ARBITER_INTERFACE);
|
||
|
if (InterfaceBufferSize < sizeof(ARBITER_INTERFACE)) {
|
||
|
return STATUS_BUFFER_TOO_SMALL;
|
||
|
}
|
||
|
|
||
|
*(PARBITER_INTERFACE)Interface = ArbInterface;
|
||
|
|
||
|
DEBUG_PRINT(3, ("Providing Irq Arbiter for FDO %08x since Pci Irq Routing is enabled!", DeviceObject));
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|