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