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);
|
||
}
|
||
|