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


Reply via email to