@@ -67,29 +67,92 @@ GetPciSegmentInfo (
6767 return NULL ;
6868 }
6969
70- DEBUG ((DEBUG_INFO , "PCIe: PciSegmentInfoLib: %u segments from MCFG\n" , EntryCount ));
70+ DEBUG ((DEBUG_INFO , "PCIe: PciSegmentInfoLib: %u MCFG entries \n" , EntryCount ));
7171
72+ Entries = (MCFG_ALLOCATION_ENTRY * )(McfgHdr + 1 );
73+
74+ //
75+ // Coalesce MCFG entries that share a PCI Segment Group Number into a single
76+ // PCI_SEGMENT_INFO. The upstream consumer (PciSegmentLibCommon.c) expects
77+ // exactly one entry per segment and matches by segment number alone, and
78+ // PCI_SEGMENT_INFO can hold only one ECAM base per segment.
79+ //
80+ // The PCI Firmware Spec (§4.1.1, §4.1.2 Table 4-3) DOES permit multiple
81+ // same-segment host bridges with distinct, discontinuous ECAM base
82+ // addresses. We do not support that here: this platform's VMM always lays
83+ // same-segment host bridges over a single contiguous ECAM, so every
84+ // same-segment entry carries the same bus-0-relative BaseAddress. We assert
85+ // that invariant and fail loudly if it is ever violated, rather than
86+ // silently dropping a distinct base we cannot represent.
87+ //
88+ // Allocate up to EntryCount slots (upper bound on unique segments).
89+ //
7290 mSegmentInfo = AllocateZeroPool (EntryCount * sizeof (PCI_SEGMENT_INFO ));
7391 if (mSegmentInfo == NULL ) {
7492 DEBUG ((DEBUG_ERROR , "PCIe: PciSegmentInfoLib: Failed to allocate segment info\n" ));
7593 * Count = 0 ;
7694 return NULL ;
7795 }
7896
79- Entries = (MCFG_ALLOCATION_ENTRY * )(McfgHdr + 1 );
80-
97+ //
98+ // Build coalesced entries in a single pass.
99+ //
100+ UINT32 SegIdx = 0 ;
81101 for (i = 0 ; i < EntryCount ; i ++ ) {
82- mSegmentInfo [i ].SegmentNumber = Entries [i ].PciSegmentGroupNumber ;
83- mSegmentInfo [i ].BaseAddress = Entries [i ].BaseAddress ;
84- mSegmentInfo [i ].StartBusNumber = Entries [i ].StartBusNumber ;
85- mSegmentInfo [i ].EndBusNumber = Entries [i ].EndBusNumber ;
102+ UINT32 k ;
103+ BOOLEAN Found = FALSE;
104+
105+ //
106+ // Check if we already have an entry for this segment.
107+ //
108+ for (k = 0 ; k < SegIdx ; k ++ ) {
109+ if (mSegmentInfo [k ].SegmentNumber == Entries [i ].PciSegmentGroupNumber ) {
110+ Found = TRUE;
111+ //
112+ // Validate that the BaseAddress matches the existing entry.
113+ //
114+ if (mSegmentInfo [k ].BaseAddress != Entries [i ].BaseAddress ) {
115+ DEBUG ((DEBUG_ERROR ,
116+ "PCIe: PciSegmentInfoLib: Segment %u has conflicting ECAM bases: "
117+ "%016lx vs %016lx\n" ,
118+ Entries [i ].PciSegmentGroupNumber ,
119+ mSegmentInfo [k ].BaseAddress ,
120+ Entries [i ].BaseAddress ));
121+ ASSERT (FALSE);
122+ FreePool (mSegmentInfo );
123+ mSegmentInfo = NULL ;
124+ * Count = 0 ;
125+ return NULL ;
126+ }
127+ //
128+ // Widen the bus range to encompass this entry.
129+ //
130+ if (Entries [i ].StartBusNumber < mSegmentInfo [k ].StartBusNumber ) {
131+ mSegmentInfo [k ].StartBusNumber = Entries [i ].StartBusNumber ;
132+ }
133+ if (Entries [i ].EndBusNumber > mSegmentInfo [k ].EndBusNumber ) {
134+ mSegmentInfo [k ].EndBusNumber = Entries [i ].EndBusNumber ;
135+ }
136+ break ;
137+ }
138+ }
139+
140+ if (!Found ) {
141+ mSegmentInfo [SegIdx ].SegmentNumber = Entries [i ].PciSegmentGroupNumber ;
142+ mSegmentInfo [SegIdx ].BaseAddress = Entries [i ].BaseAddress ;
143+ mSegmentInfo [SegIdx ].StartBusNumber = Entries [i ].StartBusNumber ;
144+ mSegmentInfo [SegIdx ].EndBusNumber = Entries [i ].EndBusNumber ;
145+ SegIdx ++ ;
146+ }
147+ }
86148
149+ for (i = 0 ; i < SegIdx ; i ++ ) {
87150 DEBUG ((DEBUG_INFO , "PCIe: SegmentInfo[%u]: Seg=%u ECAM=%016lx Bus=%u..%u\n" ,
88- i , Entries [i ].PciSegmentGroupNumber , Entries [i ].BaseAddress ,
89- Entries [i ].StartBusNumber , Entries [i ].EndBusNumber ));
151+ i , mSegmentInfo [i ].SegmentNumber , mSegmentInfo [i ].BaseAddress ,
152+ mSegmentInfo [i ].StartBusNumber , mSegmentInfo [i ].EndBusNumber ));
90153 }
91154
92- mSegmentCount = EntryCount ;
155+ mSegmentCount = SegIdx ;
93156 * Count = mSegmentCount ;
94157 return mSegmentInfo ;
95158}
0 commit comments