]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciHostBridgeDxe / PciHostBridge.c
CommitLineData
4a50cf4e
RN
1/** @file\r
2\r
3 Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.\r
4\r
0edb7ec5 5Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
4a50cf4e
RN
7\r
8**/\r
9\r
10#include "PciHostBridge.h"\r
11#include "PciRootBridge.h"\r
12#include "PciHostResource.h"\r
13\r
1436aea4 14EFI_CPU_IO2_PROTOCOL *mCpuIo;\r
4a50cf4e 15\r
1436aea4 16GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {\r
4a50cf4e
RN
17 L"Mem", L"I/O", L"Bus"\r
18};\r
1436aea4 19GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {\r
4a50cf4e
RN
20 L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"\r
21};\r
22\r
1436aea4
MK
23EDKII_IOMMU_PROTOCOL *mIoMmu;\r
24EFI_EVENT mIoMmuEvent;\r
25VOID *mIoMmuRegistration;\r
c15da8eb 26\r
74d0a339
HG
27/**\r
28 This routine gets translation offset from a root bridge instance by resource type.\r
29\r
30 @param RootBridge The Root Bridge Instance for the resources.\r
31 @param ResourceType The Resource Type of the translation offset.\r
32\r
33 @retval The Translation Offset of the specified resource.\r
34**/\r
35UINT64\r
36GetTranslationByResourceType (\r
1436aea4
MK
37 IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,\r
38 IN PCI_RESOURCE_TYPE ResourceType\r
74d0a339
HG
39 )\r
40{\r
41 switch (ResourceType) {\r
42 case TypeIo:\r
43 return RootBridge->Io.Translation;\r
44 case TypeMem32:\r
45 return RootBridge->Mem.Translation;\r
46 case TypePMem32:\r
47 return RootBridge->PMem.Translation;\r
48 case TypeMem64:\r
49 return RootBridge->MemAbove4G.Translation;\r
50 case TypePMem64:\r
51 return RootBridge->PMemAbove4G.Translation;\r
52 case TypeBus:\r
53 return RootBridge->Bus.Translation;\r
54 default:\r
55 ASSERT (FALSE);\r
56 return 0;\r
57 }\r
58}\r
59\r
6474f1f1
RN
60/**\r
61 Ensure the compatibility of an IO space descriptor with the IO aperture.\r
62\r
63 The IO space descriptor can come from the GCD IO space map, or it can\r
64 represent a gap between two neighboring IO space descriptors. In the latter\r
65 case, the GcdIoType field is expected to be EfiGcdIoTypeNonExistent.\r
66\r
67 If the IO space descriptor already has type EfiGcdIoTypeIo, then no action is\r
68 taken -- it is by definition compatible with the aperture.\r
69\r
70 Otherwise, the intersection of the IO space descriptor is calculated with the\r
71 aperture. If the intersection is the empty set (no overlap), no action is\r
72 taken; the IO space descriptor is compatible with the aperture.\r
73\r
74 Otherwise, the type of the descriptor is investigated again. If the type is\r
75 EfiGcdIoTypeNonExistent (representing a gap, or a genuine descriptor with\r
76 such a type), then an attempt is made to add the intersection as IO space to\r
77 the GCD IO space map. This ensures continuity for the aperture, and the\r
78 descriptor is deemed compatible with the aperture.\r
79\r
80 Otherwise, the IO space descriptor is incompatible with the IO aperture.\r
81\r
82 @param[in] Base Base address of the aperture.\r
83 @param[in] Length Length of the aperture.\r
84 @param[in] Descriptor The descriptor to ensure compatibility with the\r
85 aperture for.\r
86\r
87 @retval EFI_SUCCESS The descriptor is compatible. The GCD IO space\r
88 map may have been updated, for continuity\r
89 within the aperture.\r
90 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.\r
91 @return Error codes from gDS->AddIoSpace().\r
92**/\r
93EFI_STATUS\r
94IntersectIoDescriptor (\r
1436aea4
MK
95 IN UINT64 Base,\r
96 IN UINT64 Length,\r
97 IN CONST EFI_GCD_IO_SPACE_DESCRIPTOR *Descriptor\r
6474f1f1
RN
98 )\r
99{\r
1436aea4
MK
100 UINT64 IntersectionBase;\r
101 UINT64 IntersectionEnd;\r
102 EFI_STATUS Status;\r
6474f1f1
RN
103\r
104 if (Descriptor->GcdIoType == EfiGcdIoTypeIo) {\r
105 return EFI_SUCCESS;\r
106 }\r
107\r
108 IntersectionBase = MAX (Base, Descriptor->BaseAddress);\r
1436aea4
MK
109 IntersectionEnd = MIN (\r
110 Base + Length,\r
111 Descriptor->BaseAddress + Descriptor->Length\r
112 );\r
6474f1f1
RN
113 if (IntersectionBase >= IntersectionEnd) {\r
114 //\r
115 // The descriptor and the aperture don't overlap.\r
116 //\r
117 return EFI_SUCCESS;\r
118 }\r
119\r
120 if (Descriptor->GcdIoType == EfiGcdIoTypeNonExistent) {\r
1436aea4
MK
121 Status = gDS->AddIoSpace (\r
122 EfiGcdIoTypeIo,\r
123 IntersectionBase,\r
124 IntersectionEnd - IntersectionBase\r
125 );\r
6474f1f1 126\r
1436aea4
MK
127 DEBUG ((\r
128 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
129 "%a: %a: add [%Lx, %Lx): %r\n",\r
130 gEfiCallerBaseName,\r
131 __FUNCTION__,\r
132 IntersectionBase,\r
133 IntersectionEnd,\r
134 Status\r
135 ));\r
6474f1f1
RN
136 return Status;\r
137 }\r
138\r
1436aea4
MK
139 DEBUG ((\r
140 DEBUG_ERROR,\r
141 "%a: %a: desc [%Lx, %Lx) type %u conflicts with "\r
142 "aperture [%Lx, %Lx)\n",\r
143 gEfiCallerBaseName,\r
144 __FUNCTION__,\r
145 Descriptor->BaseAddress,\r
146 Descriptor->BaseAddress + Descriptor->Length,\r
147 (UINT32)Descriptor->GcdIoType,\r
148 Base,\r
149 Base + Length\r
150 ));\r
6474f1f1
RN
151 return EFI_INVALID_PARAMETER;\r
152}\r
153\r
154/**\r
155 Add IO space to GCD.\r
156 The routine checks the GCD database and only adds those which are\r
157 not added in the specified range to GCD.\r
158\r
159 @param Base Base address of the IO space.\r
160 @param Length Length of the IO space.\r
161\r
162 @retval EFI_SUCCES The IO space was added successfully.\r
163**/\r
164EFI_STATUS\r
165AddIoSpace (\r
1436aea4
MK
166 IN UINT64 Base,\r
167 IN UINT64 Length\r
6474f1f1
RN
168 )\r
169{\r
1436aea4
MK
170 EFI_STATUS Status;\r
171 UINTN Index;\r
172 UINTN NumberOfDescriptors;\r
173 EFI_GCD_IO_SPACE_DESCRIPTOR *IoSpaceMap;\r
6474f1f1
RN
174\r
175 Status = gDS->GetIoSpaceMap (&NumberOfDescriptors, &IoSpaceMap);\r
176 if (EFI_ERROR (Status)) {\r
1436aea4
MK
177 DEBUG ((\r
178 DEBUG_ERROR,\r
179 "%a: %a: GetIoSpaceMap(): %r\n",\r
180 gEfiCallerBaseName,\r
181 __FUNCTION__,\r
182 Status\r
183 ));\r
6474f1f1
RN
184 return Status;\r
185 }\r
186\r
187 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
188 Status = IntersectIoDescriptor (Base, Length, &IoSpaceMap[Index]);\r
189 if (EFI_ERROR (Status)) {\r
190 goto FreeIoSpaceMap;\r
191 }\r
192 }\r
193\r
1436aea4
MK
194 DEBUG_CODE_BEGIN ();\r
195 //\r
196 // Make sure there are adjacent descriptors covering [Base, Base + Length).\r
197 // It is possible that they have not been merged; merging can be prevented\r
198 // by allocation.\r
199 //\r
200 UINT64 CheckBase;\r
201 EFI_STATUS CheckStatus;\r
202 EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor;\r
203\r
204 for (CheckBase = Base;\r
205 CheckBase < Base + Length;\r
206 CheckBase = Descriptor.BaseAddress + Descriptor.Length)\r
207 {\r
208 CheckStatus = gDS->GetIoSpaceDescriptor (CheckBase, &Descriptor);\r
209 ASSERT_EFI_ERROR (CheckStatus);\r
210 ASSERT (Descriptor.GcdIoType == EfiGcdIoTypeIo);\r
211 }\r
212\r
213 DEBUG_CODE_END ();\r
6474f1f1
RN
214\r
215FreeIoSpaceMap:\r
216 FreePool (IoSpaceMap);\r
217\r
218 return Status;\r
219}\r
220\r
221/**\r
222 Ensure the compatibility of a memory space descriptor with the MMIO aperture.\r
223\r
224 The memory space descriptor can come from the GCD memory space map, or it can\r
225 represent a gap between two neighboring memory space descriptors. In the\r
226 latter case, the GcdMemoryType field is expected to be\r
227 EfiGcdMemoryTypeNonExistent.\r
228\r
229 If the memory space descriptor already has type\r
230 EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the\r
231 required capabilities, then no action is taken -- it is by definition\r
232 compatible with the aperture.\r
233\r
234 Otherwise, the intersection of the memory space descriptor is calculated with\r
235 the aperture. If the intersection is the empty set (no overlap), no action is\r
236 taken; the memory space descriptor is compatible with the aperture.\r
237\r
238 Otherwise, the type of the descriptor is investigated again. If the type is\r
239 EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with\r
240 such a type), then an attempt is made to add the intersection as MMIO space\r
241 to the GCD memory space map, with the specified capabilities. This ensures\r
242 continuity for the aperture, and the descriptor is deemed compatible with the\r
243 aperture.\r
244\r
245 Otherwise, the memory space descriptor is incompatible with the MMIO\r
246 aperture.\r
247\r
248 @param[in] Base Base address of the aperture.\r
249 @param[in] Length Length of the aperture.\r
250 @param[in] Capabilities Capabilities required by the aperture.\r
251 @param[in] Descriptor The descriptor to ensure compatibility with the\r
252 aperture for.\r
253\r
254 @retval EFI_SUCCESS The descriptor is compatible. The GCD memory\r
255 space map may have been updated, for\r
256 continuity within the aperture.\r
257 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.\r
258 @return Error codes from gDS->AddMemorySpace().\r
259**/\r
260EFI_STATUS\r
261IntersectMemoryDescriptor (\r
1436aea4
MK
262 IN UINT64 Base,\r
263 IN UINT64 Length,\r
264 IN UINT64 Capabilities,\r
265 IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Descriptor\r
6474f1f1
RN
266 )\r
267{\r
1436aea4
MK
268 UINT64 IntersectionBase;\r
269 UINT64 IntersectionEnd;\r
270 EFI_STATUS Status;\r
6474f1f1 271\r
1436aea4
MK
272 if ((Descriptor->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&\r
273 ((Descriptor->Capabilities & Capabilities) == Capabilities))\r
274 {\r
6474f1f1
RN
275 return EFI_SUCCESS;\r
276 }\r
277\r
278 IntersectionBase = MAX (Base, Descriptor->BaseAddress);\r
1436aea4
MK
279 IntersectionEnd = MIN (\r
280 Base + Length,\r
281 Descriptor->BaseAddress + Descriptor->Length\r
282 );\r
6474f1f1
RN
283 if (IntersectionBase >= IntersectionEnd) {\r
284 //\r
285 // The descriptor and the aperture don't overlap.\r
286 //\r
287 return EFI_SUCCESS;\r
288 }\r
289\r
290 if (Descriptor->GcdMemoryType == EfiGcdMemoryTypeNonExistent) {\r
1436aea4
MK
291 Status = gDS->AddMemorySpace (\r
292 EfiGcdMemoryTypeMemoryMappedIo,\r
293 IntersectionBase,\r
294 IntersectionEnd - IntersectionBase,\r
295 Capabilities\r
296 );\r
6474f1f1 297\r
1436aea4
MK
298 DEBUG ((\r
299 EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,\r
300 "%a: %a: add [%Lx, %Lx): %r\n",\r
301 gEfiCallerBaseName,\r
302 __FUNCTION__,\r
303 IntersectionBase,\r
304 IntersectionEnd,\r
305 Status\r
306 ));\r
6474f1f1
RN
307 return Status;\r
308 }\r
309\r
1436aea4
MK
310 DEBUG ((\r
311 DEBUG_ERROR,\r
312 "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "\r
313 "with aperture [%Lx, %Lx) cap %Lx\n",\r
314 gEfiCallerBaseName,\r
315 __FUNCTION__,\r
316 Descriptor->BaseAddress,\r
317 Descriptor->BaseAddress + Descriptor->Length,\r
318 (UINT32)Descriptor->GcdMemoryType,\r
319 Descriptor->Capabilities,\r
320 Base,\r
321 Base + Length,\r
322 Capabilities\r
323 ));\r
6474f1f1
RN
324 return EFI_INVALID_PARAMETER;\r
325}\r
326\r
327/**\r
328 Add MMIO space to GCD.\r
329 The routine checks the GCD database and only adds those which are\r
330 not added in the specified range to GCD.\r
331\r
332 @param Base Base address of the MMIO space.\r
333 @param Length Length of the MMIO space.\r
334 @param Capabilities Capabilities of the MMIO space.\r
335\r
336 @retval EFI_SUCCES The MMIO space was added successfully.\r
337**/\r
338EFI_STATUS\r
339AddMemoryMappedIoSpace (\r
1436aea4
MK
340 IN UINT64 Base,\r
341 IN UINT64 Length,\r
342 IN UINT64 Capabilities\r
6474f1f1
RN
343 )\r
344{\r
1436aea4
MK
345 EFI_STATUS Status;\r
346 UINTN Index;\r
347 UINTN NumberOfDescriptors;\r
348 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap;\r
6474f1f1
RN
349\r
350 Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);\r
351 if (EFI_ERROR (Status)) {\r
1436aea4
MK
352 DEBUG ((\r
353 DEBUG_ERROR,\r
354 "%a: %a: GetMemorySpaceMap(): %r\n",\r
355 gEfiCallerBaseName,\r
356 __FUNCTION__,\r
357 Status\r
358 ));\r
6474f1f1
RN
359 return Status;\r
360 }\r
361\r
362 for (Index = 0; Index < NumberOfDescriptors; Index++) {\r
1436aea4
MK
363 Status = IntersectMemoryDescriptor (\r
364 Base,\r
365 Length,\r
366 Capabilities,\r
367 &MemorySpaceMap[Index]\r
368 );\r
6474f1f1
RN
369 if (EFI_ERROR (Status)) {\r
370 goto FreeMemorySpaceMap;\r
371 }\r
372 }\r
373\r
db52c7f7 374 DEBUG_CODE_BEGIN ();\r
1436aea4
MK
375 //\r
376 // Make sure there are adjacent descriptors covering [Base, Base + Length).\r
377 // It is possible that they have not been merged; merging can be prevented\r
378 // by allocation and different capabilities.\r
379 //\r
380 UINT64 CheckBase;\r
381 EFI_STATUS CheckStatus;\r
382 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
383\r
384 for (CheckBase = Base;\r
385 CheckBase < Base + Length;\r
386 CheckBase = Descriptor.BaseAddress + Descriptor.Length)\r
387 {\r
388 CheckStatus = gDS->GetMemorySpaceDescriptor (CheckBase, &Descriptor);\r
389 ASSERT_EFI_ERROR (CheckStatus);\r
390 ASSERT (Descriptor.GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo);\r
391 ASSERT ((Descriptor.Capabilities & Capabilities) == Capabilities);\r
392 }\r
393\r
db52c7f7 394 DEBUG_CODE_END ();\r
6474f1f1
RN
395\r
396FreeMemorySpaceMap:\r
397 FreePool (MemorySpaceMap);\r
398\r
399 return Status;\r
400}\r
401\r
c15da8eb
JY
402/**\r
403 Event notification that is fired when IOMMU protocol is installed.\r
404\r
405 @param Event The Event that is being processed.\r
406 @param Context Event Context.\r
407\r
408**/\r
409VOID\r
410EFIAPI\r
411IoMmuProtocolCallback (\r
1436aea4
MK
412 IN EFI_EVENT Event,\r
413 IN VOID *Context\r
c15da8eb
JY
414 )\r
415{\r
1436aea4 416 EFI_STATUS Status;\r
c15da8eb 417\r
69b40465 418 Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);\r
1436aea4 419 if (!EFI_ERROR (Status)) {\r
c15da8eb
JY
420 gBS->CloseEvent (mIoMmuEvent);\r
421 }\r
422}\r
423\r
4a50cf4e
RN
424/**\r
425\r
426 Entry point of this driver.\r
427\r
428 @param ImageHandle Image handle of this driver.\r
429 @param SystemTable Pointer to standard EFI system table.\r
430\r
431 @retval EFI_SUCCESS Succeed.\r
432 @retval EFI_DEVICE_ERROR Fail to install PCI_ROOT_BRIDGE_IO protocol.\r
433\r
434**/\r
435EFI_STATUS\r
436EFIAPI\r
437InitializePciHostBridge (\r
1436aea4
MK
438 IN EFI_HANDLE ImageHandle,\r
439 IN EFI_SYSTEM_TABLE *SystemTable\r
4a50cf4e
RN
440 )\r
441{\r
1436aea4
MK
442 EFI_STATUS Status;\r
443 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
444 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
445 PCI_ROOT_BRIDGE *RootBridges;\r
446 UINTN RootBridgeCount;\r
447 UINTN Index;\r
448 PCI_ROOT_BRIDGE_APERTURE *MemApertures[4];\r
449 UINTN MemApertureIndex;\r
450 BOOLEAN ResourceAssigned;\r
451 LIST_ENTRY *Link;\r
452 UINT64 HostAddress;\r
4a50cf4e
RN
453\r
454 RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);\r
455 if ((RootBridges == NULL) || (RootBridgeCount == 0)) {\r
456 return EFI_UNSUPPORTED;\r
457 }\r
458\r
1436aea4 459 Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&mCpuIo);\r
4a50cf4e
RN
460 ASSERT_EFI_ERROR (Status);\r
461\r
462 //\r
463 // Most systems in the world including complex servers have only one Host Bridge.\r
464 //\r
465 HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));\r
466 ASSERT (HostBridge != NULL);\r
467\r
1436aea4
MK
468 HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;\r
469 HostBridge->CanRestarted = TRUE;\r
4a50cf4e 470 InitializeListHead (&HostBridge->RootBridges);\r
1436aea4 471 ResourceAssigned = FALSE;\r
4a50cf4e
RN
472\r
473 //\r
474 // Create Root Bridge Device Handle in this Host Bridge\r
475 //\r
476 for (Index = 0; Index < RootBridgeCount; Index++) {\r
477 //\r
478 // Create Root Bridge Handle Instance\r
479 //\r
401f8cd1 480 RootBridge = CreateRootBridge (&RootBridges[Index]);\r
4a50cf4e
RN
481 ASSERT (RootBridge != NULL);\r
482 if (RootBridge == NULL) {\r
483 continue;\r
484 }\r
485\r
401f8cd1
RN
486 //\r
487 // Make sure all root bridges share the same ResourceAssigned value.\r
488 //\r
489 if (Index == 0) {\r
490 ResourceAssigned = RootBridges[Index].ResourceAssigned;\r
491 } else {\r
492 ASSERT (ResourceAssigned == RootBridges[Index].ResourceAssigned);\r
493 }\r
494\r
f9607bef 495 if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {\r
74d0a339
HG
496 //\r
497 // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
498 // For GCD resource manipulation, we need to use host address.\r
499 //\r
1436aea4
MK
500 HostAddress = TO_HOST_ADDRESS (\r
501 RootBridges[Index].Io.Base,\r
502 RootBridges[Index].Io.Translation\r
503 );\r
74d0a339 504\r
6474f1f1 505 Status = AddIoSpace (\r
74d0a339 506 HostAddress,\r
6474f1f1
RN
507 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1\r
508 );\r
4a50cf4e 509 ASSERT_EFI_ERROR (Status);\r
401f8cd1
RN
510 if (ResourceAssigned) {\r
511 Status = gDS->AllocateIoSpace (\r
512 EfiGcdAllocateAddress,\r
513 EfiGcdIoTypeIo,\r
514 0,\r
515 RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,\r
74d0a339 516 &HostAddress,\r
401f8cd1
RN
517 gImageHandle,\r
518 NULL\r
519 );\r
520 ASSERT_EFI_ERROR (Status);\r
521 }\r
4a50cf4e
RN
522 }\r
523\r
524 //\r
525 // Add all the Mem/PMem aperture to GCD\r
526 // Mem/PMem shouldn't overlap with each other\r
527 // Root bridge which needs to combine MEM and PMEM should only report\r
528 // the MEM aperture in Mem\r
529 //\r
530 MemApertures[0] = &RootBridges[Index].Mem;\r
531 MemApertures[1] = &RootBridges[Index].MemAbove4G;\r
532 MemApertures[2] = &RootBridges[Index].PMem;\r
533 MemApertures[3] = &RootBridges[Index].PMemAbove4G;\r
534\r
5074e406 535 for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {\r
f9607bef 536 if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {\r
74d0a339
HG
537 //\r
538 // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
539 // For GCD resource manipulation, we need to use host address.\r
540 //\r
1436aea4
MK
541 HostAddress = TO_HOST_ADDRESS (\r
542 MemApertures[MemApertureIndex]->Base,\r
543 MemApertures[MemApertureIndex]->Translation\r
544 );\r
6474f1f1 545 Status = AddMemoryMappedIoSpace (\r
74d0a339 546 HostAddress,\r
6474f1f1
RN
547 MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
548 EFI_MEMORY_UC\r
549 );\r
4a50cf4e
RN
550 ASSERT_EFI_ERROR (Status);\r
551 Status = gDS->SetMemorySpaceAttributes (\r
74d0a339 552 HostAddress,\r
4a50cf4e
RN
553 MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
554 EFI_MEMORY_UC\r
555 );\r
13be90fa
RN
556 if (EFI_ERROR (Status)) {\r
557 DEBUG ((DEBUG_WARN, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status));\r
558 }\r
1436aea4 559\r
401f8cd1
RN
560 if (ResourceAssigned) {\r
561 Status = gDS->AllocateMemorySpace (\r
562 EfiGcdAllocateAddress,\r
563 EfiGcdMemoryTypeMemoryMappedIo,\r
564 0,\r
565 MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
74d0a339 566 &HostAddress,\r
401f8cd1
RN
567 gImageHandle,\r
568 NULL\r
569 );\r
570 ASSERT_EFI_ERROR (Status);\r
571 }\r
4a50cf4e
RN
572 }\r
573 }\r
1436aea4 574\r
4a50cf4e
RN
575 //\r
576 // Insert Root Bridge Handle Instance\r
577 //\r
401f8cd1
RN
578 InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);\r
579 }\r
580\r
581 //\r
582 // When resources were assigned, it's not needed to expose\r
583 // PciHostBridgeResourceAllocation protocol.\r
584 //\r
585 if (!ResourceAssigned) {\r
1436aea4
MK
586 HostBridge->ResAlloc.NotifyPhase = NotifyPhase;\r
587 HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;\r
588 HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;\r
589 HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;\r
590 HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;\r
591 HostBridge->ResAlloc.SubmitResources = SubmitResources;\r
401f8cd1
RN
592 HostBridge->ResAlloc.GetProposedResources = GetProposedResources;\r
593 HostBridge->ResAlloc.PreprocessController = PreprocessController;\r
594\r
595 Status = gBS->InstallMultipleProtocolInterfaces (\r
596 &HostBridge->Handle,\r
1436aea4
MK
597 &gEfiPciHostBridgeResourceAllocationProtocolGuid,\r
598 &HostBridge->ResAlloc,\r
401f8cd1
RN
599 NULL\r
600 );\r
601 ASSERT_EFI_ERROR (Status);\r
602 }\r
603\r
604 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
605 ; !IsNull (&HostBridge->RootBridges, Link)\r
606 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
607 )\r
608 {\r
609 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
401f8cd1
RN
610 RootBridge->RootBridgeIo.ParentHandle = HostBridge->Handle;\r
611\r
4a50cf4e
RN
612 Status = gBS->InstallMultipleProtocolInterfaces (\r
613 &RootBridge->Handle,\r
1436aea4
MK
614 &gEfiDevicePathProtocolGuid,\r
615 RootBridge->DevicePath,\r
616 &gEfiPciRootBridgeIoProtocolGuid,\r
617 &RootBridge->RootBridgeIo,\r
4a50cf4e
RN
618 NULL\r
619 );\r
620 ASSERT_EFI_ERROR (Status);\r
4a50cf4e 621 }\r
1436aea4 622\r
4a50cf4e 623 PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);\r
c15da8eb
JY
624\r
625 if (!EFI_ERROR (Status)) {\r
626 mIoMmuEvent = EfiCreateProtocolNotifyEvent (\r
627 &gEdkiiIoMmuProtocolGuid,\r
628 TPL_CALLBACK,\r
629 IoMmuProtocolCallback,\r
630 NULL,\r
631 &mIoMmuRegistration\r
632 );\r
633 }\r
634\r
4a50cf4e
RN
635 return Status;\r
636}\r
637\r
638/**\r
639 This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().\r
640\r
641 @param HostBridge The Host Bridge Instance where the resource adjustment happens.\r
642**/\r
643VOID\r
644ResourceConflict (\r
1436aea4 645 IN PCI_HOST_BRIDGE_INSTANCE *HostBridge\r
4a50cf4e
RN
646 )\r
647{\r
1436aea4
MK
648 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;\r
649 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
650 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
651 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
652 LIST_ENTRY *Link;\r
653 UINTN RootBridgeCount;\r
654 PCI_RESOURCE_TYPE Index;\r
655 PCI_RES_NODE *ResAllocNode;\r
4a50cf4e
RN
656\r
657 RootBridgeCount = 0;\r
658 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
659 ; !IsNull (&HostBridge->RootBridges, Link)\r
660 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
661 )\r
662 {\r
4a50cf4e
RN
663 RootBridgeCount++;\r
664 }\r
665\r
666 Resources = AllocatePool (\r
667 RootBridgeCount * (TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)) +\r
668 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)\r
669 );\r
670 ASSERT (Resources != NULL);\r
671\r
672 for (Link = GetFirstNode (&HostBridge->RootBridges), Descriptor = Resources\r
673 ; !IsNull (&HostBridge->RootBridges, Link)\r
674 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
675 )\r
676 {\r
4a50cf4e
RN
677 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
678 for (Index = TypeIo; Index < TypeMax; Index++) {\r
679 ResAllocNode = &RootBridge->ResAllocNode[Index];\r
680\r
1436aea4
MK
681 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
682 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
4a50cf4e
RN
683 Descriptor->AddrRangeMin = ResAllocNode->Base;\r
684 Descriptor->AddrRangeMax = ResAllocNode->Alignment;\r
f5452566
RN
685 Descriptor->AddrLen = ResAllocNode->Length;\r
686 Descriptor->SpecificFlag = 0;\r
4a50cf4e 687 switch (ResAllocNode->Type) {\r
1436aea4
MK
688 case TypeIo:\r
689 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
690 break;\r
691\r
692 case TypePMem32:\r
693 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
694 case TypeMem32:\r
695 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
696 Descriptor->AddrSpaceGranularity = 32;\r
697 break;\r
698\r
699 case TypePMem64:\r
700 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
701 case TypeMem64:\r
702 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
703 Descriptor->AddrSpaceGranularity = 64;\r
704 break;\r
705\r
706 case TypeBus:\r
707 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
708 break;\r
4a50cf4e 709\r
1436aea4
MK
710 default:\r
711 break;\r
4a50cf4e
RN
712 }\r
713\r
714 Descriptor++;\r
715 }\r
1436aea4 716\r
4a50cf4e
RN
717 //\r
718 // Terminate the root bridge resources.\r
719 //\r
1436aea4
MK
720 End = (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor;\r
721 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
4a50cf4e
RN
722 End->Checksum = 0x0;\r
723\r
1436aea4 724 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(End + 1);\r
4a50cf4e 725 }\r
1436aea4 726\r
4a50cf4e
RN
727 //\r
728 // Terminate the host bridge resources.\r
729 //\r
1436aea4
MK
730 End = (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor;\r
731 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
4a50cf4e
RN
732 End->Checksum = 0x0;\r
733\r
734 DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));\r
735 PciHostBridgeResourceConflict (HostBridge->Handle, Resources);\r
736 FreePool (Resources);\r
737}\r
738\r
63b90643
RN
739/**\r
740 Allocate Length of MMIO or IO resource with alignment BitsOfAlignment\r
741 from GCD range [BaseAddress, Limit).\r
742\r
743 @param Mmio TRUE for MMIO and FALSE for IO.\r
744 @param Length Length of the resource to allocate.\r
745 @param BitsOfAlignment Alignment of the resource to allocate.\r
746 @param BaseAddress The starting address the allocation is from.\r
747 @param Limit The ending address the allocation is to.\r
748\r
749 @retval The base address of the allocated resource or MAX_UINT64 if allocation\r
750 fails.\r
751**/\r
4a50cf4e
RN
752UINT64\r
753AllocateResource (\r
1436aea4
MK
754 BOOLEAN Mmio,\r
755 UINT64 Length,\r
756 UINTN BitsOfAlignment,\r
757 UINT64 BaseAddress,\r
758 UINT64 Limit\r
4a50cf4e
RN
759 )\r
760{\r
1436aea4 761 EFI_STATUS Status;\r
4a50cf4e
RN
762\r
763 if (BaseAddress < Limit) {\r
764 //\r
765 // Have to make sure Aligment is handled since we are doing direct address allocation\r
74d0a339
HG
766 // Strictly speaking, alignment requirement should be applied to device\r
767 // address instead of host address which is used in GCD manipulation below,\r
768 // but as we restrict the alignment of Translation to be larger than any BAR\r
769 // alignment in the root bridge, we can simplify the situation and consider\r
770 // the same alignment requirement is also applied to host address.\r
4a50cf4e
RN
771 //\r
772 BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));\r
773\r
774 while (BaseAddress + Length <= Limit + 1) {\r
775 if (Mmio) {\r
776 Status = gDS->AllocateMemorySpace (\r
777 EfiGcdAllocateAddress,\r
778 EfiGcdMemoryTypeMemoryMappedIo,\r
779 BitsOfAlignment,\r
780 Length,\r
781 &BaseAddress,\r
782 gImageHandle,\r
783 NULL\r
784 );\r
785 } else {\r
786 Status = gDS->AllocateIoSpace (\r
787 EfiGcdAllocateAddress,\r
788 EfiGcdIoTypeIo,\r
789 BitsOfAlignment,\r
790 Length,\r
791 &BaseAddress,\r
792 gImageHandle,\r
793 NULL\r
794 );\r
795 }\r
796\r
797 if (!EFI_ERROR (Status)) {\r
798 return BaseAddress;\r
799 }\r
1436aea4 800\r
4a50cf4e
RN
801 BaseAddress += LShiftU64 (1, BitsOfAlignment);\r
802 }\r
803 }\r
1436aea4 804\r
4a50cf4e
RN
805 return MAX_UINT64;\r
806}\r
63b90643 807\r
4a50cf4e
RN
808/**\r
809\r
810 Enter a certain phase of the PCI enumeration process.\r
811\r
812 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.\r
813 @param Phase The phase during enumeration.\r
814\r
815 @retval EFI_SUCCESS Succeed.\r
816 @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.\r
817 @retval EFI_NOT_READY Resources have not been submitted yet.\r
818\r
819**/\r
820EFI_STATUS\r
821EFIAPI\r
822NotifyPhase (\r
1436aea4
MK
823 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
824 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase\r
4a50cf4e
RN
825 )\r
826{\r
1436aea4
MK
827 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
828 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
829 LIST_ENTRY *Link;\r
830 EFI_PHYSICAL_ADDRESS BaseAddress;\r
831 UINTN BitsOfAlignment;\r
832 UINT64 Alignment;\r
833 EFI_STATUS Status;\r
834 EFI_STATUS ReturnStatus;\r
835 PCI_RESOURCE_TYPE Index;\r
836 PCI_RESOURCE_TYPE Index1;\r
837 PCI_RESOURCE_TYPE Index2;\r
838 BOOLEAN ResNodeHandled[TypeMax];\r
839 UINT64 MaxAlignment;\r
840 UINT64 Translation;\r
4a50cf4e
RN
841\r
842 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
843\r
844 switch (Phase) {\r
1436aea4
MK
845 case EfiPciHostBridgeBeginEnumeration:\r
846 if (!HostBridge->CanRestarted) {\r
847 return EFI_NOT_READY;\r
4a50cf4e 848 }\r
4a50cf4e 849\r
1436aea4
MK
850 //\r
851 // Reset Root Bridge\r
852 //\r
853 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
854 ; !IsNull (&HostBridge->RootBridges, Link)\r
855 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
856 )\r
857 {\r
858 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
859 for (Index = TypeIo; Index < TypeMax; Index++) {\r
860 RootBridge->ResAllocNode[Index].Type = Index;\r
861 RootBridge->ResAllocNode[Index].Base = 0;\r
862 RootBridge->ResAllocNode[Index].Length = 0;\r
863 RootBridge->ResAllocNode[Index].Status = ResNone;\r
864\r
865 RootBridge->ResourceSubmitted = FALSE;\r
866 }\r
867 }\r
4a50cf4e 868\r
1436aea4
MK
869 HostBridge->CanRestarted = TRUE;\r
870 break;\r
4a50cf4e 871\r
1436aea4
MK
872 case EfiPciHostBridgeBeginBusAllocation:\r
873 //\r
874 // No specific action is required here, can perform any chipset specific programing\r
875 //\r
876 HostBridge->CanRestarted = FALSE;\r
877 break;\r
4a50cf4e 878\r
1436aea4
MK
879 case EfiPciHostBridgeEndBusAllocation:\r
880 //\r
881 // No specific action is required here, can perform any chipset specific programing\r
882 //\r
883 break;\r
4a50cf4e 884\r
1436aea4
MK
885 case EfiPciHostBridgeBeginResourceAllocation:\r
886 //\r
887 // No specific action is required here, can perform any chipset specific programing\r
888 //\r
889 break;\r
4a50cf4e 890\r
1436aea4
MK
891 case EfiPciHostBridgeAllocateResources:\r
892 ReturnStatus = EFI_SUCCESS;\r
4a50cf4e 893\r
1436aea4
MK
894 //\r
895 // Make sure the resource for all root bridges has been submitted.\r
896 //\r
897 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
898 ; !IsNull (&HostBridge->RootBridges, Link)\r
899 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
900 )\r
901 {\r
902 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
903 if (!RootBridge->ResourceSubmitted) {\r
904 return EFI_NOT_READY;\r
905 }\r
4a50cf4e
RN
906 }\r
907\r
1436aea4
MK
908 DEBUG ((DEBUG_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));\r
909 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
910 ; !IsNull (&HostBridge->RootBridges, Link)\r
911 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
912 )\r
913 {\r
914 for (Index = TypeIo; Index < TypeBus; Index++) {\r
915 ResNodeHandled[Index] = FALSE;\r
916 }\r
4a50cf4e 917\r
1436aea4
MK
918 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
919 DEBUG ((DEBUG_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));\r
4a50cf4e 920\r
1436aea4
MK
921 for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {\r
922 if (RootBridge->ResAllocNode[Index1].Status == ResNone) {\r
923 ResNodeHandled[Index1] = TRUE;\r
924 } else {\r
74d0a339 925 //\r
1436aea4 926 // Allocate the resource node with max alignment at first\r
74d0a339 927 //\r
1436aea4
MK
928 MaxAlignment = 0;\r
929 Index = TypeMax;\r
930 for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {\r
931 if (ResNodeHandled[Index2]) {\r
932 continue;\r
933 }\r
934\r
935 if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {\r
936 MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;\r
937 Index = Index2;\r
938 }\r
939 }\r
74d0a339 940\r
1436aea4
MK
941 ASSERT (Index < TypeMax);\r
942 ResNodeHandled[Index] = TRUE;\r
943 Alignment = RootBridge->ResAllocNode[Index].Alignment;\r
944 BitsOfAlignment = LowBitSet64 (Alignment + 1);\r
945 BaseAddress = MAX_UINT64;\r
4a50cf4e 946\r
4a50cf4e 947 //\r
1436aea4
MK
948 // RESTRICTION: To simplify the situation, we require the alignment of\r
949 // Translation must be larger than any BAR alignment in the same root\r
950 // bridge, so that resource allocation alignment can be applied to\r
951 // both device address and host address.\r
4a50cf4e 952 //\r
1436aea4
MK
953 Translation = GetTranslationByResourceType (RootBridge, Index);\r
954 if ((Translation & Alignment) != 0) {\r
955 DEBUG ((\r
956 DEBUG_ERROR,\r
957 "[%a:%d] Translation %lx is not aligned to %lx!\n",\r
958 __FUNCTION__,\r
959 DEBUG_LINE_NUMBER,\r
960 Translation,\r
961 Alignment\r
962 ));\r
963 ASSERT ((Translation & Alignment) == 0);\r
964 //\r
965 // This may be caused by too large alignment or too small\r
966 // Translation; pick the 1st possibility and return out of resource,\r
967 // which can also go thru the same process for out of resource\r
968 // outside the loop.\r
969 //\r
970 ReturnStatus = EFI_OUT_OF_RESOURCES;\r
971 continue;\r
972 }\r
4a50cf4e 973\r
1436aea4
MK
974 switch (Index) {\r
975 case TypeIo:\r
976 //\r
977 // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
978 // For AllocateResource is manipulating GCD resource, we need to use\r
979 // host address here.\r
980 //\r
981 BaseAddress = AllocateResource (\r
982 FALSE,\r
983 RootBridge->ResAllocNode[Index].Length,\r
984 MIN (15, BitsOfAlignment),\r
985 TO_HOST_ADDRESS (\r
986 ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
987 RootBridge->Io.Translation\r
988 ),\r
989 TO_HOST_ADDRESS (\r
990 RootBridge->Io.Limit,\r
991 RootBridge->Io.Translation\r
992 )\r
993 );\r
994 break;\r
995\r
996 case TypeMem64:\r
997 BaseAddress = AllocateResource (\r
998 TRUE,\r
999 RootBridge->ResAllocNode[Index].Length,\r
1000 MIN (63, BitsOfAlignment),\r
1001 TO_HOST_ADDRESS (\r
1002 ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
1003 RootBridge->MemAbove4G.Translation\r
1004 ),\r
1005 TO_HOST_ADDRESS (\r
1006 RootBridge->MemAbove4G.Limit,\r
1007 RootBridge->MemAbove4G.Translation\r
1008 )\r
1009 );\r
1010 if (BaseAddress != MAX_UINT64) {\r
1011 break;\r
1012 }\r
1013\r
1014 //\r
1015 // If memory above 4GB is not available, try memory below 4GB\r
1016 //\r
1017\r
1018 case TypeMem32:\r
1019 BaseAddress = AllocateResource (\r
1020 TRUE,\r
1021 RootBridge->ResAllocNode[Index].Length,\r
1022 MIN (31, BitsOfAlignment),\r
1023 TO_HOST_ADDRESS (\r
1024 ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
1025 RootBridge->Mem.Translation\r
1026 ),\r
1027 TO_HOST_ADDRESS (\r
1028 RootBridge->Mem.Limit,\r
1029 RootBridge->Mem.Translation\r
1030 )\r
1031 );\r
1032 break;\r
1033\r
1034 case TypePMem64:\r
1035 BaseAddress = AllocateResource (\r
1036 TRUE,\r
1037 RootBridge->ResAllocNode[Index].Length,\r
1038 MIN (63, BitsOfAlignment),\r
1039 TO_HOST_ADDRESS (\r
1040 ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
1041 RootBridge->PMemAbove4G.Translation\r
1042 ),\r
1043 TO_HOST_ADDRESS (\r
1044 RootBridge->PMemAbove4G.Limit,\r
1045 RootBridge->PMemAbove4G.Translation\r
1046 )\r
1047 );\r
1048 if (BaseAddress != MAX_UINT64) {\r
1049 break;\r
1050 }\r
1051\r
1052 //\r
1053 // If memory above 4GB is not available, try memory below 4GB\r
1054 //\r
1055 case TypePMem32:\r
1056 BaseAddress = AllocateResource (\r
1057 TRUE,\r
1058 RootBridge->ResAllocNode[Index].Length,\r
1059 MIN (31, BitsOfAlignment),\r
1060 TO_HOST_ADDRESS (\r
1061 ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
1062 RootBridge->PMem.Translation\r
1063 ),\r
1064 TO_HOST_ADDRESS (\r
1065 RootBridge->PMem.Limit,\r
1066 RootBridge->PMem.Translation\r
1067 )\r
1068 );\r
1069 break;\r
1070\r
1071 default:\r
1072 ASSERT (FALSE);\r
1073 break;\r
1074 }\r
4a50cf4e 1075\r
1436aea4
MK
1076 DEBUG ((\r
1077 DEBUG_INFO,\r
1078 " %s: Base/Length/Alignment = %lx/%lx/%lx - ",\r
1079 mPciResourceTypeStr[Index],\r
1080 BaseAddress,\r
1081 RootBridge->ResAllocNode[Index].Length,\r
1082 Alignment\r
1083 ));\r
4a50cf4e 1084 if (BaseAddress != MAX_UINT64) {\r
1436aea4
MK
1085 RootBridge->ResAllocNode[Index].Base = BaseAddress;\r
1086 RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
1087 DEBUG ((DEBUG_INFO, "Success\n"));\r
1088 } else {\r
1089 ReturnStatus = EFI_OUT_OF_RESOURCES;\r
1090 DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));\r
4a50cf4e 1091 }\r
4a50cf4e
RN
1092 }\r
1093 }\r
1094 }\r
4a50cf4e 1095\r
1436aea4
MK
1096 if (ReturnStatus == EFI_OUT_OF_RESOURCES) {\r
1097 ResourceConflict (HostBridge);\r
1098 }\r
4a50cf4e 1099\r
1436aea4
MK
1100 //\r
1101 // Set resource to zero for nodes where allocation fails\r
1102 //\r
1103 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1104 ; !IsNull (&HostBridge->RootBridges, Link)\r
1105 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1106 )\r
1107 {\r
1108 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1109 for (Index = TypeIo; Index < TypeBus; Index++) {\r
1110 if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {\r
1111 RootBridge->ResAllocNode[Index].Length = 0;\r
1112 }\r
4a50cf4e
RN
1113 }\r
1114 }\r
4a50cf4e 1115\r
1436aea4 1116 return ReturnStatus;\r
4a50cf4e 1117\r
1436aea4
MK
1118 case EfiPciHostBridgeSetResources:\r
1119 //\r
1120 // HostBridgeInstance->CanRestarted = FALSE;\r
1121 //\r
1122 break;\r
4a50cf4e 1123\r
1436aea4
MK
1124 case EfiPciHostBridgeFreeResources:\r
1125 //\r
1126 // HostBridgeInstance->CanRestarted = FALSE;\r
1127 //\r
1128 ReturnStatus = EFI_SUCCESS;\r
1129 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1130 ; !IsNull (&HostBridge->RootBridges, Link)\r
1131 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1132 )\r
1133 {\r
1134 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1135 for (Index = TypeIo; Index < TypeBus; Index++) {\r
1136 if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {\r
1137 switch (Index) {\r
1138 case TypeIo:\r
1139 Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);\r
1140 if (EFI_ERROR (Status)) {\r
1141 ReturnStatus = Status;\r
1142 }\r
1143\r
1144 break;\r
1145\r
1146 case TypeMem32:\r
1147 case TypePMem32:\r
1148 case TypeMem64:\r
1149 case TypePMem64:\r
1150 Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);\r
1151 if (EFI_ERROR (Status)) {\r
1152 ReturnStatus = Status;\r
1153 }\r
1154\r
1155 break;\r
1156\r
1157 default:\r
1158 ASSERT (FALSE);\r
1159 break;\r
4a50cf4e 1160 }\r
4a50cf4e 1161\r
1436aea4
MK
1162 RootBridge->ResAllocNode[Index].Type = Index;\r
1163 RootBridge->ResAllocNode[Index].Base = 0;\r
1164 RootBridge->ResAllocNode[Index].Length = 0;\r
1165 RootBridge->ResAllocNode[Index].Status = ResNone;\r
4a50cf4e 1166 }\r
4a50cf4e 1167 }\r
4a50cf4e 1168\r
1436aea4
MK
1169 RootBridge->ResourceSubmitted = FALSE;\r
1170 }\r
4a50cf4e 1171\r
1436aea4
MK
1172 HostBridge->CanRestarted = TRUE;\r
1173 return ReturnStatus;\r
4a50cf4e 1174\r
1436aea4
MK
1175 case EfiPciHostBridgeEndResourceAllocation:\r
1176 //\r
1177 // The resource allocation phase is completed. No specific action is required\r
1178 // here. This notification can be used to perform any chipset specific programming.\r
1179 //\r
1180 break;\r
4a50cf4e 1181\r
1436aea4
MK
1182 case EfiPciHostBridgeEndEnumeration:\r
1183 //\r
1184 // The Host Bridge Enumeration is completed. No specific action is required here.\r
1185 // This notification can be used to perform any chipset specific programming.\r
1186 //\r
1187 break;\r
4a50cf4e 1188\r
1436aea4
MK
1189 default:\r
1190 return EFI_INVALID_PARAMETER;\r
4a50cf4e
RN
1191 }\r
1192\r
1193 return EFI_SUCCESS;\r
1194}\r
1195\r
1196/**\r
1197\r
1198 Return the device handle of the next PCI root bridge that is associated with\r
1199 this Host Bridge.\r
1200\r
1201 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1202 @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.\r
1203 On input, it holds the RootBridgeHandle returned by the most\r
1204 recent call to GetNextRootBridge().The handle for the first\r
1205 PCI Root Bridge is returned if RootBridgeHandle is NULL on input.\r
1206\r
1207 @retval EFI_SUCCESS Succeed.\r
1208 @retval EFI_NOT_FOUND Next PCI root bridge not found.\r
1209 @retval EFI_INVALID_PARAMETER Wrong parameter passed in.\r
1210\r
1211**/\r
1212EFI_STATUS\r
1213EFIAPI\r
1214GetNextRootBridge (\r
1436aea4
MK
1215 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1216 IN OUT EFI_HANDLE *RootBridgeHandle\r
4a50cf4e
RN
1217 )\r
1218{\r
1219 BOOLEAN ReturnNext;\r
1220 LIST_ENTRY *Link;\r
1221 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1222 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1223\r
1224 if (RootBridgeHandle == NULL) {\r
1225 return EFI_INVALID_PARAMETER;\r
1226 }\r
1227\r
1228 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1436aea4 1229 ReturnNext = (BOOLEAN)(*RootBridgeHandle == NULL);\r
4a50cf4e
RN
1230\r
1231 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1436aea4
MK
1232 ; !IsNull (&HostBridge->RootBridges, Link)\r
1233 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1234 )\r
1235 {\r
4a50cf4e
RN
1236 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1237 if (ReturnNext) {\r
1238 *RootBridgeHandle = RootBridge->Handle;\r
1239 return EFI_SUCCESS;\r
1240 }\r
1241\r
1436aea4 1242 ReturnNext = (BOOLEAN)(*RootBridgeHandle == RootBridge->Handle);\r
4a50cf4e
RN
1243 }\r
1244\r
1245 if (ReturnNext) {\r
1246 ASSERT (IsNull (&HostBridge->RootBridges, Link));\r
1247 return EFI_NOT_FOUND;\r
1248 } else {\r
1249 return EFI_INVALID_PARAMETER;\r
1250 }\r
1251}\r
1252\r
1253/**\r
1254\r
1255 Returns the attributes of a PCI Root Bridge.\r
1256\r
1257 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1258 @param RootBridgeHandle The device handle of the PCI Root Bridge\r
1259 that the caller is interested in.\r
1260 @param Attributes The pointer to attributes of the PCI Root Bridge.\r
1261\r
1262 @retval EFI_SUCCESS Succeed.\r
1263 @retval EFI_INVALID_PARAMETER Attributes parameter passed in is NULL or\r
1264 RootBridgeHandle is not an EFI_HANDLE\r
1265 that was returned on a previous call to\r
1266 GetNextRootBridge().\r
1267\r
1268**/\r
1269EFI_STATUS\r
1270EFIAPI\r
1271GetAttributes (\r
1436aea4
MK
1272 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1273 IN EFI_HANDLE RootBridgeHandle,\r
1274 OUT UINT64 *Attributes\r
4a50cf4e
RN
1275 )\r
1276{\r
1277 LIST_ENTRY *Link;\r
1278 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1279 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1280\r
1281 if (Attributes == NULL) {\r
1282 return EFI_INVALID_PARAMETER;\r
1283 }\r
1284\r
1285 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1286 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1436aea4
MK
1287 ; !IsNull (&HostBridge->RootBridges, Link)\r
1288 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1289 )\r
1290 {\r
4a50cf4e
RN
1291 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1292 if (RootBridgeHandle == RootBridge->Handle) {\r
1293 *Attributes = RootBridge->AllocationAttributes;\r
1294 return EFI_SUCCESS;\r
1295 }\r
1296 }\r
1297\r
1298 return EFI_INVALID_PARAMETER;\r
1299}\r
1300\r
1301/**\r
1302\r
1303 This is the request from the PCI enumerator to set up\r
1304 the specified PCI Root Bridge for bus enumeration process.\r
1305\r
1306 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1307 @param RootBridgeHandle The PCI Root Bridge to be set up.\r
1308 @param Configuration Pointer to the pointer to the PCI bus resource descriptor.\r
1309\r
1310 @retval EFI_SUCCESS Succeed.\r
1311 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.\r
1312 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1313\r
1314**/\r
1315EFI_STATUS\r
1316EFIAPI\r
1317StartBusEnumeration (\r
1436aea4
MK
1318 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1319 IN EFI_HANDLE RootBridgeHandle,\r
1320 OUT VOID **Configuration\r
4a50cf4e
RN
1321 )\r
1322{\r
1436aea4
MK
1323 LIST_ENTRY *Link;\r
1324 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1325 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1326 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1327 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
4a50cf4e
RN
1328\r
1329 if (Configuration == NULL) {\r
1330 return EFI_INVALID_PARAMETER;\r
1331 }\r
1332\r
1333 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1334 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1335 ; !IsNull (&HostBridge->RootBridges, Link)\r
1336 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
1337 )\r
1338 {\r
4a50cf4e
RN
1339 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1340 if (RootBridgeHandle == RootBridge->Handle) {\r
1341 *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1342 if (*Configuration == NULL) {\r
1343 return EFI_OUT_OF_RESOURCES;\r
1344 }\r
1345\r
1436aea4 1346 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)*Configuration;\r
4a50cf4e
RN
1347 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1348 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
1349 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;\r
1350 Descriptor->GenFlag = 0;\r
1351 Descriptor->SpecificFlag = 0;\r
1352 Descriptor->AddrSpaceGranularity = 0;\r
1353 Descriptor->AddrRangeMin = RootBridge->Bus.Base;\r
1354 Descriptor->AddrRangeMax = 0;\r
1355 Descriptor->AddrTranslationOffset = 0;\r
1356 Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;\r
1357\r
1436aea4
MK
1358 End = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Descriptor + 1);\r
1359 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
4a50cf4e
RN
1360 End->Checksum = 0x0;\r
1361\r
1362 return EFI_SUCCESS;\r
1363 }\r
1364 }\r
1365\r
1366 return EFI_INVALID_PARAMETER;\r
1367}\r
1368\r
1369/**\r
1370\r
1371 This function programs the PCI Root Bridge hardware so that\r
1372 it decodes the specified PCI bus range.\r
1373\r
1374 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1375 @param RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed.\r
1376 @param Configuration The pointer to the PCI bus resource descriptor.\r
1377\r
1378 @retval EFI_SUCCESS Succeed.\r
1379 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.\r
1380\r
1381**/\r
1382EFI_STATUS\r
1383EFIAPI\r
1384SetBusNumbers (\r
1436aea4
MK
1385 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1386 IN EFI_HANDLE RootBridgeHandle,\r
1387 IN VOID *Configuration\r
4a50cf4e
RN
1388 )\r
1389{\r
1436aea4
MK
1390 LIST_ENTRY *Link;\r
1391 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1392 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1393 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1394 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
4a50cf4e
RN
1395\r
1396 if (Configuration == NULL) {\r
1397 return EFI_INVALID_PARAMETER;\r
1398 }\r
1399\r
1436aea4
MK
1400 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;\r
1401 End = (EFI_ACPI_END_TAG_DESCRIPTOR *)(Descriptor + 1);\r
4a50cf4e
RN
1402\r
1403 //\r
1404 // Check the Configuration is valid\r
1405 //\r
1406 if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||\r
1407 (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||\r
1408 (End->Desc != ACPI_END_TAG_DESCRIPTOR)\r
1436aea4
MK
1409 )\r
1410 {\r
4a50cf4e
RN
1411 return EFI_INVALID_PARAMETER;\r
1412 }\r
1413\r
1414 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1415 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1416 ; !IsNull (&HostBridge->RootBridges, Link)\r
1417 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
1418 )\r
1419 {\r
4a50cf4e
RN
1420 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1421 if (RootBridgeHandle == RootBridge->Handle) {\r
4a50cf4e
RN
1422 if (Descriptor->AddrLen == 0) {\r
1423 return EFI_INVALID_PARAMETER;\r
1424 }\r
1425\r
1426 if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||\r
1427 (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)\r
1436aea4
MK
1428 )\r
1429 {\r
4a50cf4e
RN
1430 return EFI_INVALID_PARAMETER;\r
1431 }\r
1436aea4 1432\r
4a50cf4e
RN
1433 //\r
1434 // Update the Bus Range\r
1435 //\r
1436aea4
MK
1436 RootBridge->ResAllocNode[TypeBus].Base = Descriptor->AddrRangeMin;\r
1437 RootBridge->ResAllocNode[TypeBus].Length = Descriptor->AddrLen;\r
1438 RootBridge->ResAllocNode[TypeBus].Status = ResAllocated;\r
4a50cf4e
RN
1439 return EFI_SUCCESS;\r
1440 }\r
1441 }\r
1442\r
1443 return EFI_INVALID_PARAMETER;\r
1444}\r
1445\r
1446/**\r
1447\r
1448 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.\r
1449\r
1450 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1451 @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements.\r
1452 are being submitted.\r
1453 @param Configuration The pointer to the PCI I/O and PCI memory resource descriptor.\r
1454\r
1455 @retval EFI_SUCCESS Succeed.\r
1456 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.\r
1457**/\r
1458EFI_STATUS\r
1459EFIAPI\r
1460SubmitResources (\r
1436aea4
MK
1461 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1462 IN EFI_HANDLE RootBridgeHandle,\r
1463 IN VOID *Configuration\r
4a50cf4e
RN
1464 )\r
1465{\r
1436aea4
MK
1466 LIST_ENTRY *Link;\r
1467 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1468 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1469 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1470 PCI_RESOURCE_TYPE Type;\r
4a50cf4e
RN
1471\r
1472 //\r
1473 // Check the input parameter: Configuration\r
1474 //\r
1475 if (Configuration == NULL) {\r
1476 return EFI_INVALID_PARAMETER;\r
1477 }\r
1478\r
1479 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1480 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1481 ; !IsNull (&HostBridge->RootBridges, Link)\r
1482 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
1483 )\r
1484 {\r
4a50cf4e
RN
1485 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1486 if (RootBridgeHandle == RootBridge->Handle) {\r
87000d77 1487 DEBUG ((DEBUG_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));\r
4a50cf4e
RN
1488 //\r
1489 // Check the resource descriptors.\r
1490 // If the Configuration includes one or more invalid resource descriptors, all the resource\r
1491 // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.\r
1492 //\r
1436aea4 1493 for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
4a50cf4e
RN
1494 if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1495 return EFI_INVALID_PARAMETER;\r
1496 }\r
1497\r
1436aea4
MK
1498 DEBUG ((\r
1499 DEBUG_INFO,\r
1500 " %s: Granularity/SpecificFlag = %ld / %02x%s\n",\r
1501 mAcpiAddressSpaceTypeStr[Descriptor->ResType],\r
1502 Descriptor->AddrSpaceGranularity,\r
1503 Descriptor->SpecificFlag,\r
1504 (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""\r
1505 ));\r
87000d77 1506 DEBUG ((DEBUG_INFO, " Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));\r
4a50cf4e 1507 switch (Descriptor->ResType) {\r
1436aea4
MK
1508 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1509 if ((Descriptor->AddrSpaceGranularity != 32) && (Descriptor->AddrSpaceGranularity != 64)) {\r
1510 return EFI_INVALID_PARAMETER;\r
1511 }\r
1512\r
1513 if ((Descriptor->AddrSpaceGranularity == 32) && (Descriptor->AddrLen >= SIZE_4GB)) {\r
1514 return EFI_INVALID_PARAMETER;\r
1515 }\r
1516\r
1517 //\r
1518 // If the PCI root bridge does not support separate windows for nonprefetchable and\r
1519 // prefetchable memory, then the PCI bus driver needs to include requests for\r
1520 // prefetchable memory in the nonprefetchable memory pool.\r
1521 //\r
1522 if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&\r
1523 ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)\r
1524 )\r
1525 {\r
1526 return EFI_INVALID_PARAMETER;\r
1527 }\r
1528\r
1529 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1530 //\r
1531 // Check aligment, it should be of the form 2^n-1\r
1532 //\r
1533 if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {\r
1534 return EFI_INVALID_PARAMETER;\r
1535 }\r
1536\r
1537 break;\r
1538 default:\r
1539 ASSERT (FALSE);\r
1540 break;\r
4a50cf4e
RN
1541 }\r
1542 }\r
1436aea4 1543\r
4a50cf4e
RN
1544 if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1545 return EFI_INVALID_PARAMETER;\r
1546 }\r
1547\r
1436aea4 1548 for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {\r
4a50cf4e
RN
1549 if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {\r
1550 if (Descriptor->AddrSpaceGranularity == 32) {\r
1551 if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {\r
1552 Type = TypePMem32;\r
1553 } else {\r
1554 Type = TypeMem32;\r
1555 }\r
1556 } else {\r
1557 ASSERT (Descriptor->AddrSpaceGranularity == 64);\r
1558 if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {\r
1559 Type = TypePMem64;\r
1560 } else {\r
1561 Type = TypeMem64;\r
1562 }\r
1563 }\r
1564 } else {\r
1565 ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);\r
1566 Type = TypeIo;\r
1567 }\r
1436aea4 1568\r
4a50cf4e
RN
1569 RootBridge->ResAllocNode[Type].Length = Descriptor->AddrLen;\r
1570 RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;\r
1571 RootBridge->ResAllocNode[Type].Status = ResSubmitted;\r
1572 }\r
1436aea4 1573\r
4a50cf4e
RN
1574 RootBridge->ResourceSubmitted = TRUE;\r
1575 return EFI_SUCCESS;\r
1576 }\r
1577 }\r
1578\r
1579 return EFI_INVALID_PARAMETER;\r
1580}\r
1581\r
1582/**\r
1583\r
1584 This function returns the proposed resource settings for the specified\r
1585 PCI Root Bridge.\r
1586\r
1587 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1588 @param RootBridgeHandle The PCI Root Bridge handle.\r
1589 @param Configuration The pointer to the pointer to the PCI I/O\r
1590 and memory resource descriptor.\r
1591\r
1592 @retval EFI_SUCCESS Succeed.\r
1593 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.\r
1594 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1595\r
1596**/\r
1597EFI_STATUS\r
1598EFIAPI\r
1599GetProposedResources (\r
1436aea4
MK
1600 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1601 IN EFI_HANDLE RootBridgeHandle,\r
1602 OUT VOID **Configuration\r
4a50cf4e
RN
1603 )\r
1604{\r
1436aea4
MK
1605 LIST_ENTRY *Link;\r
1606 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1607 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1608 UINTN Index;\r
1609 UINTN Number;\r
1610 VOID *Buffer;\r
1611 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
1612 EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
1613 UINT64 ResStatus;\r
4a50cf4e
RN
1614\r
1615 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1616 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1436aea4
MK
1617 ; !IsNull (&HostBridge->RootBridges, Link)\r
1618 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1619 )\r
1620 {\r
4a50cf4e
RN
1621 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1622 if (RootBridgeHandle == RootBridge->Handle) {\r
1623 for (Index = 0, Number = 0; Index < TypeBus; Index++) {\r
1624 if (RootBridge->ResAllocNode[Index].Status != ResNone) {\r
1625 Number++;\r
1626 }\r
1627 }\r
1628\r
1629 Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));\r
1630 if (Buffer == NULL) {\r
1631 return EFI_OUT_OF_RESOURCES;\r
1632 }\r
1633\r
1436aea4 1634 Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Buffer;\r
4a50cf4e
RN
1635 for (Index = 0; Index < TypeBus; Index++) {\r
1636 ResStatus = RootBridge->ResAllocNode[Index].Status;\r
1637 if (ResStatus != ResNone) {\r
1436aea4
MK
1638 Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
1639 Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
1640 Descriptor->GenFlag = 0;\r
74d0a339
HG
1641 //\r
1642 // AddrRangeMin in Resource Descriptor here should be device address\r
1643 // instead of host address, or else PCI bus driver cannot set correct\r
1644 // address into PCI BAR registers.\r
1645 // Base in ResAllocNode is a host address, so conversion is needed.\r
1646 //\r
1436aea4
MK
1647 Descriptor->AddrRangeMin = TO_DEVICE_ADDRESS (\r
1648 RootBridge->ResAllocNode[Index].Base,\r
1649 GetTranslationByResourceType (RootBridge, Index)\r
1650 );\r
4a50cf4e
RN
1651 Descriptor->AddrRangeMax = 0;\r
1652 Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;\r
1653 Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length;\r
1654\r
1655 switch (Index) {\r
1436aea4
MK
1656 case TypeIo:\r
1657 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;\r
1658 break;\r
4a50cf4e 1659\r
1436aea4
MK
1660 case TypePMem32:\r
1661 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1662 case TypeMem32:\r
1663 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1664 Descriptor->AddrSpaceGranularity = 32;\r
1665 break;\r
4a50cf4e 1666\r
1436aea4
MK
1667 case TypePMem64:\r
1668 Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;\r
1669 case TypeMem64:\r
1670 Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;\r
1671 Descriptor->AddrSpaceGranularity = 64;\r
1672 break;\r
4a50cf4e
RN
1673 }\r
1674\r
1675 Descriptor++;\r
1676 }\r
1677 }\r
1436aea4
MK
1678\r
1679 End = (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor;\r
1680 End->Desc = ACPI_END_TAG_DESCRIPTOR;\r
1681 End->Checksum = 0;\r
4a50cf4e
RN
1682\r
1683 *Configuration = Buffer;\r
1684\r
1685 return EFI_SUCCESS;\r
1686 }\r
1687 }\r
1688\r
1689 return EFI_INVALID_PARAMETER;\r
1690}\r
1691\r
1692/**\r
1693\r
1694 This function is called for all the PCI controllers that the PCI\r
1695 bus driver finds. Can be used to Preprogram the controller.\r
1696\r
1697 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.\r
1698 @param RootBridgeHandle The PCI Root Bridge handle.\r
1699 @param PciAddress Address of the controller on the PCI bus.\r
1700 @param Phase The Phase during resource allocation.\r
1701\r
1702 @retval EFI_SUCCESS Succeed.\r
1703 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.\r
1704\r
1705**/\r
1706EFI_STATUS\r
1707EFIAPI\r
1708PreprocessController (\r
1436aea4
MK
1709 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,\r
1710 IN EFI_HANDLE RootBridgeHandle,\r
1711 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,\r
1712 IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase\r
4a50cf4e
RN
1713 )\r
1714{\r
1715 LIST_ENTRY *Link;\r
1716 PCI_HOST_BRIDGE_INSTANCE *HostBridge;\r
1717 PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
1718\r
1436aea4 1719 if ((UINT32)Phase > EfiPciBeforeResourceCollection) {\r
4a50cf4e
RN
1720 return EFI_INVALID_PARAMETER;\r
1721 }\r
1722\r
1723 HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
1724 for (Link = GetFirstNode (&HostBridge->RootBridges)\r
1725 ; !IsNull (&HostBridge->RootBridges, Link)\r
1726 ; Link = GetNextNode (&HostBridge->RootBridges, Link)\r
1436aea4
MK
1727 )\r
1728 {\r
4a50cf4e
RN
1729 RootBridge = ROOT_BRIDGE_FROM_LINK (Link);\r
1730 if (RootBridgeHandle == RootBridge->Handle) {\r
1731 return EFI_SUCCESS;\r
1732 }\r
1733 }\r
1734\r
1735 return EFI_INVALID_PARAMETER;\r
1736}\r