X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=IntelFrameworkModulePkg%2FBus%2FPci%2FPciBus%2FDxe%2FPciLib.c;fp=IntelFrameworkModulePkg%2FBus%2FPci%2FPciBus%2FDxe%2FPciLib.c;h=eaeca2ad4f24d3a22ab7ca1b25b2cdce675bf3b3;hp=0000000000000000000000000000000000000000;hb=ead42efc6b7d264d5cb9b5eb81bbddc499e42a56;hpb=83f6d1a03b9037663fb1587d135020c7333235cb diff --git a/IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c b/IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c new file mode 100644 index 0000000000..eaeca2ad4f --- /dev/null +++ b/IntelFrameworkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c @@ -0,0 +1,2885 @@ +/*++ + +Copyright (c) 2006 - 2007, Intel Corporation +All rights reserved. This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + PciLib.c + +Abstract: + + PCI Bus Driver Lib file + It abstracts some functions that can be different + between light PCI bus driver and full PCI bus driver + +Revision History + +--*/ + +#include "pcibus.h" + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest = { + PciHotPlugRequestNotify +}; + + +VOID +InstallHotPlugRequestProtocol ( + IN EFI_STATUS *Status + ) +/*++ + +Routine Description: + +Arguments: + Status - A pointer to the status. + +Returns: + + None + +--*/ +{ + EFI_HANDLE Handle; + + if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return; + } + + Handle = NULL; + *Status = gBS->InstallProtocolInterface ( + &Handle, + &gEfiPciHotPlugRequestProtocolGuid, + EFI_NATIVE_INTERFACE, + &gPciHotPlugRequest + ); +} + +VOID +InstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return; + } + + if (IS_CARDBUS_BRIDGE (&PciIoDevice->Parent->Pci)) { + + Status = gBS->InstallProtocolInterface ( + &PciIoDevice->Handle, + &gEfiPciHotplugDeviceGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + } +} + +VOID +UninstallPciHotplugGuid ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + EFI_STATUS Status; + + if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return; + } + + Status = gBS->OpenProtocol ( + PciIoDevice->Handle, + &gEfiPciHotplugDeviceGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + + if (Status == EFI_SUCCESS) { + // + // This may triger CardBus driver to stop for + // Pccard devices opened the GUID via BY_DRIVER + // + Status = gBS->UninstallProtocolInterface ( + PciIoDevice->Handle, + &gEfiPciHotplugDeviceGuid, + NULL + ); + } +} + +VOID +GetBackPcCardBar ( + IN PCI_IO_DEVICE *PciIoDevice + ) +/*++ + +Routine Description: + + +Arguments: + + PciIoDevice - A pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +{ + UINT32 Address; + + if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return; + } + + // + // Read PciBar information from the bar register + // + if (!gFullEnumeration) { + + Address = 0; + PciIoRead ( + &(PciIoDevice->PciIo), + EfiPciIoWidthUint32, + 0x1c, + 1, + &Address + ); + + (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address); + (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000; + (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32; + + Address = 0; + PciIoRead ( + &(PciIoDevice->PciIo), + EfiPciIoWidthUint32, + 0x20, + 1, + &Address + ); + (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address); + (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000; + (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32; + + Address = 0; + PciIoRead ( + &(PciIoDevice->PciIo), + EfiPciIoWidthUint32, + 0x2c, + 1, + &Address + ); + (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address); + (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100; + (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16; + + Address = 0; + PciIoRead ( + &(PciIoDevice->PciIo), + EfiPciIoWidthUint32, + 0x34, + 1, + &Address + ); + (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address); + (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100; + (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16; + + } + + if (gPciHotPlugInit != NULL) { + GetResourcePaddingForHpb (PciIoDevice); + } +} + +EFI_STATUS +RemoveRejectedPciDevices ( + EFI_HANDLE RootBridgeHandle, + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + +Arguments: + + RootBridgeHandle - An efi handle. + Bridge - An pointer to the PCI_IO_DEVICE. + +Returns: + + None + +--*/ +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *Temp; + LIST_ENTRY *CurrentLink; + LIST_ENTRY *LastLink; + + if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return EFI_SUCCESS; + } + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &Bridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_PCI_BRIDGE (&Temp->Pci)) { + // + // Remove rejected devices recusively + // + RemoveRejectedPciDevices (RootBridgeHandle, Temp); + } else { + // + // Skip rejection for all PPBs, while detect rejection for others + // + if (IsPciDeviceRejected (Temp)) { + + // + // For P2C, remove all devices on it + // + + if (!IsListEmpty (&Temp->ChildList)) { + RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp); + } + + // + // Finally remove itself + // + + LastLink = CurrentLink->BackLink; + RemoveEntryList (CurrentLink); + FreePciDevice (Temp); + + CurrentLink = LastLink; + } + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciHostBridgeResourceAllocator ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +{ + if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport ( + PciResAlloc + ); + } else { + return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport ( + PciResAlloc + ); + } +} + + +EFI_STATUS +PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *RootBridgeDev; + EFI_HANDLE RootBridgeHandle; + VOID *AcpiConfig; + EFI_STATUS Status; + UINT64 IoBase; + UINT64 Mem32Base; + UINT64 PMem32Base; + UINT64 Mem64Base; + UINT64 PMem64Base; + UINT64 MaxOptionRomSize; + PCI_RESOURCE_NODE *IoBridge; + PCI_RESOURCE_NODE *Mem32Bridge; + PCI_RESOURCE_NODE *PMem32Bridge; + PCI_RESOURCE_NODE *Mem64Bridge; + PCI_RESOURCE_NODE *PMem64Bridge; + PCI_RESOURCE_NODE IoPool; + PCI_RESOURCE_NODE Mem32Pool; + PCI_RESOURCE_NODE PMem32Pool; + PCI_RESOURCE_NODE Mem64Pool; + PCI_RESOURCE_NODE PMem64Pool; + REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData; + + // + // Initialize resource pool + // + + InitializeResourcePool (&IoPool, PciBarTypeIo16); + InitializeResourcePool (&Mem32Pool, PciBarTypeMem32); + InitializeResourcePool (&PMem32Pool, PciBarTypePMem32); + InitializeResourcePool (&Mem64Pool, PciBarTypeMem64); + InitializeResourcePool (&PMem64Pool, PciBarTypePMem64); + + RootBridgeDev = NULL; + RootBridgeHandle = 0; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get host bridge handle for status report + // + ExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle; + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + + IoBridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFF, + 0, + PciBarTypeIo16, + PciResUsageTypical + ); + + Mem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem32, + PciResUsageTypical + ); + + PMem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem32, + PciResUsageTypical + ); + + Mem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem64, + PciResUsageTypical + ); + + PMem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem64, + PciResUsageTypical + ); + + // + // Create resourcemap by going through all the devices subject to this root bridge + // + Status = CreateResourceMap ( + RootBridgeDev, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + // + // Get the max ROM size that the root bridge can process + // + RootBridgeDev->RomSize = Mem32Bridge->Length; + + // + // Get Max Option Rom size for current root bridge + // + MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev); + + // + // Enlarger the mem32 resource to accomdate the option rom + // if the mem32 resource is not enough to hold the rom + // + if (MaxOptionRomSize > Mem32Bridge->Length) { + + Mem32Bridge->Length = MaxOptionRomSize; + RootBridgeDev->RomSize = MaxOptionRomSize; + + // + // Alignment should be adjusted as well + // + if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) { + Mem32Bridge->Alignment = MaxOptionRomSize - 1; + } + } + + // + // Based on the all the resource tree, contruct ACPI resource node to + // submit the resource aperture to pci host bridge protocol + // + Status = ConstructAcpiResourceRequestor ( + RootBridgeDev, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge, + &AcpiConfig + ); + + // + // Insert these resource nodes into the database + // + InsertResourceNode (&IoPool, IoBridge); + InsertResourceNode (&Mem32Pool, Mem32Bridge); + InsertResourceNode (&PMem32Pool, PMem32Bridge); + InsertResourceNode (&Mem64Pool, Mem64Bridge); + InsertResourceNode (&PMem64Pool, PMem64Bridge); + + if (Status == EFI_SUCCESS) { + // + // Submit the resource requirement + // + Status = PciResAlloc->SubmitResources ( + PciResAlloc, + RootBridgeDev->Handle, + AcpiConfig + ); + } + // + // Free acpi resource node + // + if (AcpiConfig != NULL) { + FreePool (AcpiConfig); + } + + if (EFI_ERROR (Status)) { + // + // Destroy all the resource tree + // + DestroyResourceTree (&IoPool); + DestroyResourceTree (&Mem32Pool); + DestroyResourceTree (&PMem32Pool); + DestroyResourceTree (&Mem64Pool); + DestroyResourceTree (&PMem64Pool); + return Status; + } + } + // + // End while + // + + // + // Notify pci bus driver starts to program the resource + // + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources); + + if (EFI_ERROR (Status)) { + // + // Allocation failed, then return + // + return EFI_OUT_OF_RESOURCES; + } + // + // Raise the EFI_IOB_PCI_RES_ALLOC status code + // + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC, + (VOID *) &ExtendedData, + sizeof (ExtendedData) + ); + + // + // Notify pci bus driver starts to program the resource + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources); + + RootBridgeDev = NULL; + + RootBridgeHandle = 0; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get acpi resource node for all the resource types + // + AcpiConfig = NULL; + Status = PciResAlloc->GetProposedResources ( + PciResAlloc, + RootBridgeDev->Handle, + &AcpiConfig + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the resource base by interpreting acpi resource node + // + // + GetResourceBase ( + AcpiConfig, + &IoBase, + &Mem32Base, + &PMem32Base, + &Mem64Base, + &PMem64Base + ); + + // + // Process option rom for this root bridge + // + Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize); + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + Status = GetResourceMap ( + RootBridgeDev, + &IoBridge, + &Mem32Bridge, + &PMem32Bridge, + &Mem64Bridge, + &PMem64Bridge, + &IoPool, + &Mem32Pool, + &PMem32Pool, + &Mem64Pool, + &PMem64Pool + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Program IO resources + // + ProgramResource ( + IoBase, + IoBridge + ); + + // + // Program Mem32 resources + // + ProgramResource ( + Mem32Base, + Mem32Bridge + ); + + // + // Program PMem32 resources + // + ProgramResource ( + PMem32Base, + PMem32Bridge + ); + + // + // Program Mem64 resources + // + ProgramResource ( + Mem64Base, + Mem64Bridge + ); + + // + // Program PMem64 resources + // + ProgramResource ( + PMem64Base, + PMem64Bridge + ); + + if (AcpiConfig != NULL) { + FreePool (AcpiConfig); + } + } + + // + // Destroy all the resource tree + // + DestroyResourceTree (&IoPool); + DestroyResourceTree (&Mem32Pool); + DestroyResourceTree (&PMem32Pool); + DestroyResourceTree (&Mem64Pool); + DestroyResourceTree (&PMem64Pool); + + // + // Notify the resource allocation phase is to end + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation); + + return EFI_SUCCESS; +} + + +EFI_STATUS +PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + Host brige resource allocator. + +Arguments: + + PciResAlloc - A pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL. + +Returns: + + EFI Status. + +--*/ +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + PCI_IO_DEVICE *RootBridgeDev; + EFI_HANDLE RootBridgeHandle; + VOID *AcpiConfig; + EFI_STATUS Status; + UINT64 IoBase; + UINT64 Mem32Base; + UINT64 PMem32Base; + UINT64 Mem64Base; + UINT64 PMem64Base; + UINT64 IoResStatus; + UINT64 Mem32ResStatus; + UINT64 PMem32ResStatus; + UINT64 Mem64ResStatus; + UINT64 PMem64ResStatus; + UINT64 MaxOptionRomSize; + PCI_RESOURCE_NODE *IoBridge; + PCI_RESOURCE_NODE *Mem32Bridge; + PCI_RESOURCE_NODE *PMem32Bridge; + PCI_RESOURCE_NODE *Mem64Bridge; + PCI_RESOURCE_NODE *PMem64Bridge; + PCI_RESOURCE_NODE IoPool; + PCI_RESOURCE_NODE Mem32Pool; + PCI_RESOURCE_NODE PMem32Pool; + PCI_RESOURCE_NODE Mem64Pool; + PCI_RESOURCE_NODE PMem64Pool; + BOOLEAN ReAllocate; + REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA HandleExtendedData; + REPORT_STATUS_CODE_LIBRARY_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData; + + // + // Reallocate flag + // + ReAllocate = FALSE; + + // + // It will try several times if the resource allocation fails + // + while (TRUE) { + + // + // Initialize resource pool + // + InitializeResourcePool (&IoPool, PciBarTypeIo16); + InitializeResourcePool (&Mem32Pool, PciBarTypeMem32); + InitializeResourcePool (&PMem32Pool, PciBarTypePMem32); + InitializeResourcePool (&Mem64Pool, PciBarTypeMem64); + InitializeResourcePool (&PMem64Pool, PciBarTypePMem64); + + RootBridgeDev = NULL; + RootBridgeHandle = 0; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + + IoBridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFF, + 0, + PciBarTypeIo16, + PciResUsageTypical + ); + + Mem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem32, + PciResUsageTypical + ); + + PMem32Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem32, + PciResUsageTypical + ); + + Mem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypeMem64, + PciResUsageTypical + ); + + PMem64Bridge = CreateResourceNode ( + RootBridgeDev, + 0, + 0xFFFFF, + 0, + PciBarTypePMem64, + PciResUsageTypical + ); + + // + // Create resourcemap by going through all the devices subject to this root bridge + // + Status = CreateResourceMap ( + RootBridgeDev, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge + ); + + // + // Get the max ROM size that the root bridge can process + // + RootBridgeDev->RomSize = Mem32Bridge->Length; + + // + // Skip to enlarge the resource request during realloction + // + if (!ReAllocate) { + // + // Get Max Option Rom size for current root bridge + // + MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev); + + // + // Enlarger the mem32 resource to accomdate the option rom + // if the mem32 resource is not enough to hold the rom + // + if (MaxOptionRomSize > Mem32Bridge->Length) { + + Mem32Bridge->Length = MaxOptionRomSize; + RootBridgeDev->RomSize = MaxOptionRomSize; + + // + // Alignment should be adjusted as well + // + if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) { + Mem32Bridge->Alignment = MaxOptionRomSize - 1; + } + } + } + + // + // Based on the all the resource tree, contruct ACPI resource node to + // submit the resource aperture to pci host bridge protocol + // + Status = ConstructAcpiResourceRequestor ( + RootBridgeDev, + IoBridge, + Mem32Bridge, + PMem32Bridge, + Mem64Bridge, + PMem64Bridge, + &AcpiConfig + ); + + // + // Insert these resource nodes into the database + // + InsertResourceNode (&IoPool, IoBridge); + InsertResourceNode (&Mem32Pool, Mem32Bridge); + InsertResourceNode (&PMem32Pool, PMem32Bridge); + InsertResourceNode (&Mem64Pool, Mem64Bridge); + InsertResourceNode (&PMem64Pool, PMem64Bridge); + + if (Status == EFI_SUCCESS) { + // + // Submit the resource requirement + // + Status = PciResAlloc->SubmitResources ( + PciResAlloc, + RootBridgeDev->Handle, + AcpiConfig + ); + } + + // + // Free acpi resource node + // + if (AcpiConfig != NULL) { + FreePool (AcpiConfig); + } + + if (EFI_ERROR (Status)) { + // + // Destroy all the resource tree + // + DestroyResourceTree (&IoPool); + DestroyResourceTree (&Mem32Pool); + DestroyResourceTree (&PMem32Pool); + DestroyResourceTree (&Mem64Pool); + DestroyResourceTree (&PMem64Pool); + return Status; + } + } + + // + // Notify pci bus driver starts to program the resource + // + + Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources); + + if (!EFI_ERROR (Status)) { + // + // Allocation succeed, then continue the following + // + break; + } + + // + // If the resource allocation is unsuccessful, free resources on bridge + // + + RootBridgeDev = NULL; + RootBridgeHandle = 0; + + IoResStatus = EFI_RESOURCE_SATISFIED; + Mem32ResStatus = EFI_RESOURCE_SATISFIED; + PMem32ResStatus = EFI_RESOURCE_SATISFIED; + Mem64ResStatus = EFI_RESOURCE_SATISFIED; + PMem64ResStatus = EFI_RESOURCE_SATISFIED; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get host bridge handle for status report + // + HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle; + + // + // Get acpi resource node for all the resource types + // + AcpiConfig = NULL; + + Status = PciResAlloc->GetProposedResources ( + PciResAlloc, + RootBridgeDev->Handle, + &AcpiConfig + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if (AcpiConfig != NULL) { + // + // Adjust resource allocation policy for each RB + // + GetResourceAllocationStatus ( + AcpiConfig, + &IoResStatus, + &Mem32ResStatus, + &PMem32ResStatus, + &Mem64ResStatus, + &PMem64ResStatus + ); + FreePool (AcpiConfig); + } + } + // + // End while + // + + // + // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code + // + // + // It is very difficult to follow the spec here + // Device path , Bar index can not be get here + // + ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData)); + + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT, + (VOID *) &AllocFailExtendedData, + sizeof (AllocFailExtendedData) + ); + + Status = PciHostBridgeAdjustAllocation ( + &IoPool, + &Mem32Pool, + &PMem32Pool, + &Mem64Pool, + &PMem64Pool, + IoResStatus, + Mem32ResStatus, + PMem32ResStatus, + Mem64ResStatus, + PMem64ResStatus + ); + + // + // Destroy all the resource tree + // + DestroyResourceTree (&IoPool); + DestroyResourceTree (&Mem32Pool); + DestroyResourceTree (&PMem32Pool); + DestroyResourceTree (&Mem64Pool); + DestroyResourceTree (&PMem64Pool); + + NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources); + + if (EFI_ERROR (Status)) { + return Status; + } + + ReAllocate = TRUE; + + } + // + // End main while + // + + // + // Raise the EFI_IOB_PCI_RES_ALLOC status code + // + REPORT_STATUS_CODE_WITH_EXTENDED_DATA ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC, + (VOID *) &HandleExtendedData, + sizeof (HandleExtendedData) + ); + + // + // Notify pci bus driver starts to program the resource + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources); + + RootBridgeDev = NULL; + + RootBridgeHandle = 0; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + // + // Get acpi resource node for all the resource types + // + AcpiConfig = NULL; + Status = PciResAlloc->GetProposedResources ( + PciResAlloc, + RootBridgeDev->Handle, + &AcpiConfig + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the resource base by interpreting acpi resource node + // + // + GetResourceBase ( + AcpiConfig, + &IoBase, + &Mem32Base, + &PMem32Base, + &Mem64Base, + &PMem64Base + ); + + // + // Process option rom for this root bridge + // + Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize); + + // + // Create the entire system resource map from the information collected by + // enumerator. Several resource tree was created + // + Status = GetResourceMap ( + RootBridgeDev, + &IoBridge, + &Mem32Bridge, + &PMem32Bridge, + &Mem64Bridge, + &PMem64Bridge, + &IoPool, + &Mem32Pool, + &PMem32Pool, + &Mem64Pool, + &PMem64Pool + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Program IO resources + // + ProgramResource ( + IoBase, + IoBridge + ); + + // + // Program Mem32 resources + // + ProgramResource ( + Mem32Base, + Mem32Bridge + ); + + // + // Program PMem32 resources + // + ProgramResource ( + PMem32Base, + PMem32Bridge + ); + + // + // Program Mem64 resources + // + ProgramResource ( + Mem64Base, + Mem64Bridge + ); + + // + // Program PMem64 resources + // + ProgramResource ( + PMem64Base, + PMem64Bridge + ); + + if (AcpiConfig != NULL) { + gBS->FreePool (AcpiConfig); + } + } + + // + // Destroy all the resource tree + // + DestroyResourceTree (&IoPool); + DestroyResourceTree (&Mem32Pool); + DestroyResourceTree (&PMem32Pool); + DestroyResourceTree (&Mem64Pool); + DestroyResourceTree (&PMem64Pool); + + // + // Notify the resource allocation phase is to end + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation); + + return EFI_SUCCESS; +} + + +EFI_STATUS +PciScanBus ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber, + OUT UINT8 *PaddedBusRange + ) +{ + if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return PciScanBus_WithHotPlugDeviceSupport ( + Bridge, + StartBusNumber, + SubBusNumber, + PaddedBusRange + ); + } else { + return PciScanBus_WithoutHotPlugDeviceSupport ( + Bridge, + StartBusNumber, + SubBusNumber, + PaddedBusRange + ); + } +} + + +EFI_STATUS +PciScanBus_WithoutHotPlugDeviceSupport ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber, + OUT UINT8 *PaddedBusRange + ) +/*++ + +Routine Description: + + This routine is used to assign bus number to the given PCI bus system + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: StartBusNumber - add argument and description to function comment +// TODO: SubBusNumber - add argument and description to function comment +// TODO: PaddedBusRange - add argument and description to function comment +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT8 Func; + UINT64 Address; + UINTN SecondBus; + UINT16 Register; + PCI_IO_DEVICE *PciDevice; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + SecondBus = 0; + Register = 0; + + ResetAllPpbBusReg (Bridge, StartBusNumber); + + for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { + for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { + + // + // Check to see whether a pci device is present + // + Status = PciDevicePresent ( + PciRootBridgeIo, + &Pci, + StartBusNumber, + Device, + Func + ); + + if (!EFI_ERROR (Status) && + (IS_PCI_BRIDGE (&Pci) || + IS_CARDBUS_BRIDGE (&Pci))) { + + // + // Get the bridge information + // + Status = PciSearchDevice ( + Bridge, + &Pci, + StartBusNumber, + Device, + Func, + &PciDevice + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + (*SubBusNumber)++; + + SecondBus = (*SubBusNumber); + + Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber); + + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); + + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint16, + Address, + 1, + &Register + ); + + // + // Initialize SubBusNumber to SecondBus + // + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint8, + Address, + 1, + SubBusNumber + ); + // + // If it is PPB, resursively search down this bridge + // + if (IS_PCI_BRIDGE (&Pci)) { + // + // Temporarily initialize SubBusNumber to maximum bus number to ensure the + // PCI configuration transaction to go through any PPB + // + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + Register = 0xFF; + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint8, + Address, + 1, + &Register + ); + + PreprocessController ( + PciDevice, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + EfiPciBeforeChildBusEnumeration + ); + + Status = PciScanBus ( + PciDevice, + (UINT8) (SecondBus), + SubBusNumber, + PaddedBusRange + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + // + // Set the current maximum bus number under the PPB + // + + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint8, + Address, + 1, + SubBusNumber + ); + + } + + if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { + + // + // Skip sub functions, this is not a multi function device + // + + Func = PCI_MAX_FUNC; + } + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciScanBus_WithHotPlugDeviceSupport ( + IN PCI_IO_DEVICE *Bridge, + IN UINT8 StartBusNumber, + OUT UINT8 *SubBusNumber, + OUT UINT8 *PaddedBusRange + ) +/*++ + +Routine Description: + + This routine is used to assign bus number to the given PCI bus system + +Arguments: + + Bridge - A pointer to the PCI_IO_DEVICE structure. + StartBusNumber - The start bus number. + SubBusNumber - A pointer to the sub bus number. + PaddedBusRange - A pointer to the padded bus range. + +Returns: + + None + +--*/ +// TODO: EFI_DEVICE_ERROR - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + PCI_TYPE00 Pci; + UINT8 Device; + UINT8 Func; + UINT64 Address; + UINTN SecondBus; + UINT16 Register; + UINTN HpIndex; + PCI_IO_DEVICE *PciDevice; + EFI_EVENT Event; + EFI_HPC_STATE State; + UINT64 PciAddress; + EFI_HPC_PADDING_ATTRIBUTES Attributes; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 BusRange; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + BOOLEAN BusPadding; + + PciRootBridgeIo = Bridge->PciRootBridgeIo; + SecondBus = 0; + Register = 0; + State = 0; + Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0; + BusRange = 0; + + ResetAllPpbBusReg (Bridge, StartBusNumber); + + for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { + for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { + + // + // Check to see whether a pci device is present + // + Status = PciDevicePresent ( + PciRootBridgeIo, + &Pci, + StartBusNumber, + Device, + Func + ); + + if (EFI_ERROR (Status)) { + if (Func == 0) { + // + // Skip sub functions, this is not a multi function device + // + Func = PCI_MAX_FUNC; + } + + continue; + } + + // + // Get the PCI device information + // + Status = PciSearchDevice ( + Bridge, + &Pci, + StartBusNumber, + Device, + Func, + &PciDevice + ); + + ASSERT (!EFI_ERROR (Status)); + + PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0); + + if (!IS_PCI_BRIDGE (&Pci)) { + // + // PCI bridges will be called later + // Here just need for PCI device or PCI to cardbus controller + // EfiPciBeforeChildBusEnumeration for PCI Device Node + // + PreprocessController ( + PciDevice, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + EfiPciBeforeChildBusEnumeration + ); + } + + // + // For Pci Hotplug controller devcie only + // + if (gPciHotPlugInit != NULL) { + // + // Check if it is a Hotplug PCI controller + // + if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) { + + if (!gPciRootHpcData[HpIndex].Initialized) { + + Status = CreateEventForHpc (HpIndex, &Event); + + ASSERT (!EFI_ERROR (Status)); + + Status = gPciHotPlugInit->InitializeRootHpc ( + gPciHotPlugInit, + gPciRootHpcPool[HpIndex].HpcDevicePath, + PciAddress, + Event, + &State + ); + + PreprocessController ( + PciDevice, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + EfiPciBeforeChildBusEnumeration + ); + continue; + } + } + } + + if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) { + // + // For PPB + // Get the bridge information + // + BusPadding = FALSE; + if (gPciHotPlugInit != NULL) { + + if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) { + + // + // If it is initialized, get the padded bus range + // + Status = gPciHotPlugInit->GetResourcePadding ( + gPciHotPlugInit, + gPciRootHpcPool[HpIndex].HpbDevicePath, + PciAddress, + &State, + (VOID **) &Descriptors, + &Attributes + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + BusRange = 0; + Status = PciGetBusRange ( + &Descriptors, + NULL, + NULL, + &BusRange + ); + + gBS->FreePool (Descriptors); + + if (EFI_ERROR (Status)) { + return Status; + } + + BusPadding = TRUE; + } + } + + (*SubBusNumber)++; + SecondBus = *SubBusNumber; + + Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber); + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); + + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint16, + Address, + 1, + &Register + ); + + + // + // If it is PPB, resursively search down this bridge + // + if (IS_PCI_BRIDGE (&Pci)) { + + // + // Initialize SubBusNumber to Maximum bus number + // + Register = 0xFF; + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint8, + Address, + 1, + &Register + ); + + // + // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige + // + PreprocessController ( + PciDevice, + PciDevice->BusNumber, + PciDevice->DeviceNumber, + PciDevice->FunctionNumber, + EfiPciBeforeChildBusEnumeration + ); + + Status = PciScanBus ( + PciDevice, + (UINT8) (SecondBus), + SubBusNumber, + PaddedBusRange + ); + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } + + if (BusPadding) { + // + // Ensure the device is enabled and initialized + // + if ((Attributes == EfiPaddingPciRootBridge) && + (State & EFI_HPC_STATE_ENABLED) && + (State & EFI_HPC_STATE_INITIALIZED) ) { + *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange); + } else { + *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber); + } + } + + // + // Set the current maximum bus number under the PPB + // + Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A); + + Status = PciRootBridgeIoWrite ( + PciRootBridgeIo, + &Pci, + EfiPciWidthUint8, + Address, + 1, + SubBusNumber + ); + } + + if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { + + // + // Skip sub functions, this is not a multi function device + // + Func = PCI_MAX_FUNC; + } + + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciRootBridgeP2CProcess ( + IN PCI_IO_DEVICE *Bridge + ) +/*++ + +Routine Description: + + Process Option Rom on this host bridge + +Arguments: + +Returns: + + None + +--*/ +// TODO: Bridge - add argument and description to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + LIST_ENTRY *CurrentLink; + PCI_IO_DEVICE *Temp; + EFI_HPC_STATE State; + UINT64 PciAddress; + EFI_STATUS Status; + + CurrentLink = Bridge->ChildList.ForwardLink; + + while (CurrentLink && CurrentLink != &Bridge->ChildList) { + + Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); + + if (IS_CARDBUS_BRIDGE (&Temp->Pci)) { + + if (gPciHotPlugInit && Temp->Allocated) { + + // + // Raise the EFI_IOB_PCI_HPC_INIT status code + // + REPORT_STATUS_CODE_WITH_DEVICE_PATH ( + EFI_PROGRESS_CODE, + EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT, + Temp->DevicePath + ); + + PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0); + Status = gPciHotPlugInit->InitializeRootHpc ( + gPciHotPlugInit, + Temp->DevicePath, + PciAddress, + NULL, + &State + ); + + if (!EFI_ERROR (Status)) { + Status = PciBridgeEnumerator (Temp); + + if (EFI_ERROR (Status)) { + return Status; + } + } + + CurrentLink = CurrentLink->ForwardLink; + continue; + + } + } + + if (!IsListEmpty (&Temp->ChildList)) { + Status = PciRootBridgeP2CProcess (Temp); + } + + CurrentLink = CurrentLink->ForwardLink; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciHostBridgeP2CProcess ( + IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + +Arguments: + +Returns: + + None + +--*/ +// TODO: PciResAlloc - add argument and description to function comment +// TODO: EFI_NOT_FOUND - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_HANDLE RootBridgeHandle; + PCI_IO_DEVICE *RootBridgeDev; + EFI_STATUS Status; + + if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + return EFI_SUCCESS; + } + + RootBridgeHandle = NULL; + + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // Get RootBridg Device by handle + // + RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_NOT_FOUND; + } + + Status = PciRootBridgeP2CProcess (RootBridgeDev); + + if (EFI_ERROR (Status)) { + return Status; + } + + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PciHostBridgeEnumerator ( + EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc + ) +/*++ + +Routine Description: + + This function is used to enumerate the entire host bridge + in a given platform + +Arguments: + + PciResAlloc - A pointer to the resource allocate protocol. + +Returns: + + None + +--*/ +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_HANDLE RootBridgeHandle; + PCI_IO_DEVICE *RootBridgeDev; + EFI_STATUS Status; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; + UINT16 MinBus; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + + InitializeHotPlugSupport (); + + // + // Notify the bus allocation phase is about to start + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); + + RootBridgeHandle = NULL; + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // if a root bridge instance is found, create root bridge device for it + // + + RootBridgeDev = CreateRootBridge (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Enumerate all the buses under this root bridge + // + + Status = PciRootBridgeEnumerator ( + PciResAlloc, + RootBridgeDev + ); + + DestroyRootBridge (RootBridgeDev); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Notify the bus allocation phase is finished for the first time + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation); + + if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { + + if (gPciHotPlugInit != NULL) { + // + // Wait for all HPC initialized + // + Status = AllRootHPCInitialized (STALL_1_SECOND * 15); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Notify the bus allocation phase is about to start for the 2nd time + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation); + + RootBridgeHandle = NULL; + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // if a root bridge instance is found, create root bridge device for it + // + + RootBridgeDev = CreateRootBridge (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Enumerate all the buses under this root bridge + // + + Status = PciRootBridgeEnumerator ( + PciResAlloc, + RootBridgeDev + ); + + DestroyRootBridge (RootBridgeDev); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Notify the bus allocation phase is to end for the 2nd time + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation); + } + } + + // + // Notify the resource allocation phase is to start + // + NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation); + + RootBridgeHandle = NULL; + while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) { + + // + // if a root bridge instance is found, create root bridge device for it + // + + RootBridgeDev = CreateRootBridge (RootBridgeHandle); + + if (RootBridgeDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = StartManagingRootBridge (RootBridgeDev); + + if (EFI_ERROR (Status)) { + return Status; + } + + PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo; + Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors); + + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Determine root bridge attribute by calling interface of Pcihostbridge + // protocol + // + DetermineRootBridgeAttributes ( + PciResAlloc, + RootBridgeDev + ); + + // + // Collect all the resource information under this root bridge + // A database that records all the information about pci device subject to this + // root bridge will then be created + // + Status = PciPciDeviceInfoCollector ( + RootBridgeDev, + (UINT8) MinBus + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + InsertRootBridge (RootBridgeDev); + + // + // Record the hostbridge handle + // + AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle); + } + + return EFI_SUCCESS; +} + +/** + Read PCI device configuration register by specified address. + + This function check the incompatiblilites on PCI device. Return the register + value. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param PciIo A pointer to EFI_PCI_PROTOCOL. + @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +STATIC +EFI_STATUS +ReadConfigData ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL + IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + IN UINT64 Width, + IN UINT64 Address, + IN OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT64 AccessWidth; + EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData; + UINT64 AccessAddress; + UINTN Stride; + UINT64 TempBuffer; + UINT8 *Pointer; + + ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL)); + + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) { + // + // check access compatibility at first time + // + Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData); + + if (Status == EFI_SUCCESS) { + // + // there exist incompatibility on this operation + // + AccessWidth = Width; + + if (PciRegisterAccessData->Width != VALUE_NOCARE) { + AccessWidth = PciRegisterAccessData->Width; + } + + AccessAddress = Address & ~((1 << AccessWidth) - 1); + + TempBuffer = 0; + Stride = 0; + Pointer = (UINT8 *) &TempBuffer; + + while (1) { + + if (PciRootBridgeIo != NULL) { + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth, + AccessAddress, + 1, + Pointer + ); + } else if (PciIo != NULL) { + Status = PciIo->Pci.Read ( + PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth, + (UINT32) AccessAddress, + 1, + Pointer + ); + } + + if (Status != EFI_SUCCESS) { + return Status; + } + + Stride = 1 << AccessWidth; + AccessAddress += Stride; + if (AccessAddress >= (Address + (1 << Width))) { + // + // if all datas have been read, exist + // + break; + } + + Pointer += Stride; + + if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) { + // + // if current offset doesn't reach the end + // + continue; + } + + FreePool (PciRegisterAccessData); + + // + // continue checking access incompatibility + // + Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData); + if (Status == EFI_SUCCESS) { + if (PciRegisterAccessData->Width != VALUE_NOCARE) { + AccessWidth = PciRegisterAccessData->Width; + } + } + } + + FreePool (PciRegisterAccessData); + + switch (Width) { + case EfiPciWidthUint8: + * (UINT8 *) Buffer = (UINT8) TempBuffer; + break; + case EfiPciWidthUint16: + * (UINT16 *) Buffer = (UINT16) TempBuffer; + break; + case EfiPciWidthUint32: + * (UINT32 *) Buffer = (UINT32) TempBuffer; + break; + default: + return EFI_UNSUPPORTED; + } + + return Status; + } + } + // + // AccessWidth incompatible check not supportted + // or, there doesn't exist incompatibility on this operation + // + if (PciRootBridgeIo != NULL) { + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + 1, + Buffer + ); + + } else { + Status = PciIo->Pci.Read ( + PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH) Width, + (UINT32) Address, + 1, + Buffer + ); + } + + return Status; +} + +/** + Update register value by checking PCI device incompatibility. + + This function check register value incompatibilites on PCI device. Return the register + value. + + @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO. + @param AccessType Access type, READ or WRITE. + @Param Address The address within the PCI configuration space. + @param Buffer Store the register data. + + @retval EFI_SUCCESS The data has been updated. + +**/ +STATIC +EFI_STATUS +UpdateConfigData ( + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + IN UINT64 AccessType, + IN UINT64 Width, + IN UINT64 Address, + IN OUT VOID *Buffer +) +{ + EFI_STATUS Status; + EFI_PCI_REGISTER_VALUE_DATA *PciRegisterData; + UINT32 AndValue; + UINT32 OrValue; + UINT32 TempValue; + + // + // check register value incompatibility + // + Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData); + + if (Status == EFI_SUCCESS) { + + AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Address & 0x3) * 8); + OrValue = ((UINT32) PciRegisterData->OrValue) >> (((UINT8) Address & 0x3) * 8); + + TempValue = * (UINT32 *) Buffer; + if (PciRegisterData->AndValue != VALUE_NOCARE) { + TempValue &= AndValue; + } + if (PciRegisterData->OrValue != VALUE_NOCARE) { + TempValue |= OrValue; + } + + switch (Width) { + case EfiPciWidthUint8: + *(UINT8 *)Buffer = (UINT8) TempValue; + break; + + case EfiPciWidthUint16: + *(UINT16 *)Buffer = (UINT16) TempValue; + break; + case EfiPciWidthUint32: + *(UINT32 *)Buffer = TempValue; + break; + + default: + return EFI_UNSUPPORTED; + } + + FreePool (PciRegisterData); + } + + return Status; +} + +/** + Write PCI device configuration register by specified address. + + This function check the incompatiblilites on PCI device, and write date + into register. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param PciIo A pointer to EFI_PCI_PROTOCOL. + @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +STATIC +EFI_STATUS +WriteConfigData ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL + IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL + IN EFI_PCI_DEVICE_INFO *PciDeviceInfo, + IN UINT64 Width, + IN UINT64 Address, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + UINT64 AccessWidth; + EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData; + UINT64 AccessAddress; + UINTN Stride; + UINT8 *Pointer; + UINT64 Data; + UINTN Shift; + + ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL)); + + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) { + // + // check access compatibility at first time + // + Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData); + + if (Status == EFI_SUCCESS) { + // + // there exist incompatibility on this operation + // + AccessWidth = Width; + + if (PciRegisterAccessData->Width != VALUE_NOCARE) { + AccessWidth = PciRegisterAccessData->Width; + } + + AccessAddress = Address & ~((1 << AccessWidth) - 1); + + Stride = 0; + Pointer = (UINT8 *) &Buffer; + Data = * (UINT64 *) Buffer; + + while (1) { + + if (AccessWidth > Width) { + // + // if actual access width is larger than orignal one, additional data need to be read back firstly + // + Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data); + if (Status != EFI_SUCCESS) { + return Status; + } + + // + // check data read incompatibility + // + UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data); + + Shift = (UINTN) ((Address - AccessAddress) * 8); + switch (Width) { + case EfiPciWidthUint8: + Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift)); + break; + + case EfiPciWidthUint16: + Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift)); + break; + } + + // + // check data write incompatibility + // + UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, AccessAddress * 0xff, &Data); + } + + if (PciRootBridgeIo != NULL) { + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth, + AccessAddress, + 1, + &Data + ); + } else { + Status = PciIo->Pci.Write ( + PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth, + (UINT32) AccessAddress, + 1, + &Data + ); + } + + if (Status != EFI_SUCCESS) { + return Status; + } + + Data = RShiftU64 (Data, ((1 << AccessWidth) * 8)); + + Stride = 1 << AccessWidth; + AccessAddress += Stride; + if (AccessAddress >= (Address + (1 << Width))) { + // + // if all datas have been written, exist + // + break; + } + + Pointer += Stride; + + if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) { + // + // if current offset doesn't reach the end + // + continue; + } + + FreePool (PciRegisterAccessData); + + // + // continue checking access incompatibility + // + Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData); + if (Status == EFI_SUCCESS) { + if (PciRegisterAccessData->Width != VALUE_NOCARE) { + AccessWidth = PciRegisterAccessData->Width; + } + } + }; + + FreePool (PciRegisterAccessData); + + return Status; + } + + } + // + // AccessWidth incompatible check not supportted + // or, there doesn't exist incompatibility on this operation + // + if (PciRootBridgeIo != NULL) { + Status = PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width, + Address, + 1, + Buffer + ); + } else { + Status = PciIo->Pci.Write ( + PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH) Width, + (UINT32) Address, + 1, + Buffer + ); + } + + return Status; +} + +/** + Abstract PCI device device information. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param PciIo A pointer to EFI_PCI_PROTOCOL. + @param Pci A pointer to PCI_TYPE00. + @Param Address The address within the PCI configuration space for the PCI controller. + @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO. + + @retval EFI_SUCCESS Pci device device information has been abstracted. + +**/ +STATIC +EFI_STATUS +GetPciDeviceDeviceInfo ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL + IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL + IN PCI_TYPE00 *Pci, OPTIONAL + IN UINT64 Address, OPTIONAL + OUT EFI_PCI_DEVICE_INFO *PciDeviceInfo +) +{ + EFI_STATUS Status; + UINT64 PciAddress; + UINT32 PciConfigData; + PCI_IO_DEVICE *PciIoDevice; + + ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL)); + + if (PciIo != NULL) { + PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo); + + // + // get pointer to PCI_TYPE00 from PciIoDevice + // + Pci = &PciIoDevice->Pci; + } + + if (Pci == NULL) { + // + // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly + // + PciAddress = Address & 0xffffffffffffff00ULL; + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + PciAddress, + 1, + &PciConfigData + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + if ((PciConfigData & 0xffff) == 0xffff) { + return EFI_NOT_FOUND; + } + + PciDeviceInfo->VendorID = PciConfigData & 0xffff; + PciDeviceInfo->DeviceID = PciConfigData >> 16; + + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + PciAddress + 8, + 1, + &PciConfigData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PciDeviceInfo->RevisionID = PciConfigData & 0xf; + + Status = PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + PciAddress + 0x2c, + 1, + &PciConfigData + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff; + PciDeviceInfo->SubsystemID = PciConfigData >> 16; + + } else { + PciDeviceInfo->VendorID = Pci->Hdr.VendorId; + PciDeviceInfo->DeviceID = Pci->Hdr.DeviceId; + PciDeviceInfo->RevisionID = Pci->Hdr.RevisionID; + PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID; + PciDeviceInfo->SubsystemID = Pci->Device.SubsystemID; + } + + return EFI_SUCCESS; +} + +/** + Read PCI configuration space with incompatibility check. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL. + @param Pci A pointer to PCI_TYPE00. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +STATIC +EFI_STATUS +PciIncompatibilityCheckRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL + IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL + IN PCI_TYPE00 *Pci, OPTIONAL + IN UINTN Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer +) +{ + EFI_STATUS Status; + EFI_PCI_DEVICE_INFO PciDeviceInfo; + UINT32 Stride; + + ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL)); + + // + // get PCI device device information + // + Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo); + if (Status != EFI_SUCCESS) { + return Status; + } + + Stride = 1 << Width; + + for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) { + + // + // read configuration register + // + Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer); + + if (Status != EFI_SUCCESS) { + return Status; + } + + // + // update the data read from configuration register + // + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) { + UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer); + } + } + + return EFI_SUCCESS; +} + +/** + Write PCI configuration space with incompatibility check. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL. + @param Pci A pointer to PCI_TYPE00. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +STATIC +EFI_STATUS +PciIncompatibilityCheckWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL + IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL + IN PCI_TYPE00 *Pci, OPTIONAL + IN UINTN Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer +) +{ + EFI_STATUS Status; + EFI_PCI_DEVICE_INFO PciDeviceInfo; + UINT32 Stride; + UINT64 Data; + + ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL)); + + // + // get PCI device device information + // + Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo); + if (Status != EFI_SUCCESS) { + return Status; + } + + Stride = 1 << Width; + + for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) { + + Data = 0; + + switch (Width) { + case EfiPciWidthUint8: + Data = * (UINT8 *) Buffer; + break; + case EfiPciWidthUint16: + Data = * (UINT16 *) Buffer; + break; + + case EfiPciWidthUint32: + Data = * (UINT32 *) Buffer; + break; + + default: + return EFI_UNSUPPORTED; + } + + // + // update the data writen into configuration register + // + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) { + UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data); + } + + // + // write configuration register + // + Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data); + + if (Status != EFI_SUCCESS) { + return Status; + } + } + + return EFI_SUCCESS; +} + +/** + Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pci A pointer to PCI_TYPE00. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +PciRootBridgeIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, OPTIONAL + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) { + // + // if PCI incompatibility check enabled + // + return PciIncompatibilityCheckRead ( + PciRootBridgeIo, + NULL, + Pci, + (UINTN) Width, + Address, + Count, + Buffer + ); + } else { + return PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + Width, + Address, + Count, + Buffer + ); + } +} + +/** + Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + + @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. + @param Pci A pointer to PCI_TYPE00. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +PciRootBridgeIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, + IN PCI_TYPE00 *Pci, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) { + // + // if PCI incompatibility check enabled + // + return PciIncompatibilityCheckWrite ( + PciRootBridgeIo, + NULL, + Pci, + Width, + Address, + Count, + Buffer + ); + + } else { + return PciRootBridgeIo->Pci.Write ( + PciRootBridgeIo, + Width, + Address, + Count, + Buffer + ); + } +} + +/** + Read PCI configuration space through EFI_PCI_IO_PROTOCOL. + + @param PciIo A pointer to the EFI_PCI_O_PROTOCOL. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +PciIoRead ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) { + // + // if PCI incompatibility check enabled + // + return PciIncompatibilityCheckRead ( + NULL, + PciIo, + NULL, + (UINTN) Width, + Address, + Count, + Buffer + ); + } else { + return PciIo->Pci.Read ( + PciIo, + Width, + Address, + Count, + Buffer + ); + } +} + +/** + Write PCI configuration space through EFI_PCI_IO_PROTOCOL. + + @param PciIo A pointer to the EFI_PCI_O_PROTOCOL. + @param Width Signifies the width of the memory operations. + @Param Address The address within the PCI configuration space for the PCI controller. + @param Buffer For read operations, the destination buffer to store the results. For + write operations, the source buffer to write data from. + + @retval EFI_SUCCESS The data was read from or written to the PCI root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + +**/ +EFI_STATUS +PciIoWrite ( + IN EFI_PCI_IO_PROTOCOL *PciIo, + IN EFI_PCI_IO_PROTOCOL_WIDTH Width, + IN UINT32 Address, + IN UINTN Count, + IN OUT VOID *Buffer + ) +{ + if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) { + + // + // if PCI incompatibility check enabled + // + return PciIncompatibilityCheckWrite ( + NULL, + PciIo, + NULL, + Width, + Address, + Count, + Buffer + ); + + } else { + return PciIo->Pci.Write ( + PciIo, + Width, + Address, + Count, + Buffer + ); + } +}