windows-nt/Source/XPSP1/NT/base/busdrv/pci/arb_comn.c

493 lines
12 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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);
}