3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 PCI Bus Driver Lib file
19 It abstracts some functions that can be different
20 between light PCI bus driver and full PCI bus driver
28 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest
= {
29 PciHotPlugRequestNotify
34 InstallHotPlugRequestProtocol (
42 Status - A pointer to the status.
52 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
57 *Status
= gBS
->InstallProtocolInterface (
59 &gEfiPciHotPlugRequestProtocolGuid
,
66 InstallPciHotplugGuid (
67 IN PCI_IO_DEVICE
*PciIoDevice
75 PciIoDevice - A pointer to the PCI_IO_DEVICE.
85 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
89 if (IS_CARDBUS_BRIDGE (&PciIoDevice
->Parent
->Pci
)) {
91 Status
= gBS
->InstallProtocolInterface (
93 &gEfiPciHotplugDeviceGuid
,
97 ASSERT_EFI_ERROR (Status
);
102 UninstallPciHotplugGuid (
103 IN PCI_IO_DEVICE
*PciIoDevice
111 PciIoDevice - A pointer to the PCI_IO_DEVICE.
121 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
125 Status
= gBS
->OpenProtocol (
127 &gEfiPciHotplugDeviceGuid
,
131 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
134 if (Status
== EFI_SUCCESS
) {
136 // This may triger CardBus driver to stop for
137 // Pccard devices opened the GUID via BY_DRIVER
139 Status
= gBS
->UninstallProtocolInterface (
141 &gEfiPciHotplugDeviceGuid
,
149 IN PCI_IO_DEVICE
*PciIoDevice
158 PciIoDevice - A pointer to the PCI_IO_DEVICE.
168 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
173 // Read PciBar information from the bar register
175 if (!gFullEnumeration
) {
179 &(PciIoDevice
->PciIo
),
186 (PciIoDevice
->PciBar
)[P2C_MEM_1
].BaseAddress
= (UINT64
) (Address
);
187 (PciIoDevice
->PciBar
)[P2C_MEM_1
].Length
= 0x2000000;
188 (PciIoDevice
->PciBar
)[P2C_MEM_1
].BarType
= PciBarTypeMem32
;
192 &(PciIoDevice
->PciIo
),
198 (PciIoDevice
->PciBar
)[P2C_MEM_2
].BaseAddress
= (UINT64
) (Address
);
199 (PciIoDevice
->PciBar
)[P2C_MEM_2
].Length
= 0x2000000;
200 (PciIoDevice
->PciBar
)[P2C_MEM_2
].BarType
= PciBarTypePMem32
;
204 &(PciIoDevice
->PciIo
),
210 (PciIoDevice
->PciBar
)[P2C_IO_1
].BaseAddress
= (UINT64
) (Address
);
211 (PciIoDevice
->PciBar
)[P2C_IO_1
].Length
= 0x100;
212 (PciIoDevice
->PciBar
)[P2C_IO_1
].BarType
= PciBarTypeIo16
;
216 &(PciIoDevice
->PciIo
),
222 (PciIoDevice
->PciBar
)[P2C_IO_2
].BaseAddress
= (UINT64
) (Address
);
223 (PciIoDevice
->PciBar
)[P2C_IO_2
].Length
= 0x100;
224 (PciIoDevice
->PciBar
)[P2C_IO_2
].BarType
= PciBarTypeIo16
;
228 if (gPciHotPlugInit
!= NULL
) {
229 GetResourcePaddingForHpb (PciIoDevice
);
234 RemoveRejectedPciDevices (
235 EFI_HANDLE RootBridgeHandle
,
236 IN PCI_IO_DEVICE
*Bridge
245 RootBridgeHandle - An efi handle.
246 Bridge - An pointer to the PCI_IO_DEVICE.
253 // TODO: EFI_SUCCESS - add return value to function comment
256 LIST_ENTRY
*CurrentLink
;
257 LIST_ENTRY
*LastLink
;
259 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
263 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
265 while (CurrentLink
&& CurrentLink
!= &Bridge
->ChildList
) {
267 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
269 if (IS_PCI_BRIDGE (&Temp
->Pci
)) {
271 // Remove rejected devices recusively
273 RemoveRejectedPciDevices (RootBridgeHandle
, Temp
);
276 // Skip rejection for all PPBs, while detect rejection for others
278 if (IsPciDeviceRejected (Temp
)) {
281 // For P2C, remove all devices on it
284 if (!IsListEmpty (&Temp
->ChildList
)) {
285 RemoveAllPciDeviceOnBridge (RootBridgeHandle
, Temp
);
289 // Finally remove itself
292 LastLink
= CurrentLink
->BackLink
;
293 RemoveEntryList (CurrentLink
);
294 FreePciDevice (Temp
);
296 CurrentLink
= LastLink
;
300 CurrentLink
= CurrentLink
->ForwardLink
;
307 PciHostBridgeResourceAllocator (
308 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
311 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
312 return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
316 return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
324 PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
325 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
338 // TODO: PciResAlloc - add argument and description to function comment
339 // TODO: EFI_NOT_FOUND - add return value to function comment
340 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
341 // TODO: EFI_NOT_FOUND - add return value to function comment
342 // TODO: EFI_SUCCESS - add return value to function comment
344 PCI_IO_DEVICE
*RootBridgeDev
;
345 EFI_HANDLE RootBridgeHandle
;
353 UINT64 MaxOptionRomSize
;
354 PCI_RESOURCE_NODE
*IoBridge
;
355 PCI_RESOURCE_NODE
*Mem32Bridge
;
356 PCI_RESOURCE_NODE
*PMem32Bridge
;
357 PCI_RESOURCE_NODE
*Mem64Bridge
;
358 PCI_RESOURCE_NODE
*PMem64Bridge
;
359 PCI_RESOURCE_NODE IoPool
;
360 PCI_RESOURCE_NODE Mem32Pool
;
361 PCI_RESOURCE_NODE PMem32Pool
;
362 PCI_RESOURCE_NODE Mem64Pool
;
363 PCI_RESOURCE_NODE PMem64Pool
;
364 REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData
;
367 // Initialize resource pool
370 InitializeResourcePool (&IoPool
, PciBarTypeIo16
);
371 InitializeResourcePool (&Mem32Pool
, PciBarTypeMem32
);
372 InitializeResourcePool (&PMem32Pool
, PciBarTypePMem32
);
373 InitializeResourcePool (&Mem64Pool
, PciBarTypeMem64
);
374 InitializeResourcePool (&PMem64Pool
, PciBarTypePMem64
);
376 RootBridgeDev
= NULL
;
377 RootBridgeHandle
= 0;
379 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
381 // Get RootBridg Device by handle
383 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
385 if (RootBridgeDev
== NULL
) {
386 return EFI_NOT_FOUND
;
390 // Get host bridge handle for status report
392 ExtendedData
.Handle
= RootBridgeDev
->PciRootBridgeIo
->ParentHandle
;
395 // Create the entire system resource map from the information collected by
396 // enumerator. Several resource tree was created
399 IoBridge
= CreateResourceNode (
408 Mem32Bridge
= CreateResourceNode (
417 PMem32Bridge
= CreateResourceNode (
426 Mem64Bridge
= CreateResourceNode (
435 PMem64Bridge
= CreateResourceNode (
445 // Create resourcemap by going through all the devices subject to this root bridge
447 Status
= CreateResourceMap (
457 // Get the max ROM size that the root bridge can process
459 RootBridgeDev
->RomSize
= Mem32Bridge
->Length
;
462 // Get Max Option Rom size for current root bridge
464 MaxOptionRomSize
= GetMaxOptionRomSize (RootBridgeDev
);
467 // Enlarger the mem32 resource to accomdate the option rom
468 // if the mem32 resource is not enough to hold the rom
470 if (MaxOptionRomSize
> Mem32Bridge
->Length
) {
472 Mem32Bridge
->Length
= MaxOptionRomSize
;
473 RootBridgeDev
->RomSize
= MaxOptionRomSize
;
476 // Alignment should be adjusted as well
478 if (Mem32Bridge
->Alignment
< MaxOptionRomSize
- 1) {
479 Mem32Bridge
->Alignment
= MaxOptionRomSize
- 1;
484 // Based on the all the resource tree, contruct ACPI resource node to
485 // submit the resource aperture to pci host bridge protocol
487 Status
= ConstructAcpiResourceRequestor (
498 // Insert these resource nodes into the database
500 InsertResourceNode (&IoPool
, IoBridge
);
501 InsertResourceNode (&Mem32Pool
, Mem32Bridge
);
502 InsertResourceNode (&PMem32Pool
, PMem32Bridge
);
503 InsertResourceNode (&Mem64Pool
, Mem64Bridge
);
504 InsertResourceNode (&PMem64Pool
, PMem64Bridge
);
506 if (Status
== EFI_SUCCESS
) {
508 // Submit the resource requirement
510 Status
= PciResAlloc
->SubmitResources (
512 RootBridgeDev
->Handle
,
517 // Free acpi resource node
519 if (AcpiConfig
!= NULL
) {
520 FreePool (AcpiConfig
);
523 if (EFI_ERROR (Status
)) {
525 // Destroy all the resource tree
527 DestroyResourceTree (&IoPool
);
528 DestroyResourceTree (&Mem32Pool
);
529 DestroyResourceTree (&PMem32Pool
);
530 DestroyResourceTree (&Mem64Pool
);
531 DestroyResourceTree (&PMem64Pool
);
540 // Notify pci bus driver starts to program the resource
542 Status
= NotifyPhase (PciResAlloc
, EfiPciHostBridgeAllocateResources
);
544 if (EFI_ERROR (Status
)) {
546 // Allocation failed, then return
548 return EFI_OUT_OF_RESOURCES
;
551 // Raise the EFI_IOB_PCI_RES_ALLOC status code
553 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
555 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_RES_ALLOC
,
556 (VOID
*) &ExtendedData
,
557 sizeof (ExtendedData
)
561 // Notify pci bus driver starts to program the resource
563 NotifyPhase (PciResAlloc
, EfiPciHostBridgeSetResources
);
565 RootBridgeDev
= NULL
;
567 RootBridgeHandle
= 0;
569 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
571 // Get RootBridg Device by handle
573 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
575 if (RootBridgeDev
== NULL
) {
576 return EFI_NOT_FOUND
;
580 // Get acpi resource node for all the resource types
583 Status
= PciResAlloc
->GetProposedResources (
585 RootBridgeDev
->Handle
,
589 if (EFI_ERROR (Status
)) {
594 // Get the resource base by interpreting acpi resource node
607 // Process option rom for this root bridge
609 Status
= ProcessOptionRom (RootBridgeDev
, Mem32Base
, RootBridgeDev
->RomSize
);
612 // Create the entire system resource map from the information collected by
613 // enumerator. Several resource tree was created
615 Status
= GetResourceMap (
629 if (EFI_ERROR (Status
)) {
634 // Program IO resources
642 // Program Mem32 resources
650 // Program PMem32 resources
658 // Program Mem64 resources
666 // Program PMem64 resources
673 if (AcpiConfig
!= NULL
) {
674 FreePool (AcpiConfig
);
679 // Destroy all the resource tree
681 DestroyResourceTree (&IoPool
);
682 DestroyResourceTree (&Mem32Pool
);
683 DestroyResourceTree (&PMem32Pool
);
684 DestroyResourceTree (&Mem64Pool
);
685 DestroyResourceTree (&PMem64Pool
);
688 // Notify the resource allocation phase is to end
690 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndResourceAllocation
);
697 PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
698 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
704 Host brige resource allocator.
708 PciResAlloc - A pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
715 // TODO: EFI_NOT_FOUND - add return value to function comment
716 // TODO: EFI_NOT_FOUND - add return value to function comment
717 // TODO: EFI_NOT_FOUND - add return value to function comment
718 // TODO: EFI_SUCCESS - add return value to function comment
720 PCI_IO_DEVICE
*RootBridgeDev
;
721 EFI_HANDLE RootBridgeHandle
;
730 UINT64 Mem32ResStatus
;
731 UINT64 PMem32ResStatus
;
732 UINT64 Mem64ResStatus
;
733 UINT64 PMem64ResStatus
;
734 UINT64 MaxOptionRomSize
;
735 PCI_RESOURCE_NODE
*IoBridge
;
736 PCI_RESOURCE_NODE
*Mem32Bridge
;
737 PCI_RESOURCE_NODE
*PMem32Bridge
;
738 PCI_RESOURCE_NODE
*Mem64Bridge
;
739 PCI_RESOURCE_NODE
*PMem64Bridge
;
740 PCI_RESOURCE_NODE IoPool
;
741 PCI_RESOURCE_NODE Mem32Pool
;
742 PCI_RESOURCE_NODE PMem32Pool
;
743 PCI_RESOURCE_NODE Mem64Pool
;
744 PCI_RESOURCE_NODE PMem64Pool
;
746 REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA HandleExtendedData
;
747 REPORT_STATUS_CODE_LIBRARY_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData
;
755 // It will try several times if the resource allocation fails
760 // Initialize resource pool
762 InitializeResourcePool (&IoPool
, PciBarTypeIo16
);
763 InitializeResourcePool (&Mem32Pool
, PciBarTypeMem32
);
764 InitializeResourcePool (&PMem32Pool
, PciBarTypePMem32
);
765 InitializeResourcePool (&Mem64Pool
, PciBarTypeMem64
);
766 InitializeResourcePool (&PMem64Pool
, PciBarTypePMem64
);
768 RootBridgeDev
= NULL
;
769 RootBridgeHandle
= 0;
771 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
774 // Get RootBridg Device by handle
776 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
778 if (RootBridgeDev
== NULL
) {
779 return EFI_NOT_FOUND
;
783 // Create the entire system resource map from the information collected by
784 // enumerator. Several resource tree was created
787 IoBridge
= CreateResourceNode (
796 Mem32Bridge
= CreateResourceNode (
805 PMem32Bridge
= CreateResourceNode (
814 Mem64Bridge
= CreateResourceNode (
823 PMem64Bridge
= CreateResourceNode (
833 // Create resourcemap by going through all the devices subject to this root bridge
835 Status
= CreateResourceMap (
845 // Get the max ROM size that the root bridge can process
847 RootBridgeDev
->RomSize
= Mem32Bridge
->Length
;
850 // Skip to enlarge the resource request during realloction
854 // Get Max Option Rom size for current root bridge
856 MaxOptionRomSize
= GetMaxOptionRomSize (RootBridgeDev
);
859 // Enlarger the mem32 resource to accomdate the option rom
860 // if the mem32 resource is not enough to hold the rom
862 if (MaxOptionRomSize
> Mem32Bridge
->Length
) {
864 Mem32Bridge
->Length
= MaxOptionRomSize
;
865 RootBridgeDev
->RomSize
= MaxOptionRomSize
;
868 // Alignment should be adjusted as well
870 if (Mem32Bridge
->Alignment
< MaxOptionRomSize
- 1) {
871 Mem32Bridge
->Alignment
= MaxOptionRomSize
- 1;
877 // Based on the all the resource tree, contruct ACPI resource node to
878 // submit the resource aperture to pci host bridge protocol
880 Status
= ConstructAcpiResourceRequestor (
891 // Insert these resource nodes into the database
893 InsertResourceNode (&IoPool
, IoBridge
);
894 InsertResourceNode (&Mem32Pool
, Mem32Bridge
);
895 InsertResourceNode (&PMem32Pool
, PMem32Bridge
);
896 InsertResourceNode (&Mem64Pool
, Mem64Bridge
);
897 InsertResourceNode (&PMem64Pool
, PMem64Bridge
);
899 if (Status
== EFI_SUCCESS
) {
901 // Submit the resource requirement
903 Status
= PciResAlloc
->SubmitResources (
905 RootBridgeDev
->Handle
,
911 // Free acpi resource node
913 if (AcpiConfig
!= NULL
) {
914 FreePool (AcpiConfig
);
917 if (EFI_ERROR (Status
)) {
919 // Destroy all the resource tree
921 DestroyResourceTree (&IoPool
);
922 DestroyResourceTree (&Mem32Pool
);
923 DestroyResourceTree (&PMem32Pool
);
924 DestroyResourceTree (&Mem64Pool
);
925 DestroyResourceTree (&PMem64Pool
);
931 // Notify pci bus driver starts to program the resource
934 Status
= NotifyPhase (PciResAlloc
, EfiPciHostBridgeAllocateResources
);
936 if (!EFI_ERROR (Status
)) {
938 // Allocation succeed, then continue the following
944 // If the resource allocation is unsuccessful, free resources on bridge
947 RootBridgeDev
= NULL
;
948 RootBridgeHandle
= 0;
950 IoResStatus
= EFI_RESOURCE_SATISFIED
;
951 Mem32ResStatus
= EFI_RESOURCE_SATISFIED
;
952 PMem32ResStatus
= EFI_RESOURCE_SATISFIED
;
953 Mem64ResStatus
= EFI_RESOURCE_SATISFIED
;
954 PMem64ResStatus
= EFI_RESOURCE_SATISFIED
;
956 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
958 // Get RootBridg Device by handle
960 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
961 if (RootBridgeDev
== NULL
) {
962 return EFI_NOT_FOUND
;
966 // Get host bridge handle for status report
968 HandleExtendedData
.Handle
= RootBridgeDev
->PciRootBridgeIo
->ParentHandle
;
971 // Get acpi resource node for all the resource types
975 Status
= PciResAlloc
->GetProposedResources (
977 RootBridgeDev
->Handle
,
981 if (EFI_ERROR (Status
)) {
985 if (AcpiConfig
!= NULL
) {
987 // Adjust resource allocation policy for each RB
989 GetResourceAllocationStatus (
997 FreePool (AcpiConfig
);
1005 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
1008 // It is very difficult to follow the spec here
1009 // Device path , Bar index can not be get here
1011 ZeroMem (&AllocFailExtendedData
, sizeof (AllocFailExtendedData
));
1013 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1015 EFI_IO_BUS_PCI
| EFI_IOB_EC_RESOURCE_CONFLICT
,
1016 (VOID
*) &AllocFailExtendedData
,
1017 sizeof (AllocFailExtendedData
)
1020 Status
= PciHostBridgeAdjustAllocation (
1034 // Destroy all the resource tree
1036 DestroyResourceTree (&IoPool
);
1037 DestroyResourceTree (&Mem32Pool
);
1038 DestroyResourceTree (&PMem32Pool
);
1039 DestroyResourceTree (&Mem64Pool
);
1040 DestroyResourceTree (&PMem64Pool
);
1042 NotifyPhase (PciResAlloc
, EfiPciHostBridgeFreeResources
);
1044 if (EFI_ERROR (Status
)) {
1056 // Raise the EFI_IOB_PCI_RES_ALLOC status code
1058 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1060 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_RES_ALLOC
,
1061 (VOID
*) &HandleExtendedData
,
1062 sizeof (HandleExtendedData
)
1066 // Notify pci bus driver starts to program the resource
1068 NotifyPhase (PciResAlloc
, EfiPciHostBridgeSetResources
);
1070 RootBridgeDev
= NULL
;
1072 RootBridgeHandle
= 0;
1074 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1077 // Get RootBridg Device by handle
1079 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
1081 if (RootBridgeDev
== NULL
) {
1082 return EFI_NOT_FOUND
;
1086 // Get acpi resource node for all the resource types
1089 Status
= PciResAlloc
->GetProposedResources (
1091 RootBridgeDev
->Handle
,
1095 if (EFI_ERROR (Status
)) {
1100 // Get the resource base by interpreting acpi resource node
1113 // Process option rom for this root bridge
1115 Status
= ProcessOptionRom (RootBridgeDev
, Mem32Base
, RootBridgeDev
->RomSize
);
1118 // Create the entire system resource map from the information collected by
1119 // enumerator. Several resource tree was created
1121 Status
= GetResourceMap (
1135 if (EFI_ERROR (Status
)) {
1140 // Program IO resources
1148 // Program Mem32 resources
1156 // Program PMem32 resources
1164 // Program Mem64 resources
1172 // Program PMem64 resources
1179 if (AcpiConfig
!= NULL
) {
1180 gBS
->FreePool (AcpiConfig
);
1185 // Destroy all the resource tree
1187 DestroyResourceTree (&IoPool
);
1188 DestroyResourceTree (&Mem32Pool
);
1189 DestroyResourceTree (&PMem32Pool
);
1190 DestroyResourceTree (&Mem64Pool
);
1191 DestroyResourceTree (&PMem64Pool
);
1194 // Notify the resource allocation phase is to end
1196 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndResourceAllocation
);
1204 IN PCI_IO_DEVICE
*Bridge
,
1205 IN UINT8 StartBusNumber
,
1206 OUT UINT8
*SubBusNumber
,
1207 OUT UINT8
*PaddedBusRange
1210 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1211 return PciScanBus_WithHotPlugDeviceSupport (
1218 return PciScanBus_WithoutHotPlugDeviceSupport (
1229 PciScanBus_WithoutHotPlugDeviceSupport (
1230 IN PCI_IO_DEVICE
*Bridge
,
1231 IN UINT8 StartBusNumber
,
1232 OUT UINT8
*SubBusNumber
,
1233 OUT UINT8
*PaddedBusRange
1237 Routine Description:
1239 This routine is used to assign bus number to the given PCI bus system
1248 // TODO: Bridge - add argument and description to function comment
1249 // TODO: StartBusNumber - add argument and description to function comment
1250 // TODO: SubBusNumber - add argument and description to function comment
1251 // TODO: PaddedBusRange - add argument and description to function comment
1252 // TODO: EFI_DEVICE_ERROR - add return value to function comment
1253 // TODO: EFI_SUCCESS - add return value to function comment
1262 PCI_IO_DEVICE
*PciDevice
;
1263 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1265 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
1269 ResetAllPpbBusReg (Bridge
, StartBusNumber
);
1271 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
1272 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
1275 // Check to see whether a pci device is present
1277 Status
= PciDevicePresent (
1285 if (!EFI_ERROR (Status
) &&
1286 (IS_PCI_BRIDGE (&Pci
) ||
1287 IS_CARDBUS_BRIDGE (&Pci
))) {
1290 // Get the bridge information
1292 Status
= PciSearchDevice (
1301 if (EFI_ERROR (Status
)) {
1307 SecondBus
= (*SubBusNumber
);
1309 Register
= (UINT16
) ((SecondBus
<< 8) | (UINT16
) StartBusNumber
);
1311 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
1313 Status
= PciRootBridgeIoWrite (
1323 // Initialize SubBusNumber to SecondBus
1325 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1326 Status
= PciRootBridgeIoWrite (
1335 // If it is PPB, resursively search down this bridge
1337 if (IS_PCI_BRIDGE (&Pci
)) {
1339 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
1340 // PCI configuration transaction to go through any PPB
1342 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1344 Status
= PciRootBridgeIoWrite (
1353 PreprocessController (
1355 PciDevice
->BusNumber
,
1356 PciDevice
->DeviceNumber
,
1357 PciDevice
->FunctionNumber
,
1358 EfiPciBeforeChildBusEnumeration
1361 Status
= PciScanBus (
1363 (UINT8
) (SecondBus
),
1368 if (EFI_ERROR (Status
)) {
1369 return EFI_DEVICE_ERROR
;
1374 // Set the current maximum bus number under the PPB
1377 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1379 Status
= PciRootBridgeIoWrite (
1390 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
1393 // Skip sub functions, this is not a multi function device
1396 Func
= PCI_MAX_FUNC
;
1405 PciScanBus_WithHotPlugDeviceSupport (
1406 IN PCI_IO_DEVICE
*Bridge
,
1407 IN UINT8 StartBusNumber
,
1408 OUT UINT8
*SubBusNumber
,
1409 OUT UINT8
*PaddedBusRange
1413 Routine Description:
1415 This routine is used to assign bus number to the given PCI bus system
1419 Bridge - A pointer to the PCI_IO_DEVICE structure.
1420 StartBusNumber - The start bus number.
1421 SubBusNumber - A pointer to the sub bus number.
1422 PaddedBusRange - A pointer to the padded bus range.
1429 // TODO: EFI_DEVICE_ERROR - add return value to function comment
1430 // TODO: EFI_SUCCESS - add return value to function comment
1440 PCI_IO_DEVICE
*PciDevice
;
1442 EFI_HPC_STATE State
;
1444 EFI_HPC_PADDING_ATTRIBUTES Attributes
;
1445 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
1447 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1450 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
1454 Attributes
= (EFI_HPC_PADDING_ATTRIBUTES
) 0;
1457 ResetAllPpbBusReg (Bridge
, StartBusNumber
);
1459 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
1460 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
1463 // Check to see whether a pci device is present
1465 Status
= PciDevicePresent (
1473 if (EFI_ERROR (Status
)) {
1476 // Skip sub functions, this is not a multi function device
1478 Func
= PCI_MAX_FUNC
;
1485 // Get the PCI device information
1487 Status
= PciSearchDevice (
1496 ASSERT (!EFI_ERROR (Status
));
1498 PciAddress
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0);
1500 if (!IS_PCI_BRIDGE (&Pci
)) {
1502 // PCI bridges will be called later
1503 // Here just need for PCI device or PCI to cardbus controller
1504 // EfiPciBeforeChildBusEnumeration for PCI Device Node
1506 PreprocessController (
1508 PciDevice
->BusNumber
,
1509 PciDevice
->DeviceNumber
,
1510 PciDevice
->FunctionNumber
,
1511 EfiPciBeforeChildBusEnumeration
1516 // For Pci Hotplug controller devcie only
1518 if (gPciHotPlugInit
!= NULL
) {
1520 // Check if it is a Hotplug PCI controller
1522 if (IsRootPciHotPlugController (PciDevice
->DevicePath
, &HpIndex
)) {
1524 if (!gPciRootHpcData
[HpIndex
].Initialized
) {
1526 Status
= CreateEventForHpc (HpIndex
, &Event
);
1528 ASSERT (!EFI_ERROR (Status
));
1530 Status
= gPciHotPlugInit
->InitializeRootHpc (
1532 gPciRootHpcPool
[HpIndex
].HpcDevicePath
,
1538 PreprocessController (
1540 PciDevice
->BusNumber
,
1541 PciDevice
->DeviceNumber
,
1542 PciDevice
->FunctionNumber
,
1543 EfiPciBeforeChildBusEnumeration
1550 if (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
)) {
1553 // Get the bridge information
1556 if (gPciHotPlugInit
!= NULL
) {
1558 if (IsRootPciHotPlugBus (PciDevice
->DevicePath
, &HpIndex
)) {
1561 // If it is initialized, get the padded bus range
1563 Status
= gPciHotPlugInit
->GetResourcePadding (
1565 gPciRootHpcPool
[HpIndex
].HpbDevicePath
,
1568 (VOID
**) &Descriptors
,
1572 if (EFI_ERROR (Status
)) {
1577 Status
= PciGetBusRange (
1584 gBS
->FreePool (Descriptors
);
1586 if (EFI_ERROR (Status
)) {
1595 SecondBus
= *SubBusNumber
;
1597 Register
= (UINT16
) ((SecondBus
<< 8) | (UINT16
) StartBusNumber
);
1598 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
1600 Status
= PciRootBridgeIoWrite (
1611 // If it is PPB, resursively search down this bridge
1613 if (IS_PCI_BRIDGE (&Pci
)) {
1616 // Initialize SubBusNumber to Maximum bus number
1619 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1620 Status
= PciRootBridgeIoWrite (
1630 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
1632 PreprocessController (
1634 PciDevice
->BusNumber
,
1635 PciDevice
->DeviceNumber
,
1636 PciDevice
->FunctionNumber
,
1637 EfiPciBeforeChildBusEnumeration
1640 Status
= PciScanBus (
1642 (UINT8
) (SecondBus
),
1647 if (EFI_ERROR (Status
)) {
1648 return EFI_DEVICE_ERROR
;
1654 // Ensure the device is enabled and initialized
1656 if ((Attributes
== EfiPaddingPciRootBridge
) &&
1657 (State
& EFI_HPC_STATE_ENABLED
) &&
1658 (State
& EFI_HPC_STATE_INITIALIZED
) ) {
1659 *PaddedBusRange
= (UINT8
) ((UINT8
) (BusRange
) +*PaddedBusRange
);
1661 *SubBusNumber
= (UINT8
) ((UINT8
) (BusRange
) +*SubBusNumber
);
1666 // Set the current maximum bus number under the PPB
1668 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1670 Status
= PciRootBridgeIoWrite (
1680 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
1683 // Skip sub functions, this is not a multi function device
1685 Func
= PCI_MAX_FUNC
;
1695 PciRootBridgeP2CProcess (
1696 IN PCI_IO_DEVICE
*Bridge
1700 Routine Description:
1702 Process Option Rom on this host bridge
1711 // TODO: Bridge - add argument and description to function comment
1712 // TODO: EFI_SUCCESS - add return value to function comment
1714 LIST_ENTRY
*CurrentLink
;
1715 PCI_IO_DEVICE
*Temp
;
1716 EFI_HPC_STATE State
;
1720 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
1722 while (CurrentLink
&& CurrentLink
!= &Bridge
->ChildList
) {
1724 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1726 if (IS_CARDBUS_BRIDGE (&Temp
->Pci
)) {
1728 if (gPciHotPlugInit
&& Temp
->Allocated
) {
1731 // Raise the EFI_IOB_PCI_HPC_INIT status code
1733 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1735 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_HPC_INIT
,
1739 PciAddress
= EFI_PCI_ADDRESS (Temp
->BusNumber
, Temp
->DeviceNumber
, Temp
->FunctionNumber
, 0);
1740 Status
= gPciHotPlugInit
->InitializeRootHpc (
1748 if (!EFI_ERROR (Status
)) {
1749 Status
= PciBridgeEnumerator (Temp
);
1751 if (EFI_ERROR (Status
)) {
1756 CurrentLink
= CurrentLink
->ForwardLink
;
1762 if (!IsListEmpty (&Temp
->ChildList
)) {
1763 Status
= PciRootBridgeP2CProcess (Temp
);
1766 CurrentLink
= CurrentLink
->ForwardLink
;
1773 PciHostBridgeP2CProcess (
1774 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
1778 Routine Description:
1787 // TODO: PciResAlloc - add argument and description to function comment
1788 // TODO: EFI_NOT_FOUND - add return value to function comment
1789 // TODO: EFI_SUCCESS - add return value to function comment
1791 EFI_HANDLE RootBridgeHandle
;
1792 PCI_IO_DEVICE
*RootBridgeDev
;
1795 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1799 RootBridgeHandle
= NULL
;
1801 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1804 // Get RootBridg Device by handle
1806 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
1808 if (RootBridgeDev
== NULL
) {
1809 return EFI_NOT_FOUND
;
1812 Status
= PciRootBridgeP2CProcess (RootBridgeDev
);
1814 if (EFI_ERROR (Status
)) {
1824 PciHostBridgeEnumerator (
1825 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
1829 Routine Description:
1831 This function is used to enumerate the entire host bridge
1836 PciResAlloc - A pointer to the resource allocate protocol.
1843 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1844 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1845 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1846 // TODO: EFI_SUCCESS - add return value to function comment
1848 EFI_HANDLE RootBridgeHandle
;
1849 PCI_IO_DEVICE
*RootBridgeDev
;
1851 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1853 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
1855 InitializeHotPlugSupport ();
1858 // Notify the bus allocation phase is about to start
1860 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginBusAllocation
);
1862 RootBridgeHandle
= NULL
;
1863 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1866 // if a root bridge instance is found, create root bridge device for it
1869 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1871 if (RootBridgeDev
== NULL
) {
1872 return EFI_OUT_OF_RESOURCES
;
1876 // Enumerate all the buses under this root bridge
1879 Status
= PciRootBridgeEnumerator (
1884 if (EFI_ERROR (Status
)) {
1888 DestroyRootBridge (RootBridgeDev
);
1891 // Error proccess here
1895 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1898 // Notify the bus allocation phase is finished for the first time
1900 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1903 if (gPciHotPlugInit
!= NULL
) {
1905 // Wait for all HPC initialized
1907 Status
= AllRootHPCInitialized (STALL_1_SECOND
* 15);
1909 if (EFI_ERROR (Status
)) {
1914 // Notify the bus allocation phase is about to start for the 2nd time
1916 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginBusAllocation
);
1918 RootBridgeHandle
= NULL
;
1919 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1922 // if a root bridge instance is found, create root bridge device for it
1925 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1927 if (RootBridgeDev
== NULL
) {
1928 return EFI_OUT_OF_RESOURCES
;
1932 // Enumerate all the buses under this root bridge
1935 Status
= PciRootBridgeEnumerator (
1940 DestroyRootBridge (RootBridgeDev
);
1941 if (EFI_ERROR (Status
)) {
1947 // Notify the bus allocation phase is to end
1949 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1953 // Notify the bus allocation phase is to end
1955 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1959 // Notify the resource allocation phase is to start
1961 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginResourceAllocation
);
1963 RootBridgeHandle
= NULL
;
1964 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1967 // if a root bridge instance is found, create root bridge device for it
1970 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1972 if (RootBridgeDev
== NULL
) {
1973 return EFI_OUT_OF_RESOURCES
;
1976 Status
= StartManagingRootBridge (RootBridgeDev
);
1978 if (EFI_ERROR (Status
)) {
1982 PciRootBridgeIo
= RootBridgeDev
->PciRootBridgeIo
;
1983 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**) &Descriptors
);
1985 if (EFI_ERROR (Status
)) {
1989 Status
= PciGetBusRange (&Descriptors
, &MinBus
, NULL
, NULL
);
1991 if (EFI_ERROR (Status
)) {
1996 // Determine root bridge attribute by calling interface of Pcihostbridge
1999 DetermineRootBridgeAttributes (
2005 // Collect all the resource information under this root bridge
2006 // A database that records all the information about pci device subject to this
2007 // root bridge will then be created
2009 Status
= PciPciDeviceInfoCollector (
2014 if (EFI_ERROR (Status
)) {
2018 InsertRootBridge (RootBridgeDev
);
2021 // Record the hostbridge handle
2023 AddHostBridgeEnumerator (RootBridgeDev
->PciRootBridgeIo
->ParentHandle
);
2030 Read PCI device configuration register by specified address.
2032 This function check the incompatiblilites on PCI device. Return the register
2035 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2036 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2037 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2038 @param Width Signifies the width of the memory operations.
2039 @Param Address The address within the PCI configuration space for the PCI controller.
2040 @param Buffer For read operations, the destination buffer to store the results. For
2041 write operations, the source buffer to write data from.
2043 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2044 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2045 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2046 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2052 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2053 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2054 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2062 EFI_PCI_REGISTER_ACCESS_DATA
*PciRegisterAccessData
;
2063 UINT64 AccessAddress
;
2068 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2070 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT
) {
2072 // check access compatibility at first time
2074 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_READ
, Address
& 0xff, Width
, &PciRegisterAccessData
);
2076 if (Status
== EFI_SUCCESS
) {
2078 // there exist incompatibility on this operation
2080 AccessWidth
= Width
;
2082 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2083 AccessWidth
= PciRegisterAccessData
->Width
;
2086 AccessAddress
= Address
& ~((1 << AccessWidth
) - 1);
2090 Pointer
= (UINT8
*) &TempBuffer
;
2094 if (PciRootBridgeIo
!= NULL
) {
2095 Status
= PciRootBridgeIo
->Pci
.Read (
2097 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) AccessWidth
,
2102 } else if (PciIo
!= NULL
) {
2103 Status
= PciIo
->Pci
.Read (
2105 (EFI_PCI_IO_PROTOCOL_WIDTH
) AccessWidth
,
2106 (UINT32
) AccessAddress
,
2112 if (Status
!= EFI_SUCCESS
) {
2116 Stride
= 1 << AccessWidth
;
2117 AccessAddress
+= Stride
;
2118 if (AccessAddress
>= (Address
+ (1 << Width
))) {
2120 // if all datas have been read, exist
2127 if ((AccessAddress
& 0xff) < PciRegisterAccessData
->EndOffset
) {
2129 // if current offset doesn't reach the end
2134 FreePool (PciRegisterAccessData
);
2137 // continue checking access incompatibility
2139 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_READ
, AccessAddress
& 0xff, AccessWidth
, &PciRegisterAccessData
);
2140 if (Status
== EFI_SUCCESS
) {
2141 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2142 AccessWidth
= PciRegisterAccessData
->Width
;
2147 FreePool (PciRegisterAccessData
);
2150 case EfiPciWidthUint8
:
2151 * (UINT8
*) Buffer
= (UINT8
) TempBuffer
;
2153 case EfiPciWidthUint16
:
2154 * (UINT16
*) Buffer
= (UINT16
) TempBuffer
;
2156 case EfiPciWidthUint32
:
2157 * (UINT32
*) Buffer
= (UINT32
) TempBuffer
;
2160 return EFI_UNSUPPORTED
;
2167 // AccessWidth incompatible check not supportted
2168 // or, there doesn't exist incompatibility on this operation
2170 if (PciRootBridgeIo
!= NULL
) {
2171 Status
= PciRootBridgeIo
->Pci
.Read (
2173 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
2180 Status
= PciIo
->Pci
.Read (
2182 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
2193 Update register value by checking PCI device incompatibility.
2195 This function check register value incompatibilites on PCI device. Return the register
2198 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2199 @param AccessType Access type, READ or WRITE.
2200 @Param Address The address within the PCI configuration space.
2201 @param Buffer Store the register data.
2203 @retval EFI_SUCCESS The data has been updated.
2209 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2210 IN UINT64 AccessType
,
2217 EFI_PCI_REGISTER_VALUE_DATA
*PciRegisterData
;
2223 // check register value incompatibility
2225 Status
= PciRegisterUpdateCheck (PciDeviceInfo
, AccessType
, Address
& 0xff, &PciRegisterData
);
2227 if (Status
== EFI_SUCCESS
) {
2229 AndValue
= (PciRegisterData
->AndValue
) >> ((Address
& 0x3) * 8);
2230 OrValue
= (PciRegisterData
->OrValue
) >> ((Address
& 0x3) * 8);
2232 TempValue
= * (UINT32
*) Buffer
;
2234 if (PciRegisterData
->AndValue
!= VALUE_NOCARE
) {
2235 TempValue
&= (UINT32
) AndValue
;
2237 if (PciRegisterData
->OrValue
!= VALUE_NOCARE
) {
2238 TempValue
|= (UINT32
) OrValue
;
2242 case EfiPciWidthUint8
:
2243 *(UINT32
*)Buffer
= *(UINT32
*)Buffer
& 0xffffff00 + (UINT8
)TempValue
;
2246 case EfiPciWidthUint16
:
2247 *(UINT32
*)Buffer
= *(UINT32
*)Buffer
& 0xffff0000 + (UINT16
)TempValue
;
2249 case EfiPciWidthUint32
:
2250 *(UINT32
*)Buffer
= TempValue
;
2254 return EFI_UNSUPPORTED
;
2257 FreePool (PciRegisterData
);
2264 Write PCI device configuration register by specified address.
2266 This function check the incompatiblilites on PCI device, and write date
2269 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2270 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2271 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2272 @param Width Signifies the width of the memory operations.
2273 @Param Address The address within the PCI configuration space for the PCI controller.
2274 @param Buffer For read operations, the destination buffer to store the results. For
2275 write operations, the source buffer to write data from.
2277 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2278 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2279 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2280 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2286 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2287 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2288 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2296 EFI_PCI_REGISTER_ACCESS_DATA
*PciRegisterAccessData
;
2297 UINT64 AccessAddress
;
2303 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2305 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT
) {
2307 // check access compatibility at first time
2309 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_WRITE
, Address
& 0xff, Width
, &PciRegisterAccessData
);
2311 if (Status
== EFI_SUCCESS
) {
2313 // there exist incompatibility on this operation
2315 AccessWidth
= Width
;
2317 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2318 AccessWidth
= PciRegisterAccessData
->Width
;
2321 AccessAddress
= Address
& ~((1 << AccessWidth
) - 1);
2324 Pointer
= (UINT8
*) &Buffer
;
2325 Data
= * (UINT64
*) Buffer
;
2329 if (AccessWidth
> Width
) {
2331 // if actual access width is larger than orignal one, additional data need to be read back firstly
2333 Status
= ReadConfigData (PciRootBridgeIo
, PciIo
, PciDeviceInfo
, AccessWidth
, AccessAddress
, &Data
);
2334 if (Status
!= EFI_SUCCESS
) {
2339 // check data read incompatibility
2341 UpdateConfigData (PciDeviceInfo
, PCI_REGISTER_READ
, AccessWidth
, AccessAddress
& 0xff, &Data
);
2343 Shift
= (Address
- AccessAddress
) * 8;
2345 case EfiPciWidthUint8
:
2346 Data
= (* (UINT8
*) Buffer
) << Shift
| (Data
& ~(0xff << Shift
));
2349 case EfiPciWidthUint16
:
2350 Data
= (* (UINT16
*) Buffer
) << Shift
| (Data
& ~(0xffff << Shift
));
2355 // check data write incompatibility
2357 UpdateConfigData (PciDeviceInfo
, PCI_REGISTER_WRITE
, AccessWidth
, AccessAddress
* 0xff, &Data
);
2360 if (PciRootBridgeIo
!= NULL
) {
2361 Status
= PciRootBridgeIo
->Pci
.Write (
2363 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) AccessWidth
,
2369 Status
= PciIo
->Pci
.Write (
2371 (EFI_PCI_IO_PROTOCOL_WIDTH
) AccessWidth
,
2372 (UINT32
) AccessAddress
,
2378 if (Status
!= EFI_SUCCESS
) {
2382 Data
= Data
>> ((1 << AccessWidth
) * 8);
2384 Stride
= 1 << AccessWidth
;
2385 AccessAddress
+= Stride
;
2386 if (AccessAddress
>= (Address
+ (1 << Width
))) {
2388 // if all datas have been written, exist
2395 if ((AccessAddress
& 0xff) < PciRegisterAccessData
->EndOffset
) {
2397 // if current offset doesn't reach the end
2402 FreePool (PciRegisterAccessData
);
2405 // continue checking access incompatibility
2407 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_WRITE
, AccessAddress
& 0xff, AccessWidth
, &PciRegisterAccessData
);
2408 if (Status
== EFI_SUCCESS
) {
2409 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2410 AccessWidth
= PciRegisterAccessData
->Width
;
2415 FreePool (PciRegisterAccessData
);
2422 // AccessWidth incompatible check not supportted
2423 // or, there doesn't exist incompatibility on this operation
2425 if (PciRootBridgeIo
!= NULL
) {
2426 Status
= PciRootBridgeIo
->Pci
.Write (
2428 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
2434 Status
= PciIo
->Pci
.Write (
2436 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
2447 Abstract PCI device device information.
2449 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2450 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2451 @param Pci A pointer to PCI_TYPE00.
2452 @Param Address The address within the PCI configuration space for the PCI controller.
2453 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2455 @retval EFI_SUCCESS Pci device device information has been abstracted.
2460 GetPciDeviceDeviceInfo (
2461 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2462 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2463 IN PCI_TYPE00
*Pci
, OPTIONAL
2464 IN UINT64 Address
, OPTIONAL
2465 OUT EFI_PCI_DEVICE_INFO
*PciDeviceInfo
2470 UINT32 PciConfigData
;
2471 PCI_IO_DEVICE
*PciIoDevice
;
2473 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2475 if (PciIo
!= NULL
) {
2476 PciIoDevice
= PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo
);
2479 // get pointer to PCI_TYPE00 from PciIoDevice
2481 Pci
= &PciIoDevice
->Pci
;
2486 // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly
2488 PciAddress
= Address
& 0xffffffffffffff00ULL
;
2489 Status
= PciRootBridgeIo
->Pci
.Read (
2497 if (EFI_ERROR (Status
)) {
2501 if ((PciConfigData
& 0xffff) == 0xffff) {
2502 return EFI_NOT_FOUND
;
2505 PciDeviceInfo
->VendorID
= PciConfigData
& 0xffff;
2506 PciDeviceInfo
->DeviceID
= PciConfigData
>> 16;
2508 Status
= PciRootBridgeIo
->Pci
.Read (
2515 if (EFI_ERROR (Status
)) {
2519 PciDeviceInfo
->RevisionID
= PciConfigData
& 0xf;
2521 Status
= PciRootBridgeIo
->Pci
.Read (
2529 if (EFI_ERROR (Status
)) {
2533 PciDeviceInfo
->SubsystemVendorID
= PciConfigData
& 0xffff;
2534 PciDeviceInfo
->SubsystemID
= PciConfigData
>> 16;
2537 PciDeviceInfo
->VendorID
= Pci
->Hdr
.VendorId
;
2538 PciDeviceInfo
->DeviceID
= Pci
->Hdr
.DeviceId
;
2539 PciDeviceInfo
->RevisionID
= Pci
->Hdr
.RevisionID
;
2540 PciDeviceInfo
->SubsystemVendorID
= Pci
->Device
.SubsystemVendorID
;
2541 PciDeviceInfo
->SubsystemID
= Pci
->Device
.SubsystemID
;
2548 Read PCI configuration space with incompatibility check.
2550 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2551 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2552 @param Pci A pointer to PCI_TYPE00.
2553 @param Width Signifies the width of the memory operations.
2554 @Param Address The address within the PCI configuration space for the PCI controller.
2555 @param Buffer For read operations, the destination buffer to store the results. For
2556 write operations, the source buffer to write data from.
2558 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2559 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2560 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2561 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2566 PciIncompatibilityCheckRead (
2567 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2568 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2569 IN PCI_TYPE00
*Pci
, OPTIONAL
2577 EFI_PCI_DEVICE_INFO PciDeviceInfo
;
2580 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2583 // get PCI device device information
2585 Status
= GetPciDeviceDeviceInfo (PciRootBridgeIo
, PciIo
, Pci
, Address
, &PciDeviceInfo
);
2586 if (Status
!= EFI_SUCCESS
) {
2590 Stride
= 1 << Width
;
2592 for (; Count
> 0; Count
--, Address
+= Stride
, Buffer
= (UINT8
*)Buffer
+ Stride
) {
2595 // read configuration register
2597 Status
= ReadConfigData (PciRootBridgeIo
, PciIo
, &PciDeviceInfo
, (UINT64
) Width
, Address
, Buffer
);
2599 if (Status
!= EFI_SUCCESS
) {
2604 // update the data read from configuration register
2606 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT
) {
2607 UpdateConfigData (&PciDeviceInfo
, PCI_REGISTER_READ
, Width
, Address
& 0xff, Buffer
);
2615 Write PCI configuration space with incompatibility check.
2617 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2618 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2619 @param Pci A pointer to PCI_TYPE00.
2620 @param Width Signifies the width of the memory operations.
2621 @Param Address The address within the PCI configuration space for the PCI controller.
2622 @param Buffer For read operations, the destination buffer to store the results. For
2623 write operations, the source buffer to write data from.
2625 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2626 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2627 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2628 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2633 PciIncompatibilityCheckWrite (
2634 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2635 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2636 IN PCI_TYPE00
*Pci
, OPTIONAL
2644 EFI_PCI_DEVICE_INFO PciDeviceInfo
;
2648 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2651 // get PCI device device information
2653 Status
= GetPciDeviceDeviceInfo (PciRootBridgeIo
, PciIo
, Pci
, Address
, &PciDeviceInfo
);
2654 if (Status
!= EFI_SUCCESS
) {
2658 Stride
= 1 << Width
;
2660 for (; Count
> 0; Count
--, Address
+= Stride
, Buffer
= (UINT8
*) Buffer
+ Stride
) {
2665 case EfiPciWidthUint8
:
2666 Data
= * (UINT8
*) Buffer
;
2668 case EfiPciWidthUint16
:
2669 Data
= * (UINT16
*) Buffer
;
2672 case EfiPciWidthUint32
:
2673 Data
= * (UINT32
*) Buffer
;
2677 return EFI_UNSUPPORTED
;
2681 // update the data writen into configuration register
2683 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT
) {
2684 UpdateConfigData (&PciDeviceInfo
, PCI_REGISTER_WRITE
, Width
, Address
& 0xff, &Data
);
2688 // write configuration register
2690 Status
= WriteConfigData (PciRootBridgeIo
, PciIo
, &PciDeviceInfo
, Width
, Address
, &Data
);
2692 if (Status
!= EFI_SUCCESS
) {
2701 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2703 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2704 @param Pci A pointer to PCI_TYPE00.
2705 @param Width Signifies the width of the memory operations.
2706 @Param Address The address within the PCI configuration space for the PCI controller.
2707 @param Buffer For read operations, the destination buffer to store the results. For
2708 write operations, the source buffer to write data from.
2710 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2711 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2712 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2713 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2717 PciRootBridgeIoRead (
2718 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
2719 IN PCI_TYPE00
*Pci
, OPTIONAL
2720 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
2726 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_READ_SUPPORT
) {
2728 // if PCI incompatibility check enabled
2730 return PciIncompatibilityCheckRead (
2740 return PciRootBridgeIo
->Pci
.Read (
2751 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2753 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2754 @param Pci A pointer to PCI_TYPE00.
2755 @param Width Signifies the width of the memory operations.
2756 @Param Address The address within the PCI configuration space for the PCI controller.
2757 @param Buffer For read operations, the destination buffer to store the results. For
2758 write operations, the source buffer to write data from.
2760 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2761 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2762 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2763 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2767 PciRootBridgeIoWrite (
2768 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
2770 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
2776 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_WRITE_SUPPORT
) {
2778 // if PCI incompatibility check enabled
2780 return PciIncompatibilityCheckWrite (
2791 return PciRootBridgeIo
->Pci
.Write (
2802 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.
2804 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2805 @param Width Signifies the width of the memory operations.
2806 @Param Address The address within the PCI configuration space for the PCI controller.
2807 @param Buffer For read operations, the destination buffer to store the results. For
2808 write operations, the source buffer to write data from.
2810 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2811 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2812 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2813 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2818 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2819 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
2825 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_READ_SUPPORT
) {
2827 // if PCI incompatibility check enabled
2829 return PciIncompatibilityCheckRead (
2839 return PciIo
->Pci
.Read (
2850 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.
2852 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2853 @param Width Signifies the width of the memory operations.
2854 @Param Address The address within the PCI configuration space for the PCI controller.
2855 @param Buffer For read operations, the destination buffer to store the results. For
2856 write operations, the source buffer to write data from.
2858 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2859 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2860 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2861 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2866 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2867 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
2873 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_WRITE_SUPPORT
) {
2876 // if PCI incompatibility check enabled
2878 return PciIncompatibilityCheckWrite (
2889 return PciIo
->Pci
.Write (