3 Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
5 Copyright (c) 1999 - 2017, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "PciHostBridge.h"
17 #include "PciRootBridge.h"
18 #include "PciHostResource.h"
21 EFI_METRONOME_ARCH_PROTOCOL
*mMetronome
;
22 EFI_CPU_IO2_PROTOCOL
*mCpuIo
;
24 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16
*mAcpiAddressSpaceTypeStr
[] = {
25 L
"Mem", L
"I/O", L
"Bus"
27 GLOBAL_REMOVE_IF_UNREFERENCED CHAR16
*mPciResourceTypeStr
[] = {
28 L
"I/O", L
"Mem", L
"PMem", L
"Mem64", L
"PMem64", L
"Bus"
31 EDKII_IOMMU_PROTOCOL
*mIoMmuProtocol
;
32 EFI_EVENT mIoMmuEvent
;
33 VOID
*mIoMmuRegistration
;
36 This routine gets translation offset from a root bridge instance by resource type.
38 @param RootBridge The Root Bridge Instance for the resources.
39 @param ResourceType The Resource Type of the translation offset.
41 @retval The Translation Offset of the specified resource.
44 GetTranslationByResourceType (
45 IN PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
,
46 IN PCI_RESOURCE_TYPE ResourceType
49 switch (ResourceType
) {
51 return RootBridge
->Io
.Translation
;
53 return RootBridge
->Mem
.Translation
;
55 return RootBridge
->PMem
.Translation
;
57 return RootBridge
->MemAbove4G
.Translation
;
59 return RootBridge
->PMemAbove4G
.Translation
;
61 return RootBridge
->Bus
.Translation
;
69 Ensure the compatibility of an IO space descriptor with the IO aperture.
71 The IO space descriptor can come from the GCD IO space map, or it can
72 represent a gap between two neighboring IO space descriptors. In the latter
73 case, the GcdIoType field is expected to be EfiGcdIoTypeNonExistent.
75 If the IO space descriptor already has type EfiGcdIoTypeIo, then no action is
76 taken -- it is by definition compatible with the aperture.
78 Otherwise, the intersection of the IO space descriptor is calculated with the
79 aperture. If the intersection is the empty set (no overlap), no action is
80 taken; the IO space descriptor is compatible with the aperture.
82 Otherwise, the type of the descriptor is investigated again. If the type is
83 EfiGcdIoTypeNonExistent (representing a gap, or a genuine descriptor with
84 such a type), then an attempt is made to add the intersection as IO space to
85 the GCD IO space map. This ensures continuity for the aperture, and the
86 descriptor is deemed compatible with the aperture.
88 Otherwise, the IO space descriptor is incompatible with the IO aperture.
90 @param[in] Base Base address of the aperture.
91 @param[in] Length Length of the aperture.
92 @param[in] Descriptor The descriptor to ensure compatibility with the
95 @retval EFI_SUCCESS The descriptor is compatible. The GCD IO space
96 map may have been updated, for continuity
98 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
99 @return Error codes from gDS->AddIoSpace().
102 IntersectIoDescriptor (
105 IN CONST EFI_GCD_IO_SPACE_DESCRIPTOR
*Descriptor
108 UINT64 IntersectionBase
;
109 UINT64 IntersectionEnd
;
112 if (Descriptor
->GcdIoType
== EfiGcdIoTypeIo
) {
116 IntersectionBase
= MAX (Base
, Descriptor
->BaseAddress
);
117 IntersectionEnd
= MIN (Base
+ Length
,
118 Descriptor
->BaseAddress
+ Descriptor
->Length
);
119 if (IntersectionBase
>= IntersectionEnd
) {
121 // The descriptor and the aperture don't overlap.
126 if (Descriptor
->GcdIoType
== EfiGcdIoTypeNonExistent
) {
127 Status
= gDS
->AddIoSpace (EfiGcdIoTypeIo
, IntersectionBase
,
128 IntersectionEnd
- IntersectionBase
);
130 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
,
131 "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName
, __FUNCTION__
,
132 IntersectionBase
, IntersectionEnd
, Status
));
136 DEBUG ((EFI_D_ERROR
, "%a: %a: desc [%Lx, %Lx) type %u conflicts with "
137 "aperture [%Lx, %Lx)\n", gEfiCallerBaseName
, __FUNCTION__
,
138 Descriptor
->BaseAddress
, Descriptor
->BaseAddress
+ Descriptor
->Length
,
139 (UINT32
)Descriptor
->GcdIoType
, Base
, Base
+ Length
));
140 return EFI_INVALID_PARAMETER
;
145 The routine checks the GCD database and only adds those which are
146 not added in the specified range to GCD.
148 @param Base Base address of the IO space.
149 @param Length Length of the IO space.
151 @retval EFI_SUCCES The IO space was added successfully.
161 UINTN NumberOfDescriptors
;
162 EFI_GCD_IO_SPACE_DESCRIPTOR
*IoSpaceMap
;
164 Status
= gDS
->GetIoSpaceMap (&NumberOfDescriptors
, &IoSpaceMap
);
165 if (EFI_ERROR (Status
)) {
166 DEBUG ((EFI_D_ERROR
, "%a: %a: GetIoSpaceMap(): %r\n",
167 gEfiCallerBaseName
, __FUNCTION__
, Status
));
171 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
172 Status
= IntersectIoDescriptor (Base
, Length
, &IoSpaceMap
[Index
]);
173 if (EFI_ERROR (Status
)) {
180 // Make sure there are adjacent descriptors covering [Base, Base + Length).
181 // It is possible that they have not been merged; merging can be prevented
185 EFI_STATUS CheckStatus
;
186 EFI_GCD_IO_SPACE_DESCRIPTOR Descriptor
;
188 for (CheckBase
= Base
;
189 CheckBase
< Base
+ Length
;
190 CheckBase
= Descriptor
.BaseAddress
+ Descriptor
.Length
) {
191 CheckStatus
= gDS
->GetIoSpaceDescriptor (CheckBase
, &Descriptor
);
192 ASSERT_EFI_ERROR (CheckStatus
);
193 ASSERT (Descriptor
.GcdIoType
== EfiGcdIoTypeIo
);
198 FreePool (IoSpaceMap
);
204 Ensure the compatibility of a memory space descriptor with the MMIO aperture.
206 The memory space descriptor can come from the GCD memory space map, or it can
207 represent a gap between two neighboring memory space descriptors. In the
208 latter case, the GcdMemoryType field is expected to be
209 EfiGcdMemoryTypeNonExistent.
211 If the memory space descriptor already has type
212 EfiGcdMemoryTypeMemoryMappedIo, and its capabilities are a superset of the
213 required capabilities, then no action is taken -- it is by definition
214 compatible with the aperture.
216 Otherwise, the intersection of the memory space descriptor is calculated with
217 the aperture. If the intersection is the empty set (no overlap), no action is
218 taken; the memory space descriptor is compatible with the aperture.
220 Otherwise, the type of the descriptor is investigated again. If the type is
221 EfiGcdMemoryTypeNonExistent (representing a gap, or a genuine descriptor with
222 such a type), then an attempt is made to add the intersection as MMIO space
223 to the GCD memory space map, with the specified capabilities. This ensures
224 continuity for the aperture, and the descriptor is deemed compatible with the
227 Otherwise, the memory space descriptor is incompatible with the MMIO
230 @param[in] Base Base address of the aperture.
231 @param[in] Length Length of the aperture.
232 @param[in] Capabilities Capabilities required by the aperture.
233 @param[in] Descriptor The descriptor to ensure compatibility with the
236 @retval EFI_SUCCESS The descriptor is compatible. The GCD memory
237 space map may have been updated, for
238 continuity within the aperture.
239 @retval EFI_INVALID_PARAMETER The descriptor is incompatible.
240 @return Error codes from gDS->AddMemorySpace().
243 IntersectMemoryDescriptor (
246 IN UINT64 Capabilities
,
247 IN CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*Descriptor
250 UINT64 IntersectionBase
;
251 UINT64 IntersectionEnd
;
254 if (Descriptor
->GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
&&
255 (Descriptor
->Capabilities
& Capabilities
) == Capabilities
) {
259 IntersectionBase
= MAX (Base
, Descriptor
->BaseAddress
);
260 IntersectionEnd
= MIN (Base
+ Length
,
261 Descriptor
->BaseAddress
+ Descriptor
->Length
);
262 if (IntersectionBase
>= IntersectionEnd
) {
264 // The descriptor and the aperture don't overlap.
269 if (Descriptor
->GcdMemoryType
== EfiGcdMemoryTypeNonExistent
) {
270 Status
= gDS
->AddMemorySpace (EfiGcdMemoryTypeMemoryMappedIo
,
271 IntersectionBase
, IntersectionEnd
- IntersectionBase
,
274 DEBUG ((EFI_ERROR (Status
) ? EFI_D_ERROR
: EFI_D_VERBOSE
,
275 "%a: %a: add [%Lx, %Lx): %r\n", gEfiCallerBaseName
, __FUNCTION__
,
276 IntersectionBase
, IntersectionEnd
, Status
));
280 DEBUG ((EFI_D_ERROR
, "%a: %a: desc [%Lx, %Lx) type %u cap %Lx conflicts "
281 "with aperture [%Lx, %Lx) cap %Lx\n", gEfiCallerBaseName
, __FUNCTION__
,
282 Descriptor
->BaseAddress
, Descriptor
->BaseAddress
+ Descriptor
->Length
,
283 (UINT32
)Descriptor
->GcdMemoryType
, Descriptor
->Capabilities
,
284 Base
, Base
+ Length
, Capabilities
));
285 return EFI_INVALID_PARAMETER
;
289 Add MMIO space to GCD.
290 The routine checks the GCD database and only adds those which are
291 not added in the specified range to GCD.
293 @param Base Base address of the MMIO space.
294 @param Length Length of the MMIO space.
295 @param Capabilities Capabilities of the MMIO space.
297 @retval EFI_SUCCES The MMIO space was added successfully.
300 AddMemoryMappedIoSpace (
303 IN UINT64 Capabilities
308 UINTN NumberOfDescriptors
;
309 EFI_GCD_MEMORY_SPACE_DESCRIPTOR
*MemorySpaceMap
;
311 Status
= gDS
->GetMemorySpaceMap (&NumberOfDescriptors
, &MemorySpaceMap
);
312 if (EFI_ERROR (Status
)) {
313 DEBUG ((EFI_D_ERROR
, "%a: %a: GetMemorySpaceMap(): %r\n",
314 gEfiCallerBaseName
, __FUNCTION__
, Status
));
318 for (Index
= 0; Index
< NumberOfDescriptors
; Index
++) {
319 Status
= IntersectMemoryDescriptor (Base
, Length
, Capabilities
,
320 &MemorySpaceMap
[Index
]);
321 if (EFI_ERROR (Status
)) {
322 goto FreeMemorySpaceMap
;
328 // Make sure there are adjacent descriptors covering [Base, Base + Length).
329 // It is possible that they have not been merged; merging can be prevented
330 // by allocation and different capabilities.
333 EFI_STATUS CheckStatus
;
334 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
336 for (CheckBase
= Base
;
337 CheckBase
< Base
+ Length
;
338 CheckBase
= Descriptor
.BaseAddress
+ Descriptor
.Length
) {
339 CheckStatus
= gDS
->GetMemorySpaceDescriptor (CheckBase
, &Descriptor
);
340 ASSERT_EFI_ERROR (CheckStatus
);
341 ASSERT (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeMemoryMappedIo
);
342 ASSERT ((Descriptor
.Capabilities
& Capabilities
) == Capabilities
);
347 FreePool (MemorySpaceMap
);
353 Event notification that is fired when IOMMU protocol is installed.
355 @param Event The Event that is being processed.
356 @param Context Event Context.
361 IoMmuProtocolCallback (
368 Status
= gBS
->LocateProtocol (&gEdkiiIoMmuProtocolGuid
, NULL
, (VOID
**)&mIoMmuProtocol
);
369 if (!EFI_ERROR(Status
)) {
370 gBS
->CloseEvent (mIoMmuEvent
);
376 Entry point of this driver.
378 @param ImageHandle Image handle of this driver.
379 @param SystemTable Pointer to standard EFI system table.
381 @retval EFI_SUCCESS Succeed.
382 @retval EFI_DEVICE_ERROR Fail to install PCI_ROOT_BRIDGE_IO protocol.
387 InitializePciHostBridge (
388 IN EFI_HANDLE ImageHandle
,
389 IN EFI_SYSTEM_TABLE
*SystemTable
393 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
394 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
395 PCI_ROOT_BRIDGE
*RootBridges
;
396 UINTN RootBridgeCount
;
398 PCI_ROOT_BRIDGE_APERTURE
*MemApertures
[4];
399 UINTN MemApertureIndex
;
400 BOOLEAN ResourceAssigned
;
404 RootBridges
= PciHostBridgeGetRootBridges (&RootBridgeCount
);
405 if ((RootBridges
== NULL
) || (RootBridgeCount
== 0)) {
406 return EFI_UNSUPPORTED
;
409 Status
= gBS
->LocateProtocol (&gEfiMetronomeArchProtocolGuid
, NULL
, (VOID
**) &mMetronome
);
410 ASSERT_EFI_ERROR (Status
);
411 Status
= gBS
->LocateProtocol (&gEfiCpuIo2ProtocolGuid
, NULL
, (VOID
**) &mCpuIo
);
412 ASSERT_EFI_ERROR (Status
);
415 // Most systems in the world including complex servers have only one Host Bridge.
417 HostBridge
= AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE
));
418 ASSERT (HostBridge
!= NULL
);
420 HostBridge
->Signature
= PCI_HOST_BRIDGE_SIGNATURE
;
421 HostBridge
->CanRestarted
= TRUE
;
422 InitializeListHead (&HostBridge
->RootBridges
);
423 ResourceAssigned
= FALSE
;
426 // Create Root Bridge Device Handle in this Host Bridge
428 for (Index
= 0; Index
< RootBridgeCount
; Index
++) {
430 // Create Root Bridge Handle Instance
432 RootBridge
= CreateRootBridge (&RootBridges
[Index
]);
433 ASSERT (RootBridge
!= NULL
);
434 if (RootBridge
== NULL
) {
439 // Make sure all root bridges share the same ResourceAssigned value.
442 ResourceAssigned
= RootBridges
[Index
].ResourceAssigned
;
444 ASSERT (ResourceAssigned
== RootBridges
[Index
].ResourceAssigned
);
447 if (RootBridges
[Index
].Io
.Base
<= RootBridges
[Index
].Io
.Limit
) {
449 // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
450 // For GCD resource manipulation, we need to use host address.
452 HostAddress
= TO_HOST_ADDRESS (RootBridges
[Index
].Io
.Base
,
453 RootBridges
[Index
].Io
.Translation
);
455 Status
= AddIoSpace (
457 RootBridges
[Index
].Io
.Limit
- RootBridges
[Index
].Io
.Base
+ 1
459 ASSERT_EFI_ERROR (Status
);
460 if (ResourceAssigned
) {
461 Status
= gDS
->AllocateIoSpace (
462 EfiGcdAllocateAddress
,
465 RootBridges
[Index
].Io
.Limit
- RootBridges
[Index
].Io
.Base
+ 1,
470 ASSERT_EFI_ERROR (Status
);
475 // Add all the Mem/PMem aperture to GCD
476 // Mem/PMem shouldn't overlap with each other
477 // Root bridge which needs to combine MEM and PMEM should only report
478 // the MEM aperture in Mem
480 MemApertures
[0] = &RootBridges
[Index
].Mem
;
481 MemApertures
[1] = &RootBridges
[Index
].MemAbove4G
;
482 MemApertures
[2] = &RootBridges
[Index
].PMem
;
483 MemApertures
[3] = &RootBridges
[Index
].PMemAbove4G
;
485 for (MemApertureIndex
= 0; MemApertureIndex
< ARRAY_SIZE (MemApertures
); MemApertureIndex
++) {
486 if (MemApertures
[MemApertureIndex
]->Base
<= MemApertures
[MemApertureIndex
]->Limit
) {
488 // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
489 // For GCD resource manipulation, we need to use host address.
491 HostAddress
= TO_HOST_ADDRESS (MemApertures
[MemApertureIndex
]->Base
,
492 MemApertures
[MemApertureIndex
]->Translation
);
493 Status
= AddMemoryMappedIoSpace (
495 MemApertures
[MemApertureIndex
]->Limit
- MemApertures
[MemApertureIndex
]->Base
+ 1,
498 ASSERT_EFI_ERROR (Status
);
499 Status
= gDS
->SetMemorySpaceAttributes (
501 MemApertures
[MemApertureIndex
]->Limit
- MemApertures
[MemApertureIndex
]->Base
+ 1,
504 if (EFI_ERROR (Status
)) {
505 DEBUG ((DEBUG_WARN
, "PciHostBridge driver failed to set EFI_MEMORY_UC to MMIO aperture - %r.\n", Status
));
507 if (ResourceAssigned
) {
508 Status
= gDS
->AllocateMemorySpace (
509 EfiGcdAllocateAddress
,
510 EfiGcdMemoryTypeMemoryMappedIo
,
512 MemApertures
[MemApertureIndex
]->Limit
- MemApertures
[MemApertureIndex
]->Base
+ 1,
517 ASSERT_EFI_ERROR (Status
);
522 // Insert Root Bridge Handle Instance
524 InsertTailList (&HostBridge
->RootBridges
, &RootBridge
->Link
);
528 // When resources were assigned, it's not needed to expose
529 // PciHostBridgeResourceAllocation protocol.
531 if (!ResourceAssigned
) {
532 HostBridge
->ResAlloc
.NotifyPhase
= NotifyPhase
;
533 HostBridge
->ResAlloc
.GetNextRootBridge
= GetNextRootBridge
;
534 HostBridge
->ResAlloc
.GetAllocAttributes
= GetAttributes
;
535 HostBridge
->ResAlloc
.StartBusEnumeration
= StartBusEnumeration
;
536 HostBridge
->ResAlloc
.SetBusNumbers
= SetBusNumbers
;
537 HostBridge
->ResAlloc
.SubmitResources
= SubmitResources
;
538 HostBridge
->ResAlloc
.GetProposedResources
= GetProposedResources
;
539 HostBridge
->ResAlloc
.PreprocessController
= PreprocessController
;
541 Status
= gBS
->InstallMultipleProtocolInterfaces (
543 &gEfiPciHostBridgeResourceAllocationProtocolGuid
, &HostBridge
->ResAlloc
,
546 ASSERT_EFI_ERROR (Status
);
549 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
550 ; !IsNull (&HostBridge
->RootBridges
, Link
)
551 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
553 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
554 RootBridge
->RootBridgeIo
.ParentHandle
= HostBridge
->Handle
;
556 Status
= gBS
->InstallMultipleProtocolInterfaces (
558 &gEfiDevicePathProtocolGuid
, RootBridge
->DevicePath
,
559 &gEfiPciRootBridgeIoProtocolGuid
, &RootBridge
->RootBridgeIo
,
562 ASSERT_EFI_ERROR (Status
);
564 PciHostBridgeFreeRootBridges (RootBridges
, RootBridgeCount
);
566 if (!EFI_ERROR (Status
)) {
567 mIoMmuEvent
= EfiCreateProtocolNotifyEvent (
568 &gEdkiiIoMmuProtocolGuid
,
570 IoMmuProtocolCallback
,
580 This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
582 @param HostBridge The Host Bridge Instance where the resource adjustment happens.
586 IN PCI_HOST_BRIDGE_INSTANCE
*HostBridge
589 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Resources
;
590 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
591 EFI_ACPI_END_TAG_DESCRIPTOR
*End
;
592 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
594 UINTN RootBridgeCount
;
595 PCI_RESOURCE_TYPE Index
;
596 PCI_RES_NODE
*ResAllocNode
;
599 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
600 ; !IsNull (&HostBridge
->RootBridges
, Link
)
601 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
606 Resources
= AllocatePool (
607 RootBridgeCount
* (TypeMax
* sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR
)) +
608 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR
)
610 ASSERT (Resources
!= NULL
);
612 for (Link
= GetFirstNode (&HostBridge
->RootBridges
), Descriptor
= Resources
613 ; !IsNull (&HostBridge
->RootBridges
, Link
)
614 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
616 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
617 for (Index
= TypeIo
; Index
< TypeMax
; Index
++) {
618 ResAllocNode
= &RootBridge
->ResAllocNode
[Index
];
620 Descriptor
->Desc
= ACPI_ADDRESS_SPACE_DESCRIPTOR
;
621 Descriptor
->Len
= sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) - 3;
622 Descriptor
->AddrRangeMin
= ResAllocNode
->Base
;
623 Descriptor
->AddrRangeMax
= ResAllocNode
->Alignment
;
624 Descriptor
->AddrLen
= ResAllocNode
->Length
;
625 Descriptor
->SpecificFlag
= 0;
626 switch (ResAllocNode
->Type
) {
629 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_IO
;
633 Descriptor
->SpecificFlag
= EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
;
635 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_MEM
;
636 Descriptor
->AddrSpaceGranularity
= 32;
640 Descriptor
->SpecificFlag
= EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
;
642 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_MEM
;
643 Descriptor
->AddrSpaceGranularity
= 64;
647 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_BUS
;
657 // Terminate the root bridge resources.
659 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) Descriptor
;
660 End
->Desc
= ACPI_END_TAG_DESCRIPTOR
;
663 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) (End
+ 1);
666 // Terminate the host bridge resources.
668 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) Descriptor
;
669 End
->Desc
= ACPI_END_TAG_DESCRIPTOR
;
672 DEBUG ((DEBUG_ERROR
, "Call PciHostBridgeResourceConflict().\n"));
673 PciHostBridgeResourceConflict (HostBridge
->Handle
, Resources
);
674 FreePool (Resources
);
678 Allocate Length of MMIO or IO resource with alignment BitsOfAlignment
679 from GCD range [BaseAddress, Limit).
681 @param Mmio TRUE for MMIO and FALSE for IO.
682 @param Length Length of the resource to allocate.
683 @param BitsOfAlignment Alignment of the resource to allocate.
684 @param BaseAddress The starting address the allocation is from.
685 @param Limit The ending address the allocation is to.
687 @retval The base address of the allocated resource or MAX_UINT64 if allocation
694 UINTN BitsOfAlignment
,
701 if (BaseAddress
< Limit
) {
703 // Have to make sure Aligment is handled since we are doing direct address allocation
704 // Strictly speaking, alignment requirement should be applied to device
705 // address instead of host address which is used in GCD manipulation below,
706 // but as we restrict the alignment of Translation to be larger than any BAR
707 // alignment in the root bridge, we can simplify the situation and consider
708 // the same alignment requirement is also applied to host address.
710 BaseAddress
= ALIGN_VALUE (BaseAddress
, LShiftU64 (1, BitsOfAlignment
));
712 while (BaseAddress
+ Length
<= Limit
+ 1) {
714 Status
= gDS
->AllocateMemorySpace (
715 EfiGcdAllocateAddress
,
716 EfiGcdMemoryTypeMemoryMappedIo
,
724 Status
= gDS
->AllocateIoSpace (
725 EfiGcdAllocateAddress
,
735 if (!EFI_ERROR (Status
)) {
738 BaseAddress
+= LShiftU64 (1, BitsOfAlignment
);
746 Enter a certain phase of the PCI enumeration process.
748 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
749 @param Phase The phase during enumeration.
751 @retval EFI_SUCCESS Succeed.
752 @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.
753 @retval EFI_NOT_READY Resources have not been submitted yet.
759 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
760 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
763 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
764 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
766 EFI_PHYSICAL_ADDRESS BaseAddress
;
767 UINTN BitsOfAlignment
;
770 EFI_STATUS ReturnStatus
;
771 PCI_RESOURCE_TYPE Index
;
772 PCI_RESOURCE_TYPE Index1
;
773 PCI_RESOURCE_TYPE Index2
;
774 BOOLEAN ResNodeHandled
[TypeMax
];
778 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
781 case EfiPciHostBridgeBeginEnumeration
:
782 if (!HostBridge
->CanRestarted
) {
783 return EFI_NOT_READY
;
788 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
789 ; !IsNull (&HostBridge
->RootBridges
, Link
)
790 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
792 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
793 for (Index
= TypeIo
; Index
< TypeMax
; Index
++) {
794 RootBridge
->ResAllocNode
[Index
].Type
= Index
;
795 RootBridge
->ResAllocNode
[Index
].Base
= 0;
796 RootBridge
->ResAllocNode
[Index
].Length
= 0;
797 RootBridge
->ResAllocNode
[Index
].Status
= ResNone
;
799 RootBridge
->ResourceSubmitted
= FALSE
;
803 HostBridge
->CanRestarted
= TRUE
;
806 case EfiPciHostBridgeBeginBusAllocation
:
808 // No specific action is required here, can perform any chipset specific programing
810 HostBridge
->CanRestarted
= FALSE
;
813 case EfiPciHostBridgeEndBusAllocation
:
815 // No specific action is required here, can perform any chipset specific programing
819 case EfiPciHostBridgeBeginResourceAllocation
:
821 // No specific action is required here, can perform any chipset specific programing
825 case EfiPciHostBridgeAllocateResources
:
826 ReturnStatus
= EFI_SUCCESS
;
829 // Make sure the resource for all root bridges has been submitted.
831 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
832 ; !IsNull (&HostBridge
->RootBridges
, Link
)
833 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
835 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
836 if (!RootBridge
->ResourceSubmitted
) {
837 return EFI_NOT_READY
;
841 DEBUG ((EFI_D_INFO
, "PciHostBridge: NotifyPhase (AllocateResources)\n"));
842 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
843 ; !IsNull (&HostBridge
->RootBridges
, Link
)
844 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
846 for (Index
= TypeIo
; Index
< TypeBus
; Index
++) {
847 ResNodeHandled
[Index
] = FALSE
;
850 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
851 DEBUG ((EFI_D_INFO
, " RootBridge: %s\n", RootBridge
->DevicePathStr
));
853 for (Index1
= TypeIo
; Index1
< TypeBus
; Index1
++) {
854 if (RootBridge
->ResAllocNode
[Index1
].Status
== ResNone
) {
855 ResNodeHandled
[Index1
] = TRUE
;
858 // Allocate the resource node with max alignment at first
862 for (Index2
= TypeIo
; Index2
< TypeBus
; Index2
++) {
863 if (ResNodeHandled
[Index2
]) {
866 if (MaxAlignment
<= RootBridge
->ResAllocNode
[Index2
].Alignment
) {
867 MaxAlignment
= RootBridge
->ResAllocNode
[Index2
].Alignment
;
872 ASSERT (Index
< TypeMax
);
873 ResNodeHandled
[Index
] = TRUE
;
874 Alignment
= RootBridge
->ResAllocNode
[Index
].Alignment
;
875 BitsOfAlignment
= LowBitSet64 (Alignment
+ 1);
876 BaseAddress
= MAX_UINT64
;
879 // RESTRICTION: To simplify the situation, we require the alignment of
880 // Translation must be larger than any BAR alignment in the same root
881 // bridge, so that resource allocation alignment can be applied to
882 // both device address and host address.
884 Translation
= GetTranslationByResourceType (RootBridge
, Index
);
885 if ((Translation
& Alignment
) != 0) {
886 DEBUG ((DEBUG_ERROR
, "[%a:%d] Translation %lx is not aligned to %lx!\n",
887 __FUNCTION__
, __LINE__
, Translation
, Alignment
889 ASSERT ((Translation
& Alignment
) == 0);
891 // This may be caused by too large alignment or too small
892 // Translation; pick the 1st possibility and return out of resource,
893 // which can also go thru the same process for out of resource
896 ReturnStatus
= EFI_OUT_OF_RESOURCES
;
903 // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.
904 // For AllocateResource is manipulating GCD resource, we need to use
905 // host address here.
907 BaseAddress
= AllocateResource (
909 RootBridge
->ResAllocNode
[Index
].Length
,
910 MIN (15, BitsOfAlignment
),
911 TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge
->Io
.Base
, Alignment
+ 1),
912 RootBridge
->Io
.Translation
),
913 TO_HOST_ADDRESS (RootBridge
->Io
.Limit
,
914 RootBridge
->Io
.Translation
)
919 BaseAddress
= AllocateResource (
921 RootBridge
->ResAllocNode
[Index
].Length
,
922 MIN (63, BitsOfAlignment
),
923 TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge
->MemAbove4G
.Base
, Alignment
+ 1),
924 RootBridge
->MemAbove4G
.Translation
),
925 TO_HOST_ADDRESS (RootBridge
->MemAbove4G
.Limit
,
926 RootBridge
->MemAbove4G
.Translation
)
928 if (BaseAddress
!= MAX_UINT64
) {
932 // If memory above 4GB is not available, try memory below 4GB
936 BaseAddress
= AllocateResource (
938 RootBridge
->ResAllocNode
[Index
].Length
,
939 MIN (31, BitsOfAlignment
),
940 TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge
->Mem
.Base
, Alignment
+ 1),
941 RootBridge
->Mem
.Translation
),
942 TO_HOST_ADDRESS (RootBridge
->Mem
.Limit
,
943 RootBridge
->Mem
.Translation
)
948 BaseAddress
= AllocateResource (
950 RootBridge
->ResAllocNode
[Index
].Length
,
951 MIN (63, BitsOfAlignment
),
952 TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge
->PMemAbove4G
.Base
, Alignment
+ 1),
953 RootBridge
->PMemAbove4G
.Translation
),
954 TO_HOST_ADDRESS (RootBridge
->PMemAbove4G
.Limit
,
955 RootBridge
->PMemAbove4G
.Translation
)
957 if (BaseAddress
!= MAX_UINT64
) {
961 // If memory above 4GB is not available, try memory below 4GB
964 BaseAddress
= AllocateResource (
966 RootBridge
->ResAllocNode
[Index
].Length
,
967 MIN (31, BitsOfAlignment
),
968 TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge
->PMem
.Base
, Alignment
+ 1),
969 RootBridge
->PMem
.Translation
),
970 TO_HOST_ADDRESS (RootBridge
->PMem
.Limit
,
971 RootBridge
->PMem
.Translation
)
980 DEBUG ((DEBUG_INFO
, " %s: Base/Length/Alignment = %lx/%lx/%lx - ",
981 mPciResourceTypeStr
[Index
], BaseAddress
, RootBridge
->ResAllocNode
[Index
].Length
, Alignment
));
982 if (BaseAddress
!= MAX_UINT64
) {
983 RootBridge
->ResAllocNode
[Index
].Base
= BaseAddress
;
984 RootBridge
->ResAllocNode
[Index
].Status
= ResAllocated
;
985 DEBUG ((DEBUG_INFO
, "Success\n"));
987 ReturnStatus
= EFI_OUT_OF_RESOURCES
;
988 DEBUG ((DEBUG_ERROR
, "Out Of Resource!\n"));
994 if (ReturnStatus
== EFI_OUT_OF_RESOURCES
) {
995 ResourceConflict (HostBridge
);
999 // Set resource to zero for nodes where allocation fails
1001 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1002 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1003 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1005 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1006 for (Index
= TypeIo
; Index
< TypeBus
; Index
++) {
1007 if (RootBridge
->ResAllocNode
[Index
].Status
!= ResAllocated
) {
1008 RootBridge
->ResAllocNode
[Index
].Length
= 0;
1012 return ReturnStatus
;
1014 case EfiPciHostBridgeSetResources
:
1016 // HostBridgeInstance->CanRestarted = FALSE;
1020 case EfiPciHostBridgeFreeResources
:
1022 // HostBridgeInstance->CanRestarted = FALSE;
1024 ReturnStatus
= EFI_SUCCESS
;
1025 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1026 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1027 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1029 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1030 for (Index
= TypeIo
; Index
< TypeBus
; Index
++) {
1031 if (RootBridge
->ResAllocNode
[Index
].Status
== ResAllocated
) {
1034 Status
= gDS
->FreeIoSpace (RootBridge
->ResAllocNode
[Index
].Base
, RootBridge
->ResAllocNode
[Index
].Length
);
1035 if (EFI_ERROR (Status
)) {
1036 ReturnStatus
= Status
;
1044 Status
= gDS
->FreeMemorySpace (RootBridge
->ResAllocNode
[Index
].Base
, RootBridge
->ResAllocNode
[Index
].Length
);
1045 if (EFI_ERROR (Status
)) {
1046 ReturnStatus
= Status
;
1055 RootBridge
->ResAllocNode
[Index
].Type
= Index
;
1056 RootBridge
->ResAllocNode
[Index
].Base
= 0;
1057 RootBridge
->ResAllocNode
[Index
].Length
= 0;
1058 RootBridge
->ResAllocNode
[Index
].Status
= ResNone
;
1062 RootBridge
->ResourceSubmitted
= FALSE
;
1065 HostBridge
->CanRestarted
= TRUE
;
1066 return ReturnStatus
;
1068 case EfiPciHostBridgeEndResourceAllocation
:
1070 // The resource allocation phase is completed. No specific action is required
1071 // here. This notification can be used to perform any chipset specific programming.
1075 case EfiPciHostBridgeEndEnumeration
:
1077 // The Host Bridge Enumeration is completed. No specific action is required here.
1078 // This notification can be used to perform any chipset specific programming.
1083 return EFI_INVALID_PARAMETER
;
1091 Return the device handle of the next PCI root bridge that is associated with
1094 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1095 @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.
1096 On input, it holds the RootBridgeHandle returned by the most
1097 recent call to GetNextRootBridge().The handle for the first
1098 PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
1100 @retval EFI_SUCCESS Succeed.
1101 @retval EFI_NOT_FOUND Next PCI root bridge not found.
1102 @retval EFI_INVALID_PARAMETER Wrong parameter passed in.
1108 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1109 IN OUT EFI_HANDLE
*RootBridgeHandle
1114 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1115 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1117 if (RootBridgeHandle
== NULL
) {
1118 return EFI_INVALID_PARAMETER
;
1121 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1122 ReturnNext
= (BOOLEAN
) (*RootBridgeHandle
== NULL
);
1124 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1125 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1126 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1128 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1130 *RootBridgeHandle
= RootBridge
->Handle
;
1134 ReturnNext
= (BOOLEAN
) (*RootBridgeHandle
== RootBridge
->Handle
);
1138 ASSERT (IsNull (&HostBridge
->RootBridges
, Link
));
1139 return EFI_NOT_FOUND
;
1141 return EFI_INVALID_PARAMETER
;
1147 Returns the attributes of a PCI Root Bridge.
1149 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1150 @param RootBridgeHandle The device handle of the PCI Root Bridge
1151 that the caller is interested in.
1152 @param Attributes The pointer to attributes of the PCI Root Bridge.
1154 @retval EFI_SUCCESS Succeed.
1155 @retval EFI_INVALID_PARAMETER Attributes parameter passed in is NULL or
1156 RootBridgeHandle is not an EFI_HANDLE
1157 that was returned on a previous call to
1158 GetNextRootBridge().
1164 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1165 IN EFI_HANDLE RootBridgeHandle
,
1166 OUT UINT64
*Attributes
1170 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1171 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1173 if (Attributes
== NULL
) {
1174 return EFI_INVALID_PARAMETER
;
1177 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1178 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1179 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1180 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1182 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1183 if (RootBridgeHandle
== RootBridge
->Handle
) {
1184 *Attributes
= RootBridge
->AllocationAttributes
;
1189 return EFI_INVALID_PARAMETER
;
1194 This is the request from the PCI enumerator to set up
1195 the specified PCI Root Bridge for bus enumeration process.
1197 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1198 @param RootBridgeHandle The PCI Root Bridge to be set up.
1199 @param Configuration Pointer to the pointer to the PCI bus resource descriptor.
1201 @retval EFI_SUCCESS Succeed.
1202 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.
1203 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
1208 StartBusEnumeration (
1209 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1210 IN EFI_HANDLE RootBridgeHandle
,
1211 OUT VOID
**Configuration
1215 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1216 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1217 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
1218 EFI_ACPI_END_TAG_DESCRIPTOR
*End
;
1220 if (Configuration
== NULL
) {
1221 return EFI_INVALID_PARAMETER
;
1224 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1225 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1226 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1227 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1229 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1230 if (RootBridgeHandle
== RootBridge
->Handle
) {
1231 *Configuration
= AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR
));
1232 if (*Configuration
== NULL
) {
1233 return EFI_OUT_OF_RESOURCES
;
1236 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) *Configuration
;
1237 Descriptor
->Desc
= ACPI_ADDRESS_SPACE_DESCRIPTOR
;
1238 Descriptor
->Len
= sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) - 3;
1239 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_BUS
;
1240 Descriptor
->GenFlag
= 0;
1241 Descriptor
->SpecificFlag
= 0;
1242 Descriptor
->AddrSpaceGranularity
= 0;
1243 Descriptor
->AddrRangeMin
= RootBridge
->Bus
.Base
;
1244 Descriptor
->AddrRangeMax
= 0;
1245 Descriptor
->AddrTranslationOffset
= 0;
1246 Descriptor
->AddrLen
= RootBridge
->Bus
.Limit
- RootBridge
->Bus
.Base
+ 1;
1248 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) (Descriptor
+ 1);
1249 End
->Desc
= ACPI_END_TAG_DESCRIPTOR
;
1250 End
->Checksum
= 0x0;
1256 return EFI_INVALID_PARAMETER
;
1261 This function programs the PCI Root Bridge hardware so that
1262 it decodes the specified PCI bus range.
1264 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1265 @param RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed.
1266 @param Configuration The pointer to the PCI bus resource descriptor.
1268 @retval EFI_SUCCESS Succeed.
1269 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.
1275 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1276 IN EFI_HANDLE RootBridgeHandle
,
1277 IN VOID
*Configuration
1281 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1282 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1283 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
1284 EFI_ACPI_END_TAG_DESCRIPTOR
*End
;
1286 if (Configuration
== NULL
) {
1287 return EFI_INVALID_PARAMETER
;
1290 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
;
1291 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) (Descriptor
+ 1);
1294 // Check the Configuration is valid
1296 if ((Descriptor
->Desc
!= ACPI_ADDRESS_SPACE_DESCRIPTOR
) ||
1297 (Descriptor
->ResType
!= ACPI_ADDRESS_SPACE_TYPE_BUS
) ||
1298 (End
->Desc
!= ACPI_END_TAG_DESCRIPTOR
)
1300 return EFI_INVALID_PARAMETER
;
1303 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1304 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1305 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1306 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1308 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1309 if (RootBridgeHandle
== RootBridge
->Handle
) {
1311 if (Descriptor
->AddrLen
== 0) {
1312 return EFI_INVALID_PARAMETER
;
1315 if ((Descriptor
->AddrRangeMin
< RootBridge
->Bus
.Base
) ||
1316 (Descriptor
->AddrRangeMin
+ Descriptor
->AddrLen
- 1 > RootBridge
->Bus
.Limit
)
1318 return EFI_INVALID_PARAMETER
;
1321 // Update the Bus Range
1323 RootBridge
->ResAllocNode
[TypeBus
].Base
= Descriptor
->AddrRangeMin
;
1324 RootBridge
->ResAllocNode
[TypeBus
].Length
= Descriptor
->AddrLen
;
1325 RootBridge
->ResAllocNode
[TypeBus
].Status
= ResAllocated
;
1330 return EFI_INVALID_PARAMETER
;
1335 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
1337 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1338 @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements.
1339 are being submitted.
1340 @param Configuration The pointer to the PCI I/O and PCI memory resource descriptor.
1342 @retval EFI_SUCCESS Succeed.
1343 @retval EFI_INVALID_PARAMETER Wrong parameters passed in.
1348 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1349 IN EFI_HANDLE RootBridgeHandle
,
1350 IN VOID
*Configuration
1354 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1355 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1356 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
1357 PCI_RESOURCE_TYPE Type
;
1360 // Check the input parameter: Configuration
1362 if (Configuration
== NULL
) {
1363 return EFI_INVALID_PARAMETER
;
1366 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1367 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1368 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1369 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1371 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1372 if (RootBridgeHandle
== RootBridge
->Handle
) {
1373 DEBUG ((EFI_D_INFO
, "PciHostBridge: SubmitResources for %s\n", RootBridge
->DevicePathStr
));
1375 // Check the resource descriptors.
1376 // If the Configuration includes one or more invalid resource descriptors, all the resource
1377 // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.
1379 for (Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
1380 if (Descriptor
->ResType
> ACPI_ADDRESS_SPACE_TYPE_BUS
) {
1381 return EFI_INVALID_PARAMETER
;
1384 DEBUG ((EFI_D_INFO
, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",
1385 mAcpiAddressSpaceTypeStr
[Descriptor
->ResType
], Descriptor
->AddrSpaceGranularity
, Descriptor
->SpecificFlag
,
1386 (Descriptor
->SpecificFlag
& EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) != 0 ? L
" (Prefetchable)" : L
""
1388 DEBUG ((EFI_D_INFO
, " Length/Alignment = 0x%lx / 0x%lx\n", Descriptor
->AddrLen
, Descriptor
->AddrRangeMax
));
1389 switch (Descriptor
->ResType
) {
1390 case ACPI_ADDRESS_SPACE_TYPE_MEM
:
1391 if (Descriptor
->AddrSpaceGranularity
!= 32 && Descriptor
->AddrSpaceGranularity
!= 64) {
1392 return EFI_INVALID_PARAMETER
;
1394 if (Descriptor
->AddrSpaceGranularity
== 32 && Descriptor
->AddrLen
>= SIZE_4GB
) {
1395 return EFI_INVALID_PARAMETER
;
1398 // If the PCI root bridge does not support separate windows for nonprefetchable and
1399 // prefetchable memory, then the PCI bus driver needs to include requests for
1400 // prefetchable memory in the nonprefetchable memory pool.
1402 if (((RootBridge
->AllocationAttributes
& EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM
) != 0) &&
1403 ((Descriptor
->SpecificFlag
& EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) != 0)
1405 return EFI_INVALID_PARAMETER
;
1407 case ACPI_ADDRESS_SPACE_TYPE_IO
:
1409 // Check aligment, it should be of the form 2^n-1
1411 if (GetPowerOfTwo64 (Descriptor
->AddrRangeMax
+ 1) != (Descriptor
->AddrRangeMax
+ 1)) {
1412 return EFI_INVALID_PARAMETER
;
1420 if (Descriptor
->Desc
!= ACPI_END_TAG_DESCRIPTOR
) {
1421 return EFI_INVALID_PARAMETER
;
1424 for (Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Configuration
; Descriptor
->Desc
== ACPI_ADDRESS_SPACE_DESCRIPTOR
; Descriptor
++) {
1425 if (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
) {
1426 if (Descriptor
->AddrSpaceGranularity
== 32) {
1427 if ((Descriptor
->SpecificFlag
& EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) != 0) {
1433 ASSERT (Descriptor
->AddrSpaceGranularity
== 64);
1434 if ((Descriptor
->SpecificFlag
& EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
) != 0) {
1441 ASSERT (Descriptor
->ResType
== ACPI_ADDRESS_SPACE_TYPE_IO
);
1444 RootBridge
->ResAllocNode
[Type
].Length
= Descriptor
->AddrLen
;
1445 RootBridge
->ResAllocNode
[Type
].Alignment
= Descriptor
->AddrRangeMax
;
1446 RootBridge
->ResAllocNode
[Type
].Status
= ResSubmitted
;
1448 RootBridge
->ResourceSubmitted
= TRUE
;
1453 return EFI_INVALID_PARAMETER
;
1458 This function returns the proposed resource settings for the specified
1461 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1462 @param RootBridgeHandle The PCI Root Bridge handle.
1463 @param Configuration The pointer to the pointer to the PCI I/O
1464 and memory resource descriptor.
1466 @retval EFI_SUCCESS Succeed.
1467 @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.
1468 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
1473 GetProposedResources (
1474 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1475 IN EFI_HANDLE RootBridgeHandle
,
1476 OUT VOID
**Configuration
1480 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1481 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1485 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptor
;
1486 EFI_ACPI_END_TAG_DESCRIPTOR
*End
;
1489 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1490 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1491 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1492 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1494 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1495 if (RootBridgeHandle
== RootBridge
->Handle
) {
1496 for (Index
= 0, Number
= 0; Index
< TypeBus
; Index
++) {
1497 if (RootBridge
->ResAllocNode
[Index
].Status
!= ResNone
) {
1502 Buffer
= AllocateZeroPool (Number
* sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR
));
1503 if (Buffer
== NULL
) {
1504 return EFI_OUT_OF_RESOURCES
;
1507 Descriptor
= (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*) Buffer
;
1508 for (Index
= 0; Index
< TypeBus
; Index
++) {
1509 ResStatus
= RootBridge
->ResAllocNode
[Index
].Status
;
1510 if (ResStatus
!= ResNone
) {
1511 Descriptor
->Desc
= ACPI_ADDRESS_SPACE_DESCRIPTOR
;
1512 Descriptor
->Len
= sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
) - 3;;
1513 Descriptor
->GenFlag
= 0;
1515 // AddrRangeMin in Resource Descriptor here should be device address
1516 // instead of host address, or else PCI bus driver cannot set correct
1517 // address into PCI BAR registers.
1518 // Base in ResAllocNode is a host address, so conversion is needed.
1520 Descriptor
->AddrRangeMin
= TO_DEVICE_ADDRESS (RootBridge
->ResAllocNode
[Index
].Base
,
1521 GetTranslationByResourceType (RootBridge
, Index
));
1522 Descriptor
->AddrRangeMax
= 0;
1523 Descriptor
->AddrTranslationOffset
= (ResStatus
== ResAllocated
) ? EFI_RESOURCE_SATISFIED
: PCI_RESOURCE_LESS
;
1524 Descriptor
->AddrLen
= RootBridge
->ResAllocNode
[Index
].Length
;
1529 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_IO
;
1533 Descriptor
->SpecificFlag
= EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
;
1535 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_MEM
;
1536 Descriptor
->AddrSpaceGranularity
= 32;
1540 Descriptor
->SpecificFlag
= EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE
;
1542 Descriptor
->ResType
= ACPI_ADDRESS_SPACE_TYPE_MEM
;
1543 Descriptor
->AddrSpaceGranularity
= 64;
1550 End
= (EFI_ACPI_END_TAG_DESCRIPTOR
*) Descriptor
;
1551 End
->Desc
= ACPI_END_TAG_DESCRIPTOR
;
1554 *Configuration
= Buffer
;
1560 return EFI_INVALID_PARAMETER
;
1565 This function is called for all the PCI controllers that the PCI
1566 bus driver finds. Can be used to Preprogram the controller.
1568 @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
1569 @param RootBridgeHandle The PCI Root Bridge handle.
1570 @param PciAddress Address of the controller on the PCI bus.
1571 @param Phase The Phase during resource allocation.
1573 @retval EFI_SUCCESS Succeed.
1574 @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
1579 PreprocessController (
1580 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*This
,
1581 IN EFI_HANDLE RootBridgeHandle
,
1582 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress
,
1583 IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
1587 PCI_HOST_BRIDGE_INSTANCE
*HostBridge
;
1588 PCI_ROOT_BRIDGE_INSTANCE
*RootBridge
;
1590 if ((UINT32
) Phase
> EfiPciBeforeResourceCollection
) {
1591 return EFI_INVALID_PARAMETER
;
1594 HostBridge
= PCI_HOST_BRIDGE_FROM_THIS (This
);
1595 for (Link
= GetFirstNode (&HostBridge
->RootBridges
)
1596 ; !IsNull (&HostBridge
->RootBridges
, Link
)
1597 ; Link
= GetNextNode (&HostBridge
->RootBridges
, Link
)
1599 RootBridge
= ROOT_BRIDGE_FROM_LINK (Link
);
1600 if (RootBridgeHandle
== RootBridge
->Handle
) {
1605 return EFI_INVALID_PARAMETER
;