1 | /** @file
|
---|
2 | PCI Segment Information Library that returns one segment whose
|
---|
3 | segment base address is retrieved from AcpiBoardInfo HOB.
|
---|
4 |
|
---|
5 | Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
---|
6 | Copyright (c) 2024, Rivos Inc. All rights reserved.<BR>
|
---|
7 |
|
---|
8 | SPDX-License-Identifier: BSD-2-Clause-Patent
|
---|
9 |
|
---|
10 | **/
|
---|
11 |
|
---|
12 | #include <PiDxe.h>
|
---|
13 | #include <Guid/AcpiBoardInfoGuid.h>
|
---|
14 |
|
---|
15 | #include <Library/HobLib.h>
|
---|
16 | #include <Library/PciSegmentInfoLib.h>
|
---|
17 | #include <Library/DebugLib.h>
|
---|
18 | #include <UniversalPayload/PciRootBridges.h>
|
---|
19 | #include <Library/PciLib.h>
|
---|
20 | #include <Library/MemoryAllocationLib.h>
|
---|
21 | #include <Library/PcdLib.h>
|
---|
22 | #include <Library/BaseMemoryLib.h>
|
---|
23 | #include <Guid/PciSegmentInfoGuid.h>
|
---|
24 |
|
---|
25 | static PCI_SEGMENT_INFO *mPciSegments;
|
---|
26 | static UINTN mCount;
|
---|
27 |
|
---|
28 | /**
|
---|
29 | Find segment info from all root bridges
|
---|
30 |
|
---|
31 | @param[in] PciRootBridgeInfo Pointer of Universal Payload PCI Root Bridge Info Hob
|
---|
32 | @param[in] UplSegmentInfo Pointer of Universal UPL Segment Info
|
---|
33 |
|
---|
34 | @param[out] NumberOfRootBridges Number of root bridges detected
|
---|
35 |
|
---|
36 | **/
|
---|
37 | VOID
|
---|
38 | RetrieveMultiSegmentInfoFromHob (
|
---|
39 | IN UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo,
|
---|
40 | IN UPL_PCI_SEGMENT_INFO_HOB *UplSegmentInfo,
|
---|
41 | OUT UINTN *NumberOfRootBridges
|
---|
42 | )
|
---|
43 | {
|
---|
44 | UINTN Size;
|
---|
45 | UINT8 IndexForExistingSegments;
|
---|
46 | UINT8 NumberOfExistingSegments;
|
---|
47 | UINT8 IndexForRb;
|
---|
48 | PCI_SEGMENT_INFO *pPciSegments;
|
---|
49 |
|
---|
50 | if (PciRootBridgeInfo == NULL) {
|
---|
51 | mPciSegments = NULL;
|
---|
52 | return;
|
---|
53 | }
|
---|
54 |
|
---|
55 | IndexForExistingSegments = 0;
|
---|
56 | NumberOfExistingSegments = 0;
|
---|
57 | IndexForRb = 0;
|
---|
58 | Size = PciRootBridgeInfo->Count * sizeof (PCI_SEGMENT_INFO);
|
---|
59 |
|
---|
60 | *NumberOfRootBridges = PciRootBridgeInfo->Count;
|
---|
61 |
|
---|
62 | pPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (Size);
|
---|
63 | if (pPciSegments == NULL) {
|
---|
64 | ASSERT (pPciSegments != NULL);
|
---|
65 | return;
|
---|
66 | }
|
---|
67 |
|
---|
68 | ZeroMem (pPciSegments, PciRootBridgeInfo->Count * sizeof (PCI_SEGMENT_INFO));
|
---|
69 |
|
---|
70 | //
|
---|
71 | // RBs may share the same Segment number, but mPciSegments should not have duplicate segment data.
|
---|
72 | // 1. if RB Segment is same with existing one, update StartBus and EndBus of existing one
|
---|
73 | // 2. if RB Segment is different from all existing ones, add it to the existing Segments data buffer.
|
---|
74 | // pPciSegments is local temporary data buffer that will be freed later (size depends on numbers of RB)
|
---|
75 | // mPciSegments is global data that will be updated with the pPciSegments for caller to utilize. (size depends on numbers of different PciSegments)
|
---|
76 | //
|
---|
77 | NumberOfExistingSegments = 1;
|
---|
78 | pPciSegments[0].BaseAddress = UplSegmentInfo->SegmentInfo[0].BaseAddress;
|
---|
79 | pPciSegments[0].SegmentNumber = (UINT16)(PciRootBridgeInfo->RootBridge[0].Segment);
|
---|
80 | pPciSegments[0].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[0].Bus.Base;
|
---|
81 | pPciSegments[0].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[0].Bus.Limit;
|
---|
82 | for (IndexForRb = 1; IndexForRb < PciRootBridgeInfo->Count; IndexForRb++) {
|
---|
83 | for (IndexForExistingSegments = 0; IndexForExistingSegments < NumberOfExistingSegments; IndexForExistingSegments++) {
|
---|
84 | if (pPciSegments[IndexForExistingSegments].SegmentNumber == PciRootBridgeInfo->RootBridge[IndexForRb].Segment) {
|
---|
85 | if (pPciSegments[IndexForExistingSegments].StartBusNumber > PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Base) {
|
---|
86 | pPciSegments[IndexForExistingSegments].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Base;
|
---|
87 | }
|
---|
88 |
|
---|
89 | if (pPciSegments[IndexForExistingSegments].EndBusNumber < PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Limit) {
|
---|
90 | pPciSegments[IndexForExistingSegments].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Limit;
|
---|
91 | }
|
---|
92 |
|
---|
93 | break; // breaking after a match found
|
---|
94 | }
|
---|
95 | }
|
---|
96 |
|
---|
97 | if (IndexForExistingSegments >= NumberOfExistingSegments) {
|
---|
98 | //
|
---|
99 | // No match found, add it to segments data buffer
|
---|
100 | //
|
---|
101 | pPciSegments[NumberOfExistingSegments].BaseAddress = UplSegmentInfo->SegmentInfo[IndexForRb].BaseAddress;
|
---|
102 | pPciSegments[NumberOfExistingSegments].SegmentNumber = (UINT16)(PciRootBridgeInfo->RootBridge[IndexForRb].Segment);
|
---|
103 | pPciSegments[NumberOfExistingSegments].StartBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Base;
|
---|
104 | pPciSegments[NumberOfExistingSegments].EndBusNumber = (UINT8)PciRootBridgeInfo->RootBridge[IndexForRb].Bus.Limit;
|
---|
105 | NumberOfExistingSegments++;
|
---|
106 | }
|
---|
107 | }
|
---|
108 |
|
---|
109 | //
|
---|
110 | // Prepare data for returning to caller
|
---|
111 | //
|
---|
112 | *NumberOfRootBridges = NumberOfExistingSegments;
|
---|
113 | Size = NumberOfExistingSegments * sizeof (PCI_SEGMENT_INFO);
|
---|
114 | mPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (Size);
|
---|
115 | if (mPciSegments == NULL) {
|
---|
116 | ASSERT (FALSE);
|
---|
117 | return;
|
---|
118 | }
|
---|
119 |
|
---|
120 | CopyMem (&mPciSegments[0], &pPciSegments[0], Size);
|
---|
121 | if (pPciSegments != NULL) {
|
---|
122 | FreePool (pPciSegments);
|
---|
123 | }
|
---|
124 |
|
---|
125 | return;
|
---|
126 | }
|
---|
127 |
|
---|
128 | /**
|
---|
129 | Find segment info from all root bridges for legacy systems
|
---|
130 |
|
---|
131 | @param[in] PciRootBridgeInfo Pointer of Universal Payload PCI Root Bridge Info Hob
|
---|
132 | @param[out] NumberOfRootBridges Number of root bridges detected
|
---|
133 |
|
---|
134 | **/
|
---|
135 | VOID
|
---|
136 | RetrieveSegmentInfoFromHob (
|
---|
137 | OUT UINTN *NumberOfRootBridges
|
---|
138 | )
|
---|
139 | {
|
---|
140 | EFI_HOB_GUID_TYPE *GuidHob;
|
---|
141 | ACPI_BOARD_INFO *AcpiBoardInfo;
|
---|
142 |
|
---|
143 | *NumberOfRootBridges = 1;
|
---|
144 | // old model relies on gUefiAcpiBoardInfoGuid and hardcoded values for single segment only.
|
---|
145 | // This is only for backward compatibility, new platforms should adopt new model even in single segment cases.
|
---|
146 | //
|
---|
147 | mPciSegments = (PCI_SEGMENT_INFO *)AllocatePool (sizeof (PCI_SEGMENT_INFO));
|
---|
148 | ASSERT (mPciSegments != NULL);
|
---|
149 | GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);
|
---|
150 | ASSERT (GuidHob != NULL);
|
---|
151 | if (GuidHob != NULL) {
|
---|
152 | AcpiBoardInfo = (ACPI_BOARD_INFO *)GET_GUID_HOB_DATA (GuidHob);
|
---|
153 | mPciSegments->SegmentNumber = 0;
|
---|
154 | mPciSegments->BaseAddress = AcpiBoardInfo->PcieBaseAddress;
|
---|
155 | mPciSegments->StartBusNumber = 0;
|
---|
156 | mPciSegments->EndBusNumber = 0xFF;
|
---|
157 | }
|
---|
158 | }
|
---|
159 |
|
---|
160 | /**
|
---|
161 | Return info for all root bridges
|
---|
162 |
|
---|
163 | @return All the root bridge info instances in an array.
|
---|
164 | **/
|
---|
165 | UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *
|
---|
166 | Get_RBInfo (
|
---|
167 | VOID
|
---|
168 | )
|
---|
169 | {
|
---|
170 | UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo;
|
---|
171 | EFI_HOB_GUID_TYPE *GuidHob;
|
---|
172 | UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
|
---|
173 |
|
---|
174 | //
|
---|
175 | // Find Universal Payload PCI Root Bridge Info hob
|
---|
176 | //
|
---|
177 | GuidHob = GetFirstGuidHob (&gUniversalPayloadPciRootBridgeInfoGuid);
|
---|
178 | if ((GuidHob == NULL) || (sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob))) {
|
---|
179 | return NULL;
|
---|
180 | }
|
---|
181 |
|
---|
182 | GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);
|
---|
183 | if (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob)) {
|
---|
184 | return NULL;
|
---|
185 | }
|
---|
186 |
|
---|
187 | if ((GenericHeader->Revision != UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION) || (GenericHeader->Length < sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES))) {
|
---|
188 | return NULL;
|
---|
189 | }
|
---|
190 |
|
---|
191 | //
|
---|
192 | // UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES structure is used when Revision equals to UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION
|
---|
193 | //
|
---|
194 | PciRootBridgeInfo = (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *)GET_GUID_HOB_DATA (GuidHob);
|
---|
195 | if (PciRootBridgeInfo->Count <= (GET_GUID_HOB_DATA_SIZE (GuidHob) - sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES)) / sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE)) {
|
---|
196 | return PciRootBridgeInfo;
|
---|
197 | }
|
---|
198 |
|
---|
199 | return NULL;
|
---|
200 | }
|
---|
201 |
|
---|
202 | /**
|
---|
203 | Return info for all root bridge segments
|
---|
204 |
|
---|
205 | @return All the segment info instances in an array.
|
---|
206 | **/
|
---|
207 | UPL_PCI_SEGMENT_INFO_HOB *
|
---|
208 | Get_UPLSegInfo (
|
---|
209 | VOID
|
---|
210 | )
|
---|
211 | {
|
---|
212 | UPL_PCI_SEGMENT_INFO_HOB *UplSegmentInfo;
|
---|
213 | EFI_HOB_GUID_TYPE *GuidHob;
|
---|
214 | UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader;
|
---|
215 |
|
---|
216 | //
|
---|
217 | // Find Universal Payload Segment Info hob
|
---|
218 | //
|
---|
219 | GuidHob = GetFirstGuidHob (&gUplPciSegmentInfoHobGuid);
|
---|
220 | if ((GuidHob == NULL) || (sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) > GET_GUID_HOB_DATA_SIZE (GuidHob))) {
|
---|
221 | return NULL;
|
---|
222 | }
|
---|
223 |
|
---|
224 | GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob);
|
---|
225 | if (GenericHeader->Length > GET_GUID_HOB_DATA_SIZE (GuidHob)) {
|
---|
226 | return NULL;
|
---|
227 | }
|
---|
228 |
|
---|
229 | if ((GenericHeader->Revision != UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION) || (GenericHeader->Length < sizeof (UPL_PCI_SEGMENT_INFO_HOB))) {
|
---|
230 | return NULL;
|
---|
231 | }
|
---|
232 |
|
---|
233 | //
|
---|
234 | // UPL_PCI_SEGMENT_INFO_HOB structure is used when Revision equals to UPL_PCI_SEGMENT_INFO_HOB_REVISION
|
---|
235 | //
|
---|
236 | UplSegmentInfo = (UPL_PCI_SEGMENT_INFO_HOB *)GET_GUID_HOB_DATA (GuidHob);
|
---|
237 | if (UplSegmentInfo->Count <= (GET_GUID_HOB_DATA_SIZE (GuidHob) - sizeof (UPL_PCI_SEGMENT_INFO_HOB)) / sizeof (UPL_SEGMENT_INFO)) {
|
---|
238 | return UplSegmentInfo;
|
---|
239 | }
|
---|
240 |
|
---|
241 | return NULL;
|
---|
242 | }
|
---|
243 |
|
---|
244 | /**
|
---|
245 | Return all the root bridge instances in an array.
|
---|
246 |
|
---|
247 | @param Count Return the count of root bridge instances.
|
---|
248 |
|
---|
249 | @return All the root bridge instances in an array.
|
---|
250 | The array should be passed into PciHostBridgeFreeRootBridges()
|
---|
251 | when it's not used.
|
---|
252 | **/
|
---|
253 | PCI_SEGMENT_INFO *
|
---|
254 | EFIAPI
|
---|
255 | GetPciSegmentInfo (
|
---|
256 | UINTN *Count
|
---|
257 | )
|
---|
258 | {
|
---|
259 | UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo;
|
---|
260 | UPL_PCI_SEGMENT_INFO_HOB *UplSegmentInfo;
|
---|
261 |
|
---|
262 | if (mPciSegments != NULL) {
|
---|
263 | *Count = mCount;
|
---|
264 | return mPciSegments;
|
---|
265 | }
|
---|
266 |
|
---|
267 | UplSegmentInfo = Get_UPLSegInfo ();
|
---|
268 |
|
---|
269 | if (UplSegmentInfo == NULL) {
|
---|
270 | RetrieveSegmentInfoFromHob (Count);
|
---|
271 | } else {
|
---|
272 | PciRootBridgeInfo = Get_RBInfo ();
|
---|
273 | if (PciRootBridgeInfo == NULL) {
|
---|
274 | return 0;
|
---|
275 | }
|
---|
276 |
|
---|
277 | RetrieveMultiSegmentInfoFromHob (PciRootBridgeInfo, UplSegmentInfo, Count);
|
---|
278 | }
|
---|
279 |
|
---|
280 | mCount = *Count;
|
---|
281 | return mPciSegments;
|
---|
282 | }
|
---|