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