|
|
/*++
Copyright (c) Microsoft Corporation. All rights reserved.
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
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#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 ) { PAGED_CODE();
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;
PAGED_CODE();
//
// 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;
PAGED_CODE();
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_RESOURCE_REQUIREMENTS_CHANGED) { 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;
PAGED_CODE();
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, MAXULONGLONG, 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 ) { PAGED_CODE();
*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; }
|