3 PCI Bus Driver Lib file
4 It abstracts some functions that can be different
5 between light PCI bus driver and full PCI bus driver
7 Copyright (c) 2006 - 2008, Intel Corporation
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest
= {
21 PciHotPlugRequestNotify
25 Install protocol gEfiPciHotPlugRequestProtocolGuid
26 @param Status return status of protocol installation.
29 InstallHotPlugRequestProtocol (
35 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
40 *Status
= gBS
->InstallProtocolInterface (
42 &gEfiPciHotPlugRequestProtocolGuid
,
49 Install protocol gEfiPciHotplugDeviceGuid into hotplug device
52 @param PciIoDevice hotplug device instance.
56 InstallPciHotplugGuid (
57 IN PCI_IO_DEVICE
*PciIoDevice
62 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
66 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Parent
->Pci
)) {
68 Status
= gBS
->InstallProtocolInterface (
70 &gEfiPciHotplugDeviceGuid
,
74 ASSERT_EFI_ERROR (Status
);
79 UnInstall protocol gEfiPciHotplugDeviceGuid into hotplug device
82 @param PciIoDevice hotplug device instance.
86 UninstallPciHotplugGuid (
87 IN PCI_IO_DEVICE
*PciIoDevice
92 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
96 Status
= gBS
->OpenProtocol (
98 &gEfiPciHotplugDeviceGuid
,
102 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
105 if (Status
== EFI_SUCCESS
) {
107 // This may triger CardBus driver to stop for
108 // Pccard devices opened the GUID via BY_DRIVER
110 Status
= gBS
->UninstallProtocolInterface (
112 &gEfiPciHotplugDeviceGuid
,
119 Retrieve the BAR information via PciIo interface.
121 @param PciIoDevice Pci device instance.
125 IN PCI_IO_DEVICE
*PciIoDevice
130 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
135 // Read PciBar information from the bar register
137 if (!gFullEnumeration
) {
141 &(PciIoDevice
->PciIo
),
148 (PciIoDevice
->PciBar
)[P2C_MEM_1
].BaseAddress
= (UINT64
) (Address
);
149 (PciIoDevice
->PciBar
)[P2C_MEM_1
].Length
= 0x2000000;
150 (PciIoDevice
->PciBar
)[P2C_MEM_1
].BarType
= PciBarTypeMem32
;
154 &(PciIoDevice
->PciIo
),
160 (PciIoDevice
->PciBar
)[P2C_MEM_2
].BaseAddress
= (UINT64
) (Address
);
161 (PciIoDevice
->PciBar
)[P2C_MEM_2
].Length
= 0x2000000;
162 (PciIoDevice
->PciBar
)[P2C_MEM_2
].BarType
= PciBarTypePMem32
;
166 &(PciIoDevice
->PciIo
),
172 (PciIoDevice
->PciBar
)[P2C_IO_1
].BaseAddress
= (UINT64
) (Address
);
173 (PciIoDevice
->PciBar
)[P2C_IO_1
].Length
= 0x100;
174 (PciIoDevice
->PciBar
)[P2C_IO_1
].BarType
= PciBarTypeIo16
;
178 &(PciIoDevice
->PciIo
),
184 (PciIoDevice
->PciBar
)[P2C_IO_2
].BaseAddress
= (UINT64
) (Address
);
185 (PciIoDevice
->PciBar
)[P2C_IO_2
].Length
= 0x100;
186 (PciIoDevice
->PciBar
)[P2C_IO_2
].BarType
= PciBarTypeIo16
;
190 if (gPciHotPlugInit
!= NULL
) {
191 GetResourcePaddingForHpb (PciIoDevice
);
196 Remove rejected pci device from specific root bridge
199 @param RootBridgeHandle specific parent root bridge handle.
200 @param Bridge Bridge device instance.
202 @retval EFI_SUCCESS Success operation.
205 RemoveRejectedPciDevices (
206 EFI_HANDLE RootBridgeHandle
,
207 IN PCI_IO_DEVICE
*Bridge
211 LIST_ENTRY
*CurrentLink
;
212 LIST_ENTRY
*LastLink
;
214 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
218 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
220 while (CurrentLink
!= NULL
&& CurrentLink
!= &Bridge
->ChildList
) {
222 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
224 if (IS_PCI_BRIDGE (&Temp
->Pci
)) {
226 // Remove rejected devices recusively
228 RemoveRejectedPciDevices (RootBridgeHandle
, Temp
);
231 // Skip rejection for all PPBs, while detect rejection for others
233 if (IsPciDeviceRejected (Temp
)) {
236 // For P2C, remove all devices on it
239 if (!IsListEmpty (&Temp
->ChildList
)) {
240 RemoveAllPciDeviceOnBridge (RootBridgeHandle
, Temp
);
244 // Finally remove itself
247 LastLink
= CurrentLink
->BackLink
;
248 RemoveEntryList (CurrentLink
);
249 FreePciDevice (Temp
);
251 CurrentLink
= LastLink
;
255 CurrentLink
= CurrentLink
->ForwardLink
;
262 Wrapper function for allocating resource for pci host bridge.
264 @param PciResAlloc Point to protocol instance EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
268 PciHostBridgeResourceAllocator (
269 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
272 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
273 return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
277 return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
284 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
286 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
288 @retval EFI_SUCCESS Success.
291 PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
292 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
295 PCI_IO_DEVICE
*RootBridgeDev
;
296 EFI_HANDLE RootBridgeHandle
;
304 UINT64 MaxOptionRomSize
;
305 PCI_RESOURCE_NODE
*IoBridge
;
306 PCI_RESOURCE_NODE
*Mem32Bridge
;
307 PCI_RESOURCE_NODE
*PMem32Bridge
;
308 PCI_RESOURCE_NODE
*Mem64Bridge
;
309 PCI_RESOURCE_NODE
*PMem64Bridge
;
310 PCI_RESOURCE_NODE IoPool
;
311 PCI_RESOURCE_NODE Mem32Pool
;
312 PCI_RESOURCE_NODE PMem32Pool
;
313 PCI_RESOURCE_NODE Mem64Pool
;
314 PCI_RESOURCE_NODE PMem64Pool
;
315 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD ExtendedData
;
318 // Initialize resource pool
321 InitializeResourcePool (&IoPool
, PciBarTypeIo16
);
322 InitializeResourcePool (&Mem32Pool
, PciBarTypeMem32
);
323 InitializeResourcePool (&PMem32Pool
, PciBarTypePMem32
);
324 InitializeResourcePool (&Mem64Pool
, PciBarTypeMem64
);
325 InitializeResourcePool (&PMem64Pool
, PciBarTypePMem64
);
327 RootBridgeDev
= NULL
;
328 RootBridgeHandle
= 0;
330 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
332 // Get RootBridg Device by handle
334 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
336 if (RootBridgeDev
== NULL
) {
337 return EFI_NOT_FOUND
;
341 // Get host bridge handle for status report
343 ExtendedData
.Handle
= RootBridgeDev
->PciRootBridgeIo
->ParentHandle
;
346 // Create the entire system resource map from the information collected by
347 // enumerator. Several resource tree was created
350 IoBridge
= CreateResourceNode (
359 Mem32Bridge
= CreateResourceNode (
368 PMem32Bridge
= CreateResourceNode (
377 Mem64Bridge
= CreateResourceNode (
386 PMem64Bridge
= CreateResourceNode (
396 // Create resourcemap by going through all the devices subject to this root bridge
398 Status
= CreateResourceMap (
408 // Get the max ROM size that the root bridge can process
410 RootBridgeDev
->RomSize
= Mem32Bridge
->Length
;
413 // Get Max Option Rom size for current root bridge
415 MaxOptionRomSize
= GetMaxOptionRomSize (RootBridgeDev
);
418 // Enlarger the mem32 resource to accomdate the option rom
419 // if the mem32 resource is not enough to hold the rom
421 if (MaxOptionRomSize
> Mem32Bridge
->Length
) {
423 Mem32Bridge
->Length
= MaxOptionRomSize
;
424 RootBridgeDev
->RomSize
= MaxOptionRomSize
;
427 // Alignment should be adjusted as well
429 if (Mem32Bridge
->Alignment
< MaxOptionRomSize
- 1) {
430 Mem32Bridge
->Alignment
= MaxOptionRomSize
- 1;
435 // Based on the all the resource tree, contruct ACPI resource node to
436 // submit the resource aperture to pci host bridge protocol
438 Status
= ConstructAcpiResourceRequestor (
449 // Insert these resource nodes into the database
451 InsertResourceNode (&IoPool
, IoBridge
);
452 InsertResourceNode (&Mem32Pool
, Mem32Bridge
);
453 InsertResourceNode (&PMem32Pool
, PMem32Bridge
);
454 InsertResourceNode (&Mem64Pool
, Mem64Bridge
);
455 InsertResourceNode (&PMem64Pool
, PMem64Bridge
);
457 if (Status
== EFI_SUCCESS
) {
459 // Submit the resource requirement
461 Status
= PciResAlloc
->SubmitResources (
463 RootBridgeDev
->Handle
,
468 // Free acpi resource node
470 if (AcpiConfig
!= NULL
) {
471 FreePool (AcpiConfig
);
474 if (EFI_ERROR (Status
)) {
476 // Destroy all the resource tree
478 DestroyResourceTree (&IoPool
);
479 DestroyResourceTree (&Mem32Pool
);
480 DestroyResourceTree (&PMem32Pool
);
481 DestroyResourceTree (&Mem64Pool
);
482 DestroyResourceTree (&PMem64Pool
);
491 // Notify pci bus driver starts to program the resource
493 Status
= NotifyPhase (PciResAlloc
, EfiPciHostBridgeAllocateResources
);
495 if (EFI_ERROR (Status
)) {
497 // Allocation failed, then return
499 return EFI_OUT_OF_RESOURCES
;
502 // Raise the EFI_IOB_PCI_RES_ALLOC status code
504 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
506 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_RES_ALLOC
,
507 (VOID
*) &ExtendedData
,
508 sizeof (ExtendedData
)
512 // Notify pci bus driver starts to program the resource
514 NotifyPhase (PciResAlloc
, EfiPciHostBridgeSetResources
);
516 RootBridgeDev
= NULL
;
518 RootBridgeHandle
= 0;
520 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
522 // Get RootBridg Device by handle
524 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
526 if (RootBridgeDev
== NULL
) {
527 return EFI_NOT_FOUND
;
531 // Get acpi resource node for all the resource types
534 Status
= PciResAlloc
->GetProposedResources (
536 RootBridgeDev
->Handle
,
540 if (EFI_ERROR (Status
)) {
545 // Get the resource base by interpreting acpi resource node
558 // Process option rom for this root bridge
560 Status
= ProcessOptionRom (RootBridgeDev
, Mem32Base
, RootBridgeDev
->RomSize
);
563 // Create the entire system resource map from the information collected by
564 // enumerator. Several resource tree was created
566 Status
= GetResourceMap (
580 if (EFI_ERROR (Status
)) {
585 // Program IO resources
593 // Program Mem32 resources
601 // Program PMem32 resources
609 // Program Mem64 resources
617 // Program PMem64 resources
624 if (AcpiConfig
!= NULL
) {
625 FreePool (AcpiConfig
);
630 // Destroy all the resource tree
632 DestroyResourceTree (&IoPool
);
633 DestroyResourceTree (&Mem32Pool
);
634 DestroyResourceTree (&PMem32Pool
);
635 DestroyResourceTree (&Mem64Pool
);
636 DestroyResourceTree (&PMem64Pool
);
639 // Notify the resource allocation phase is to end
641 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndResourceAllocation
);
647 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
649 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
651 @retval EFI_SUCCESS Success.
654 PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
655 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
658 PCI_IO_DEVICE
*RootBridgeDev
;
659 EFI_HANDLE RootBridgeHandle
;
668 UINT64 Mem32ResStatus
;
669 UINT64 PMem32ResStatus
;
670 UINT64 Mem64ResStatus
;
671 UINT64 PMem64ResStatus
;
672 UINT64 MaxOptionRomSize
;
673 PCI_RESOURCE_NODE
*IoBridge
;
674 PCI_RESOURCE_NODE
*Mem32Bridge
;
675 PCI_RESOURCE_NODE
*PMem32Bridge
;
676 PCI_RESOURCE_NODE
*Mem64Bridge
;
677 PCI_RESOURCE_NODE
*PMem64Bridge
;
678 PCI_RESOURCE_NODE IoPool
;
679 PCI_RESOURCE_NODE Mem32Pool
;
680 PCI_RESOURCE_NODE PMem32Pool
;
681 PCI_RESOURCE_NODE Mem64Pool
;
682 PCI_RESOURCE_NODE PMem64Pool
;
684 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData
;
685 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData
;
693 // It will try several times if the resource allocation fails
698 // Initialize resource pool
700 InitializeResourcePool (&IoPool
, PciBarTypeIo16
);
701 InitializeResourcePool (&Mem32Pool
, PciBarTypeMem32
);
702 InitializeResourcePool (&PMem32Pool
, PciBarTypePMem32
);
703 InitializeResourcePool (&Mem64Pool
, PciBarTypeMem64
);
704 InitializeResourcePool (&PMem64Pool
, PciBarTypePMem64
);
706 RootBridgeDev
= NULL
;
707 RootBridgeHandle
= 0;
709 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
712 // Get RootBridg Device by handle
714 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
716 if (RootBridgeDev
== NULL
) {
717 return EFI_NOT_FOUND
;
721 // Create the entire system resource map from the information collected by
722 // enumerator. Several resource tree was created
725 IoBridge
= CreateResourceNode (
734 Mem32Bridge
= CreateResourceNode (
743 PMem32Bridge
= CreateResourceNode (
752 Mem64Bridge
= CreateResourceNode (
761 PMem64Bridge
= CreateResourceNode (
771 // Create resourcemap by going through all the devices subject to this root bridge
773 Status
= CreateResourceMap (
783 // Get the max ROM size that the root bridge can process
785 RootBridgeDev
->RomSize
= Mem32Bridge
->Length
;
788 // Skip to enlarge the resource request during realloction
792 // Get Max Option Rom size for current root bridge
794 MaxOptionRomSize
= GetMaxOptionRomSize (RootBridgeDev
);
797 // Enlarger the mem32 resource to accomdate the option rom
798 // if the mem32 resource is not enough to hold the rom
800 if (MaxOptionRomSize
> Mem32Bridge
->Length
) {
802 Mem32Bridge
->Length
= MaxOptionRomSize
;
803 RootBridgeDev
->RomSize
= MaxOptionRomSize
;
806 // Alignment should be adjusted as well
808 if (Mem32Bridge
->Alignment
< MaxOptionRomSize
- 1) {
809 Mem32Bridge
->Alignment
= MaxOptionRomSize
- 1;
815 // Based on the all the resource tree, contruct ACPI resource node to
816 // submit the resource aperture to pci host bridge protocol
818 Status
= ConstructAcpiResourceRequestor (
829 // Insert these resource nodes into the database
831 InsertResourceNode (&IoPool
, IoBridge
);
832 InsertResourceNode (&Mem32Pool
, Mem32Bridge
);
833 InsertResourceNode (&PMem32Pool
, PMem32Bridge
);
834 InsertResourceNode (&Mem64Pool
, Mem64Bridge
);
835 InsertResourceNode (&PMem64Pool
, PMem64Bridge
);
837 if (Status
== EFI_SUCCESS
) {
839 // Submit the resource requirement
841 Status
= PciResAlloc
->SubmitResources (
843 RootBridgeDev
->Handle
,
849 // Free acpi resource node
851 if (AcpiConfig
!= NULL
) {
852 FreePool (AcpiConfig
);
855 if (EFI_ERROR (Status
)) {
857 // Destroy all the resource tree
859 DestroyResourceTree (&IoPool
);
860 DestroyResourceTree (&Mem32Pool
);
861 DestroyResourceTree (&PMem32Pool
);
862 DestroyResourceTree (&Mem64Pool
);
863 DestroyResourceTree (&PMem64Pool
);
869 // Notify pci bus driver starts to program the resource
872 Status
= NotifyPhase (PciResAlloc
, EfiPciHostBridgeAllocateResources
);
874 if (!EFI_ERROR (Status
)) {
876 // Allocation succeed, then continue the following
882 // If the resource allocation is unsuccessful, free resources on bridge
885 RootBridgeDev
= NULL
;
886 RootBridgeHandle
= 0;
888 IoResStatus
= EFI_RESOURCE_SATISFIED
;
889 Mem32ResStatus
= EFI_RESOURCE_SATISFIED
;
890 PMem32ResStatus
= EFI_RESOURCE_SATISFIED
;
891 Mem64ResStatus
= EFI_RESOURCE_SATISFIED
;
892 PMem64ResStatus
= EFI_RESOURCE_SATISFIED
;
894 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
896 // Get RootBridg Device by handle
898 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
899 if (RootBridgeDev
== NULL
) {
900 return EFI_NOT_FOUND
;
904 // Get host bridge handle for status report
906 HandleExtendedData
.Handle
= RootBridgeDev
->PciRootBridgeIo
->ParentHandle
;
909 // Get acpi resource node for all the resource types
913 Status
= PciResAlloc
->GetProposedResources (
915 RootBridgeDev
->Handle
,
919 if (EFI_ERROR (Status
)) {
923 if (AcpiConfig
!= NULL
) {
925 // Adjust resource allocation policy for each RB
927 GetResourceAllocationStatus (
935 FreePool (AcpiConfig
);
943 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
946 // It is very difficult to follow the spec here
947 // Device path , Bar index can not be get here
949 ZeroMem (&AllocFailExtendedData
, sizeof (AllocFailExtendedData
));
951 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
953 EFI_IO_BUS_PCI
| EFI_IOB_EC_RESOURCE_CONFLICT
,
954 (VOID
*) &AllocFailExtendedData
,
955 sizeof (AllocFailExtendedData
)
958 Status
= PciHostBridgeAdjustAllocation (
972 // Destroy all the resource tree
974 DestroyResourceTree (&IoPool
);
975 DestroyResourceTree (&Mem32Pool
);
976 DestroyResourceTree (&PMem32Pool
);
977 DestroyResourceTree (&Mem64Pool
);
978 DestroyResourceTree (&PMem64Pool
);
980 NotifyPhase (PciResAlloc
, EfiPciHostBridgeFreeResources
);
982 if (EFI_ERROR (Status
)) {
994 // Raise the EFI_IOB_PCI_RES_ALLOC status code
996 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
998 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_RES_ALLOC
,
999 (VOID
*) &HandleExtendedData
,
1000 sizeof (HandleExtendedData
)
1004 // Notify pci bus driver starts to program the resource
1006 NotifyPhase (PciResAlloc
, EfiPciHostBridgeSetResources
);
1008 RootBridgeDev
= NULL
;
1010 RootBridgeHandle
= 0;
1012 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1015 // Get RootBridg Device by handle
1017 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
1019 if (RootBridgeDev
== NULL
) {
1020 return EFI_NOT_FOUND
;
1024 // Get acpi resource node for all the resource types
1027 Status
= PciResAlloc
->GetProposedResources (
1029 RootBridgeDev
->Handle
,
1033 if (EFI_ERROR (Status
)) {
1038 // Get the resource base by interpreting acpi resource node
1051 // Process option rom for this root bridge
1053 Status
= ProcessOptionRom (RootBridgeDev
, Mem32Base
, RootBridgeDev
->RomSize
);
1056 // Create the entire system resource map from the information collected by
1057 // enumerator. Several resource tree was created
1059 Status
= GetResourceMap (
1073 if (EFI_ERROR (Status
)) {
1078 // Program IO resources
1086 // Program Mem32 resources
1094 // Program PMem32 resources
1102 // Program Mem64 resources
1110 // Program PMem64 resources
1117 if (AcpiConfig
!= NULL
) {
1118 gBS
->FreePool (AcpiConfig
);
1123 // Destroy all the resource tree
1125 DestroyResourceTree (&IoPool
);
1126 DestroyResourceTree (&Mem32Pool
);
1127 DestroyResourceTree (&PMem32Pool
);
1128 DestroyResourceTree (&Mem64Pool
);
1129 DestroyResourceTree (&PMem64Pool
);
1132 // Notify the resource allocation phase is to end
1134 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndResourceAllocation
);
1140 Wapper function of scanning pci bus and assign bus number to the given PCI bus system
1141 Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
1143 @param Bridge Bridge device instance.
1144 @param StartBusNumber start point.
1145 @param SubBusNumber Point to sub bus number.
1146 @param PaddedBusRange Customized bus number.
1148 @retval EFI_SUCCESS Success.
1149 @retval EFI_DEVICE_ERROR Fail to scan bus.
1153 IN PCI_IO_DEVICE
*Bridge
,
1154 IN UINT8 StartBusNumber
,
1155 OUT UINT8
*SubBusNumber
,
1156 OUT UINT8
*PaddedBusRange
1159 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1160 return PciScanBus_WithHotPlugDeviceSupport (
1167 return PciScanBus_WithoutHotPlugDeviceSupport (
1177 Wapper function of scanning pci bus and assign bus number to the given PCI bus system
1178 Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
1180 @param Bridge Bridge device instance.
1181 @param StartBusNumber start point.
1182 @param SubBusNumber Point to sub bus number.
1183 @param PaddedBusRange Customized bus number.
1185 @retval EFI_SUCCESS Success.
1186 @retval EFI_DEVICE_ERROR Fail to scan bus.
1189 PciScanBus_WithoutHotPlugDeviceSupport (
1190 IN PCI_IO_DEVICE
*Bridge
,
1191 IN UINT8 StartBusNumber
,
1192 OUT UINT8
*SubBusNumber
,
1193 OUT UINT8
*PaddedBusRange
1203 PCI_IO_DEVICE
*PciDevice
;
1204 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1206 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
1210 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
1211 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
1214 // Check to see whether a pci device is present
1216 Status
= PciDevicePresent (
1224 if (!EFI_ERROR (Status
)) {
1225 DEBUG((EFI_D_ERROR
, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber
, Device
, Func
));
1227 if (IS_PCI_BRIDGE (&Pci
) ||
1228 IS_CARDBUS_BRIDGE (&Pci
)) {
1231 // Get the bridge information
1233 Status
= PciSearchDevice (
1242 if (EFI_ERROR (Status
)) {
1247 // Add feature to support customized secondary bus number
1249 if (*SubBusNumber
== 0) {
1250 *SubBusNumber
= *PaddedBusRange
;
1251 *PaddedBusRange
= 0;
1256 SecondBus
= (*SubBusNumber
);
1258 Register
= (UINT16
) ((SecondBus
<< 8) | (UINT16
) StartBusNumber
);
1260 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
1262 Status
= PciRootBridgeIoWrite (
1272 // Initialize SubBusNumber to SecondBus
1274 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1275 Status
= PciRootBridgeIoWrite (
1284 // If it is PPB, resursively search down this bridge
1286 if (IS_PCI_BRIDGE (&Pci
)) {
1288 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
1289 // PCI configuration transaction to go through any PPB
1291 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1293 Status
= PciRootBridgeIoWrite (
1302 PreprocessController (
1304 PciDevice
->BusNumber
,
1305 PciDevice
->DeviceNumber
,
1306 PciDevice
->FunctionNumber
,
1307 EfiPciBeforeChildBusEnumeration
1310 DEBUG((EFI_D_ERROR
, "Scan PPB(%02d,%02d,%02d)\n", PciDevice
->BusNumber
, PciDevice
->DeviceNumber
,PciDevice
->FunctionNumber
));
1311 Status
= PciScanBus (
1313 (UINT8
) (SecondBus
),
1318 if (EFI_ERROR (Status
)) {
1319 return EFI_DEVICE_ERROR
;
1324 // Set the current maximum bus number under the PPB
1327 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1329 Status
= PciRootBridgeIoWrite (
1340 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
1343 // Skip sub functions, this is not a multi function device
1346 Func
= PCI_MAX_FUNC
;
1355 Wapper function of scanning pci bus and assign bus number to the given PCI bus system
1356 Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
1358 @param Bridge Bridge device instance.
1359 @param StartBusNumber start point.
1360 @param SubBusNumber Point to sub bus number.
1361 @param PaddedBusRange Customized bus number.
1363 @retval EFI_SUCCESS Success.
1364 @retval EFI_DEVICE_ERROR Fail to scan bus.
1367 PciScanBus_WithHotPlugDeviceSupport (
1368 IN PCI_IO_DEVICE
*Bridge
,
1369 IN UINT8 StartBusNumber
,
1370 OUT UINT8
*SubBusNumber
,
1371 OUT UINT8
*PaddedBusRange
1382 PCI_IO_DEVICE
*PciDevice
;
1384 EFI_HPC_STATE State
;
1386 EFI_HPC_PADDING_ATTRIBUTES Attributes
;
1387 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
1389 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1392 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
1396 Attributes
= (EFI_HPC_PADDING_ATTRIBUTES
) 0;
1399 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
1400 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
1403 // Check to see whether a pci device is present
1405 Status
= PciDevicePresent (
1413 if (EFI_ERROR (Status
)) {
1416 // Skip sub functions, this is not a multi function device
1418 Func
= PCI_MAX_FUNC
;
1424 DEBUG((EFI_D_ERROR
, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber
, Device
, Func
));
1427 // Get the PCI device information
1429 Status
= PciSearchDevice (
1438 ASSERT (!EFI_ERROR (Status
));
1440 PciAddress
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0);
1442 if (!IS_PCI_BRIDGE (&Pci
)) {
1444 // PCI bridges will be called later
1445 // Here just need for PCI device or PCI to cardbus controller
1446 // EfiPciBeforeChildBusEnumeration for PCI Device Node
1448 PreprocessController (
1450 PciDevice
->BusNumber
,
1451 PciDevice
->DeviceNumber
,
1452 PciDevice
->FunctionNumber
,
1453 EfiPciBeforeChildBusEnumeration
1458 // For Pci Hotplug controller devcie only
1460 if (gPciHotPlugInit
!= NULL
) {
1462 // Check if it is a Hotplug PCI controller
1464 if (IsRootPciHotPlugController (PciDevice
->DevicePath
, &HpIndex
)) {
1466 if (!gPciRootHpcData
[HpIndex
].Initialized
) {
1468 Status
= CreateEventForHpc (HpIndex
, &Event
);
1470 ASSERT (!EFI_ERROR (Status
));
1472 Status
= gPciHotPlugInit
->InitializeRootHpc (
1474 gPciRootHpcPool
[HpIndex
].HpcDevicePath
,
1480 PreprocessController (
1482 PciDevice
->BusNumber
,
1483 PciDevice
->DeviceNumber
,
1484 PciDevice
->FunctionNumber
,
1485 EfiPciBeforeChildBusEnumeration
1491 if (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
)) {
1494 // Get the bridge information
1497 if (gPciHotPlugInit
!= NULL
) {
1499 if (IsRootPciHotPlugBus (PciDevice
->DevicePath
, &HpIndex
)) {
1502 // If it is initialized, get the padded bus range
1504 Status
= gPciHotPlugInit
->GetResourcePadding (
1506 gPciRootHpcPool
[HpIndex
].HpbDevicePath
,
1509 (VOID
**) &Descriptors
,
1513 if (EFI_ERROR (Status
)) {
1518 Status
= PciGetBusRange (
1525 gBS
->FreePool (Descriptors
);
1527 if (EFI_ERROR (Status
)) {
1536 // Add feature to support customized secondary bus number
1538 if (*SubBusNumber
== 0) {
1539 *SubBusNumber
= *PaddedBusRange
;
1540 *PaddedBusRange
= 0;
1544 SecondBus
= *SubBusNumber
;
1546 Register
= (UINT16
) ((SecondBus
<< 8) | (UINT16
) StartBusNumber
);
1547 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
1549 Status
= PciRootBridgeIoWrite (
1560 // If it is PPB, resursively search down this bridge
1562 if (IS_PCI_BRIDGE (&Pci
)) {
1565 // Initialize SubBusNumber to Maximum bus number
1568 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1569 Status
= PciRootBridgeIoWrite (
1579 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
1581 PreprocessController (
1583 PciDevice
->BusNumber
,
1584 PciDevice
->DeviceNumber
,
1585 PciDevice
->FunctionNumber
,
1586 EfiPciBeforeChildBusEnumeration
1589 DEBUG((EFI_D_ERROR
, "Scan PPB(%02d,%02d,%02d)\n", PciDevice
->BusNumber
, PciDevice
->DeviceNumber
,PciDevice
->FunctionNumber
));
1590 Status
= PciScanBus (
1592 (UINT8
) (SecondBus
),
1597 if (EFI_ERROR (Status
)) {
1598 return EFI_DEVICE_ERROR
;
1604 // Ensure the device is enabled and initialized
1606 if ((Attributes
== EfiPaddingPciRootBridge
) &&
1607 (State
& EFI_HPC_STATE_ENABLED
) != 0 &&
1608 (State
& EFI_HPC_STATE_INITIALIZED
) != 0) {
1609 *PaddedBusRange
= (UINT8
) ((UINT8
) (BusRange
) +*PaddedBusRange
);
1611 *SubBusNumber
= (UINT8
) ((UINT8
) (BusRange
) +*SubBusNumber
);
1616 // Set the current maximum bus number under the PPB
1618 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1620 Status
= PciRootBridgeIoWrite (
1630 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
1633 // Skip sub functions, this is not a multi function device
1635 Func
= PCI_MAX_FUNC
;
1645 Process Option Rom on this host bridge.
1647 @param Bridge Pci bridge device instance.
1649 @retval EFI_SUCCESS Success.
1652 PciRootBridgeP2CProcess (
1653 IN PCI_IO_DEVICE
*Bridge
1656 LIST_ENTRY
*CurrentLink
;
1657 PCI_IO_DEVICE
*Temp
;
1658 EFI_HPC_STATE State
;
1662 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
1664 while (CurrentLink
!= NULL
&& CurrentLink
!= &Bridge
->ChildList
) {
1666 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1668 if (IS_CARDBUS_BRIDGE (&Temp
->Pci
)) {
1670 if (gPciHotPlugInit
!= NULL
&& Temp
->Allocated
) {
1673 // Raise the EFI_IOB_PCI_HPC_INIT status code
1675 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1677 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_HPC_INIT
,
1681 PciAddress
= EFI_PCI_ADDRESS (Temp
->BusNumber
, Temp
->DeviceNumber
, Temp
->FunctionNumber
, 0);
1682 Status
= gPciHotPlugInit
->InitializeRootHpc (
1690 if (!EFI_ERROR (Status
)) {
1691 Status
= PciBridgeEnumerator (Temp
);
1693 if (EFI_ERROR (Status
)) {
1698 CurrentLink
= CurrentLink
->ForwardLink
;
1704 if (!IsListEmpty (&Temp
->ChildList
)) {
1705 Status
= PciRootBridgeP2CProcess (Temp
);
1708 CurrentLink
= CurrentLink
->ForwardLink
;
1715 Process Option Rom on this host bridge.
1717 @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
1719 @retval EFI_NOT_FOUND Can not find the root bridge instance.
1720 @retval EFI_SUCCESS Success process.
1723 PciHostBridgeP2CProcess (
1724 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
1727 EFI_HANDLE RootBridgeHandle
;
1728 PCI_IO_DEVICE
*RootBridgeDev
;
1731 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1735 RootBridgeHandle
= NULL
;
1737 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1740 // Get RootBridg Device by handle
1742 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
1744 if (RootBridgeDev
== NULL
) {
1745 return EFI_NOT_FOUND
;
1748 Status
= PciRootBridgeP2CProcess (RootBridgeDev
);
1750 if (EFI_ERROR (Status
)) {
1760 This function is used to enumerate the entire host bridge
1761 in a given platform.
1763 @param PciResAlloc A pointer to the resource allocate protocol.
1765 @retval EFI_OUT_OF_RESOURCES no enough resource.
1766 @retval EFI_SUCCESS Success.
1770 PciHostBridgeEnumerator (
1771 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
1774 EFI_HANDLE RootBridgeHandle
;
1775 PCI_IO_DEVICE
*RootBridgeDev
;
1777 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1779 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
1780 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Configuration
;
1781 UINT8 StartBusNumber
;
1782 LIST_ENTRY RootBridgeList
;
1785 InitializeHotPlugSupport ();
1787 InitializeListHead (&RootBridgeList
);
1790 // Notify the bus allocation phase is about to start
1792 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginBusAllocation
);
1794 DEBUG((EFI_D_ERROR
, "PCI Bus First Scanning\n"));
1795 RootBridgeHandle
= NULL
;
1796 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1799 // if a root bridge instance is found, create root bridge device for it
1802 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1804 if (RootBridgeDev
== NULL
) {
1805 return EFI_OUT_OF_RESOURCES
;
1809 // Enumerate all the buses under this root bridge
1812 Status
= PciRootBridgeEnumerator (
1817 if (gPciHotPlugInit
!= NULL
) {
1818 InsertTailList (&RootBridgeList
, &(RootBridgeDev
->Link
));
1820 DestroyRootBridge (RootBridgeDev
);
1822 if (EFI_ERROR (Status
)) {
1828 // Notify the bus allocation phase is finished for the first time
1830 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1832 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1834 if (gPciHotPlugInit
!= NULL
) {
1836 // Reset all assigned PCI bus number in all PPB
1838 RootBridgeHandle
= NULL
;
1839 Link
= GetFirstNode (&RootBridgeList
);
1840 while ((PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) &&
1841 (!IsNull (&RootBridgeList
, Link
))) {
1842 RootBridgeDev
= PCI_IO_DEVICE_FROM_LINK (Link
);
1844 // Get the Bus information
1846 Status
= PciResAlloc
->StartBusEnumeration (
1849 (VOID
**) &Configuration
1851 if (EFI_ERROR (Status
)) {
1856 // Get the bus number to start with
1858 StartBusNumber
= (UINT8
) (Configuration
->AddrRangeMin
);
1860 ResetAllPpbBusNumber (
1865 gBS
->FreePool (Configuration
);
1866 Link
= GetNextNode (&RootBridgeList
, Link
);
1867 DestroyRootBridge (RootBridgeDev
);
1871 // Wait for all HPC initialized
1873 Status
= AllRootHPCInitialized (STALL_1_SECOND
* 15);
1875 if (EFI_ERROR (Status
)) {
1880 // Notify the bus allocation phase is about to start for the 2nd time
1882 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginBusAllocation
);
1884 DEBUG((EFI_D_ERROR
, "PCI Bus Second Scanning\n"));
1885 RootBridgeHandle
= NULL
;
1886 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1889 // if a root bridge instance is found, create root bridge device for it
1892 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1894 if (RootBridgeDev
== NULL
) {
1895 return EFI_OUT_OF_RESOURCES
;
1899 // Enumerate all the buses under this root bridge
1902 Status
= PciRootBridgeEnumerator (
1907 DestroyRootBridge (RootBridgeDev
);
1908 if (EFI_ERROR (Status
)) {
1914 // Notify the bus allocation phase is to end for the 2nd time
1916 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1921 // Notify the resource allocation phase is to start
1923 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginResourceAllocation
);
1925 RootBridgeHandle
= NULL
;
1926 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1929 // if a root bridge instance is found, create root bridge device for it
1932 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1934 if (RootBridgeDev
== NULL
) {
1935 return EFI_OUT_OF_RESOURCES
;
1938 Status
= StartManagingRootBridge (RootBridgeDev
);
1940 if (EFI_ERROR (Status
)) {
1944 PciRootBridgeIo
= RootBridgeDev
->PciRootBridgeIo
;
1945 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**) &Descriptors
);
1947 if (EFI_ERROR (Status
)) {
1951 Status
= PciGetBusRange (&Descriptors
, &MinBus
, NULL
, NULL
);
1953 if (EFI_ERROR (Status
)) {
1958 // Determine root bridge attribute by calling interface of Pcihostbridge
1961 DetermineRootBridgeAttributes (
1967 // Collect all the resource information under this root bridge
1968 // A database that records all the information about pci device subject to this
1969 // root bridge will then be created
1971 Status
= PciPciDeviceInfoCollector (
1976 if (EFI_ERROR (Status
)) {
1980 InsertRootBridge (RootBridgeDev
);
1983 // Record the hostbridge handle
1985 AddHostBridgeEnumerator (RootBridgeDev
->PciRootBridgeIo
->ParentHandle
);
1992 Read PCI device configuration register by specified address.
1994 This function check the incompatiblilites on PCI device. Return the register
1997 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1998 @param PciIo A pointer to EFI_PCI_PROTOCOL.
1999 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2000 @param Width Signifies the width of the memory operations.
2001 @param Address The address within the PCI configuration space for the PCI controller.
2002 @param Buffer For read operations, the destination buffer to store the results. For
2003 write operations, the source buffer to write data from.
2005 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2006 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2007 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2008 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2013 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2014 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2015 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2023 EFI_PCI_REGISTER_ACCESS_DATA
*PciRegisterAccessData
;
2024 UINT64 AccessAddress
;
2029 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2031 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT
) {
2033 // check access compatibility at first time
2035 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_READ
, Address
& 0xff, Width
, &PciRegisterAccessData
);
2037 if (Status
== EFI_SUCCESS
) {
2039 // there exist incompatibility on this operation
2041 AccessWidth
= Width
;
2043 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2044 AccessWidth
= PciRegisterAccessData
->Width
;
2047 AccessAddress
= Address
& ~((1 << AccessWidth
) - 1);
2051 Pointer
= (UINT8
*) &TempBuffer
;
2055 if (PciRootBridgeIo
!= NULL
) {
2056 Status
= PciRootBridgeIo
->Pci
.Read (
2058 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) AccessWidth
,
2063 } else if (PciIo
!= NULL
) {
2064 Status
= PciIo
->Pci
.Read (
2066 (EFI_PCI_IO_PROTOCOL_WIDTH
) AccessWidth
,
2067 (UINT32
) AccessAddress
,
2073 if (Status
!= EFI_SUCCESS
) {
2077 Stride
= (UINTN
)1 << AccessWidth
;
2078 AccessAddress
+= Stride
;
2079 if (AccessAddress
>= (Address
+ LShiftU64 (1ULL, (UINTN
)Width
))) {
2081 // if all datas have been read, exist
2088 if ((AccessAddress
& 0xff) < PciRegisterAccessData
->EndOffset
) {
2090 // if current offset doesn't reach the end
2095 FreePool (PciRegisterAccessData
);
2098 // continue checking access incompatibility
2100 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_READ
, AccessAddress
& 0xff, AccessWidth
, &PciRegisterAccessData
);
2101 if (Status
== EFI_SUCCESS
) {
2102 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2103 AccessWidth
= PciRegisterAccessData
->Width
;
2108 FreePool (PciRegisterAccessData
);
2111 case EfiPciWidthUint8
:
2112 * (UINT8
*) Buffer
= (UINT8
) TempBuffer
;
2114 case EfiPciWidthUint16
:
2115 * (UINT16
*) Buffer
= (UINT16
) TempBuffer
;
2117 case EfiPciWidthUint32
:
2118 * (UINT32
*) Buffer
= (UINT32
) TempBuffer
;
2121 return EFI_UNSUPPORTED
;
2128 // AccessWidth incompatible check not supportted
2129 // or, there doesn't exist incompatibility on this operation
2131 if (PciRootBridgeIo
!= NULL
) {
2132 Status
= PciRootBridgeIo
->Pci
.Read (
2134 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
2141 Status
= PciIo
->Pci
.Read (
2143 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
2154 Update register value by checking PCI device incompatibility.
2156 This function check register value incompatibilites on PCI device. Return the register
2159 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2160 @param AccessType Access type, READ or WRITE.
2161 @param Width Signifies the width of the memory operations.
2162 @param Address The address within the PCI configuration space.
2163 @param Buffer Store the register data.
2165 @retval EFI_SUCCESS The data has been updated.
2170 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2171 IN UINT64 AccessType
,
2178 EFI_PCI_REGISTER_VALUE_DATA
*PciRegisterData
;
2184 // check register value incompatibility
2186 Status
= PciRegisterUpdateCheck (PciDeviceInfo
, AccessType
, Address
& 0xff, &PciRegisterData
);
2188 if (Status
== EFI_SUCCESS
) {
2190 AndValue
= ((UINT32
) PciRegisterData
->AndValue
) >> (((UINT8
) Address
& 0x3) * 8);
2191 OrValue
= ((UINT32
) PciRegisterData
->OrValue
) >> (((UINT8
) Address
& 0x3) * 8);
2193 TempValue
= * (UINT32
*) Buffer
;
2194 if (PciRegisterData
->AndValue
!= VALUE_NOCARE
) {
2195 TempValue
&= AndValue
;
2197 if (PciRegisterData
->OrValue
!= VALUE_NOCARE
) {
2198 TempValue
|= OrValue
;
2202 case EfiPciWidthUint8
:
2203 *(UINT8
*)Buffer
= (UINT8
) TempValue
;
2206 case EfiPciWidthUint16
:
2207 *(UINT16
*)Buffer
= (UINT16
) TempValue
;
2209 case EfiPciWidthUint32
:
2210 *(UINT32
*)Buffer
= TempValue
;
2214 return EFI_UNSUPPORTED
;
2217 FreePool (PciRegisterData
);
2224 Write PCI device configuration register by specified address.
2226 This function check the incompatiblilites on PCI device, and write date
2229 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2230 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2231 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2232 @param Width Signifies the width of the memory operations.
2233 @param Address The address within the PCI configuration space for the PCI controller.
2234 @param Buffer For read operations, the destination buffer to store the results. For
2235 write operations, the source buffer to write data from.
2237 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2238 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2239 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2240 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2245 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2246 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2247 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2255 EFI_PCI_REGISTER_ACCESS_DATA
*PciRegisterAccessData
;
2256 UINT64 AccessAddress
;
2262 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2264 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT
) {
2266 // check access compatibility at first time
2268 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_WRITE
, Address
& 0xff, Width
, &PciRegisterAccessData
);
2270 if (Status
== EFI_SUCCESS
) {
2272 // there exist incompatibility on this operation
2274 AccessWidth
= Width
;
2276 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2277 AccessWidth
= PciRegisterAccessData
->Width
;
2280 AccessAddress
= Address
& ~((1 << AccessWidth
) - 1);
2283 Pointer
= (UINT8
*) &Buffer
;
2284 Data
= * (UINT64
*) Buffer
;
2288 if (AccessWidth
> Width
) {
2290 // if actual access width is larger than orignal one, additional data need to be read back firstly
2292 Status
= ReadConfigData (PciRootBridgeIo
, PciIo
, PciDeviceInfo
, AccessWidth
, AccessAddress
, &Data
);
2293 if (Status
!= EFI_SUCCESS
) {
2298 // check data read incompatibility
2300 UpdateConfigData (PciDeviceInfo
, PCI_REGISTER_READ
, AccessWidth
, AccessAddress
& 0xff, &Data
);
2302 Shift
= (UINTN
)(Address
- AccessAddress
) * 8;
2304 case EfiPciWidthUint8
:
2305 Data
= (* (UINT8
*) Buffer
) << Shift
| (Data
& ~(0xff << Shift
));
2308 case EfiPciWidthUint16
:
2309 Data
= (* (UINT16
*) Buffer
) << Shift
| (Data
& ~(0xffff << Shift
));
2314 // check data write incompatibility
2316 UpdateConfigData (PciDeviceInfo
, PCI_REGISTER_WRITE
, AccessWidth
, MultU64x32 (AccessAddress
, 0xff), &Data
);
2319 if (PciRootBridgeIo
!= NULL
) {
2320 Status
= PciRootBridgeIo
->Pci
.Write (
2322 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) AccessWidth
,
2328 Status
= PciIo
->Pci
.Write (
2330 (EFI_PCI_IO_PROTOCOL_WIDTH
) AccessWidth
,
2331 (UINT32
) AccessAddress
,
2337 if (Status
!= EFI_SUCCESS
) {
2341 Data
= RShiftU64 (Data
, ((1 << AccessWidth
) * 8));
2343 Stride
= (UINTN
)1 << AccessWidth
;
2344 AccessAddress
+= Stride
;
2345 if (AccessAddress
>= (Address
+ LShiftU64 (1ULL, (UINTN
)Width
))) {
2347 // if all datas have been written, exist
2354 if ((AccessAddress
& 0xff) < PciRegisterAccessData
->EndOffset
) {
2356 // if current offset doesn't reach the end
2361 FreePool (PciRegisterAccessData
);
2364 // continue checking access incompatibility
2366 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_WRITE
, AccessAddress
& 0xff, AccessWidth
, &PciRegisterAccessData
);
2367 if (Status
== EFI_SUCCESS
) {
2368 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2369 AccessWidth
= PciRegisterAccessData
->Width
;
2374 FreePool (PciRegisterAccessData
);
2381 // AccessWidth incompatible check not supportted
2382 // or, there doesn't exist incompatibility on this operation
2384 if (PciRootBridgeIo
!= NULL
) {
2385 Status
= PciRootBridgeIo
->Pci
.Write (
2387 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
2393 Status
= PciIo
->Pci
.Write (
2395 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
2406 Abstract PCI device device information.
2408 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2409 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2410 @param Pci A pointer to PCI_TYPE00.
2411 @param Address The address within the PCI configuration space for the PCI controller.
2412 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2414 @retval EFI_SUCCESS Pci device device information has been abstracted.
2418 GetPciDeviceDeviceInfo (
2419 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2420 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2421 IN PCI_TYPE00
*Pci
, OPTIONAL
2422 IN UINT64 Address
, OPTIONAL
2423 OUT EFI_PCI_DEVICE_INFO
*PciDeviceInfo
2428 UINT32 PciConfigData
;
2429 PCI_IO_DEVICE
*PciIoDevice
;
2431 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2433 if (PciIo
!= NULL
) {
2434 PciIoDevice
= PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo
);
2437 // get pointer to PCI_TYPE00 from PciIoDevice
2439 Pci
= &PciIoDevice
->Pci
;
2444 // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly
2446 PciAddress
= Address
& 0xffffffffffffff00ULL
;
2447 Status
= PciRootBridgeIo
->Pci
.Read (
2455 if (EFI_ERROR (Status
)) {
2459 if ((PciConfigData
& 0xffff) == 0xffff) {
2460 return EFI_NOT_FOUND
;
2463 PciDeviceInfo
->VendorID
= PciConfigData
& 0xffff;
2464 PciDeviceInfo
->DeviceID
= PciConfigData
>> 16;
2466 Status
= PciRootBridgeIo
->Pci
.Read (
2473 if (EFI_ERROR (Status
)) {
2477 PciDeviceInfo
->RevisionID
= PciConfigData
& 0xf;
2479 Status
= PciRootBridgeIo
->Pci
.Read (
2487 if (EFI_ERROR (Status
)) {
2491 PciDeviceInfo
->SubsystemVendorID
= PciConfigData
& 0xffff;
2492 PciDeviceInfo
->SubsystemID
= PciConfigData
>> 16;
2495 PciDeviceInfo
->VendorID
= Pci
->Hdr
.VendorId
;
2496 PciDeviceInfo
->DeviceID
= Pci
->Hdr
.DeviceId
;
2497 PciDeviceInfo
->RevisionID
= Pci
->Hdr
.RevisionID
;
2498 PciDeviceInfo
->SubsystemVendorID
= Pci
->Device
.SubsystemVendorID
;
2499 PciDeviceInfo
->SubsystemID
= Pci
->Device
.SubsystemID
;
2506 Read PCI configuration space with incompatibility check.
2508 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2509 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2510 @param Pci A pointer to PCI_TYPE00.
2511 @param Width Signifies the width of the memory operations.
2512 @param Address The address within the PCI configuration space for the PCI controller.
2513 @param Count The number of unit to be read.
2514 @param Buffer For read operations, the destination buffer to store the results. For
2515 write operations, the source buffer to write data from.
2517 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2518 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2519 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2520 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2524 PciIncompatibilityCheckRead (
2525 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2526 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2527 IN PCI_TYPE00
*Pci
, OPTIONAL
2535 EFI_PCI_DEVICE_INFO PciDeviceInfo
;
2538 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2541 // get PCI device device information
2543 Status
= GetPciDeviceDeviceInfo (PciRootBridgeIo
, PciIo
, Pci
, Address
, &PciDeviceInfo
);
2544 if (Status
!= EFI_SUCCESS
) {
2548 Stride
= 1 << Width
;
2550 for (; Count
> 0; Count
--, Address
+= Stride
, Buffer
= (UINT8
*)Buffer
+ Stride
) {
2553 // read configuration register
2555 Status
= ReadConfigData (PciRootBridgeIo
, PciIo
, &PciDeviceInfo
, (UINT64
) Width
, Address
, Buffer
);
2557 if (Status
!= EFI_SUCCESS
) {
2562 // update the data read from configuration register
2564 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT
) {
2565 UpdateConfigData (&PciDeviceInfo
, PCI_REGISTER_READ
, Width
, Address
& 0xff, Buffer
);
2573 Write PCI configuration space with incompatibility check.
2575 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2576 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2577 @param Pci A pointer to PCI_TYPE00.
2578 @param Width Signifies the width of the memory operations.
2579 @param Address The address within the PCI configuration space for the PCI controller.
2580 @param Count The number of unit to be write.
2581 @param Buffer For read operations, the destination buffer to store the results. For
2582 write operations, the source buffer to write data from.
2584 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2585 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2586 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2587 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2591 PciIncompatibilityCheckWrite (
2592 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2593 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2594 IN PCI_TYPE00
*Pci
, OPTIONAL
2602 EFI_PCI_DEVICE_INFO PciDeviceInfo
;
2606 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2609 // get PCI device device information
2611 Status
= GetPciDeviceDeviceInfo (PciRootBridgeIo
, PciIo
, Pci
, Address
, &PciDeviceInfo
);
2612 if (Status
!= EFI_SUCCESS
) {
2616 Stride
= 1 << Width
;
2618 for (; Count
> 0; Count
--, Address
+= Stride
, Buffer
= (UINT8
*) Buffer
+ Stride
) {
2623 case EfiPciWidthUint8
:
2624 Data
= * (UINT8
*) Buffer
;
2626 case EfiPciWidthUint16
:
2627 Data
= * (UINT16
*) Buffer
;
2630 case EfiPciWidthUint32
:
2631 Data
= * (UINT32
*) Buffer
;
2635 return EFI_UNSUPPORTED
;
2639 // update the data writen into configuration register
2641 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT
) {
2642 UpdateConfigData (&PciDeviceInfo
, PCI_REGISTER_WRITE
, Width
, Address
& 0xff, &Data
);
2646 // write configuration register
2648 Status
= WriteConfigData (PciRootBridgeIo
, PciIo
, &PciDeviceInfo
, Width
, Address
, &Data
);
2650 if (Status
!= EFI_SUCCESS
) {
2659 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2661 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2662 @param Pci A pointer to PCI_TYPE00.
2663 @param Width Signifies the width of the memory operations.
2664 @param Address The address within the PCI configuration space for the PCI controller.
2665 @param Count The number of unit to be read.
2666 @param Buffer For read operations, the destination buffer to store the results. For
2667 write operations, the source buffer to write data from.
2669 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2670 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2671 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2672 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2676 PciRootBridgeIoRead (
2677 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
2678 IN PCI_TYPE00
*Pci
, OPTIONAL
2679 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
2685 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_READ_SUPPORT
) {
2687 // if PCI incompatibility check enabled
2689 return PciIncompatibilityCheckRead (
2699 return PciRootBridgeIo
->Pci
.Read (
2710 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2712 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2713 @param Pci A pointer to PCI_TYPE00.
2714 @param Width Signifies the width of the memory operations.
2715 @param Address The address within the PCI configuration space for the PCI controller.
2716 @param Count The number of unit to be read.
2717 @param Buffer For read operations, the destination buffer to store the results. For
2718 write operations, the source buffer to write data from.
2720 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2721 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2722 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2723 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2727 PciRootBridgeIoWrite (
2728 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
2730 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
2736 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_WRITE_SUPPORT
) {
2738 // if PCI incompatibility check enabled
2740 return PciIncompatibilityCheckWrite (
2751 return PciRootBridgeIo
->Pci
.Write (
2762 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.
2764 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2765 @param Width Signifies the width of the memory operations.
2766 @param Address The address within the PCI configuration space for the PCI controller.
2767 @param Count The number of unit to be read.
2768 @param Buffer For read operations, the destination buffer to store the results. For
2769 write operations, the source buffer to write data from.
2771 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2772 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2773 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2774 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2779 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2780 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
2786 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_READ_SUPPORT
) {
2788 // if PCI incompatibility check enabled
2790 return PciIncompatibilityCheckRead (
2800 return PciIo
->Pci
.Read (
2811 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.
2813 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2814 @param Width Signifies the width of the memory operations.
2815 @param Address The address within the PCI configuration space for the PCI controller.
2816 @param Count The number of unit to be read.
2817 @param Buffer For read operations, the destination buffer to store the results. For
2818 write operations, the source buffer to write data from.
2820 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2821 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2822 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2823 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2828 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2829 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
2835 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_WRITE_SUPPORT
) {
2838 // if PCI incompatibility check enabled
2840 return PciIncompatibilityCheckWrite (
2851 return PciIo
->Pci
.Write (