1006 lines
24 KiB
C
1006 lines
24 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
busno.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements routines pertaining to PCI bus numbers.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Andy Thornton (andrewth) 9/5/98
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "pcip.h"
|
||
|
|
||
|
VOID
|
||
|
PciSpreadBridges(
|
||
|
IN PPCI_FDO_EXTENSION Parent,
|
||
|
IN UCHAR BridgeCount
|
||
|
);
|
||
|
|
||
|
UCHAR
|
||
|
PciFindBridgeNumberLimit(
|
||
|
IN PPCI_FDO_EXTENSION BridgeParent,
|
||
|
IN UCHAR Base
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
PciFitBridge(
|
||
|
IN PPCI_FDO_EXTENSION ParentFdoExtension,
|
||
|
IN PPCI_PDO_EXTENSION BridgePdoExtension
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
PciSetBusNumbers(
|
||
|
IN PPCI_PDO_EXTENSION PdoExtension,
|
||
|
IN UCHAR Primary,
|
||
|
IN UCHAR Secondary,
|
||
|
IN UCHAR Subordinate
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
PciUpdateAncestorSubordinateBuses(
|
||
|
IN PPCI_FDO_EXTENSION FdoExtension,
|
||
|
IN UCHAR Subordinate
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
PciDisableBridge(
|
||
|
IN PPCI_PDO_EXTENSION Bridge
|
||
|
);
|
||
|
|
||
|
UCHAR
|
||
|
PciFindBridgeNumberLimitWorker(
|
||
|
IN PPCI_FDO_EXTENSION BridgeParent,
|
||
|
IN PPCI_FDO_EXTENSION CurrentParent,
|
||
|
IN UCHAR Base,
|
||
|
OUT PBOOLEAN RootConstrained
|
||
|
);
|
||
|
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
|
||
|
#pragma alloc_text(PAGE, PciConfigureBusNumbers)
|
||
|
#pragma alloc_text(PAGE, PciAreBusNumbersConfigured)
|
||
|
#pragma alloc_text(PAGE, PciSpreadBridges)
|
||
|
#pragma alloc_text(PAGE, PciFindBridgeNumberLimit)
|
||
|
#pragma alloc_text(PAGE, PciFitBridge)
|
||
|
#pragma alloc_text(PAGE, PciSetBusNumbers)
|
||
|
#pragma alloc_text(PAGE, PciUpdateAncestorSubordinateBuses)
|
||
|
#pragma alloc_text(PAGE, PciDisableBridge)
|
||
|
#pragma alloc_text(PAGE, PciFindBridgeNumberLimitWorker)
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PciConfigureBusNumbers(
|
||
|
PPCI_FDO_EXTENSION Parent
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine is called after scanning a PCI bus (root or bridge) and
|
||
|
configures the bus numbers for any newly encountered bridges if possible.
|
||
|
|
||
|
Any unconfigurable bridges will be set to Primary = Secondary = Subordinate = 0
|
||
|
and their IO, Memory and BusMaster bits will be disabled. When PCI is later
|
||
|
asked to Add to them it will fail.
|
||
|
|
||
|
The Parent->Mutex lock should be held before calling this function
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Parent - The bridge we have just enumerated.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PPCI_PDO_EXTENSION current, parentPdo = NULL;
|
||
|
UCHAR bridgeCount = 0, configuredBridgeCount = 0;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
if (!PCI_IS_ROOT_FDO(Parent)) {
|
||
|
parentPdo = (PPCI_PDO_EXTENSION)Parent->PhysicalDeviceObject->DeviceExtension;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Walk the list of child PDO's for this bus and count the number of
|
||
|
// bridges and configured bridges
|
||
|
//
|
||
|
ExAcquireFastMutex(&Parent->ChildListMutex);
|
||
|
|
||
|
for (current = Parent->ChildBridgePdoList;
|
||
|
current;
|
||
|
current = current->NextBridge) {
|
||
|
|
||
|
if (current->NotPresent) {
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"Skipping not present bridge PDOX @ %p\n",
|
||
|
current
|
||
|
);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
bridgeCount++;
|
||
|
|
||
|
//
|
||
|
// If we configured the parent then all the children are considered
|
||
|
// to be unconfigured. Root buses are always configured
|
||
|
//
|
||
|
|
||
|
if ((parentPdo &&
|
||
|
parentPdo->Dependent.type1.WeChangedBusNumbers &&
|
||
|
(current->DeviceState == PciNotStarted))
|
||
|
|| (!PciAreBusNumbersConfigured(current))) {
|
||
|
|
||
|
//
|
||
|
// Disable this bridge and we will fix it later
|
||
|
//
|
||
|
PciDisableBridge(current);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// The bios must have configured this bridge and it looks valid so
|
||
|
// leave it alone!
|
||
|
//
|
||
|
|
||
|
configuredBridgeCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ExReleaseFastMutex(&Parent->ChildListMutex);
|
||
|
|
||
|
//
|
||
|
// Now there are four posibilities...
|
||
|
//
|
||
|
|
||
|
if (bridgeCount == 0) {
|
||
|
|
||
|
//
|
||
|
// There are no bridges so not a lot to do...
|
||
|
//
|
||
|
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"PCI - No bridges found on bus 0x%x\n",
|
||
|
Parent->BaseBus
|
||
|
);
|
||
|
|
||
|
|
||
|
} else if (bridgeCount == configuredBridgeCount) {
|
||
|
|
||
|
//
|
||
|
// All the bridges are configured - still not a lot to do...
|
||
|
//
|
||
|
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"PCI - 0x%x bridges found on bus 0x%x - all already configured\n",
|
||
|
bridgeCount,
|
||
|
Parent->BaseBus
|
||
|
);
|
||
|
|
||
|
|
||
|
} else if (configuredBridgeCount == 0) {
|
||
|
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"PCI - 0x%x bridges found on bus 0x%x - all need configuration\n",
|
||
|
bridgeCount,
|
||
|
Parent->BaseBus
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// All the bridges require configuration so we should use a spreading
|
||
|
// out algorithm
|
||
|
//
|
||
|
|
||
|
PciSpreadBridges(Parent, bridgeCount);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Some of the bridges are configured and some are not - we should try
|
||
|
// to fit the unconfigured ones into the holes left by the configured
|
||
|
// ones
|
||
|
//
|
||
|
|
||
|
ASSERT(configuredBridgeCount < bridgeCount);
|
||
|
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"PCI - 0x%x bridges found on bus 0x%x - 0x%x need configuration\n",
|
||
|
bridgeCount,
|
||
|
Parent->BaseBus,
|
||
|
bridgeCount - configuredBridgeCount
|
||
|
);
|
||
|
|
||
|
|
||
|
//
|
||
|
// Walk the list of PDO's again and configure each one seperatly
|
||
|
//
|
||
|
|
||
|
for (current = Parent->ChildBridgePdoList;
|
||
|
current;
|
||
|
current = current->NextBridge) {
|
||
|
|
||
|
if (current->NotPresent) {
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"Skipping not present bridge PDOX @ %p\n",
|
||
|
current
|
||
|
);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fit the bridge if we disabled it.
|
||
|
//
|
||
|
|
||
|
if ((parentPdo &&
|
||
|
parentPdo->Dependent.type1.WeChangedBusNumbers &&
|
||
|
(current->DeviceState == PciNotStarted))
|
||
|
|| (!PciAreBusNumbersConfigured(current))) {
|
||
|
|
||
|
ASSERT(current->Dependent.type1.PrimaryBus == 0
|
||
|
&& current->Dependent.type1.SecondaryBus == 0
|
||
|
&& current->Dependent.type1.SubordinateBus == 0
|
||
|
);
|
||
|
|
||
|
PciFitBridge(Parent, current);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOLEAN
|
||
|
PciAreBusNumbersConfigured(
|
||
|
IN PPCI_PDO_EXTENSION Bridge
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This checks if the bus numbers assigned to the bridge are valid
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Bridge - the bridge to check
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
TRUE if numbers are valid FALSE otherwise.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// Check this bridge is configured to run on the bus we found it.
|
||
|
//
|
||
|
|
||
|
if (Bridge->Dependent.type1.PrimaryBus != Bridge->ParentFdoExtension->BaseBus) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Ensure the child bus number is greater than the parent bus.
|
||
|
// (HP Omnibooks actually break this rule when not plugged into
|
||
|
// their docking stations).
|
||
|
//
|
||
|
|
||
|
if (Bridge->Dependent.type1.SecondaryBus <= Bridge->Dependent.type1.PrimaryBus) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// And finally, make sure the secondary bus is in the range
|
||
|
// of busses the bridge is programmed for. Paranoia.
|
||
|
//
|
||
|
|
||
|
if (Bridge->Dependent.type1.SubordinateBus < Bridge->Dependent.type1.SecondaryBus) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PciSpreadBridges(
|
||
|
IN PPCI_FDO_EXTENSION Parent,
|
||
|
IN UCHAR BridgeCount
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine attemps to spread out the available bus numbers between the
|
||
|
unconfigured bridges. It is only called if ALL the bridges on a particular
|
||
|
bus are not configured - eg we just hot docked!
|
||
|
|
||
|
If a particular brigde can not be configured it is disabled (Decodes OFF and
|
||
|
bus number 0->0-0) and the subsequent AddDevice will fail.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Parent - The FDO extension for the bridge we are enumerating.
|
||
|
|
||
|
BridgeCount - The number of bridges at this level
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
UCHAR base, limit, numberCount, currentNumber, spread, maxAssigned = 0;
|
||
|
PPCI_PDO_EXTENSION current;
|
||
|
BOOLEAN outOfNumbers = FALSE;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(Parent->BaseBus < PCI_MAX_BRIDGE_NUMBER);
|
||
|
|
||
|
//
|
||
|
// Seeing as we only get here if all the bridges arn't configured the base
|
||
|
// is the lowest bus out parent passes
|
||
|
//
|
||
|
|
||
|
base = (UCHAR)Parent->BaseBus;
|
||
|
|
||
|
//
|
||
|
// The limit is constrained by the siblings of the parent bridge or in the
|
||
|
// case that there are none, by the siblings of the parent's parent and so on
|
||
|
// until we find a sibling or run out of buses in which case the constraint
|
||
|
// is the maximum bus number passed by this root.
|
||
|
//
|
||
|
|
||
|
limit = PciFindBridgeNumberLimit(Parent, base);
|
||
|
|
||
|
if (limit < base) {
|
||
|
//
|
||
|
// This normally means the BIOS or HAL messed up and got the subordinate
|
||
|
// bus number for the root bus wrong. There's not much we can do..
|
||
|
//
|
||
|
|
||
|
ASSERT(limit >= base);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now see if we have enough numbers available to number all the busses
|
||
|
//
|
||
|
|
||
|
numberCount = limit - base;
|
||
|
|
||
|
if (numberCount == 0) {
|
||
|
//
|
||
|
// We don't have any bus numbers available - bail now
|
||
|
//
|
||
|
return;
|
||
|
|
||
|
} else if (BridgeCount >= numberCount) {
|
||
|
//
|
||
|
// We have just/not enough - don't spread things out!
|
||
|
//
|
||
|
spread = 1;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Try and spread things out a bit so we can accomodate subordinate
|
||
|
// bridges of the one we are configuring. Also leave some space on the
|
||
|
// parent bus for any bridges that appear here (the + 1). As we have no idea
|
||
|
// what is behind each bridge treat them equally...
|
||
|
//
|
||
|
|
||
|
spread = numberCount / (BridgeCount + 1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now assign the bus numbers - we have already disabled all the unconfigured
|
||
|
// bridges
|
||
|
//
|
||
|
currentNumber = base + 1;
|
||
|
|
||
|
for (current = Parent->ChildBridgePdoList;
|
||
|
current;
|
||
|
current = current->NextBridge) {
|
||
|
|
||
|
if (current->NotPresent) {
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"Skipping not present bridge PDOX @ %p\n",
|
||
|
current
|
||
|
);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Now go and write it out to the hardware
|
||
|
//
|
||
|
|
||
|
ASSERT(!PciAreBusNumbersConfigured(current));
|
||
|
|
||
|
//
|
||
|
// Primary is the bus we are on, secondary is our bus number.
|
||
|
// We don't know if there are any bridges there - we have left space
|
||
|
// just in case - therefore we don't pass any bus numbers. If we
|
||
|
// need to, the subordinate number can be updated later.
|
||
|
//
|
||
|
|
||
|
PciSetBusNumbers(current,
|
||
|
base,
|
||
|
currentNumber,
|
||
|
currentNumber
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Remember the max number we assigned
|
||
|
//
|
||
|
|
||
|
maxAssigned = currentNumber;
|
||
|
|
||
|
//
|
||
|
// Check if we have run out of numbers
|
||
|
//
|
||
|
|
||
|
if ((currentNumber + spread) < currentNumber // wrapped
|
||
|
|| (currentNumber + spread) > limit) {
|
||
|
|
||
|
break;
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// Move onto the next number
|
||
|
//
|
||
|
currentNumber += spread;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we have programmed the bridges - we need to go back and update the
|
||
|
// subordinate bus numbers for all ancestor bridges.
|
||
|
//
|
||
|
|
||
|
ASSERT(maxAssigned > 0);
|
||
|
|
||
|
PciUpdateAncestorSubordinateBuses(Parent, maxAssigned);
|
||
|
|
||
|
}
|
||
|
|
||
|
UCHAR
|
||
|
PciFindBridgeNumberLimitWorker(
|
||
|
IN PPCI_FDO_EXTENSION BridgeParent,
|
||
|
IN PPCI_FDO_EXTENSION CurrentParent,
|
||
|
IN UCHAR Base,
|
||
|
OUT PBOOLEAN RootConstrained
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This determines the subordinate bus number a bridge on the bus BridgeParent
|
||
|
with secondary number Base can have given the constraints of the configured
|
||
|
busses in the system.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
BridgeParent - The bus on which the bridge resides
|
||
|
|
||
|
CurrentParent - The current bridge we are looking at (used for synchronization)
|
||
|
|
||
|
Base - The primary bus number of this bridge (ie the parent's secondary bus number)
|
||
|
|
||
|
Constraint - The number of the bus that constrains us
|
||
|
|
||
|
RootConstrained - Set to TRUE if we were constrained by a root appeture, FALSE
|
||
|
if constrained by another bridge
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PPCI_PDO_EXTENSION current;
|
||
|
UCHAR currentNumber, closest = 0;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
if (BridgeParent != CurrentParent) {
|
||
|
|
||
|
//
|
||
|
// We're going to mess with the child pdo list - lock the state...
|
||
|
//
|
||
|
ExAcquireFastMutex(&CurrentParent->ChildListMutex);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Look for any bridge that will constrain us
|
||
|
//
|
||
|
|
||
|
for (current = CurrentParent->ChildBridgePdoList;
|
||
|
current;
|
||
|
current = current->NextBridge) {
|
||
|
|
||
|
if (current->NotPresent) {
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"Skipping not present bridge PDOX @ %p\n",
|
||
|
current
|
||
|
);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Unconfigured bridges can't constrain us
|
||
|
//
|
||
|
|
||
|
if (!PciAreBusNumbersConfigured(current)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
currentNumber = current->Dependent.type1.SecondaryBus;
|
||
|
|
||
|
if (currentNumber > Base
|
||
|
&& (currentNumber < closest || closest == 0)) {
|
||
|
closest = currentNumber;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// If we haven't found a closest bridge then move up one level - yes this
|
||
|
// is recursive but is bounded by the depth of the pci tree is the best way
|
||
|
// of dealing with the hierarchial locking.
|
||
|
//
|
||
|
if (closest == 0) {
|
||
|
|
||
|
if (CurrentParent->ParentFdoExtension == NULL) {
|
||
|
|
||
|
//
|
||
|
// We have reached the root without finding a sibling
|
||
|
//
|
||
|
|
||
|
*RootConstrained = TRUE;
|
||
|
closest = CurrentParent->MaxSubordinateBus;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
closest = PciFindBridgeNumberLimitWorker(BridgeParent,
|
||
|
CurrentParent->ParentFdoExtension,
|
||
|
Base,
|
||
|
RootConstrained
|
||
|
);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// We are constrained by a bridge so by definition not by a root.
|
||
|
//
|
||
|
|
||
|
*RootConstrained = FALSE;
|
||
|
}
|
||
|
|
||
|
if (BridgeParent != CurrentParent) {
|
||
|
|
||
|
ExReleaseFastMutex(&CurrentParent->ChildListMutex);
|
||
|
}
|
||
|
|
||
|
return closest;
|
||
|
|
||
|
}
|
||
|
|
||
|
UCHAR
|
||
|
PciFindBridgeNumberLimit(
|
||
|
IN PPCI_FDO_EXTENSION Bridge,
|
||
|
IN UCHAR Base
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This determines the subordinate bus number a bridge on the bus BridgeParent
|
||
|
with secondary number Base can have given the constraints of the configured
|
||
|
busses in the system.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
BridgeParent - The bus on which the bridge resides
|
||
|
|
||
|
Base - The primary bus number of this bridge (ie the parent's secondary bus number)
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
The max subordinate value.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
|
||
|
BOOLEAN rootConstrained;
|
||
|
UCHAR constraint;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
constraint = PciFindBridgeNumberLimitWorker(Bridge,
|
||
|
Bridge,
|
||
|
Base,
|
||
|
&rootConstrained
|
||
|
);
|
||
|
|
||
|
|
||
|
|
||
|
if (rootConstrained) {
|
||
|
|
||
|
//
|
||
|
// We are constrained by the maximum bus number that this root bus passes
|
||
|
// - this is therefore the max subordinate bus.
|
||
|
//
|
||
|
|
||
|
return constraint;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// If we are not constrained by a root bus we must be constrained by a
|
||
|
// bridge and thus the max subordinate value we can assign to the bus is
|
||
|
// one less that the bridge that constrained us. (A bridge must have a
|
||
|
// bus number greater that 1 so we can't wrap)
|
||
|
//
|
||
|
|
||
|
ASSERT(constraint > 0);
|
||
|
return constraint - 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PciFitBridge(
|
||
|
IN PPCI_FDO_EXTENSION Parent,
|
||
|
IN PPCI_PDO_EXTENSION Bridge
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine attemps to find a range of bus numbers for Bridge given the
|
||
|
constraints of the already configured bridges.
|
||
|
|
||
|
If a particular brigde can not be configured it is disabled (Decodes OFF and
|
||
|
bus number 0->0-0) and the subsequent AddDevice will fail.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Parent - The FDO extension for the bridge we are enumerating.
|
||
|
|
||
|
Bridge - The brige we want to configure
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PPCI_PDO_EXTENSION current;
|
||
|
UCHAR base, limit, gap, bestBase = 0, biggestGap = 0, lowest = 0xFF;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
for (current = Parent->ChildBridgePdoList;
|
||
|
current;
|
||
|
current = current->NextBridge) {
|
||
|
|
||
|
if (current->NotPresent) {
|
||
|
PciDebugPrint(PciDbgBusNumbers,
|
||
|
"Skipping not present bridge PDOX @ %p\n",
|
||
|
current
|
||
|
);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Only look at configured bridges - buses we disabled have
|
||
|
// bus numbers 0->0-0 which is helpfully invalid
|
||
|
//
|
||
|
|
||
|
if (PciAreBusNumbersConfigured(current)) {
|
||
|
|
||
|
//
|
||
|
// Get the base and limit for each bridge and calculate which bridge
|
||
|
// has the biggest gap.
|
||
|
//
|
||
|
|
||
|
base = (UCHAR) current->Dependent.type1.SubordinateBus;
|
||
|
limit = PciFindBridgeNumberLimit(Parent, base);
|
||
|
|
||
|
//
|
||
|
// This ASSERT might fail if a BIOS or HAL misreported the limits
|
||
|
// of a root bridge. For example, an ACPI BIOS might have a _CRS
|
||
|
// for the root bridge that specifies bus-numbers 0 to 0 (length 1)
|
||
|
// are passed down, even though the real range is 0 to 255.
|
||
|
//
|
||
|
|
||
|
ASSERT(limit >= base);
|
||
|
|
||
|
gap = limit - base;
|
||
|
|
||
|
if (gap > biggestGap) {
|
||
|
|
||
|
ASSERT(gap > 0);
|
||
|
|
||
|
biggestGap = gap;
|
||
|
bestBase = base + 1;
|
||
|
}
|
||
|
|
||
|
if (current->Dependent.type1.SecondaryBus < lowest) {
|
||
|
lowest = current->Dependent.type1.SecondaryBus;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now make sure the gap between the bus we are on and the first bridge
|
||
|
// is not the biggest - lowest must always be greater that the parents bus
|
||
|
// number or it is miss configured and would have failed the
|
||
|
// BusNumbersConfigured test above.
|
||
|
//
|
||
|
|
||
|
ASSERT(lowest > Parent->BaseBus);
|
||
|
|
||
|
gap = lowest - (Parent->BaseBus + 1);
|
||
|
|
||
|
if (gap > biggestGap) {
|
||
|
|
||
|
ASSERT(gap > 0);
|
||
|
|
||
|
biggestGap = gap;
|
||
|
bestBase = Parent->BaseBus + 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Did we find anywhere to put the bridge?
|
||
|
//
|
||
|
|
||
|
if (biggestGap >= 1) {
|
||
|
|
||
|
//
|
||
|
// Ok - we have some space to play with so we can configure out bridge
|
||
|
// right in the middle of the gap, if the bestGap is 1 (ie the bridge
|
||
|
// just fits) then this still works.
|
||
|
//
|
||
|
|
||
|
base = bestBase + (biggestGap / 2);
|
||
|
|
||
|
//
|
||
|
// Set subordinate equal to secondary as we are just leaving room for
|
||
|
// any bridges.
|
||
|
//
|
||
|
|
||
|
PciSetBusNumbers(Bridge, Parent->BaseBus, base, base);
|
||
|
|
||
|
//
|
||
|
// Update the ancestor subordinates if we configured the bridge
|
||
|
//
|
||
|
|
||
|
PciUpdateAncestorSubordinateBuses(Parent,
|
||
|
Bridge->Dependent.type1.SecondaryBus
|
||
|
);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PciSetBusNumbers(
|
||
|
IN PPCI_PDO_EXTENSION PdoExtension,
|
||
|
IN UCHAR Primary,
|
||
|
IN UCHAR Secondary,
|
||
|
IN UCHAR Subordinate
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine sets the bus numbers for a bridge and tracks if we have changed
|
||
|
bus numbers.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PdoExtension - The PDO for the bridge
|
||
|
|
||
|
Primary - The primary bus number to assign
|
||
|
|
||
|
Secondary - The secondary bus number to assign
|
||
|
|
||
|
Subordinate - The subordinate bus number to assign
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCI_COMMON_HEADER commonHeader;
|
||
|
PPCI_COMMON_CONFIG commonConfig = (PPCI_COMMON_CONFIG)&commonHeader;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(Primary < Secondary || (Primary == 0 && Secondary == 0));
|
||
|
ASSERT(Secondary <= Subordinate);
|
||
|
|
||
|
//
|
||
|
// Fill in in the config. Note that the Primary/Secondary/Subordinate bus
|
||
|
// numbers are in the same place for type1 and type2 headers.
|
||
|
//
|
||
|
|
||
|
commonConfig->u.type1.PrimaryBus = Primary;
|
||
|
commonConfig->u.type1.SecondaryBus = Secondary;
|
||
|
commonConfig->u.type1.SubordinateBus = Subordinate;
|
||
|
|
||
|
//
|
||
|
// Grab the PCI Bus lock - this will let hwverifier reliably check the
|
||
|
// config space against our extension.
|
||
|
//
|
||
|
|
||
|
ExAcquireFastMutex(&PciBusLock);
|
||
|
|
||
|
//
|
||
|
// Remember in the PDO
|
||
|
//
|
||
|
|
||
|
PdoExtension->Dependent.type1.PrimaryBus = Primary;
|
||
|
PdoExtension->Dependent.type1.SecondaryBus = Secondary;
|
||
|
PdoExtension->Dependent.type1.SubordinateBus = Subordinate;
|
||
|
PdoExtension->Dependent.type1.WeChangedBusNumbers = TRUE;
|
||
|
|
||
|
PciWriteDeviceConfig(
|
||
|
PdoExtension,
|
||
|
&commonConfig->u.type1.PrimaryBus,
|
||
|
FIELD_OFFSET(PCI_COMMON_CONFIG, u.type1.PrimaryBus),
|
||
|
sizeof(Primary) + sizeof(Secondary) + sizeof(Subordinate)
|
||
|
);
|
||
|
|
||
|
ExReleaseFastMutex(&PciBusLock);
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
PciUpdateAncestorSubordinateBuses(
|
||
|
IN PPCI_FDO_EXTENSION FdoExtension,
|
||
|
IN UCHAR Subordinate
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine walks the bridge hierarchy updating the subordinate bus numbers
|
||
|
of each ancestor to ensure that numbers up to Subordinate are passed.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FdoExtension - The Fdo for the parent of the bridge(s) we have just configured
|
||
|
|
||
|
Subordinate - The maximum (subordinate) bus number to pass
|
||
|
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PPCI_FDO_EXTENSION current;
|
||
|
PPCI_PDO_EXTENSION currentPdo;
|
||
|
|
||
|
PAGED_CODE();
|
||
|
|
||
|
//
|
||
|
// For all ancestors except the root update the subordinate bus number
|
||
|
//
|
||
|
|
||
|
for (current = FdoExtension;
|
||
|
current->ParentFdoExtension; // Root has no parent
|
||
|
current = current->ParentFdoExtension) {
|
||
|
|
||
|
currentPdo = (PPCI_PDO_EXTENSION)current->PhysicalDeviceObject->DeviceExtension;
|
||
|
|
||
|
ASSERT(!currentPdo->NotPresent);
|
||
|
|
||
|
if (currentPdo->Dependent.type1.SubordinateBus < Subordinate) {
|
||
|
|
||
|
currentPdo->Dependent.type1.SubordinateBus = Subordinate;
|
||
|
|
||
|
PciWriteDeviceConfig(currentPdo,
|
||
|
&Subordinate,
|
||
|
FIELD_OFFSET(PCI_COMMON_CONFIG,
|
||
|
u.type1.SubordinateBus),
|
||
|
sizeof(Subordinate)
|
||
|
);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Ok so now we're at the root - can't be too careful on a checked build
|
||
|
// so lets make sure the subordinate value we came up with actually gets
|
||
|
// down this root...
|
||
|
//
|
||
|
|
||
|
ASSERT(PCI_IS_ROOT_FDO(current));
|
||
|
ASSERT(Subordinate <= current->MaxSubordinateBus);
|
||
|
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
PciDisableBridge(
|
||
|
IN PPCI_PDO_EXTENSION Bridge
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This routine disables a bridge by turing of its decodes and zeroing its
|
||
|
bus numbers.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
PdoExtension - The PDO for the bridge
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
node
|
||
|
--*/
|
||
|
|
||
|
|
||
|
{
|
||
|
PAGED_CODE();
|
||
|
|
||
|
ASSERT(Bridge->DeviceState == PciNotStarted);
|
||
|
|
||
|
//
|
||
|
// Zero all the bus numbers so we shouldn't pass any config cycles
|
||
|
//
|
||
|
|
||
|
PciSetBusNumbers(Bridge, 0, 0, 0);
|
||
|
|
||
|
// NTRAID #62594 - 04/03/2000 - andrewth
|
||
|
// Close the windows in case this is the VGA bridge which we must
|
||
|
// leave decoding...
|
||
|
|
||
|
//
|
||
|
// Turn off the decodes so we don't pass IO or Memory cycles and bus
|
||
|
// master so we don't generate any
|
||
|
//
|
||
|
|
||
|
PciDecodeEnable(Bridge, FALSE, NULL);
|
||
|
|
||
|
}
|