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