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 Retrieve the BAR information via PciIo interface.
51 @param PciIoDevice Pci device instance.
55 IN PCI_IO_DEVICE
*PciIoDevice
60 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
65 // Read PciBar information from the bar register
67 if (!gFullEnumeration
) {
71 &(PciIoDevice
->PciIo
),
78 (PciIoDevice
->PciBar
)[P2C_MEM_1
].BaseAddress
= (UINT64
) (Address
);
79 (PciIoDevice
->PciBar
)[P2C_MEM_1
].Length
= 0x2000000;
80 (PciIoDevice
->PciBar
)[P2C_MEM_1
].BarType
= PciBarTypeMem32
;
84 &(PciIoDevice
->PciIo
),
90 (PciIoDevice
->PciBar
)[P2C_MEM_2
].BaseAddress
= (UINT64
) (Address
);
91 (PciIoDevice
->PciBar
)[P2C_MEM_2
].Length
= 0x2000000;
92 (PciIoDevice
->PciBar
)[P2C_MEM_2
].BarType
= PciBarTypePMem32
;
96 &(PciIoDevice
->PciIo
),
102 (PciIoDevice
->PciBar
)[P2C_IO_1
].BaseAddress
= (UINT64
) (Address
);
103 (PciIoDevice
->PciBar
)[P2C_IO_1
].Length
= 0x100;
104 (PciIoDevice
->PciBar
)[P2C_IO_1
].BarType
= PciBarTypeIo16
;
108 &(PciIoDevice
->PciIo
),
114 (PciIoDevice
->PciBar
)[P2C_IO_2
].BaseAddress
= (UINT64
) (Address
);
115 (PciIoDevice
->PciBar
)[P2C_IO_2
].Length
= 0x100;
116 (PciIoDevice
->PciBar
)[P2C_IO_2
].BarType
= PciBarTypeIo16
;
120 if (gPciHotPlugInit
!= NULL
) {
121 GetResourcePaddingForHpb (PciIoDevice
);
126 Remove rejected pci device from specific root bridge
129 @param RootBridgeHandle specific parent root bridge handle.
130 @param Bridge Bridge device instance.
132 @retval EFI_SUCCESS Success operation.
135 RemoveRejectedPciDevices (
136 EFI_HANDLE RootBridgeHandle
,
137 IN PCI_IO_DEVICE
*Bridge
141 LIST_ENTRY
*CurrentLink
;
142 LIST_ENTRY
*LastLink
;
144 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
148 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
150 while (CurrentLink
!= NULL
&& CurrentLink
!= &Bridge
->ChildList
) {
152 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
154 if (IS_PCI_BRIDGE (&Temp
->Pci
)) {
156 // Remove rejected devices recusively
158 RemoveRejectedPciDevices (RootBridgeHandle
, Temp
);
161 // Skip rejection for all PPBs, while detect rejection for others
163 if (IsPciDeviceRejected (Temp
)) {
166 // For P2C, remove all devices on it
169 if (!IsListEmpty (&Temp
->ChildList
)) {
170 RemoveAllPciDeviceOnBridge (RootBridgeHandle
, Temp
);
174 // Finally remove itself
177 LastLink
= CurrentLink
->BackLink
;
178 RemoveEntryList (CurrentLink
);
179 FreePciDevice (Temp
);
181 CurrentLink
= LastLink
;
185 CurrentLink
= CurrentLink
->ForwardLink
;
192 Wrapper function for allocating resource for pci host bridge.
194 @param PciResAlloc Point to protocol instance EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
198 PciHostBridgeResourceAllocator (
199 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
202 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
203 return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
207 return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
214 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
216 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
218 @retval EFI_SUCCESS Success.
221 PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
222 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
225 PCI_IO_DEVICE
*RootBridgeDev
;
226 EFI_HANDLE RootBridgeHandle
;
234 UINT64 MaxOptionRomSize
;
235 PCI_RESOURCE_NODE
*IoBridge
;
236 PCI_RESOURCE_NODE
*Mem32Bridge
;
237 PCI_RESOURCE_NODE
*PMem32Bridge
;
238 PCI_RESOURCE_NODE
*Mem64Bridge
;
239 PCI_RESOURCE_NODE
*PMem64Bridge
;
240 PCI_RESOURCE_NODE IoPool
;
241 PCI_RESOURCE_NODE Mem32Pool
;
242 PCI_RESOURCE_NODE PMem32Pool
;
243 PCI_RESOURCE_NODE Mem64Pool
;
244 PCI_RESOURCE_NODE PMem64Pool
;
245 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD ExtendedData
;
248 // Initialize resource pool
251 InitializeResourcePool (&IoPool
, PciBarTypeIo16
);
252 InitializeResourcePool (&Mem32Pool
, PciBarTypeMem32
);
253 InitializeResourcePool (&PMem32Pool
, PciBarTypePMem32
);
254 InitializeResourcePool (&Mem64Pool
, PciBarTypeMem64
);
255 InitializeResourcePool (&PMem64Pool
, PciBarTypePMem64
);
257 RootBridgeDev
= NULL
;
258 RootBridgeHandle
= 0;
260 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
262 // Get RootBridg Device by handle
264 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
266 if (RootBridgeDev
== NULL
) {
267 return EFI_NOT_FOUND
;
271 // Get host bridge handle for status report
273 ExtendedData
.Handle
= RootBridgeDev
->PciRootBridgeIo
->ParentHandle
;
276 // Create the entire system resource map from the information collected by
277 // enumerator. Several resource tree was created
280 IoBridge
= CreateResourceNode (
289 Mem32Bridge
= CreateResourceNode (
298 PMem32Bridge
= CreateResourceNode (
307 Mem64Bridge
= CreateResourceNode (
316 PMem64Bridge
= CreateResourceNode (
326 // Create resourcemap by going through all the devices subject to this root bridge
328 Status
= CreateResourceMap (
338 // Get the max ROM size that the root bridge can process
340 RootBridgeDev
->RomSize
= Mem32Bridge
->Length
;
343 // Get Max Option Rom size for current root bridge
345 MaxOptionRomSize
= GetMaxOptionRomSize (RootBridgeDev
);
348 // Enlarger the mem32 resource to accomdate the option rom
349 // if the mem32 resource is not enough to hold the rom
351 if (MaxOptionRomSize
> Mem32Bridge
->Length
) {
353 Mem32Bridge
->Length
= MaxOptionRomSize
;
354 RootBridgeDev
->RomSize
= MaxOptionRomSize
;
357 // Alignment should be adjusted as well
359 if (Mem32Bridge
->Alignment
< MaxOptionRomSize
- 1) {
360 Mem32Bridge
->Alignment
= MaxOptionRomSize
- 1;
365 // Based on the all the resource tree, contruct ACPI resource node to
366 // submit the resource aperture to pci host bridge protocol
368 Status
= ConstructAcpiResourceRequestor (
379 // Insert these resource nodes into the database
381 InsertResourceNode (&IoPool
, IoBridge
);
382 InsertResourceNode (&Mem32Pool
, Mem32Bridge
);
383 InsertResourceNode (&PMem32Pool
, PMem32Bridge
);
384 InsertResourceNode (&Mem64Pool
, Mem64Bridge
);
385 InsertResourceNode (&PMem64Pool
, PMem64Bridge
);
387 if (Status
== EFI_SUCCESS
) {
389 // Submit the resource requirement
391 Status
= PciResAlloc
->SubmitResources (
393 RootBridgeDev
->Handle
,
398 // Free acpi resource node
400 if (AcpiConfig
!= NULL
) {
401 FreePool (AcpiConfig
);
404 if (EFI_ERROR (Status
)) {
406 // Destroy all the resource tree
408 DestroyResourceTree (&IoPool
);
409 DestroyResourceTree (&Mem32Pool
);
410 DestroyResourceTree (&PMem32Pool
);
411 DestroyResourceTree (&Mem64Pool
);
412 DestroyResourceTree (&PMem64Pool
);
421 // Notify pci bus driver starts to program the resource
423 Status
= NotifyPhase (PciResAlloc
, EfiPciHostBridgeAllocateResources
);
425 if (EFI_ERROR (Status
)) {
427 // Allocation failed, then return
429 return EFI_OUT_OF_RESOURCES
;
432 // Raise the EFI_IOB_PCI_RES_ALLOC status code
434 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
436 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_RES_ALLOC
,
437 (VOID
*) &ExtendedData
,
438 sizeof (ExtendedData
)
442 // Notify pci bus driver starts to program the resource
444 NotifyPhase (PciResAlloc
, EfiPciHostBridgeSetResources
);
446 RootBridgeDev
= NULL
;
448 RootBridgeHandle
= 0;
450 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
452 // Get RootBridg Device by handle
454 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
456 if (RootBridgeDev
== NULL
) {
457 return EFI_NOT_FOUND
;
461 // Get acpi resource node for all the resource types
464 Status
= PciResAlloc
->GetProposedResources (
466 RootBridgeDev
->Handle
,
470 if (EFI_ERROR (Status
)) {
475 // Get the resource base by interpreting acpi resource node
488 // Process option rom for this root bridge
490 Status
= ProcessOptionRom (RootBridgeDev
, Mem32Base
, RootBridgeDev
->RomSize
);
493 // Create the entire system resource map from the information collected by
494 // enumerator. Several resource tree was created
496 Status
= GetResourceMap (
510 if (EFI_ERROR (Status
)) {
515 // Program IO resources
523 // Program Mem32 resources
531 // Program PMem32 resources
539 // Program Mem64 resources
547 // Program PMem64 resources
554 if (AcpiConfig
!= NULL
) {
555 FreePool (AcpiConfig
);
560 // Destroy all the resource tree
562 DestroyResourceTree (&IoPool
);
563 DestroyResourceTree (&Mem32Pool
);
564 DestroyResourceTree (&PMem32Pool
);
565 DestroyResourceTree (&Mem64Pool
);
566 DestroyResourceTree (&PMem64Pool
);
569 // Notify the resource allocation phase is to end
571 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndResourceAllocation
);
577 Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
579 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
581 @retval EFI_SUCCESS Success.
584 PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
585 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
588 PCI_IO_DEVICE
*RootBridgeDev
;
589 EFI_HANDLE RootBridgeHandle
;
598 UINT64 Mem32ResStatus
;
599 UINT64 PMem32ResStatus
;
600 UINT64 Mem64ResStatus
;
601 UINT64 PMem64ResStatus
;
602 UINT64 MaxOptionRomSize
;
603 PCI_RESOURCE_NODE
*IoBridge
;
604 PCI_RESOURCE_NODE
*Mem32Bridge
;
605 PCI_RESOURCE_NODE
*PMem32Bridge
;
606 PCI_RESOURCE_NODE
*Mem64Bridge
;
607 PCI_RESOURCE_NODE
*PMem64Bridge
;
608 PCI_RESOURCE_NODE IoPool
;
609 PCI_RESOURCE_NODE Mem32Pool
;
610 PCI_RESOURCE_NODE PMem32Pool
;
611 PCI_RESOURCE_NODE Mem64Pool
;
612 PCI_RESOURCE_NODE PMem64Pool
;
614 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData
;
615 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData
;
623 // It will try several times if the resource allocation fails
628 // Initialize resource pool
630 InitializeResourcePool (&IoPool
, PciBarTypeIo16
);
631 InitializeResourcePool (&Mem32Pool
, PciBarTypeMem32
);
632 InitializeResourcePool (&PMem32Pool
, PciBarTypePMem32
);
633 InitializeResourcePool (&Mem64Pool
, PciBarTypeMem64
);
634 InitializeResourcePool (&PMem64Pool
, PciBarTypePMem64
);
636 RootBridgeDev
= NULL
;
637 RootBridgeHandle
= 0;
639 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
642 // Get RootBridg Device by handle
644 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
646 if (RootBridgeDev
== NULL
) {
647 return EFI_NOT_FOUND
;
651 // Create the entire system resource map from the information collected by
652 // enumerator. Several resource tree was created
655 IoBridge
= CreateResourceNode (
664 Mem32Bridge
= CreateResourceNode (
673 PMem32Bridge
= CreateResourceNode (
682 Mem64Bridge
= CreateResourceNode (
691 PMem64Bridge
= CreateResourceNode (
701 // Create resourcemap by going through all the devices subject to this root bridge
703 Status
= CreateResourceMap (
713 // Get the max ROM size that the root bridge can process
715 RootBridgeDev
->RomSize
= Mem32Bridge
->Length
;
718 // Skip to enlarge the resource request during realloction
722 // Get Max Option Rom size for current root bridge
724 MaxOptionRomSize
= GetMaxOptionRomSize (RootBridgeDev
);
727 // Enlarger the mem32 resource to accomdate the option rom
728 // if the mem32 resource is not enough to hold the rom
730 if (MaxOptionRomSize
> Mem32Bridge
->Length
) {
732 Mem32Bridge
->Length
= MaxOptionRomSize
;
733 RootBridgeDev
->RomSize
= MaxOptionRomSize
;
736 // Alignment should be adjusted as well
738 if (Mem32Bridge
->Alignment
< MaxOptionRomSize
- 1) {
739 Mem32Bridge
->Alignment
= MaxOptionRomSize
- 1;
745 // Based on the all the resource tree, contruct ACPI resource node to
746 // submit the resource aperture to pci host bridge protocol
748 Status
= ConstructAcpiResourceRequestor (
759 // Insert these resource nodes into the database
761 InsertResourceNode (&IoPool
, IoBridge
);
762 InsertResourceNode (&Mem32Pool
, Mem32Bridge
);
763 InsertResourceNode (&PMem32Pool
, PMem32Bridge
);
764 InsertResourceNode (&Mem64Pool
, Mem64Bridge
);
765 InsertResourceNode (&PMem64Pool
, PMem64Bridge
);
767 if (Status
== EFI_SUCCESS
) {
769 // Submit the resource requirement
771 Status
= PciResAlloc
->SubmitResources (
773 RootBridgeDev
->Handle
,
779 // Free acpi resource node
781 if (AcpiConfig
!= NULL
) {
782 FreePool (AcpiConfig
);
785 if (EFI_ERROR (Status
)) {
787 // Destroy all the resource tree
789 DestroyResourceTree (&IoPool
);
790 DestroyResourceTree (&Mem32Pool
);
791 DestroyResourceTree (&PMem32Pool
);
792 DestroyResourceTree (&Mem64Pool
);
793 DestroyResourceTree (&PMem64Pool
);
799 // Notify pci bus driver starts to program the resource
802 Status
= NotifyPhase (PciResAlloc
, EfiPciHostBridgeAllocateResources
);
804 if (!EFI_ERROR (Status
)) {
806 // Allocation succeed, then continue the following
812 // If the resource allocation is unsuccessful, free resources on bridge
815 RootBridgeDev
= NULL
;
816 RootBridgeHandle
= 0;
818 IoResStatus
= EFI_RESOURCE_SATISFIED
;
819 Mem32ResStatus
= EFI_RESOURCE_SATISFIED
;
820 PMem32ResStatus
= EFI_RESOURCE_SATISFIED
;
821 Mem64ResStatus
= EFI_RESOURCE_SATISFIED
;
822 PMem64ResStatus
= EFI_RESOURCE_SATISFIED
;
824 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
826 // Get RootBridg Device by handle
828 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
829 if (RootBridgeDev
== NULL
) {
830 return EFI_NOT_FOUND
;
834 // Get host bridge handle for status report
836 HandleExtendedData
.Handle
= RootBridgeDev
->PciRootBridgeIo
->ParentHandle
;
839 // Get acpi resource node for all the resource types
843 Status
= PciResAlloc
->GetProposedResources (
845 RootBridgeDev
->Handle
,
849 if (EFI_ERROR (Status
)) {
853 if (AcpiConfig
!= NULL
) {
855 // Adjust resource allocation policy for each RB
857 GetResourceAllocationStatus (
865 FreePool (AcpiConfig
);
873 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
876 // It is very difficult to follow the spec here
877 // Device path , Bar index can not be get here
879 ZeroMem (&AllocFailExtendedData
, sizeof (AllocFailExtendedData
));
881 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
883 EFI_IO_BUS_PCI
| EFI_IOB_EC_RESOURCE_CONFLICT
,
884 (VOID
*) &AllocFailExtendedData
,
885 sizeof (AllocFailExtendedData
)
888 Status
= PciHostBridgeAdjustAllocation (
902 // Destroy all the resource tree
904 DestroyResourceTree (&IoPool
);
905 DestroyResourceTree (&Mem32Pool
);
906 DestroyResourceTree (&PMem32Pool
);
907 DestroyResourceTree (&Mem64Pool
);
908 DestroyResourceTree (&PMem64Pool
);
910 NotifyPhase (PciResAlloc
, EfiPciHostBridgeFreeResources
);
912 if (EFI_ERROR (Status
)) {
924 // Raise the EFI_IOB_PCI_RES_ALLOC status code
926 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
928 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_RES_ALLOC
,
929 (VOID
*) &HandleExtendedData
,
930 sizeof (HandleExtendedData
)
934 // Notify pci bus driver starts to program the resource
936 NotifyPhase (PciResAlloc
, EfiPciHostBridgeSetResources
);
938 RootBridgeDev
= NULL
;
940 RootBridgeHandle
= 0;
942 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
945 // Get RootBridg Device by handle
947 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
949 if (RootBridgeDev
== NULL
) {
950 return EFI_NOT_FOUND
;
954 // Get acpi resource node for all the resource types
957 Status
= PciResAlloc
->GetProposedResources (
959 RootBridgeDev
->Handle
,
963 if (EFI_ERROR (Status
)) {
968 // Get the resource base by interpreting acpi resource node
981 // Process option rom for this root bridge
983 Status
= ProcessOptionRom (RootBridgeDev
, Mem32Base
, RootBridgeDev
->RomSize
);
986 // Create the entire system resource map from the information collected by
987 // enumerator. Several resource tree was created
989 Status
= GetResourceMap (
1003 if (EFI_ERROR (Status
)) {
1008 // Program IO resources
1016 // Program Mem32 resources
1024 // Program PMem32 resources
1032 // Program Mem64 resources
1040 // Program PMem64 resources
1047 if (AcpiConfig
!= NULL
) {
1048 gBS
->FreePool (AcpiConfig
);
1053 // Destroy all the resource tree
1055 DestroyResourceTree (&IoPool
);
1056 DestroyResourceTree (&Mem32Pool
);
1057 DestroyResourceTree (&PMem32Pool
);
1058 DestroyResourceTree (&Mem64Pool
);
1059 DestroyResourceTree (&PMem64Pool
);
1062 // Notify the resource allocation phase is to end
1064 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndResourceAllocation
);
1070 Wapper function of scanning pci bus and assign bus number to the given PCI bus system
1071 Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
1073 @param Bridge Bridge device instance.
1074 @param StartBusNumber start point.
1075 @param SubBusNumber Point to sub bus number.
1076 @param PaddedBusRange Customized bus number.
1078 @retval EFI_SUCCESS Success.
1079 @retval EFI_DEVICE_ERROR Fail to scan bus.
1083 IN PCI_IO_DEVICE
*Bridge
,
1084 IN UINT8 StartBusNumber
,
1085 OUT UINT8
*SubBusNumber
,
1086 OUT UINT8
*PaddedBusRange
1089 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1090 return PciScanBus_WithHotPlugDeviceSupport (
1097 return PciScanBus_WithoutHotPlugDeviceSupport (
1107 Wapper function of scanning pci bus and assign bus number to the given PCI bus system
1108 Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
1110 @param Bridge Bridge device instance.
1111 @param StartBusNumber start point.
1112 @param SubBusNumber Point to sub bus number.
1113 @param PaddedBusRange Customized bus number.
1115 @retval EFI_SUCCESS Success.
1116 @retval EFI_DEVICE_ERROR Fail to scan bus.
1119 PciScanBus_WithoutHotPlugDeviceSupport (
1120 IN PCI_IO_DEVICE
*Bridge
,
1121 IN UINT8 StartBusNumber
,
1122 OUT UINT8
*SubBusNumber
,
1123 OUT UINT8
*PaddedBusRange
1133 PCI_IO_DEVICE
*PciDevice
;
1134 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1136 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
1140 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
1141 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
1144 // Check to see whether a pci device is present
1146 Status
= PciDevicePresent (
1154 if (!EFI_ERROR (Status
)) {
1155 DEBUG((EFI_D_ERROR
, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber
, Device
, Func
));
1157 if (IS_PCI_BRIDGE (&Pci
) ||
1158 IS_CARDBUS_BRIDGE (&Pci
)) {
1161 // Get the bridge information
1163 Status
= PciSearchDevice (
1172 if (EFI_ERROR (Status
)) {
1177 // Add feature to support customized secondary bus number
1179 if (*SubBusNumber
== 0) {
1180 *SubBusNumber
= *PaddedBusRange
;
1181 *PaddedBusRange
= 0;
1186 SecondBus
= (*SubBusNumber
);
1188 Register
= (UINT16
) ((SecondBus
<< 8) | (UINT16
) StartBusNumber
);
1190 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
1192 Status
= PciRootBridgeIoWrite (
1202 // Initialize SubBusNumber to SecondBus
1204 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1205 Status
= PciRootBridgeIoWrite (
1214 // If it is PPB, resursively search down this bridge
1216 if (IS_PCI_BRIDGE (&Pci
)) {
1218 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
1219 // PCI configuration transaction to go through any PPB
1221 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1223 Status
= PciRootBridgeIoWrite (
1232 PreprocessController (
1234 PciDevice
->BusNumber
,
1235 PciDevice
->DeviceNumber
,
1236 PciDevice
->FunctionNumber
,
1237 EfiPciBeforeChildBusEnumeration
1240 DEBUG((EFI_D_ERROR
, "Scan PPB(%02d,%02d,%02d)\n", PciDevice
->BusNumber
, PciDevice
->DeviceNumber
,PciDevice
->FunctionNumber
));
1241 Status
= PciScanBus (
1243 (UINT8
) (SecondBus
),
1248 if (EFI_ERROR (Status
)) {
1249 return EFI_DEVICE_ERROR
;
1254 // Set the current maximum bus number under the PPB
1257 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1259 Status
= PciRootBridgeIoWrite (
1270 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
1273 // Skip sub functions, this is not a multi function device
1276 Func
= PCI_MAX_FUNC
;
1285 Wapper function of scanning pci bus and assign bus number to the given PCI bus system
1286 Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
1288 @param Bridge Bridge device instance.
1289 @param StartBusNumber start point.
1290 @param SubBusNumber Point to sub bus number.
1291 @param PaddedBusRange Customized bus number.
1293 @retval EFI_SUCCESS Success.
1294 @retval EFI_DEVICE_ERROR Fail to scan bus.
1297 PciScanBus_WithHotPlugDeviceSupport (
1298 IN PCI_IO_DEVICE
*Bridge
,
1299 IN UINT8 StartBusNumber
,
1300 OUT UINT8
*SubBusNumber
,
1301 OUT UINT8
*PaddedBusRange
1312 PCI_IO_DEVICE
*PciDevice
;
1314 EFI_HPC_STATE State
;
1316 EFI_HPC_PADDING_ATTRIBUTES Attributes
;
1317 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
1319 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1322 PciRootBridgeIo
= Bridge
->PciRootBridgeIo
;
1326 Attributes
= (EFI_HPC_PADDING_ATTRIBUTES
) 0;
1329 for (Device
= 0; Device
<= PCI_MAX_DEVICE
; Device
++) {
1330 for (Func
= 0; Func
<= PCI_MAX_FUNC
; Func
++) {
1333 // Check to see whether a pci device is present
1335 Status
= PciDevicePresent (
1343 if (EFI_ERROR (Status
)) {
1346 // Skip sub functions, this is not a multi function device
1348 Func
= PCI_MAX_FUNC
;
1354 DEBUG((EFI_D_ERROR
, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber
, Device
, Func
));
1357 // Get the PCI device information
1359 Status
= PciSearchDevice (
1368 ASSERT (!EFI_ERROR (Status
));
1370 PciAddress
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0);
1372 if (!IS_PCI_BRIDGE (&Pci
)) {
1374 // PCI bridges will be called later
1375 // Here just need for PCI device or PCI to cardbus controller
1376 // EfiPciBeforeChildBusEnumeration for PCI Device Node
1378 PreprocessController (
1380 PciDevice
->BusNumber
,
1381 PciDevice
->DeviceNumber
,
1382 PciDevice
->FunctionNumber
,
1383 EfiPciBeforeChildBusEnumeration
1388 // For Pci Hotplug controller devcie only
1390 if (gPciHotPlugInit
!= NULL
) {
1392 // Check if it is a Hotplug PCI controller
1394 if (IsRootPciHotPlugController (PciDevice
->DevicePath
, &HpIndex
)) {
1396 if (!gPciRootHpcData
[HpIndex
].Initialized
) {
1398 Status
= CreateEventForHpc (HpIndex
, &Event
);
1400 ASSERT (!EFI_ERROR (Status
));
1402 Status
= gPciHotPlugInit
->InitializeRootHpc (
1404 gPciRootHpcPool
[HpIndex
].HpcDevicePath
,
1410 PreprocessController (
1412 PciDevice
->BusNumber
,
1413 PciDevice
->DeviceNumber
,
1414 PciDevice
->FunctionNumber
,
1415 EfiPciBeforeChildBusEnumeration
1421 if (IS_PCI_BRIDGE (&Pci
) || IS_CARDBUS_BRIDGE (&Pci
)) {
1424 // Get the bridge information
1427 if (gPciHotPlugInit
!= NULL
) {
1429 if (IsRootPciHotPlugBus (PciDevice
->DevicePath
, &HpIndex
)) {
1432 // If it is initialized, get the padded bus range
1434 Status
= gPciHotPlugInit
->GetResourcePadding (
1436 gPciRootHpcPool
[HpIndex
].HpbDevicePath
,
1439 (VOID
**) &Descriptors
,
1443 if (EFI_ERROR (Status
)) {
1448 Status
= PciGetBusRange (
1455 gBS
->FreePool (Descriptors
);
1457 if (EFI_ERROR (Status
)) {
1466 // Add feature to support customized secondary bus number
1468 if (*SubBusNumber
== 0) {
1469 *SubBusNumber
= *PaddedBusRange
;
1470 *PaddedBusRange
= 0;
1474 SecondBus
= *SubBusNumber
;
1476 Register
= (UINT16
) ((SecondBus
<< 8) | (UINT16
) StartBusNumber
);
1477 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x18);
1479 Status
= PciRootBridgeIoWrite (
1490 // If it is PPB, resursively search down this bridge
1492 if (IS_PCI_BRIDGE (&Pci
)) {
1495 // Initialize SubBusNumber to Maximum bus number
1498 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1499 Status
= PciRootBridgeIoWrite (
1509 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
1511 PreprocessController (
1513 PciDevice
->BusNumber
,
1514 PciDevice
->DeviceNumber
,
1515 PciDevice
->FunctionNumber
,
1516 EfiPciBeforeChildBusEnumeration
1519 DEBUG((EFI_D_ERROR
, "Scan PPB(%02d,%02d,%02d)\n", PciDevice
->BusNumber
, PciDevice
->DeviceNumber
,PciDevice
->FunctionNumber
));
1520 Status
= PciScanBus (
1522 (UINT8
) (SecondBus
),
1527 if (EFI_ERROR (Status
)) {
1528 return EFI_DEVICE_ERROR
;
1534 // Ensure the device is enabled and initialized
1536 if ((Attributes
== EfiPaddingPciRootBridge
) &&
1537 (State
& EFI_HPC_STATE_ENABLED
) != 0 &&
1538 (State
& EFI_HPC_STATE_INITIALIZED
) != 0) {
1539 *PaddedBusRange
= (UINT8
) ((UINT8
) (BusRange
) +*PaddedBusRange
);
1541 *SubBusNumber
= (UINT8
) ((UINT8
) (BusRange
) +*SubBusNumber
);
1546 // Set the current maximum bus number under the PPB
1548 Address
= EFI_PCI_ADDRESS (StartBusNumber
, Device
, Func
, 0x1A);
1550 Status
= PciRootBridgeIoWrite (
1560 if (Func
== 0 && !IS_PCI_MULTI_FUNC (&Pci
)) {
1563 // Skip sub functions, this is not a multi function device
1565 Func
= PCI_MAX_FUNC
;
1575 Process Option Rom on this host bridge.
1577 @param Bridge Pci bridge device instance.
1579 @retval EFI_SUCCESS Success.
1582 PciRootBridgeP2CProcess (
1583 IN PCI_IO_DEVICE
*Bridge
1586 LIST_ENTRY
*CurrentLink
;
1587 PCI_IO_DEVICE
*Temp
;
1588 EFI_HPC_STATE State
;
1592 CurrentLink
= Bridge
->ChildList
.ForwardLink
;
1594 while (CurrentLink
!= NULL
&& CurrentLink
!= &Bridge
->ChildList
) {
1596 Temp
= PCI_IO_DEVICE_FROM_LINK (CurrentLink
);
1598 if (IS_CARDBUS_BRIDGE (&Temp
->Pci
)) {
1600 if (gPciHotPlugInit
!= NULL
&& Temp
->Allocated
) {
1603 // Raise the EFI_IOB_PCI_HPC_INIT status code
1605 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1607 EFI_IO_BUS_PCI
| EFI_IOB_PCI_PC_HPC_INIT
,
1611 PciAddress
= EFI_PCI_ADDRESS (Temp
->BusNumber
, Temp
->DeviceNumber
, Temp
->FunctionNumber
, 0);
1612 Status
= gPciHotPlugInit
->InitializeRootHpc (
1620 if (!EFI_ERROR (Status
)) {
1621 Status
= PciBridgeEnumerator (Temp
);
1623 if (EFI_ERROR (Status
)) {
1628 CurrentLink
= CurrentLink
->ForwardLink
;
1634 if (!IsListEmpty (&Temp
->ChildList
)) {
1635 Status
= PciRootBridgeP2CProcess (Temp
);
1638 CurrentLink
= CurrentLink
->ForwardLink
;
1645 Process Option Rom on this host bridge.
1647 @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
1649 @retval EFI_NOT_FOUND Can not find the root bridge instance.
1650 @retval EFI_SUCCESS Success process.
1653 PciHostBridgeP2CProcess (
1654 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
1657 EFI_HANDLE RootBridgeHandle
;
1658 PCI_IO_DEVICE
*RootBridgeDev
;
1661 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1665 RootBridgeHandle
= NULL
;
1667 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1670 // Get RootBridg Device by handle
1672 RootBridgeDev
= GetRootBridgeByHandle (RootBridgeHandle
);
1674 if (RootBridgeDev
== NULL
) {
1675 return EFI_NOT_FOUND
;
1678 Status
= PciRootBridgeP2CProcess (RootBridgeDev
);
1680 if (EFI_ERROR (Status
)) {
1690 This function is used to enumerate the entire host bridge
1691 in a given platform.
1693 @param PciResAlloc A pointer to the resource allocate protocol.
1695 @retval EFI_OUT_OF_RESOURCES no enough resource.
1696 @retval EFI_SUCCESS Success.
1700 PciHostBridgeEnumerator (
1701 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
*PciResAlloc
1704 EFI_HANDLE RootBridgeHandle
;
1705 PCI_IO_DEVICE
*RootBridgeDev
;
1707 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
;
1709 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Descriptors
;
1710 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*Configuration
;
1711 UINT8 StartBusNumber
;
1712 LIST_ENTRY RootBridgeList
;
1715 InitializeHotPlugSupport ();
1717 InitializeListHead (&RootBridgeList
);
1720 // Notify the bus allocation phase is about to start
1722 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginBusAllocation
);
1724 DEBUG((EFI_D_ERROR
, "PCI Bus First Scanning\n"));
1725 RootBridgeHandle
= NULL
;
1726 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1729 // if a root bridge instance is found, create root bridge device for it
1732 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1734 if (RootBridgeDev
== NULL
) {
1735 return EFI_OUT_OF_RESOURCES
;
1739 // Enumerate all the buses under this root bridge
1742 Status
= PciRootBridgeEnumerator (
1747 if (gPciHotPlugInit
!= NULL
) {
1748 InsertTailList (&RootBridgeList
, &(RootBridgeDev
->Link
));
1750 DestroyRootBridge (RootBridgeDev
);
1752 if (EFI_ERROR (Status
)) {
1758 // Notify the bus allocation phase is finished for the first time
1760 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1762 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport
)) {
1764 if (gPciHotPlugInit
!= NULL
) {
1766 // Reset all assigned PCI bus number in all PPB
1768 RootBridgeHandle
= NULL
;
1769 Link
= GetFirstNode (&RootBridgeList
);
1770 while ((PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) &&
1771 (!IsNull (&RootBridgeList
, Link
))) {
1772 RootBridgeDev
= PCI_IO_DEVICE_FROM_LINK (Link
);
1774 // Get the Bus information
1776 Status
= PciResAlloc
->StartBusEnumeration (
1779 (VOID
**) &Configuration
1781 if (EFI_ERROR (Status
)) {
1786 // Get the bus number to start with
1788 StartBusNumber
= (UINT8
) (Configuration
->AddrRangeMin
);
1790 ResetAllPpbBusNumber (
1795 gBS
->FreePool (Configuration
);
1796 Link
= GetNextNode (&RootBridgeList
, Link
);
1797 DestroyRootBridge (RootBridgeDev
);
1801 // Wait for all HPC initialized
1803 Status
= AllRootHPCInitialized (STALL_1_SECOND
* 15);
1805 if (EFI_ERROR (Status
)) {
1810 // Notify the bus allocation phase is about to start for the 2nd time
1812 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginBusAllocation
);
1814 DEBUG((EFI_D_ERROR
, "PCI Bus Second Scanning\n"));
1815 RootBridgeHandle
= NULL
;
1816 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1819 // if a root bridge instance is found, create root bridge device for it
1822 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1824 if (RootBridgeDev
== NULL
) {
1825 return EFI_OUT_OF_RESOURCES
;
1829 // Enumerate all the buses under this root bridge
1832 Status
= PciRootBridgeEnumerator (
1837 DestroyRootBridge (RootBridgeDev
);
1838 if (EFI_ERROR (Status
)) {
1844 // Notify the bus allocation phase is to end for the 2nd time
1846 NotifyPhase (PciResAlloc
, EfiPciHostBridgeEndBusAllocation
);
1851 // Notify the resource allocation phase is to start
1853 NotifyPhase (PciResAlloc
, EfiPciHostBridgeBeginResourceAllocation
);
1855 RootBridgeHandle
= NULL
;
1856 while (PciResAlloc
->GetNextRootBridge (PciResAlloc
, &RootBridgeHandle
) == EFI_SUCCESS
) {
1859 // if a root bridge instance is found, create root bridge device for it
1862 RootBridgeDev
= CreateRootBridge (RootBridgeHandle
);
1864 if (RootBridgeDev
== NULL
) {
1865 return EFI_OUT_OF_RESOURCES
;
1868 Status
= StartManagingRootBridge (RootBridgeDev
);
1870 if (EFI_ERROR (Status
)) {
1874 PciRootBridgeIo
= RootBridgeDev
->PciRootBridgeIo
;
1875 Status
= PciRootBridgeIo
->Configuration (PciRootBridgeIo
, (VOID
**) &Descriptors
);
1877 if (EFI_ERROR (Status
)) {
1881 Status
= PciGetBusRange (&Descriptors
, &MinBus
, NULL
, NULL
);
1883 if (EFI_ERROR (Status
)) {
1888 // Determine root bridge attribute by calling interface of Pcihostbridge
1891 DetermineRootBridgeAttributes (
1897 // Collect all the resource information under this root bridge
1898 // A database that records all the information about pci device subject to this
1899 // root bridge will then be created
1901 Status
= PciPciDeviceInfoCollector (
1906 if (EFI_ERROR (Status
)) {
1910 InsertRootBridge (RootBridgeDev
);
1913 // Record the hostbridge handle
1915 AddHostBridgeEnumerator (RootBridgeDev
->PciRootBridgeIo
->ParentHandle
);
1922 Read PCI device configuration register by specified address.
1924 This function check the incompatiblilites on PCI device. Return the register
1927 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1928 @param PciIo A pointer to EFI_PCI_PROTOCOL.
1929 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
1930 @param Width Signifies the width of the memory operations.
1931 @param Address The address within the PCI configuration space for the PCI controller.
1932 @param Buffer For read operations, the destination buffer to store the results. For
1933 write operations, the source buffer to write data from.
1935 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1936 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
1937 @retval EFI_INVALID_PARAMETER Buffer is NULL.
1938 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
1943 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
1944 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
1945 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
1953 EFI_PCI_REGISTER_ACCESS_DATA
*PciRegisterAccessData
;
1954 UINT64 AccessAddress
;
1959 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
1961 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT
) {
1963 // check access compatibility at first time
1965 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_READ
, Address
& 0xff, Width
, &PciRegisterAccessData
);
1967 if (Status
== EFI_SUCCESS
) {
1969 // there exist incompatibility on this operation
1971 AccessWidth
= Width
;
1973 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
1974 AccessWidth
= PciRegisterAccessData
->Width
;
1977 AccessAddress
= Address
& ~((1 << AccessWidth
) - 1);
1981 Pointer
= (UINT8
*) &TempBuffer
;
1985 if (PciRootBridgeIo
!= NULL
) {
1986 Status
= PciRootBridgeIo
->Pci
.Read (
1988 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) AccessWidth
,
1993 } else if (PciIo
!= NULL
) {
1994 Status
= PciIo
->Pci
.Read (
1996 (EFI_PCI_IO_PROTOCOL_WIDTH
) AccessWidth
,
1997 (UINT32
) AccessAddress
,
2003 if (Status
!= EFI_SUCCESS
) {
2007 Stride
= (UINTN
)1 << AccessWidth
;
2008 AccessAddress
+= Stride
;
2009 if (AccessAddress
>= (Address
+ LShiftU64 (1ULL, (UINTN
)Width
))) {
2011 // if all datas have been read, exist
2018 if ((AccessAddress
& 0xff) < PciRegisterAccessData
->EndOffset
) {
2020 // if current offset doesn't reach the end
2025 FreePool (PciRegisterAccessData
);
2028 // continue checking access incompatibility
2030 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_READ
, AccessAddress
& 0xff, AccessWidth
, &PciRegisterAccessData
);
2031 if (Status
== EFI_SUCCESS
) {
2032 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2033 AccessWidth
= PciRegisterAccessData
->Width
;
2038 FreePool (PciRegisterAccessData
);
2041 case EfiPciWidthUint8
:
2042 * (UINT8
*) Buffer
= (UINT8
) TempBuffer
;
2044 case EfiPciWidthUint16
:
2045 * (UINT16
*) Buffer
= (UINT16
) TempBuffer
;
2047 case EfiPciWidthUint32
:
2048 * (UINT32
*) Buffer
= (UINT32
) TempBuffer
;
2051 return EFI_UNSUPPORTED
;
2058 // AccessWidth incompatible check not supportted
2059 // or, there doesn't exist incompatibility on this operation
2061 if (PciRootBridgeIo
!= NULL
) {
2062 Status
= PciRootBridgeIo
->Pci
.Read (
2064 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
2071 Status
= PciIo
->Pci
.Read (
2073 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
2084 Update register value by checking PCI device incompatibility.
2086 This function check register value incompatibilites on PCI device. Return the register
2089 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2090 @param AccessType Access type, READ or WRITE.
2091 @param Width Signifies the width of the memory operations.
2092 @param Address The address within the PCI configuration space.
2093 @param Buffer Store the register data.
2095 @retval EFI_SUCCESS The data has been updated.
2100 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2101 IN UINT64 AccessType
,
2108 EFI_PCI_REGISTER_VALUE_DATA
*PciRegisterData
;
2114 // check register value incompatibility
2116 Status
= PciRegisterUpdateCheck (PciDeviceInfo
, AccessType
, Address
& 0xff, &PciRegisterData
);
2118 if (Status
== EFI_SUCCESS
) {
2120 AndValue
= ((UINT32
) PciRegisterData
->AndValue
) >> (((UINT8
) Address
& 0x3) * 8);
2121 OrValue
= ((UINT32
) PciRegisterData
->OrValue
) >> (((UINT8
) Address
& 0x3) * 8);
2123 TempValue
= * (UINT32
*) Buffer
;
2124 if (PciRegisterData
->AndValue
!= VALUE_NOCARE
) {
2125 TempValue
&= AndValue
;
2127 if (PciRegisterData
->OrValue
!= VALUE_NOCARE
) {
2128 TempValue
|= OrValue
;
2132 case EfiPciWidthUint8
:
2133 *(UINT8
*)Buffer
= (UINT8
) TempValue
;
2136 case EfiPciWidthUint16
:
2137 *(UINT16
*)Buffer
= (UINT16
) TempValue
;
2139 case EfiPciWidthUint32
:
2140 *(UINT32
*)Buffer
= TempValue
;
2144 return EFI_UNSUPPORTED
;
2147 FreePool (PciRegisterData
);
2154 Write PCI device configuration register by specified address.
2156 This function check the incompatiblilites on PCI device, and write date
2159 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2160 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2161 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2162 @param Width Signifies the width of the memory operations.
2163 @param Address The address within the PCI configuration space for the PCI controller.
2164 @param Buffer For read operations, the destination buffer to store the results. For
2165 write operations, the source buffer to write data from.
2167 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2168 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2169 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2170 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2175 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2176 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2177 IN EFI_PCI_DEVICE_INFO
*PciDeviceInfo
,
2185 EFI_PCI_REGISTER_ACCESS_DATA
*PciRegisterAccessData
;
2186 UINT64 AccessAddress
;
2192 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2194 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT
) {
2196 // check access compatibility at first time
2198 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_WRITE
, Address
& 0xff, Width
, &PciRegisterAccessData
);
2200 if (Status
== EFI_SUCCESS
) {
2202 // there exist incompatibility on this operation
2204 AccessWidth
= Width
;
2206 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2207 AccessWidth
= PciRegisterAccessData
->Width
;
2210 AccessAddress
= Address
& ~((1 << AccessWidth
) - 1);
2213 Pointer
= (UINT8
*) &Buffer
;
2214 Data
= * (UINT64
*) Buffer
;
2218 if (AccessWidth
> Width
) {
2220 // if actual access width is larger than orignal one, additional data need to be read back firstly
2222 Status
= ReadConfigData (PciRootBridgeIo
, PciIo
, PciDeviceInfo
, AccessWidth
, AccessAddress
, &Data
);
2223 if (Status
!= EFI_SUCCESS
) {
2228 // check data read incompatibility
2230 UpdateConfigData (PciDeviceInfo
, PCI_REGISTER_READ
, AccessWidth
, AccessAddress
& 0xff, &Data
);
2232 Shift
= (UINTN
)(Address
- AccessAddress
) * 8;
2234 case EfiPciWidthUint8
:
2235 Data
= (* (UINT8
*) Buffer
) << Shift
| (Data
& ~(0xff << Shift
));
2238 case EfiPciWidthUint16
:
2239 Data
= (* (UINT16
*) Buffer
) << Shift
| (Data
& ~(0xffff << Shift
));
2244 // check data write incompatibility
2246 UpdateConfigData (PciDeviceInfo
, PCI_REGISTER_WRITE
, AccessWidth
, MultU64x32 (AccessAddress
, 0xff), &Data
);
2249 if (PciRootBridgeIo
!= NULL
) {
2250 Status
= PciRootBridgeIo
->Pci
.Write (
2252 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) AccessWidth
,
2258 Status
= PciIo
->Pci
.Write (
2260 (EFI_PCI_IO_PROTOCOL_WIDTH
) AccessWidth
,
2261 (UINT32
) AccessAddress
,
2267 if (Status
!= EFI_SUCCESS
) {
2271 Data
= RShiftU64 (Data
, ((1 << AccessWidth
) * 8));
2273 Stride
= (UINTN
)1 << AccessWidth
;
2274 AccessAddress
+= Stride
;
2275 if (AccessAddress
>= (Address
+ LShiftU64 (1ULL, (UINTN
)Width
))) {
2277 // if all datas have been written, exist
2284 if ((AccessAddress
& 0xff) < PciRegisterAccessData
->EndOffset
) {
2286 // if current offset doesn't reach the end
2291 FreePool (PciRegisterAccessData
);
2294 // continue checking access incompatibility
2296 Status
= PciRegisterAccessCheck (PciDeviceInfo
, PCI_REGISTER_WRITE
, AccessAddress
& 0xff, AccessWidth
, &PciRegisterAccessData
);
2297 if (Status
== EFI_SUCCESS
) {
2298 if (PciRegisterAccessData
->Width
!= VALUE_NOCARE
) {
2299 AccessWidth
= PciRegisterAccessData
->Width
;
2304 FreePool (PciRegisterAccessData
);
2311 // AccessWidth incompatible check not supportted
2312 // or, there doesn't exist incompatibility on this operation
2314 if (PciRootBridgeIo
!= NULL
) {
2315 Status
= PciRootBridgeIo
->Pci
.Write (
2317 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH
) Width
,
2323 Status
= PciIo
->Pci
.Write (
2325 (EFI_PCI_IO_PROTOCOL_WIDTH
) Width
,
2336 Abstract PCI device device information.
2338 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2339 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2340 @param Pci A pointer to PCI_TYPE00.
2341 @param Address The address within the PCI configuration space for the PCI controller.
2342 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2344 @retval EFI_SUCCESS Pci device device information has been abstracted.
2348 GetPciDeviceDeviceInfo (
2349 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2350 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2351 IN PCI_TYPE00
*Pci
, OPTIONAL
2352 IN UINT64 Address
, OPTIONAL
2353 OUT EFI_PCI_DEVICE_INFO
*PciDeviceInfo
2358 UINT32 PciConfigData
;
2359 PCI_IO_DEVICE
*PciIoDevice
;
2361 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2363 if (PciIo
!= NULL
) {
2364 PciIoDevice
= PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo
);
2367 // get pointer to PCI_TYPE00 from PciIoDevice
2369 Pci
= &PciIoDevice
->Pci
;
2374 // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly
2376 PciAddress
= Address
& 0xffffffffffffff00ULL
;
2377 Status
= PciRootBridgeIo
->Pci
.Read (
2385 if (EFI_ERROR (Status
)) {
2389 if ((PciConfigData
& 0xffff) == 0xffff) {
2390 return EFI_NOT_FOUND
;
2393 PciDeviceInfo
->VendorID
= PciConfigData
& 0xffff;
2394 PciDeviceInfo
->DeviceID
= PciConfigData
>> 16;
2396 Status
= PciRootBridgeIo
->Pci
.Read (
2403 if (EFI_ERROR (Status
)) {
2407 PciDeviceInfo
->RevisionID
= PciConfigData
& 0xf;
2409 Status
= PciRootBridgeIo
->Pci
.Read (
2417 if (EFI_ERROR (Status
)) {
2421 PciDeviceInfo
->SubsystemVendorID
= PciConfigData
& 0xffff;
2422 PciDeviceInfo
->SubsystemID
= PciConfigData
>> 16;
2425 PciDeviceInfo
->VendorID
= Pci
->Hdr
.VendorId
;
2426 PciDeviceInfo
->DeviceID
= Pci
->Hdr
.DeviceId
;
2427 PciDeviceInfo
->RevisionID
= Pci
->Hdr
.RevisionID
;
2428 PciDeviceInfo
->SubsystemVendorID
= Pci
->Device
.SubsystemVendorID
;
2429 PciDeviceInfo
->SubsystemID
= Pci
->Device
.SubsystemID
;
2436 Read PCI configuration space with incompatibility check.
2438 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2439 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2440 @param Pci A pointer to PCI_TYPE00.
2441 @param Width Signifies the width of the memory operations.
2442 @param Address The address within the PCI configuration space for the PCI controller.
2443 @param Count The number of unit to be read.
2444 @param Buffer For read operations, the destination buffer to store the results. For
2445 write operations, the source buffer to write data from.
2447 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2448 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2449 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2450 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2454 PciIncompatibilityCheckRead (
2455 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2456 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2457 IN PCI_TYPE00
*Pci
, OPTIONAL
2465 EFI_PCI_DEVICE_INFO PciDeviceInfo
;
2468 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2471 // get PCI device device information
2473 Status
= GetPciDeviceDeviceInfo (PciRootBridgeIo
, PciIo
, Pci
, Address
, &PciDeviceInfo
);
2474 if (Status
!= EFI_SUCCESS
) {
2478 Stride
= 1 << Width
;
2480 for (; Count
> 0; Count
--, Address
+= Stride
, Buffer
= (UINT8
*)Buffer
+ Stride
) {
2483 // read configuration register
2485 Status
= ReadConfigData (PciRootBridgeIo
, PciIo
, &PciDeviceInfo
, (UINT64
) Width
, Address
, Buffer
);
2487 if (Status
!= EFI_SUCCESS
) {
2492 // update the data read from configuration register
2494 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT
) {
2495 UpdateConfigData (&PciDeviceInfo
, PCI_REGISTER_READ
, Width
, Address
& 0xff, Buffer
);
2503 Write PCI configuration space with incompatibility check.
2505 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2506 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2507 @param Pci A pointer to PCI_TYPE00.
2508 @param Width Signifies the width of the memory operations.
2509 @param Address The address within the PCI configuration space for the PCI controller.
2510 @param Count The number of unit to be write.
2511 @param Buffer For read operations, the destination buffer to store the results. For
2512 write operations, the source buffer to write data from.
2514 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2515 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2516 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2517 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2521 PciIncompatibilityCheckWrite (
2522 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
, OPTIONAL
2523 IN EFI_PCI_IO_PROTOCOL
*PciIo
, OPTIONAL
2524 IN PCI_TYPE00
*Pci
, OPTIONAL
2532 EFI_PCI_DEVICE_INFO PciDeviceInfo
;
2536 ASSERT ((PciRootBridgeIo
== NULL
) ^ (PciIo
== NULL
));
2539 // get PCI device device information
2541 Status
= GetPciDeviceDeviceInfo (PciRootBridgeIo
, PciIo
, Pci
, Address
, &PciDeviceInfo
);
2542 if (Status
!= EFI_SUCCESS
) {
2546 Stride
= 1 << Width
;
2548 for (; Count
> 0; Count
--, Address
+= Stride
, Buffer
= (UINT8
*) Buffer
+ Stride
) {
2553 case EfiPciWidthUint8
:
2554 Data
= * (UINT8
*) Buffer
;
2556 case EfiPciWidthUint16
:
2557 Data
= * (UINT16
*) Buffer
;
2560 case EfiPciWidthUint32
:
2561 Data
= * (UINT32
*) Buffer
;
2565 return EFI_UNSUPPORTED
;
2569 // update the data writen into configuration register
2571 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT
) {
2572 UpdateConfigData (&PciDeviceInfo
, PCI_REGISTER_WRITE
, Width
, Address
& 0xff, &Data
);
2576 // write configuration register
2578 Status
= WriteConfigData (PciRootBridgeIo
, PciIo
, &PciDeviceInfo
, Width
, Address
, &Data
);
2580 if (Status
!= EFI_SUCCESS
) {
2589 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2591 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2592 @param Pci A pointer to PCI_TYPE00.
2593 @param Width Signifies the width of the memory operations.
2594 @param Address The address within the PCI configuration space for the PCI controller.
2595 @param Count The number of unit to be read.
2596 @param Buffer For read operations, the destination buffer to store the results. For
2597 write operations, the source buffer to write data from.
2599 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2600 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2601 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2602 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2606 PciRootBridgeIoRead (
2607 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
2608 IN PCI_TYPE00
*Pci
, OPTIONAL
2609 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
2615 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_READ_SUPPORT
) {
2617 // if PCI incompatibility check enabled
2619 return PciIncompatibilityCheckRead (
2629 return PciRootBridgeIo
->Pci
.Read (
2640 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2642 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2643 @param Pci A pointer to PCI_TYPE00.
2644 @param Width Signifies the width of the memory operations.
2645 @param Address The address within the PCI configuration space for the PCI controller.
2646 @param Count The number of unit to be read.
2647 @param Buffer For read operations, the destination buffer to store the results. For
2648 write operations, the source buffer to write data from.
2650 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2651 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2652 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2653 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2657 PciRootBridgeIoWrite (
2658 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
*PciRootBridgeIo
,
2660 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width
,
2666 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_WRITE_SUPPORT
) {
2668 // if PCI incompatibility check enabled
2670 return PciIncompatibilityCheckWrite (
2681 return PciRootBridgeIo
->Pci
.Write (
2692 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.
2694 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2695 @param Width Signifies the width of the memory operations.
2696 @param Address The address within the PCI configuration space for the PCI controller.
2697 @param Count The number of unit to be read.
2698 @param Buffer For read operations, the destination buffer to store the results. For
2699 write operations, the source buffer to write data from.
2701 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2702 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2703 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2704 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2709 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2710 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
2716 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_READ_SUPPORT
) {
2718 // if PCI incompatibility check enabled
2720 return PciIncompatibilityCheckRead (
2730 return PciIo
->Pci
.Read (
2741 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.
2743 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2744 @param Width Signifies the width of the memory operations.
2745 @param Address The address within the PCI configuration space for the PCI controller.
2746 @param Count The number of unit to be read.
2747 @param Buffer For read operations, the destination buffer to store the results. For
2748 write operations, the source buffer to write data from.
2750 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2751 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2752 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2753 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2758 IN EFI_PCI_IO_PROTOCOL
*PciIo
,
2759 IN EFI_PCI_IO_PROTOCOL_WIDTH Width
,
2765 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask
) & PCI_INCOMPATIBLE_WRITE_SUPPORT
) {
2768 // if PCI incompatibility check enabled
2770 return PciIncompatibilityCheckWrite (
2781 return PciIo
->Pci
.Write (