493 lines
12 KiB
C
493 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
arb_comn.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains arbitration generic "utility" routines
|
|||
|
for the PCI driver.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Peter Johnston (peterj) 1-Apr-1997
|
|||
|
Andrew Thornton (andrewth) 15-May-1997
|
|||
|
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pcip.h"
|
|||
|
|
|||
|
#define PCI_CONTEXT_TO_INSTANCE(context) \
|
|||
|
CONTAINING_RECORD(context, PCI_ARBITER_INSTANCE, CommonInstance)
|
|||
|
|
|||
|
//
|
|||
|
// Plain text (short) description of each arbiter type.
|
|||
|
// (For debug).
|
|||
|
//
|
|||
|
// N.B. Order corresponds to PCI Signature enumeration.
|
|||
|
//
|
|||
|
|
|||
|
PUCHAR PciArbiterNames[] = {
|
|||
|
"I/O Port",
|
|||
|
"Memory",
|
|||
|
"Interrupt",
|
|||
|
"Bus Number"
|
|||
|
};
|
|||
|
VOID
|
|||
|
PciArbiterDestructor(
|
|||
|
IN PVOID Extension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when a PCI Secondary Extension that
|
|||
|
contains an arbiter instance is being torn down. Its function
|
|||
|
is to do any arbiter specific teardown.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension Address of PCI secondary extension containing
|
|||
|
the arbiter.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PPCI_ARBITER_INSTANCE instance;
|
|||
|
PARBITER_INSTANCE arbiter;
|
|||
|
PARBITER_MEMORY_EXTENSION extension;
|
|||
|
|
|||
|
instance = (PPCI_ARBITER_INSTANCE)Extension;
|
|||
|
arbiter = &instance->CommonInstance;
|
|||
|
|
|||
|
ASSERT(!arbiter->ReferenceCount);
|
|||
|
ASSERT(!arbiter->TransactionInProgress);
|
|||
|
|
|||
|
//
|
|||
|
// NTRAID #54671 - 04/03/2000 - andrewth
|
|||
|
// This is rather gross but it fixes the leak from the memory
|
|||
|
// arbiter.
|
|||
|
//
|
|||
|
|
|||
|
if (arbiter->ResourceType == CmResourceTypeMemory) {
|
|||
|
|
|||
|
extension = arbiter->Extension;
|
|||
|
|
|||
|
ASSERT(extension);
|
|||
|
|
|||
|
ArbFreeOrderingList(&extension->PrefetchableOrdering);
|
|||
|
ArbFreeOrderingList(&extension->NonprefetchableOrdering);
|
|||
|
ArbFreeOrderingList(&extension->OriginalOrdering);
|
|||
|
|
|||
|
//
|
|||
|
// Arbiter->OrderingList is one of the above three lists we just freed -
|
|||
|
// don't free it again
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(&arbiter->OrderingList, sizeof(ARBITER_ORDERING_LIST));
|
|||
|
}
|
|||
|
|
|||
|
ArbDeleteArbiterInstance(arbiter);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PciArbiterInitializeInterface(
|
|||
|
IN PVOID DeviceExtension,
|
|||
|
IN PCI_SIGNATURE DesiredInterface,
|
|||
|
IN OUT PARBITER_INTERFACE ArbiterInterface
|
|||
|
)
|
|||
|
{
|
|||
|
PPCI_ARBITER_INSTANCE instance;
|
|||
|
PPCI_FDO_EXTENSION fdoExtension = (PPCI_FDO_EXTENSION)DeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// Find the arbiter instance (context) for this resource type
|
|||
|
// on this FDO.
|
|||
|
//
|
|||
|
|
|||
|
instance = PciFindSecondaryExtension(fdoExtension, DesiredInterface);
|
|||
|
if (instance == NULL) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
//
|
|||
|
// Check if this bridge is doing subtractive decoding in
|
|||
|
// which case there will be no arbiter for IO or Memory.
|
|||
|
//
|
|||
|
// N.B. Only relevant to debug, either way the call will
|
|||
|
// fail but we don't want to actually assert if this is
|
|||
|
// the case.
|
|||
|
//
|
|||
|
|
|||
|
if (!PCI_IS_ROOT_FDO(fdoExtension)) {
|
|||
|
|
|||
|
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION)
|
|||
|
fdoExtension->PhysicalDeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT_PCI_PDO_EXTENSION(pdoExtension);
|
|||
|
|
|||
|
if (pdoExtension->Dependent.type1.SubtractiveDecode) {
|
|||
|
|
|||
|
//
|
|||
|
// Subtractive, no arbiters.
|
|||
|
//
|
|||
|
|
|||
|
return STATUS_INVALID_PARAMETER_2;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ASSERTMSG("couldn't locate arbiter for resource.", instance);
|
|||
|
|
|||
|
#endif
|
|||
|
return STATUS_INVALID_PARAMETER_5;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill in the rest of the caller's arbiter interface structure.
|
|||
|
//
|
|||
|
|
|||
|
ArbiterInterface->Context = &instance->CommonInstance;
|
|||
|
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgObnoxious,
|
|||
|
"PCI - %S Arbiter Interface Initialized.\n",
|
|||
|
instance->CommonInstance.Name
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PciInitializeArbiters(
|
|||
|
IN PVOID DeviceExtension
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PPCI_INTERFACE *interfaceEntry;
|
|||
|
PCI_SIGNATURE arbiterType;
|
|||
|
PPCI_ARBITER_INSTANCE instance;
|
|||
|
PPCI_FDO_EXTENSION fdoExtension = (PPCI_FDO_EXTENSION)DeviceExtension;
|
|||
|
PRTL_RANGE_LIST *range;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
ASSERT_PCI_FDO_EXTENSION(fdoExtension);
|
|||
|
|
|||
|
//
|
|||
|
// For each resource type for which we do arbitration, initialize
|
|||
|
// a context.
|
|||
|
//
|
|||
|
|
|||
|
for (arbiterType = PciArb_Io;
|
|||
|
arbiterType <= PciArb_BusNumber;
|
|||
|
arbiterType++) {
|
|||
|
|
|||
|
//
|
|||
|
// If this bridge provides this resource via subtractive
|
|||
|
// decode, get the system to fall thru to the parent
|
|||
|
// arbiter by not creating an arbiter at this level.
|
|||
|
//
|
|||
|
|
|||
|
if (!PCI_IS_ROOT_FDO(fdoExtension)) {
|
|||
|
|
|||
|
PPCI_PDO_EXTENSION pdoExtension = (PPCI_PDO_EXTENSION)
|
|||
|
fdoExtension->PhysicalDeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT_PCI_PDO_EXTENSION(pdoExtension);
|
|||
|
|
|||
|
if (pdoExtension->Dependent.type1.SubtractiveDecode) {
|
|||
|
|
|||
|
//
|
|||
|
// Skip creation of this arbiter.
|
|||
|
//
|
|||
|
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgVerbose,
|
|||
|
"PCI Not creating arbiters for subtractive bus %d\n",
|
|||
|
pdoExtension->Dependent.type1.SecondaryBus
|
|||
|
);
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find this entry in the interface table (if not found, skip
|
|||
|
// it).
|
|||
|
//
|
|||
|
|
|||
|
for (interfaceEntry = PciInterfaces;
|
|||
|
*interfaceEntry;
|
|||
|
interfaceEntry++) {
|
|||
|
|
|||
|
if ((*interfaceEntry)->Signature == arbiterType) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (*interfaceEntry == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Did not find an interface entry. This means we don't
|
|||
|
// actually implement this arbiter type.
|
|||
|
//
|
|||
|
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgObnoxious,
|
|||
|
"PCI - FDO ext 0x%08x no %s arbiter.\n",
|
|||
|
DeviceExtension,
|
|||
|
PciArbiterNames[arbiterType - PciArb_Io]
|
|||
|
);
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
instance = ExAllocatePool(
|
|||
|
PagedPool | POOL_COLD_ALLOCATION,
|
|||
|
sizeof(PCI_ARBITER_INSTANCE)
|
|||
|
);
|
|||
|
|
|||
|
if (instance == NULL) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize PCI specific fields
|
|||
|
//
|
|||
|
|
|||
|
instance->BusFdoExtension = fdoExtension;
|
|||
|
instance->Interface = *interfaceEntry;
|
|||
|
|
|||
|
swprintf(
|
|||
|
instance->InstanceName,
|
|||
|
L"PCI %S (b=%02x)",
|
|||
|
PciArbiterNames[arbiterType - PciArb_Io],
|
|||
|
fdoExtension->BaseBus
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Allow this arbiter to do any of it's own first time
|
|||
|
// initialization.
|
|||
|
//
|
|||
|
|
|||
|
status = (*interfaceEntry)->Initializer(instance);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Push this arbiter onto the FDO's list of extensions.
|
|||
|
//
|
|||
|
|
|||
|
PciLinkSecondaryExtension(fdoExtension,
|
|||
|
instance,
|
|||
|
arbiterType,
|
|||
|
PciArbiterDestructor);
|
|||
|
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgObnoxious,
|
|||
|
"PCI - FDO ext 0x%08x %S arbiter initialized (context 0x%08x).\n",
|
|||
|
DeviceExtension,
|
|||
|
instance->CommonInstance.Name,
|
|||
|
instance
|
|||
|
);
|
|||
|
}
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PciInitializeArbiterRanges(
|
|||
|
IN PPCI_FDO_EXTENSION FdoExtension,
|
|||
|
IN PCM_RESOURCE_LIST ResourceList
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PCI_SIGNATURE arbiterType;
|
|||
|
CM_RESOURCE_TYPE resourceType;
|
|||
|
PPCI_ARBITER_INSTANCE instance;
|
|||
|
|
|||
|
//
|
|||
|
// NTRAID #95564 - 04/03/2000 - andrewth
|
|||
|
// This routine needs to be reworked, in the case where
|
|||
|
// this FDO is processing a second or subsequent START_DEVICE
|
|||
|
// IRP, the arbiter's ranges may need to be adjusted according
|
|||
|
// to the incoming resource list. Until this is done, avoid
|
|||
|
// causing problems by processing it again.
|
|||
|
//
|
|||
|
|
|||
|
if (FdoExtension->ArbitersInitialized) {
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgInformative,
|
|||
|
"PCI Warning hot start FDOx %08x, resource ranges not checked.\n",
|
|||
|
FdoExtension
|
|||
|
);
|
|||
|
return STATUS_INVALID_DEVICE_REQUEST;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if this bridge is doing subtractive decoding in
|
|||
|
// which case there will be no arbiters
|
|||
|
//
|
|||
|
|
|||
|
if (!PCI_IS_ROOT_FDO(FdoExtension)) {
|
|||
|
PPCI_PDO_EXTENSION pdoExtension;
|
|||
|
|
|||
|
pdoExtension = (PPCI_PDO_EXTENSION)
|
|||
|
FdoExtension->PhysicalDeviceObject->DeviceExtension;
|
|||
|
|
|||
|
ASSERT_PCI_PDO_EXTENSION(pdoExtension);
|
|||
|
|
|||
|
if (pdoExtension->Dependent.type1.SubtractiveDecode) {
|
|||
|
|
|||
|
//
|
|||
|
// Subtractive decode no arbiters.
|
|||
|
//
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgInformative,
|
|||
|
"PCI Skipping arbiter initialization for subtractive bridge FDOX %p\n",
|
|||
|
FdoExtension
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// For each resource type for which we do arbitration, initialize
|
|||
|
// a context.
|
|||
|
//
|
|||
|
|
|||
|
for (arbiterType = PciArb_Io;
|
|||
|
arbiterType <= PciArb_Memory;
|
|||
|
arbiterType++) {
|
|||
|
|
|||
|
//
|
|||
|
// Currently this is only supported for Memory and IO.
|
|||
|
//
|
|||
|
|
|||
|
switch (arbiterType) {
|
|||
|
|
|||
|
//
|
|||
|
// Go ahead and process these ones.
|
|||
|
//
|
|||
|
|
|||
|
case PciArb_Io:
|
|||
|
resourceType = CmResourceTypePort;
|
|||
|
break;
|
|||
|
|
|||
|
case PciArb_Memory:
|
|||
|
resourceType = CmResourceTypeMemory;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
//
|
|||
|
// Skip anything else.
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find this arbiter instance.
|
|||
|
//
|
|||
|
|
|||
|
instance = PciFindSecondaryExtension(FdoExtension, arbiterType);
|
|||
|
if (instance == NULL) {
|
|||
|
|
|||
|
//
|
|||
|
// Did not find an interface entry. This means we don't
|
|||
|
// actually implement this arbiter type.
|
|||
|
//
|
|||
|
|
|||
|
PciDebugPrint(
|
|||
|
PciDbgAlways,
|
|||
|
"PCI - FDO ext 0x%08x %s arbiter (REQUIRED) is missing.\n",
|
|||
|
FdoExtension,
|
|||
|
PciArbiterNames[arbiterType - PciArb_Io]
|
|||
|
);
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The incoming ResourceList gives the ranges this bus supports.
|
|||
|
// Convert this to an inverted range so we can exclude everything
|
|||
|
// we don't cover.
|
|||
|
//
|
|||
|
|
|||
|
status = PciRangeListFromResourceList(
|
|||
|
FdoExtension,
|
|||
|
ResourceList,
|
|||
|
resourceType,
|
|||
|
TRUE,
|
|||
|
instance->CommonInstance.Allocation
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Nothing we can do here. Additional debug stuff was
|
|||
|
// in the lower level. Skip this puppy.
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// NTRAID #95564 - 04/03/2000 - andrewth
|
|||
|
//
|
|||
|
// When ArbStartArbiter is complete it will replace
|
|||
|
// the call to PciRangeListFromResourceList.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT(instance->CommonInstance.StartArbiter);
|
|||
|
|
|||
|
status = instance->CommonInstance.StartArbiter(&instance->CommonInstance,
|
|||
|
ResourceList
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Bail initializing this arbiter and fail the start. The arbiters
|
|||
|
// will be cleaned up when we get the REMOVE_DEVICE
|
|||
|
//
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PciReferenceArbiter(
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
PPCI_ARBITER_INSTANCE instance = PCI_CONTEXT_TO_INSTANCE(Context);
|
|||
|
InterlockedIncrement(&instance->CommonInstance.ReferenceCount);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PciDereferenceArbiter(
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
{
|
|||
|
PPCI_ARBITER_INSTANCE instance = PCI_CONTEXT_TO_INSTANCE(Context);
|
|||
|
InterlockedDecrement(&instance->CommonInstance.ReferenceCount);
|
|||
|
}
|
|||
|
|