fixed ecc and k8 issues.
[edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciLib.c
blob615bbaa4dc909c7b9c51e2e8d90eaaa28f400053
1 /** @file
2 Internal library implementation for PCI Bus module.
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
15 #include "PciBus.h"
18 /**
19 Retrieve the PCI Card device BAR information via PciIo interface.
21 @param PciIoDevice PCI Card device instance.
23 **/
24 VOID
25 GetBackPcCardBar (
26 IN PCI_IO_DEVICE *PciIoDevice
29 UINT32 Address;
31 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
32 return;
36 // Read PciBar information from the bar register
38 if (!gFullEnumeration) {
39 Address = 0;
40 PciIoRead (
41 &(PciIoDevice->PciIo),
42 EfiPciIoWidthUint32,
43 PCI_CARD_MEMORY_BASE_0,
45 &Address
48 (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
49 (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
50 (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
52 Address = 0;
53 PciIoRead (
54 &(PciIoDevice->PciIo),
55 EfiPciIoWidthUint32,
56 PCI_CARD_MEMORY_BASE_1,
58 &Address
60 (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
61 (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
62 (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
64 Address = 0;
65 PciIoRead (
66 &(PciIoDevice->PciIo),
67 EfiPciIoWidthUint32,
68 PCI_CARD_IO_BASE_0_LOWER,
70 &Address
72 (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
73 (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
74 (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
76 Address = 0;
77 PciIoRead (
78 &(PciIoDevice->PciIo),
79 EfiPciIoWidthUint32,
80 PCI_CARD_IO_BASE_1_LOWER,
82 &Address
84 (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
85 (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
86 (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
90 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
91 GetResourcePaddingForHpb (PciIoDevice);
95 /**
96 Remove rejected pci device from specific root bridge
97 handle.
99 @param RootBridgeHandle Specific parent root bridge handle.
100 @param Bridge Bridge device instance.
103 VOID
104 RemoveRejectedPciDevices (
105 IN EFI_HANDLE RootBridgeHandle,
106 IN PCI_IO_DEVICE *Bridge
109 PCI_IO_DEVICE *Temp;
110 LIST_ENTRY *CurrentLink;
111 LIST_ENTRY *LastLink;
113 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
114 return;
117 CurrentLink = Bridge->ChildList.ForwardLink;
119 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
121 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
123 if (IS_PCI_BRIDGE (&Temp->Pci)) {
125 // Remove rejected devices recusively
127 RemoveRejectedPciDevices (RootBridgeHandle, Temp);
128 } else {
130 // Skip rejection for all PPBs, while detect rejection for others
132 if (IsPciDeviceRejected (Temp)) {
135 // For P2C, remove all devices on it
137 if (!IsListEmpty (&Temp->ChildList)) {
138 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
142 // Finally remove itself
144 LastLink = CurrentLink->BackLink;
145 RemoveEntryList (CurrentLink);
146 FreePciDevice (Temp);
148 CurrentLink = LastLink;
152 CurrentLink = CurrentLink->ForwardLink;
157 Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
159 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
161 @retval EFI_SUCCESS Successfully finished resource allocation.
162 @retval EFI_NOT_FOUND Cannot get root bridge instance.
163 @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
164 @retval other Some error occurred when allocating resources for the PCI Host Bridge.
166 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
169 EFI_STATUS
170 PciHostBridgeResourceAllocator (
171 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
174 PCI_IO_DEVICE *RootBridgeDev;
175 EFI_HANDLE RootBridgeHandle;
176 VOID *AcpiConfig;
177 EFI_STATUS Status;
178 UINT64 IoBase;
179 UINT64 Mem32Base;
180 UINT64 PMem32Base;
181 UINT64 Mem64Base;
182 UINT64 PMem64Base;
183 UINT64 IoResStatus;
184 UINT64 Mem32ResStatus;
185 UINT64 PMem32ResStatus;
186 UINT64 Mem64ResStatus;
187 UINT64 PMem64ResStatus;
188 UINT64 MaxOptionRomSize;
189 PCI_RESOURCE_NODE *IoBridge;
190 PCI_RESOURCE_NODE *Mem32Bridge;
191 PCI_RESOURCE_NODE *PMem32Bridge;
192 PCI_RESOURCE_NODE *Mem64Bridge;
193 PCI_RESOURCE_NODE *PMem64Bridge;
194 PCI_RESOURCE_NODE IoPool;
195 PCI_RESOURCE_NODE Mem32Pool;
196 PCI_RESOURCE_NODE PMem32Pool;
197 PCI_RESOURCE_NODE Mem64Pool;
198 PCI_RESOURCE_NODE PMem64Pool;
199 BOOLEAN ReAllocate;
200 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
201 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
204 // Reallocate flag
206 ReAllocate = FALSE;
209 // It may try several times if the resource allocation fails
211 while (TRUE) {
213 // Initialize resource pool
215 InitializeResourcePool (&IoPool, PciBarTypeIo16);
216 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
217 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
218 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
219 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
221 RootBridgeDev = NULL;
222 RootBridgeHandle = 0;
224 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
226 // Get Root Bridge Device by handle
228 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
230 if (RootBridgeDev == NULL) {
231 return EFI_NOT_FOUND;
235 // Create the entire system resource map from the information collected by
236 // enumerator. Several resource tree was created
239 IoBridge = CreateResourceNode (
240 RootBridgeDev,
242 0xFFF,
244 PciBarTypeIo16,
245 PciResUsageTypical
248 Mem32Bridge = CreateResourceNode (
249 RootBridgeDev,
251 0xFFFFF,
253 PciBarTypeMem32,
254 PciResUsageTypical
257 PMem32Bridge = CreateResourceNode (
258 RootBridgeDev,
260 0xFFFFF,
262 PciBarTypePMem32,
263 PciResUsageTypical
266 Mem64Bridge = CreateResourceNode (
267 RootBridgeDev,
269 0xFFFFF,
271 PciBarTypeMem64,
272 PciResUsageTypical
275 PMem64Bridge = CreateResourceNode (
276 RootBridgeDev,
278 0xFFFFF,
280 PciBarTypePMem64,
281 PciResUsageTypical
285 // Create resourcemap by going through all the devices subject to this root bridge
287 CreateResourceMap (
288 RootBridgeDev,
289 IoBridge,
290 Mem32Bridge,
291 PMem32Bridge,
292 Mem64Bridge,
293 PMem64Bridge
297 // Get the max ROM size that the root bridge can process
299 RootBridgeDev->RomSize = Mem32Bridge->Length;
302 // Skip to enlarge the resource request during realloction
304 if (!ReAllocate) {
306 // Get Max Option Rom size for current root bridge
308 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
311 // Enlarger the mem32 resource to accomdate the option rom
312 // if the mem32 resource is not enough to hold the rom
314 if (MaxOptionRomSize > Mem32Bridge->Length) {
316 Mem32Bridge->Length = MaxOptionRomSize;
317 RootBridgeDev->RomSize = MaxOptionRomSize;
320 // Alignment should be adjusted as well
322 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {
323 Mem32Bridge->Alignment = MaxOptionRomSize - 1;
329 // Based on the all the resource tree, contruct ACPI resource node to
330 // submit the resource aperture to pci host bridge protocol
332 Status = ConstructAcpiResourceRequestor (
333 RootBridgeDev,
334 IoBridge,
335 Mem32Bridge,
336 PMem32Bridge,
337 Mem64Bridge,
338 PMem64Bridge,
339 &AcpiConfig
343 // Insert these resource nodes into the database
345 InsertResourceNode (&IoPool, IoBridge);
346 InsertResourceNode (&Mem32Pool, Mem32Bridge);
347 InsertResourceNode (&PMem32Pool, PMem32Bridge);
348 InsertResourceNode (&Mem64Pool, Mem64Bridge);
349 InsertResourceNode (&PMem64Pool, PMem64Bridge);
351 if (Status == EFI_SUCCESS) {
353 // Submit the resource requirement
355 Status = PciResAlloc->SubmitResources (
356 PciResAlloc,
357 RootBridgeDev->Handle,
358 AcpiConfig
363 // Free acpi resource node
365 if (AcpiConfig != NULL) {
366 FreePool (AcpiConfig);
369 if (EFI_ERROR (Status)) {
371 // Destroy all the resource tree
373 DestroyResourceTree (&IoPool);
374 DestroyResourceTree (&Mem32Pool);
375 DestroyResourceTree (&PMem32Pool);
376 DestroyResourceTree (&Mem64Pool);
377 DestroyResourceTree (&PMem64Pool);
378 return Status;
382 // End while, at least one Root Bridge should be found.
384 ASSERT (RootBridgeDev != NULL);
387 // Notify platform to start to program the resource
389 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
390 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
392 // If Hot Plug is not supported
394 if (EFI_ERROR (Status)) {
396 // Allocation failed, then return
398 return EFI_OUT_OF_RESOURCES;
401 // Allocation succeed.
402 // Get host bridge handle for status report, and then skip the main while
404 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
406 break;
408 } else {
410 // If Hot Plug is supported
412 if (!EFI_ERROR (Status)) {
414 // Allocation succeed, then continue the following
416 break;
420 // If the resource allocation is unsuccessful, free resources on bridge
423 RootBridgeDev = NULL;
424 RootBridgeHandle = 0;
426 IoResStatus = EFI_RESOURCE_SATISFIED;
427 Mem32ResStatus = EFI_RESOURCE_SATISFIED;
428 PMem32ResStatus = EFI_RESOURCE_SATISFIED;
429 Mem64ResStatus = EFI_RESOURCE_SATISFIED;
430 PMem64ResStatus = EFI_RESOURCE_SATISFIED;
432 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
434 // Get RootBridg Device by handle
436 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
437 if (RootBridgeDev == NULL) {
438 return EFI_NOT_FOUND;
442 // Get host bridge handle for status report
444 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
447 // Get acpi resource node for all the resource types
449 AcpiConfig = NULL;
451 Status = PciResAlloc->GetProposedResources (
452 PciResAlloc,
453 RootBridgeDev->Handle,
454 &AcpiConfig
457 if (EFI_ERROR (Status)) {
458 return Status;
461 if (AcpiConfig != NULL) {
463 // Adjust resource allocation policy for each RB
465 GetResourceAllocationStatus (
466 AcpiConfig,
467 &IoResStatus,
468 &Mem32ResStatus,
469 &PMem32ResStatus,
470 &Mem64ResStatus,
471 &PMem64ResStatus
473 FreePool (AcpiConfig);
477 // End while
481 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
484 // It is very difficult to follow the spec here
485 // Device path , Bar index can not be get here
487 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
489 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
490 EFI_PROGRESS_CODE,
491 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
492 (VOID *) &AllocFailExtendedData,
493 sizeof (AllocFailExtendedData)
496 Status = PciHostBridgeAdjustAllocation (
497 &IoPool,
498 &Mem32Pool,
499 &PMem32Pool,
500 &Mem64Pool,
501 &PMem64Pool,
502 IoResStatus,
503 Mem32ResStatus,
504 PMem32ResStatus,
505 Mem64ResStatus,
506 PMem64ResStatus
510 // Destroy all the resource tree
512 DestroyResourceTree (&IoPool);
513 DestroyResourceTree (&Mem32Pool);
514 DestroyResourceTree (&PMem32Pool);
515 DestroyResourceTree (&Mem64Pool);
516 DestroyResourceTree (&PMem64Pool);
518 NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
520 if (EFI_ERROR (Status)) {
521 return Status;
524 ReAllocate = TRUE;
528 // End main while
532 // Raise the EFI_IOB_PCI_RES_ALLOC status code
534 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
535 EFI_PROGRESS_CODE,
536 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,
537 (VOID *) &HandleExtendedData,
538 sizeof (HandleExtendedData)
542 // Notify pci bus driver starts to program the resource
544 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
546 RootBridgeDev = NULL;
548 RootBridgeHandle = 0;
550 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
552 // Get RootBridg Device by handle
554 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
556 if (RootBridgeDev == NULL) {
557 return EFI_NOT_FOUND;
561 // Get acpi resource node for all the resource types
563 AcpiConfig = NULL;
564 Status = PciResAlloc->GetProposedResources (
565 PciResAlloc,
566 RootBridgeDev->Handle,
567 &AcpiConfig
570 if (EFI_ERROR (Status)) {
571 return Status;
575 // Get the resource base by interpreting acpi resource node
578 GetResourceBase (
579 AcpiConfig,
580 &IoBase,
581 &Mem32Base,
582 &PMem32Base,
583 &Mem64Base,
584 &PMem64Base
588 // Process option rom for this root bridge
590 ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);
593 // Create the entire system resource map from the information collected by
594 // enumerator. Several resource tree was created
596 GetResourceMap (
597 RootBridgeDev,
598 &IoBridge,
599 &Mem32Bridge,
600 &PMem32Bridge,
601 &Mem64Bridge,
602 &PMem64Bridge,
603 &IoPool,
604 &Mem32Pool,
605 &PMem32Pool,
606 &Mem64Pool,
607 &PMem64Pool
611 // Program IO resources
613 ProgramResource (
614 IoBase,
615 IoBridge
619 // Program Mem32 resources
621 ProgramResource (
622 Mem32Base,
623 Mem32Bridge
627 // Program PMem32 resources
629 ProgramResource (
630 PMem32Base,
631 PMem32Bridge
635 // Program Mem64 resources
637 ProgramResource (
638 Mem64Base,
639 Mem64Bridge
643 // Program PMem64 resources
645 ProgramResource (
646 PMem64Base,
647 PMem64Bridge
650 FreePool (AcpiConfig);
654 // Destroy all the resource tree
656 DestroyResourceTree (&IoPool);
657 DestroyResourceTree (&Mem32Pool);
658 DestroyResourceTree (&PMem32Pool);
659 DestroyResourceTree (&Mem64Pool);
660 DestroyResourceTree (&PMem64Pool);
663 // Notify the resource allocation phase is to end
665 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
667 return EFI_SUCCESS;
671 Scan pci bus and assign bus number to the given PCI bus system.
673 @param Bridge Bridge device instance.
674 @param StartBusNumber start point.
675 @param SubBusNumber Point to sub bus number.
676 @param PaddedBusRange Customized bus number.
678 @retval EFI_SUCCESS Successfully scanned and assigned bus number.
679 @retval other Some error occurred when scanning pci bus.
681 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
684 EFI_STATUS
685 PciScanBus (
686 IN PCI_IO_DEVICE *Bridge,
687 IN UINT8 StartBusNumber,
688 OUT UINT8 *SubBusNumber,
689 OUT UINT8 *PaddedBusRange
692 EFI_STATUS Status;
693 PCI_TYPE00 Pci;
694 UINT8 Device;
695 UINT8 Func;
696 UINT64 Address;
697 UINTN SecondBus;
698 UINT16 Register;
699 UINTN HpIndex;
700 PCI_IO_DEVICE *PciDevice;
701 EFI_EVENT Event;
702 EFI_HPC_STATE State;
703 UINT64 PciAddress;
704 EFI_HPC_PADDING_ATTRIBUTES Attributes;
705 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
706 UINT16 BusRange;
707 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
708 BOOLEAN BusPadding;
710 PciRootBridgeIo = Bridge->PciRootBridgeIo;
711 SecondBus = 0;
712 Register = 0;
713 State = 0;
714 Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
715 BusRange = 0;
716 BusPadding = FALSE;
717 PciDevice = NULL;
718 PciAddress = 0;
720 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
721 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
724 // Check to see whether a pci device is present
726 Status = PciDevicePresent (
727 PciRootBridgeIo,
728 &Pci,
729 StartBusNumber,
730 Device,
731 Func
734 if (EFI_ERROR (Status)) {
735 if (Func == 0) {
737 // Skip sub functions, this is not a multi function device
739 Func = PCI_MAX_FUNC;
742 continue;
745 DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));
747 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
749 // Get the PCI device information
751 Status = PciSearchDevice (
752 Bridge,
753 &Pci,
754 StartBusNumber,
755 Device,
756 Func,
757 &PciDevice
760 ASSERT (!EFI_ERROR (Status));
762 PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
764 if (!IS_PCI_BRIDGE (&Pci)) {
766 // PCI bridges will be called later
767 // Here just need for PCI device or PCI to cardbus controller
768 // EfiPciBeforeChildBusEnumeration for PCI Device Node
770 PreprocessController (
771 PciDevice,
772 PciDevice->BusNumber,
773 PciDevice->DeviceNumber,
774 PciDevice->FunctionNumber,
775 EfiPciBeforeChildBusEnumeration
780 // For Pci Hotplug controller devcie only
782 if (gPciHotPlugInit != NULL) {
784 // Check if it is a Hotplug PCI controller
786 if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
788 if (!gPciRootHpcData[HpIndex].Initialized) {
790 Status = CreateEventForHpc (HpIndex, &Event);
792 ASSERT (!EFI_ERROR (Status));
794 Status = gPciHotPlugInit->InitializeRootHpc (
795 gPciHotPlugInit,
796 gPciRootHpcPool[HpIndex].HpcDevicePath,
797 PciAddress,
798 Event,
799 &State
802 PreprocessController (
803 PciDevice,
804 PciDevice->BusNumber,
805 PciDevice->DeviceNumber,
806 PciDevice->FunctionNumber,
807 EfiPciBeforeChildBusEnumeration
814 if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
816 // For PPB
818 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
820 // If Hot Plug is not supported,
821 // get the bridge information
823 Status = PciSearchDevice (
824 Bridge,
825 &Pci,
826 StartBusNumber,
827 Device,
828 Func,
829 &PciDevice
832 if (EFI_ERROR (Status)) {
833 return Status;
835 } else {
837 // If Hot Plug is supported,
838 // Get the bridge information
840 BusPadding = FALSE;
841 if (gPciHotPlugInit != NULL) {
843 if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {
846 // If it is initialized, get the padded bus range
848 Status = gPciHotPlugInit->GetResourcePadding (
849 gPciHotPlugInit,
850 gPciRootHpcPool[HpIndex].HpbDevicePath,
851 PciAddress,
852 &State,
853 (VOID **) &Descriptors,
854 &Attributes
857 if (EFI_ERROR (Status)) {
858 return Status;
861 BusRange = 0;
862 Status = PciGetBusRange (
863 &Descriptors,
864 NULL,
865 NULL,
866 &BusRange
869 FreePool (Descriptors);
871 if (EFI_ERROR (Status)) {
872 return Status;
875 BusPadding = TRUE;
881 // Add feature to support customized secondary bus number
883 if (*SubBusNumber == 0) {
884 *SubBusNumber = *PaddedBusRange;
885 *PaddedBusRange = 0;
888 (*SubBusNumber)++;
889 SecondBus = *SubBusNumber;
891 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
892 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
894 Status = PciRootBridgeIoWrite (
895 PciRootBridgeIo,
896 &Pci,
897 EfiPciWidthUint16,
898 Address,
900 &Register
905 // If it is PPB, resursively search down this bridge
907 if (IS_PCI_BRIDGE (&Pci)) {
910 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
911 // PCI configuration transaction to go through any PPB
913 Register = 0xFF;
914 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
915 Status = PciRootBridgeIoWrite (
916 PciRootBridgeIo,
917 &Pci,
918 EfiPciWidthUint8,
919 Address,
921 &Register
925 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
927 PreprocessController (
928 PciDevice,
929 PciDevice->BusNumber,
930 PciDevice->DeviceNumber,
931 PciDevice->FunctionNumber,
932 EfiPciBeforeChildBusEnumeration
935 DEBUG((EFI_D_ERROR, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber));
936 Status = PciScanBus (
937 PciDevice,
938 (UINT8) (SecondBus),
939 SubBusNumber,
940 PaddedBusRange
942 if (EFI_ERROR (Status)) {
943 return Status;
947 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
949 // Ensure the device is enabled and initialized
951 if ((Attributes == EfiPaddingPciRootBridge) &&
952 (State & EFI_HPC_STATE_ENABLED) != 0 &&
953 (State & EFI_HPC_STATE_INITIALIZED) != 0) {
954 *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);
955 } else {
956 *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);
961 // Set the current maximum bus number under the PPB
963 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
965 Status = PciRootBridgeIoWrite (
966 PciRootBridgeIo,
967 &Pci,
968 EfiPciWidthUint8,
969 Address,
971 SubBusNumber
975 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
978 // Skip sub functions, this is not a multi function device
981 Func = PCI_MAX_FUNC;
986 return EFI_SUCCESS;
990 Process Option Rom on the specified root bridge.
992 @param Bridge Pci root bridge device instance.
994 @retval EFI_SUCCESS Success process.
995 @retval other Some error occurred when processing Option Rom on the root bridge.
998 EFI_STATUS
999 PciRootBridgeP2CProcess (
1000 IN PCI_IO_DEVICE *Bridge
1003 LIST_ENTRY *CurrentLink;
1004 PCI_IO_DEVICE *Temp;
1005 EFI_HPC_STATE State;
1006 UINT64 PciAddress;
1007 EFI_STATUS Status;
1009 CurrentLink = Bridge->ChildList.ForwardLink;
1011 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
1013 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1015 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
1017 if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1020 // Raise the EFI_IOB_PCI_HPC_INIT status code
1022 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1023 EFI_PROGRESS_CODE,
1024 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,
1025 Temp->DevicePath
1028 PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1029 Status = gPciHotPlugInit->InitializeRootHpc (
1030 gPciHotPlugInit,
1031 Temp->DevicePath,
1032 PciAddress,
1033 NULL,
1034 &State
1037 if (!EFI_ERROR (Status)) {
1038 Status = PciBridgeEnumerator (Temp);
1040 if (EFI_ERROR (Status)) {
1041 return Status;
1045 CurrentLink = CurrentLink->ForwardLink;
1046 continue;
1051 if (!IsListEmpty (&Temp->ChildList)) {
1052 Status = PciRootBridgeP2CProcess (Temp);
1055 CurrentLink = CurrentLink->ForwardLink;
1058 return EFI_SUCCESS;
1062 Process Option Rom on the specified host bridge.
1064 @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
1066 @retval EFI_SUCCESS Success process.
1067 @retval EFI_NOT_FOUND Can not find the root bridge instance.
1068 @retval other Some error occurred when processing Option Rom on the host bridge.
1071 EFI_STATUS
1072 PciHostBridgeP2CProcess (
1073 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1076 EFI_HANDLE RootBridgeHandle;
1077 PCI_IO_DEVICE *RootBridgeDev;
1078 EFI_STATUS Status;
1080 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1081 return EFI_SUCCESS;
1084 RootBridgeHandle = NULL;
1086 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1089 // Get RootBridg Device by handle
1091 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
1093 if (RootBridgeDev == NULL) {
1094 return EFI_NOT_FOUND;
1097 Status = PciRootBridgeP2CProcess (RootBridgeDev);
1098 if (EFI_ERROR (Status)) {
1099 return Status;
1104 return EFI_SUCCESS;
1108 This function is used to enumerate the entire host bridge
1109 in a given platform.
1111 @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
1113 @retval EFI_SUCCESS Successfully enumerated the host bridge.
1114 @retval EFI_OUT_OF_RESOURCES No enough memory available.
1115 @retval other Some error occurred when enumerating the host bridge.
1118 EFI_STATUS
1119 PciHostBridgeEnumerator (
1120 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1123 EFI_HANDLE RootBridgeHandle;
1124 PCI_IO_DEVICE *RootBridgeDev;
1125 EFI_STATUS Status;
1126 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1127 UINT16 MinBus;
1128 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1129 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
1130 UINT8 StartBusNumber;
1131 LIST_ENTRY RootBridgeList;
1132 LIST_ENTRY *Link;
1134 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1135 InitializeHotPlugSupport ();
1138 InitializeListHead (&RootBridgeList);
1141 // Notify the bus allocation phase is about to start
1143 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1145 DEBUG((EFI_D_ERROR, "PCI Bus First Scanning\n"));
1146 RootBridgeHandle = NULL;
1147 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1150 // if a root bridge instance is found, create root bridge device for it
1153 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1155 if (RootBridgeDev == NULL) {
1156 return EFI_OUT_OF_RESOURCES;
1160 // Enumerate all the buses under this root bridge
1162 Status = PciRootBridgeEnumerator (
1163 PciResAlloc,
1164 RootBridgeDev
1167 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1168 InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
1169 } else {
1170 DestroyRootBridge (RootBridgeDev);
1172 if (EFI_ERROR (Status)) {
1173 return Status;
1178 // Notify the bus allocation phase is finished for the first time
1180 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1182 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1184 // Reset all assigned PCI bus number in all PPB
1186 RootBridgeHandle = NULL;
1187 Link = GetFirstNode (&RootBridgeList);
1188 while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&
1189 (!IsNull (&RootBridgeList, Link))) {
1190 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
1192 // Get the Bus information
1194 Status = PciResAlloc->StartBusEnumeration (
1195 PciResAlloc,
1196 RootBridgeHandle,
1197 (VOID **) &Configuration
1199 if (EFI_ERROR (Status)) {
1200 return Status;
1204 // Get the bus number to start with
1206 StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
1208 ResetAllPpbBusNumber (
1209 RootBridgeDev,
1210 StartBusNumber
1213 FreePool (Configuration);
1214 Link = GetNextNode (&RootBridgeList, Link);
1215 DestroyRootBridge (RootBridgeDev);
1219 // Wait for all HPC initialized
1221 Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
1223 if (EFI_ERROR (Status)) {
1224 return Status;
1228 // Notify the bus allocation phase is about to start for the 2nd time
1230 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1232 DEBUG((EFI_D_ERROR, "PCI Bus Second Scanning\n"));
1233 RootBridgeHandle = NULL;
1234 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1237 // if a root bridge instance is found, create root bridge device for it
1239 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1241 if (RootBridgeDev == NULL) {
1242 return EFI_OUT_OF_RESOURCES;
1246 // Enumerate all the buses under this root bridge
1248 Status = PciRootBridgeEnumerator (
1249 PciResAlloc,
1250 RootBridgeDev
1253 DestroyRootBridge (RootBridgeDev);
1254 if (EFI_ERROR (Status)) {
1255 return Status;
1260 // Notify the bus allocation phase is to end for the 2nd time
1262 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1266 // Notify the resource allocation phase is to start
1268 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
1270 RootBridgeHandle = NULL;
1271 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1274 // if a root bridge instance is found, create root bridge device for it
1276 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1278 if (RootBridgeDev == NULL) {
1279 return EFI_OUT_OF_RESOURCES;
1282 Status = StartManagingRootBridge (RootBridgeDev);
1284 if (EFI_ERROR (Status)) {
1285 return Status;
1288 PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
1289 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1291 if (EFI_ERROR (Status)) {
1292 return Status;
1295 Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
1297 if (EFI_ERROR (Status)) {
1298 return Status;
1302 // Determine root bridge attribute by calling interface of Pcihostbridge
1303 // protocol
1305 DetermineRootBridgeAttributes (
1306 PciResAlloc,
1307 RootBridgeDev
1311 // Collect all the resource information under this root bridge
1312 // A database that records all the information about pci device subject to this
1313 // root bridge will then be created
1315 Status = PciPciDeviceInfoCollector (
1316 RootBridgeDev,
1317 (UINT8) MinBus
1320 if (EFI_ERROR (Status)) {
1321 return Status;
1324 InsertRootBridge (RootBridgeDev);
1327 // Record the hostbridge handle
1329 AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
1332 return EFI_SUCCESS;
1336 Read PCI device configuration register by specified address.
1338 This function check the incompatiblilites on PCI device. Return the register
1339 value.
1341 @param PciRootBridgeIo PCI root bridge io protocol instance.
1342 @param PciIo PCI IO protocol instance.
1343 @param PciDeviceInfo PCI device information.
1344 @param Width Signifies the width of the memory operations.
1345 @param Offset The offset within the PCI configuration space for the PCI controller.
1346 @param Buffer For read operations, the destination buffer to store the results. For
1347 write operations, the source buffer to write data from.
1349 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1350 @retval EFI_UNSUPPORTED Width is invalid for this PCI root bridge.
1351 @retval other Some error occurred when reading PCI device configuration space
1352 or checking incompatibility.
1355 EFI_STATUS
1356 ReadConfigData (
1357 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1358 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1359 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
1360 IN UINT64 Width,
1361 IN UINT64 Offset,
1362 IN OUT VOID *Buffer
1365 EFI_STATUS Status;
1366 UINT64 AccessWidth;
1367 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;
1368 UINT64 AccessAddress;
1369 UINTN Stride;
1370 UINT64 TempBuffer;
1371 UINT8 *Pointer;
1373 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1374 ASSERT (Buffer != NULL);
1376 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) != 0) {
1378 // Check access compatibility at first time
1380 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Offset & 0xff, Width, &PciRegisterAccessData);
1382 if (Status == EFI_SUCCESS) {
1384 // There exists incompatibility on this operation
1386 AccessWidth = Width;
1388 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1389 AccessWidth = PciRegisterAccessData->Width;
1392 AccessAddress = Offset & ~((1 << AccessWidth) - 1);
1394 TempBuffer = 0;
1395 Stride = 0;
1396 Pointer = (UINT8 *) &TempBuffer;
1398 while (TRUE) {
1400 if (PciRootBridgeIo != NULL) {
1401 Status = PciRootBridgeIo->Pci.Read (
1402 PciRootBridgeIo,
1403 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,
1404 AccessAddress,
1406 Pointer
1408 } else if (PciIo != NULL) {
1409 Status = PciIo->Pci.Read (
1410 PciIo,
1411 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,
1412 (UINT32) AccessAddress,
1414 Pointer
1418 if (Status != EFI_SUCCESS) {
1419 return Status;
1422 Stride = (UINTN)1 << AccessWidth;
1423 AccessAddress += Stride;
1424 if (AccessAddress >= (Offset + LShiftU64 (1ULL, (UINTN)Width))) {
1426 // If all datas have been read, exit
1428 break;
1431 Pointer += Stride;
1433 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {
1435 // If current offset doesn't reach the end
1437 continue;
1441 // Continue checking access incompatibility
1443 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);
1444 if (Status == EFI_SUCCESS) {
1445 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1446 AccessWidth = PciRegisterAccessData->Width;
1451 switch (Width) {
1452 case EfiPciWidthUint8:
1453 * (UINT8 *) Buffer = (UINT8) TempBuffer;
1454 break;
1455 case EfiPciWidthUint16:
1456 * (UINT16 *) Buffer = (UINT16) TempBuffer;
1457 break;
1458 case EfiPciWidthUint32:
1459 * (UINT32 *) Buffer = (UINT32) TempBuffer;
1460 break;
1461 default:
1462 return EFI_UNSUPPORTED;
1465 return Status;
1469 // AccessWidth incompatible check not supportted
1470 // or, there doesn't exist incompatibility on this operation
1472 if (PciRootBridgeIo != NULL) {
1473 Status = PciRootBridgeIo->Pci.Read (
1474 PciRootBridgeIo,
1475 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
1476 Offset,
1478 Buffer
1481 } else {
1482 Status = PciIo->Pci.Read (
1483 PciIo,
1484 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
1485 (UINT32) Offset,
1487 Buffer
1491 return Status;
1495 Update register value by checking PCI device incompatibility.
1497 This function check register value incompatibilites on PCI device. Return the register
1498 value.
1500 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
1501 @param AccessType Access type, READ or WRITE.
1502 @param Width Signifies the width of the memory operations.
1503 @param Offset The offset within the PCI configuration space.
1504 @param Buffer Store the register data.
1506 @retval EFI_SUCCESS The data has been updated.
1507 @retval EFI_UNSUPPORTED Width is invalid for this PCI root bridge.
1508 @retval other Some error occurred when checking incompatibility.
1511 EFI_STATUS
1512 UpdateConfigData (
1513 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
1514 IN UINT64 AccessType,
1515 IN UINT64 Width,
1516 IN UINT64 Offset,
1517 IN OUT VOID *Buffer
1520 EFI_STATUS Status;
1521 EFI_PCI_REGISTER_VALUE_DATA *PciRegisterData;
1522 UINT32 AndValue;
1523 UINT32 OrValue;
1524 UINT32 TempValue;
1526 ASSERT (Buffer != NULL);
1529 // Check register value incompatibility
1531 Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Offset & 0xff, &PciRegisterData);
1532 if (Status == EFI_SUCCESS) {
1534 AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Offset & 0x3) * 8);
1535 OrValue = ((UINT32) PciRegisterData->OrValue) >> (((UINT8) Offset & 0x3) * 8);
1537 TempValue = * (UINT32 *) Buffer;
1538 if (PciRegisterData->AndValue != VALUE_NOCARE) {
1539 TempValue &= AndValue;
1541 if (PciRegisterData->OrValue != VALUE_NOCARE) {
1542 TempValue |= OrValue;
1545 switch (Width) {
1546 case EfiPciWidthUint8:
1547 *(UINT8 *)Buffer = (UINT8) TempValue;
1548 break;
1550 case EfiPciWidthUint16:
1551 *(UINT16 *)Buffer = (UINT16) TempValue;
1552 break;
1553 case EfiPciWidthUint32:
1554 *(UINT32 *)Buffer = TempValue;
1555 break;
1557 default:
1558 return EFI_UNSUPPORTED;
1562 return Status;
1566 Write PCI device configuration register by specified address.
1568 This function check the incompatiblilites on PCI device, and write date
1569 into register.
1571 @param PciRootBridgeIo PCI root bridge io instance.
1572 @param PciIo PCI IO protocol instance.
1573 @param PciDeviceInfo PCI device information.
1574 @param Width Signifies the width of the memory operations.
1575 @param Offset The offset within the PCI configuration space for the PCI controller.
1576 @param Buffer For read operations, the destination buffer to store the results. For
1577 write operations, the source buffer to write data from.
1579 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1580 @retval other Some error occurred when writing PCI device information
1581 or checking incompatibility.
1584 EFI_STATUS
1585 WriteConfigData (
1586 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1587 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1588 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
1589 IN UINT64 Width,
1590 IN UINT64 Offset,
1591 IN VOID *Buffer
1594 EFI_STATUS Status;
1595 UINT64 AccessWidth;
1596 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;
1597 UINT64 AccessAddress;
1598 UINTN Stride;
1599 UINT8 *Pointer;
1600 UINT64 Data;
1601 UINTN Shift;
1603 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1604 ASSERT (Buffer != NULL);
1606 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) != 0) {
1608 // Check access compatibility at first time
1610 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Offset & 0xff, Width, &PciRegisterAccessData);
1612 if (Status == EFI_SUCCESS) {
1614 // There exists incompatibility on this operation
1616 AccessWidth = Width;
1618 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1619 AccessWidth = PciRegisterAccessData->Width;
1622 AccessAddress = Offset & ~((1 << AccessWidth) - 1);
1624 Stride = 0;
1625 Pointer = (UINT8 *) &Buffer;
1626 Data = * (UINT64 *) Buffer;
1628 while (TRUE) {
1630 if (AccessWidth > Width) {
1632 // If actual access width is larger than orignal one, additional data need to be read back firstly
1634 Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);
1635 if (Status != EFI_SUCCESS) {
1636 return Status;
1640 // Check data read incompatibility
1642 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);
1644 Shift = (UINTN)(Offset - AccessAddress) * 8;
1645 switch (Width) {
1646 case EfiPciWidthUint8:
1647 Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));
1648 break;
1650 case EfiPciWidthUint16:
1651 Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));
1652 break;
1656 // Check data write incompatibility
1658 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, MultU64x32 (AccessAddress, 0xff), &Data);
1661 if (PciRootBridgeIo != NULL) {
1662 Status = PciRootBridgeIo->Pci.Write (
1663 PciRootBridgeIo,
1664 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,
1665 AccessAddress,
1667 &Data
1669 } else {
1670 Status = PciIo->Pci.Write (
1671 PciIo,
1672 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,
1673 (UINT32) AccessAddress,
1675 &Data
1679 if (Status != EFI_SUCCESS) {
1680 return Status;
1683 Data = RShiftU64 (Data, ((1 << AccessWidth) * 8));
1685 Stride = (UINTN)1 << AccessWidth;
1686 AccessAddress += Stride;
1687 if (AccessAddress >= (Offset + LShiftU64 (1ULL, (UINTN)Width))) {
1689 // If all datas have been written, exit
1691 break;
1694 Pointer += Stride;
1696 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {
1698 // If current offset doesn't reach the end
1700 continue;
1704 // Continue checking access incompatibility
1706 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);
1707 if (Status == EFI_SUCCESS) {
1708 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1709 AccessWidth = PciRegisterAccessData->Width;
1714 return Status;
1719 // AccessWidth incompatible check not supportted
1720 // or, there doesn't exist incompatibility on this operation
1722 if (PciRootBridgeIo != NULL) {
1723 Status = PciRootBridgeIo->Pci.Write (
1724 PciRootBridgeIo,
1725 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
1726 Offset,
1728 Buffer
1730 } else {
1731 Status = PciIo->Pci.Write (
1732 PciIo,
1733 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
1734 (UINT32) Offset,
1736 Buffer
1740 return Status;
1744 Abstract PCI device device information.
1746 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1747 @param PciIo A pointer to EFI_PCI_PROTOCOL.
1748 @param Pci PCI device configuration space.
1749 @param Offset The offset within the PCI configuration space for the PCI controller.
1750 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
1752 @retval EFI_SUCCESS Pci device device information has been abstracted.
1753 @retval EFI_NOT_FOUND Cannot found the specified PCI device.
1754 @retval other Some error occurred when reading PCI device information.
1757 EFI_STATUS
1758 GetPciDeviceDeviceInfo (
1759 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1760 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1761 IN PCI_TYPE00 *Pci, OPTIONAL
1762 IN UINT64 Offset, OPTIONAL
1763 OUT EFI_PCI_DEVICE_INFO *PciDeviceInfo
1766 EFI_STATUS Status;
1767 UINT64 PciAddress;
1768 UINT32 PciConfigData;
1769 PCI_IO_DEVICE *PciIoDevice;
1771 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1772 ASSERT (PciDeviceInfo != NULL);
1774 if (PciIo != NULL) {
1775 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
1778 // Get pointer to PCI_TYPE00 from PciIoDevice
1780 Pci = &PciIoDevice->Pci;
1783 if (Pci == NULL) {
1785 // While PCI_TYPE00 hasn't been gotten, read PCI device device information directly
1787 PciAddress = Offset & 0xffffffffffffff00ULL;
1788 Status = PciRootBridgeIo->Pci.Read (
1789 PciRootBridgeIo,
1790 EfiPciWidthUint32,
1791 PciAddress,
1793 &PciConfigData
1796 if (EFI_ERROR (Status)) {
1797 return Status;
1800 if ((PciConfigData & 0xffff) == 0xffff) {
1801 return EFI_NOT_FOUND;
1804 PciDeviceInfo->VendorID = PciConfigData & 0xffff;
1805 PciDeviceInfo->DeviceID = PciConfigData >> 16;
1807 Status = PciRootBridgeIo->Pci.Read (
1808 PciRootBridgeIo,
1809 EfiPciWidthUint32,
1810 PciAddress + 8,
1812 &PciConfigData
1814 if (EFI_ERROR (Status)) {
1815 return Status;
1818 PciDeviceInfo->RevisionID = PciConfigData & 0xf;
1820 Status = PciRootBridgeIo->Pci.Read (
1821 PciRootBridgeIo,
1822 EfiPciWidthUint32,
1823 PciAddress + 0x2c,
1825 &PciConfigData
1828 if (EFI_ERROR (Status)) {
1829 return Status;
1832 PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;
1833 PciDeviceInfo->SubsystemID = PciConfigData >> 16;
1835 } else {
1836 PciDeviceInfo->VendorID = Pci->Hdr.VendorId;
1837 PciDeviceInfo->DeviceID = Pci->Hdr.DeviceId;
1838 PciDeviceInfo->RevisionID = Pci->Hdr.RevisionID;
1839 PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;
1840 PciDeviceInfo->SubsystemID = Pci->Device.SubsystemID;
1843 return EFI_SUCCESS;
1847 Read PCI configuration space with incompatibility check.
1849 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1850 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
1851 @param Pci A pointer to PCI_TYPE00.
1852 @param Width Signifies the width of the memory operations.
1853 @param Offset The offset within the PCI configuration space for the PCI controller.
1854 @param Count The number of unit to be read.
1855 @param Buffer For read operations, the destination buffer to store the results. For
1856 write operations, the source buffer to write data from.
1858 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1859 @retval EFI_UNSUPPORTED Buffer is NULL.
1860 @retval other Some error occurred when reading PCI configuration space.
1863 EFI_STATUS
1864 PciIncompatibilityCheckRead (
1865 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1866 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1867 IN PCI_TYPE00 *Pci, OPTIONAL
1868 IN UINTN Width,
1869 IN UINT64 Offset,
1870 IN UINTN Count,
1871 IN OUT VOID *Buffer
1874 EFI_STATUS Status;
1875 EFI_PCI_DEVICE_INFO PciDeviceInfo;
1876 UINT32 Stride;
1878 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1879 if (Buffer == NULL) {
1880 return EFI_UNSUPPORTED;
1884 // get PCI device device information
1886 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Offset, &PciDeviceInfo);
1887 if (Status != EFI_SUCCESS) {
1888 return Status;
1891 Stride = 1 << Width;
1893 for (; Count > 0; Count--, Offset += Stride, Buffer = (UINT8 *)Buffer + Stride) {
1896 // read configuration register
1898 Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Offset, Buffer);
1900 if (Status != EFI_SUCCESS) {
1901 return Status;
1905 // update the data read from configuration register
1907 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) != 0) {
1908 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Offset & 0xff, Buffer);
1912 return EFI_SUCCESS;
1916 Write PCI configuration space with incompatibility check.
1918 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1919 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
1920 @param Pci A pointer to PCI_TYPE00.
1921 @param Width Signifies the width of the memory operations.
1922 @param Offset The offset within the PCI configuration space for the PCI controller.
1923 @param Count The number of unit to be write.
1924 @param Buffer For read operations, the destination buffer to store the results. For
1925 write operations, the source buffer to write data from.
1927 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1928 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
1929 valid for the PCI configuration header of the PCI controller.
1930 Buffer is NULL.
1931 @retval other Some error occurred when writing PCI configuration space.
1934 EFI_STATUS
1935 PciIncompatibilityCheckWrite (
1936 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1937 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1938 IN PCI_TYPE00 *Pci, OPTIONAL
1939 IN UINTN Width,
1940 IN UINT64 Offset,
1941 IN UINTN Count,
1942 IN OUT VOID *Buffer
1945 EFI_STATUS Status;
1946 EFI_PCI_DEVICE_INFO PciDeviceInfo;
1947 UINT32 Stride;
1948 UINT64 Data;
1950 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1951 if (Buffer == NULL) {
1952 return EFI_UNSUPPORTED;
1956 // Get PCI device device information
1958 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Offset, &PciDeviceInfo);
1959 if (Status != EFI_SUCCESS) {
1960 return Status;
1963 Stride = 1 << Width;
1965 for (; Count > 0; Count--, Offset += Stride, Buffer = (UINT8 *) Buffer + Stride) {
1967 Data = 0;
1969 switch (Width) {
1970 case EfiPciWidthUint8:
1971 Data = * (UINT8 *) Buffer;
1972 break;
1973 case EfiPciWidthUint16:
1974 Data = * (UINT16 *) Buffer;
1975 break;
1977 case EfiPciWidthUint32:
1978 Data = * (UINT32 *) Buffer;
1979 break;
1981 default:
1982 return EFI_UNSUPPORTED;
1986 // Update the data writen into configuration register
1988 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) != 0) {
1989 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Offset & 0xff, &Data);
1993 // Write configuration register
1995 Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Offset, &Data);
1997 if (Status != EFI_SUCCESS) {
1998 return Status;
2002 return EFI_SUCCESS;
2006 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2008 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2009 @param Pci A pointer to PCI_TYPE00.
2010 @param Width Signifies the width of the memory operations.
2011 @param Offset The offset within the PCI configuration space for the PCI controller.
2012 @param Count The number of unit to be read.
2013 @param Buffer For read operations, the destination buffer to store the results. For
2014 write operations, the source buffer to write data from.
2016 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2017 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2018 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2021 EFI_STATUS
2022 PciRootBridgeIoRead (
2023 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
2024 IN PCI_TYPE00 *Pci, OPTIONAL
2025 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
2026 IN UINT64 Offset,
2027 IN UINTN Count,
2028 IN OUT VOID *Buffer
2031 EFI_STATUS Status;
2033 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) != 0) {
2035 // If PCI incompatibility check enabled
2037 Status = PciIncompatibilityCheckRead (
2038 PciRootBridgeIo,
2039 NULL,
2040 Pci,
2041 (UINTN) Width,
2042 Offset,
2043 Count,
2044 Buffer
2046 if (Status == EFI_UNSUPPORTED) {
2047 return EFI_INVALID_PARAMETER;
2048 } else {
2049 return Status;
2051 } else {
2052 return PciRootBridgeIo->Pci.Read (
2053 PciRootBridgeIo,
2054 Width,
2055 Offset,
2056 Count,
2057 Buffer
2063 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2065 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2066 @param Pci A pointer to PCI_TYPE00.
2067 @param Width Signifies the width of the memory operations.
2068 @param Offset The offset within the PCI configuration space for the PCI controller.
2069 @param Count The number of unit to be read.
2070 @param Buffer For read operations, the destination buffer to store the results. For
2071 write operations, the source buffer to write data from.
2073 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2074 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2075 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2078 EFI_STATUS
2079 PciRootBridgeIoWrite (
2080 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
2081 IN PCI_TYPE00 *Pci,
2082 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
2083 IN UINT64 Offset,
2084 IN UINTN Count,
2085 IN OUT VOID *Buffer
2088 EFI_STATUS Status;
2090 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) != 0) {
2092 // If PCI incompatibility check enabled
2094 Status = PciIncompatibilityCheckWrite (
2095 PciRootBridgeIo,
2096 NULL,
2097 Pci,
2098 Width,
2099 Offset,
2100 Count,
2101 Buffer
2103 if (Status == EFI_UNSUPPORTED) {
2104 return EFI_INVALID_PARAMETER;
2105 } else {
2106 return Status;
2109 } else {
2110 return PciRootBridgeIo->Pci.Write (
2111 PciRootBridgeIo,
2112 Width,
2113 Offset,
2114 Count,
2115 Buffer
2121 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.
2123 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2124 @param Width Signifies the width of the memory operations.
2125 @param Offset The offset within the PCI configuration space for the PCI controller.
2126 @param Count The number of unit to be read.
2127 @param Buffer For read operations, the destination buffer to store the results. For
2128 write operations, the source buffer to write data from.
2130 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
2131 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
2132 valid for the PCI configuration header of the PCI controller.
2133 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2134 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
2137 EFI_STATUS
2138 PciIoRead (
2139 IN EFI_PCI_IO_PROTOCOL *PciIo,
2140 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
2141 IN UINT32 Offset,
2142 IN UINTN Count,
2143 IN OUT VOID *Buffer
2146 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) != 0) {
2148 // If PCI incompatibility check enabled
2150 return PciIncompatibilityCheckRead (
2151 NULL,
2152 PciIo,
2153 NULL,
2154 (UINTN) Width,
2155 Offset,
2156 Count,
2157 Buffer
2159 } else {
2160 return PciIo->Pci.Read (
2161 PciIo,
2162 Width,
2163 Offset,
2164 Count,
2165 Buffer
2171 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.
2173 If PCI incompatibility check is enabled, do incompatibility check.
2175 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
2176 @param Width Signifies the width of the memory operations.
2177 @param Offset The offset within the PCI configuration space for the PCI controller.
2178 @param Count The number of PCI configuration operations to perform.
2179 @param Buffer For read operations, the destination buffer to store the results. For write
2180 operations, the source buffer to write data from.
2182 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
2183 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
2184 valid for the PCI configuration header of the PCI controller.
2185 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2186 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
2189 EFI_STATUS
2190 PciIoWrite (
2191 IN EFI_PCI_IO_PROTOCOL *PciIo,
2192 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
2193 IN UINT32 Offset,
2194 IN UINTN Count,
2195 IN OUT VOID *Buffer
2198 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) != 0) {
2200 // If PCI incompatibility check enabled
2202 return PciIncompatibilityCheckWrite (
2203 NULL,
2204 PciIo,
2205 NULL,
2206 Width,
2207 Offset,
2208 Count,
2209 Buffer
2212 } else {
2213 return PciIo->Pci.Write (
2214 PciIo,
2215 Width,
2216 Offset,
2217 Count,
2218 Buffer