CalculateResourceAperture() sizes a PCI bridge's resource window from its children's Length and Alignment, without accounting for a fixed base address assigned to a child BAR by EFI_INCOMPATIBLE_PCI_DEVICE_SUPPORT_PROTOCOL. As a result, the bridge window does not cover the fixed BAR, and ProgramPpbApperture() programs the resource allocator's base instead of the fixed base.
Track Fixed and FixedBase in PCI_RESOURCE_NODE and add ResourceNodeIsFixed() to identify fixed BARs and bridge windows inherited from fixed children. When a bridge has fixed children, CalculateResourceAperture() now sizes and places the bridge window to cover the union of their fixed address ranges. Bridges without fixed children retain the existing behavior. ProgramPpbApperture() also honors FixedBase when programming the bridge window, consistent with ProgramBar() for fixed BARs. Signed-off-by: Tushar Dave <[email protected]> --- .../Bus/Pci/PciBusDxe/PciResourceSupport.c | 110 ++++++++++++++++++ .../Bus/Pci/PciBusDxe/PciResourceSupport.h | 7 ++ 2 files changed, 117 insertions(+) diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c index 169011e647..0aa3465636 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.c @@ -324,6 +324,35 @@ CalculateApertureIo16 ( Bridge->Length = MAX (Bridge->Length, PaddingAperture); } +/** + Return TRUE, with the fixed base address, if Node must be placed at a + specific address instead of anywhere satisfying Length/Alignment. Node is + either a BAR marked fixed by IncompatiblePciDeviceSupport, or a + child bridge whose own window was already determined to be fixed. + + @param Node Resource node to check. + @param FixedBase Fixed base address of Node. + + @retval TRUE Node requires a fixed base address. + @retval FALSE Node has no fixed base address requirement. + +**/ +STATIC +BOOLEAN +ResourceNodeIsFixed ( + IN PCI_RESOURCE_NODE *Node, + OUT UINT64 *FixedBase + ) +{ + if (IS_PCI_BRIDGE (&Node->PciDev->Pci)) { + *FixedBase = Node->FixedBase; + return Node->Fixed; + } + + *FixedBase = Node->PciDev->PciBar[Node->Bar].FixedBaseAddress; + return Node->PciDev->PciBar[Node->Bar].HasFixedBaseAddress; +} + /** This function is used to calculate the resource aperture for a given bridge device. @@ -339,6 +368,10 @@ CalculateResourceAperture ( UINT64 Aperture[2]; LIST_ENTRY *CurrentLink; PCI_RESOURCE_NODE *Node; + UINT64 ChildFixedBase; + UINT64 FixedMin; + UINT64 FixedMax; + UINT64 NextFreeAddr; if (Bridge == NULL) { return; @@ -349,6 +382,71 @@ CalculateResourceAperture ( return; } + // + // If at least one child requires a fixed base address, size and place + // this bridge's window as the exact union of those addresses instead of + // packing children by size and alignment alone. + // + FixedMin = MAX_UINT64; + FixedMax = 0; + for ( CurrentLink = GetFirstNode (&Bridge->ChildList) + ; !IsNull (&Bridge->ChildList, CurrentLink) + ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink) + ) + { + Node = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (ResourceNodeIsFixed (Node, &ChildFixedBase)) { + FixedMin = MIN (FixedMin, ChildFixedBase); + FixedMax = MAX (FixedMax, ChildFixedBase + Node->Length); + } + } + + if (FixedMin < FixedMax) { + Bridge->Fixed = TRUE; + Bridge->FixedBase = FixedMin & ~Bridge->Alignment; + NextFreeAddr = FixedMax; + + for ( CurrentLink = GetFirstNode (&Bridge->ChildList) + ; !IsNull (&Bridge->ChildList, CurrentLink) + ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink) + ) + { + Node = RESOURCE_NODE_FROM_LINK (CurrentLink); + + if (ResourceNodeIsFixed (Node, &ChildFixedBase)) { + Node->Offset = ChildFixedBase - Bridge->FixedBase; + FixedMax = MAX (FixedMax, Node->Offset + Node->Length + Bridge->FixedBase); + + DEBUG ((DEBUG_INFO, + "PciBus: bridge %02x:%02x.%x child %02x:%02x.%x BAR[%d] fixed at 0x%016Lx, length 0x%Lx\n", + Bridge->PciDev->BusNumber, Bridge->PciDev->DeviceNumber, Bridge->PciDev->FunctionNumber, + Node->PciDev->BusNumber, Node->PciDev->DeviceNumber, Node->PciDev->FunctionNumber, + Node->Bar, ChildFixedBase, Node->Length)); + } else { + Node->Offset = ALIGN_VALUE (NextFreeAddr - Bridge->FixedBase, Node->Alignment + 1); + NextFreeAddr = Bridge->FixedBase + Node->Offset + Node->Length; + } + } + + Bridge->Length = ALIGN_VALUE (MAX (FixedMax, NextFreeAddr) - Bridge->FixedBase, Bridge->Alignment + 1); + + DEBUG ((DEBUG_INFO, + "PciBus: bridge %02x:%02x.%x fixed window [0x%016Lx, 0x%016Lx]\n", + Bridge->PciDev->BusNumber, Bridge->PciDev->DeviceNumber, Bridge->PciDev->FunctionNumber, + Bridge->FixedBase, Bridge->FixedBase + Bridge->Length - 1)); + + CurrentLink = Bridge->ChildList.ForwardLink; + if (CurrentLink != &Bridge->ChildList) { + Node = RESOURCE_NODE_FROM_LINK (CurrentLink); + if (Node->Alignment > Bridge->Alignment) { + Bridge->Alignment = Node->Alignment; + } + } + + return; + } + Aperture[PciResUsageTypical] = 0; Aperture[PciResUsagePadding] = 0; // @@ -1468,6 +1566,18 @@ ProgramPpbApperture ( PciIo = &(Node->PciDev->PciIo); Address = Base + Node->Offset; + // + // If CalculateResourceAperture() determined this window must cover a + // fixed BAR, use its base directly. + // + if (Node->Fixed) { + Address = Node->FixedBase; + DEBUG ((DEBUG_INFO, + "PciBus: bridge %02x:%02x.%x fixed window base 0x%016Lx (GCD 0x%016Lx)\n", + Node->PciDev->BusNumber, Node->PciDev->DeviceNumber, Node->PciDev->FunctionNumber, + Address, Base + Node->Offset)); + } + // // Indicate the PPB resource has been allocated // diff --git a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h index 148d9503c8..0682237d74 100644 --- a/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h +++ b/MdeModulePkg/Bus/Pci/PciBusDxe/PciResourceSupport.h @@ -28,6 +28,13 @@ typedef struct { BOOLEAN Reserved; PCI_RESOURCE_USAGE ResourceUsage; BOOLEAN Virtual; + + // + // TRUE if this bridge's aggregate window must be placed at + // FixedBase, because it has at least one fixed descendant. + // + BOOLEAN Fixed; + UINT64 FixedBase; } PCI_RESOURCE_NODE; #define RESOURCE_NODE_FROM_LINK(a) \ -- 2.34.1
