diff options
Diffstat (limited to 'CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c')
-rw-r--r-- | CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c new file mode 100644 index 0000000000..63ea892044 --- /dev/null +++ b/CorebootModulePkg/PciRootBridgeNoEnumerationDxe/Ia32/PcatIo.c @@ -0,0 +1,738 @@ +/*++ + +Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> +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: + PcatPciRootBridgeIo.c + +Abstract: + + EFI PC AT PCI Root Bridge Io Protocol + +Revision History + +--*/ + +#include "PcatPciRootBridge.h" + +BOOLEAN mPciOptionRomTableInstalled = FALSE; +EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoRead ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Read ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); +} + +EFI_STATUS +EFIAPI +PcatRootBridgeIoIoWrite ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + return gCpuIo->Io.Write ( + gCpuIo, + (EFI_CPU_IO_PROTOCOL_WIDTH) Width, + UserAddress, + Count, + UserBuffer + ); + +} + +EFI_STATUS +PcatRootBridgeIoGetIoPortMapping ( + OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, + OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping + ) +/*++ + + Get the IO Port Mapping. For IA-32 it is always 0. + +--*/ +{ + *IoPortMapping = 0; + *MemoryPortMapping = 0; + + return EFI_SUCCESS; +} + +EFI_STATUS +PcatRootBridgeIoPciRW ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN BOOLEAN Write, + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, + IN UINT64 UserAddress, + IN UINTN Count, + IN OUT VOID *UserBuffer + ) +{ + PCI_CONFIG_ACCESS_CF8 Pci; + PCI_CONFIG_ACCESS_CF8 PciAligned; + UINT32 InStride; + UINT32 OutStride; + UINTN PciData; + UINTN PciDataStride; + PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; + UINT64 PciExpressRegAddr; + BOOLEAN UsePciExpressAccess; + + if ((UINT32)Width >= EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + if ((Width & 0x03) >= EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); + + InStride = 1 << (Width & 0x03); + OutStride = InStride; + if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { + InStride = 0; + } + + if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { + OutStride = 0; + } + + UsePciExpressAccess = FALSE; + + CopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); + + if (PciAddress.ExtendedRegister > 0xFF) { + // + // Check PciExpressBaseAddress + // + if ((PrivateData->PciExpressBaseAddress == 0) || + (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) { + return EFI_UNSUPPORTED; + } else { + UsePciExpressAccess = TRUE; + } + } else { + if (PciAddress.ExtendedRegister != 0) { + Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF; + } else { + Pci.Bits.Reg = PciAddress.Register; + } + // + // Note: We can also use PciExpress access here, if wanted. + // + } + + if (!UsePciExpressAccess) { + Pci.Bits.Func = PciAddress.Function; + Pci.Bits.Dev = PciAddress.Device; + Pci.Bits.Bus = PciAddress.Bus; + Pci.Bits.Reserved = 0; + Pci.Bits.Enable = 1; + + // + // PCI Config access are all 32-bit alligned, but by accessing the + // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types + // are possible on PCI. + // + // To read a byte of PCI config space you load 0xcf8 and + // read 0xcfc, 0xcfd, 0xcfe, 0xcff + // + PciDataStride = Pci.Bits.Reg & 0x03; + + while (Count) { + PciAligned = Pci; + PciAligned.Bits.Reg &= 0xfc; + PciData = (UINTN)PrivateData->PciData + PciDataStride; + EfiAcquireLock(&PrivateData->PciLock); + This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); + if (Write) { + This->Io.Write (This, Width, PciData, 1, UserBuffer); + } else { + This->Io.Read (This, Width, PciData, 1, UserBuffer); + } + EfiReleaseLock(&PrivateData->PciLock); + UserBuffer = ((UINT8 *)UserBuffer) + OutStride; + PciDataStride = (PciDataStride + InStride) % 4; + Pci.Bits.Reg += InStride; + Count -= 1; + } + } else { + // + // Access PCI-Express space by using memory mapped method. + // + PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) | + (PciAddress.Bus << 20) | + (PciAddress.Device << 15) | + (PciAddress.Function << 12); + if (PciAddress.ExtendedRegister != 0) { + PciExpressRegAddr += PciAddress.ExtendedRegister; + } else { + PciExpressRegAddr += PciAddress.Register; + } + while (Count) { + if (Write) { + This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } else { + This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); + } + + UserBuffer = ((UINT8 *) UserBuffer) + OutStride; + PciExpressRegAddr += InStride; + Count -= 1; + } + } + + return EFI_SUCCESS; +} + +VOID +ScanPciBus( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + EFI_PCI_BUS_SCAN_CALLBACK Callback, + VOID *Context + ) + +{ + UINT16 Bus; + UINT16 Device; + UINT16 Func; + UINT64 Address; + PCI_TYPE00 PciHeader; + + // + // Loop through all busses + // + for (Bus = MinBus; Bus <= MaxBus; Bus++) { + // + // Loop 32 devices per bus + // + for (Device = MinDevice; Device <= MaxDevice; Device++) { + // + // Loop through 8 functions per device + // + for (Func = MinFunc; Func <= MaxFunc; Func++) { + + // + // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device + // + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the VendorID from this PCI Device's Confioguration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId); + + // + // If VendorId = 0xffff, there does not exist a device at this + // location. For each device, if there is any function on it, + // there must be 1 function at Function 0. So if Func = 0, there + // will be no more functions in the same device, so we can break + // loop to deal with the next device. + // + if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) { + break; + } + + if (PciHeader.Hdr.VendorId != 0xffff) { + + // + // Read the HeaderType to determine if this is a multi-function device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType); + + // + // Call the callback function for the device that was found + // + Callback( + IoDev, + MinBus, MaxBus, + MinDevice, MaxDevice, + MinFunc, MaxFunc, + Bus, + Device, + Func, + Context + ); + + // + // If this is not a multi-function device, we can leave the loop + // to deal with the next device. + // + if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) { + break; + } + } + } + } + } +} + +VOID +CheckForRom ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) +{ + EFI_STATUS Status; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + PCI_TYPE00 PciHeader; + PCI_TYPE01 *PciBridgeHeader; + UINT32 Register; + UINT32 RomBar; + UINT32 RomBarSize; + EFI_PHYSICAL_ADDRESS RomBuffer; + UINT32 MaxRomSize; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; + PCI_DATA_STRUCTURE Pcir; + EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; + BOOLEAN LastImage; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Save the contents of the PCI Configuration Header + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); + + if (IS_PCI_BRIDGE(&PciHeader)) { + + PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); + + // + // See if the PCI-PCI Bridge has its secondary interface enabled. + // + if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { + + // + // Disable the Prefetchable Memory Window + // + Register = 0x00000000; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); + Register = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); + + // + // Program Memory Window to the PCI Root Bridge Memory Window + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); + + // + // Enable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Recurse on the Secondary Bus Number + // + ScanPciBus( + IoDev, + PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, Context + ); + } + } else { + + // + // Check if an Option ROM Register is present and save the Option ROM Window Register + // + RomBar = 0xffffffff; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + + RomBarSize = (~(RomBar & 0xfffff800)) + 1; + + // + // Make sure the size of the ROM is between 0 and 16 MB + // + if (RomBarSize > 0 && RomBarSize <= 0x01000000) { + + // + // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window + // + RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; + RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; + if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { + MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; + RomBar = RomBar + 1; + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); + RomBar = RomBar - 1; + + // + // Enable the Memory decode for the PCI Device + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register |= 0x02; + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + + // + // Follow the chain of images to determine the size of the Option ROM present + // Keep going until the last image is found by looking at the Indicator field + // or the size of an image is 0, or the size of all the images is bigger than the + // size of the window programmed into the PPB. + // + RomBarSize = 0; + do { + + LastImage = TRUE; + + ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize, + sizeof(EfiRomHeader), + &EfiRomHeader + ); + + Pcir.ImageLength = 0; + + if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE && + EfiRomHeader.PcirOffset != 0 && + (EfiRomHeader.PcirOffset & 3) == 0 && + RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) { + ZeroMem (&Pcir, sizeof(Pcir)); + IoDev->Mem.Read ( + IoDev, + EfiPciWidthUint8, + RomBar + RomBarSize + EfiRomHeader.PcirOffset, + sizeof(Pcir), + &Pcir + ); + + if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + break; + } + if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) { + break; + } + if ((Pcir.Indicator & 0x80) == 0x00) { + LastImage = FALSE; + } + + RomBarSize += Pcir.ImageLength * 512; + } + } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); + + if (RomBarSize > 0) { + + // + // Allocate a memory buffer for the Option ROM contents. + // + Status = gBS->AllocatePages( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES(RomBarSize), + &RomBuffer + ); + + if (!EFI_ERROR (Status)) { + + // + // Copy the contents of the Option ROM to the memory buffer + // + IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); + + Status = gBS->AllocatePool( + EfiBootServicesData, + ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), + (VOID*)&TempPciOptionRomDescriptors + ); + if (mPciOptionRomTable.PciOptionRomCount > 0) { + CopyMem( + TempPciOptionRomDescriptors, + mPciOptionRomTable.PciOptionRomDescriptors, + (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) + ); + + gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); + } + + mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; + + TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); + + TempPciOptionRomDescriptors->RomAddress = RomBuffer; + TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; + TempPciOptionRomDescriptors->RomLength = RomBarSize; + TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; + TempPciOptionRomDescriptors->Bus = (UINT8)Bus; + TempPciOptionRomDescriptors->Dev = (UINT8)Device; + TempPciOptionRomDescriptors->Func = (UINT8)Func; + TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; + TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; + + mPciOptionRomTable.PciOptionRomCount++; + } + } + + // + // Disable the Memory decode for the PCI-PCI Bridge + // + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + Register &= (~0x02); + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); + } + } + } + + // + // Restore the PCI Configuration Header + // + IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); +} + +VOID +SaveCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + UINT16 Command; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); + + // + // Clear the memory enable bit + // + Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02)); + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command); +} + +VOID +RestoreCommandRegister ( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, + UINT16 MinBus, + UINT16 MaxBus, + UINT16 MinDevice, + UINT16 MaxDevice, + UINT16 MinFunc, + UINT16 MaxFunc, + UINT16 Bus, + UINT16 Device, + UINT16 Func, + IN VOID *VoidContext + ) + +{ + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; + UINT64 Address; + UINTN Index; + + Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; + + Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); + + Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; + + IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); +} + +EFI_STATUS +ScanPciRootBridgeForRoms( + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev + ) + +{ + EFI_STATUS Status; + EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; + UINT16 MinBus; + UINT16 MaxBus; + UINT64 RootWindowBase; + UINT64 RootWindowLimit; + PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; + + if (mPciOptionRomTableInstalled == FALSE) { + gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); + mPciOptionRomTableInstalled = TRUE; + } + + Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors); + if (EFI_ERROR (Status) || Descriptors == NULL) { + return EFI_NOT_FOUND; + } + + MinBus = 0xffff; + MaxBus = 0xffff; + RootWindowBase = 0; + RootWindowLimit = 0; + while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { + // + // Find bus range + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + MinBus = (UINT16)Descriptors->AddrRangeMin; + MaxBus = (UINT16)Descriptors->AddrRangeMax; + } + // + // Find memory descriptors that are not prefetchable + // + if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { + // + // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices + // + if (Descriptors->AddrRangeMax < 0x100000000ULL) { + // + // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB + // + if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { + RootWindowBase = Descriptors->AddrRangeMin; + RootWindowLimit = Descriptors->AddrRangeMax; + } + } + } + Descriptors ++; + } + + // + // Make sure a bus range was found + // + if (MinBus == 0xffff || MaxBus == 0xffff) { + return EFI_NOT_FOUND; + } + + // + // Make sure a non-prefetchable memory region was found + // + if (RootWindowBase == 0 && RootWindowLimit == 0) { + return EFI_NOT_FOUND; + } + + // + // Round the Base and Limit values to 1 MB boudaries + // + RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; + RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; + + // + // Make sure that the size of the rounded window is greater than zero + // + if (RootWindowLimit <= RootWindowBase) { + return EFI_NOT_FOUND; + } + + // + // Allocate buffer to save the Command register from all the PCI devices + // + Context.CommandRegisterBuffer = NULL; + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), + (VOID **)&Context.CommandRegisterBuffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); + + // + // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + SaveCommandRegister, &Context + ); + + // + // Recursively scan all the busses for PCI Option ROMs + // + ScanPciBus( + IoDev, + MinBus, MinBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + CheckForRom, &Context + ); + + // + // Restore the Command register in all the PCI devices + // + ScanPciBus( + IoDev, + MinBus, MaxBus, + 0, PCI_MAX_DEVICE, + 0, PCI_MAX_FUNC, + RestoreCommandRegister, &Context + ); + + // + // Free the buffer used to save all the Command register values + // + gBS->FreePool(Context.CommandRegisterBuffer); + + return EFI_SUCCESS; +} |