You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
494 lines
13 KiB
494 lines
13 KiB
/*++
|
|
|
|
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;
|
|
|
|
PCI_ASSERT(!arbiter->ReferenceCount);
|
|
PCI_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;
|
|
|
|
PCI_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;
|
|
}
|
|
|
|
}
|
|
|
|
PCI_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;
|
|
BOOLEAN ok;
|
|
|
|
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;
|
|
|
|
ok = SUCCEEDED(StringCbPrintfW(instance->InstanceName,
|
|
sizeof(instance->InstanceName),
|
|
L"PCI %S (b=%02x)",
|
|
PciArbiterNames[arbiterType - PciArb_Io],
|
|
fdoExtension->BaseBus
|
|
));
|
|
|
|
ASSERT(ok);
|
|
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
PCI_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;
|
|
}
|
|
}
|
|
|
|
FdoExtension->ArbitersInitialized = TRUE;
|
|
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);
|
|
}
|
|
|