Ejemplo n.º 1
0
/**
  Dump the resourc map of the bridge device.

  @param[in] BridgeResource   Resource descriptor of the bridge device.
**/
VOID
DumpBridgeResource (
  IN PCI_RESOURCE_NODE     *BridgeResource
  )
{
  LIST_ENTRY               *Link;
  PCI_RESOURCE_NODE        *Resource;
  PCI_BAR                  *Bar;

  if ((BridgeResource != NULL) && (BridgeResource->Length != 0)) {
    DEBUG ((
      EFI_D_INFO, "Type = %s; Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx\n",
      mBarTypeStr[MIN (BridgeResource->ResType, PciBarTypeMaxType)],
      BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress,
      BridgeResource->Length, BridgeResource->Alignment
      ));
    for ( Link = BridgeResource->ChildList.ForwardLink
        ; Link != &BridgeResource->ChildList
        ; Link = Link->ForwardLink
        ) {
      Resource = RESOURCE_NODE_FROM_LINK (Link);
      if (Resource->ResourceUsage == PciResUsageTypical) {
        Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource->PciDev->PciBar;
        DEBUG ((
          EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx;\tOwner = %s ",
          Bar[Resource->Bar].BaseAddress, Resource->Length, Resource->Alignment,
          IS_PCI_BRIDGE (&Resource->PciDev->Pci)     ? L"PPB" :
          IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" :
                                                       L"PCI"
          ));

        if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) && !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) ||
            (IS_PCI_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < PPB_IO_RANGE)) ||
            (IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < P2C_MEM_1))
            ) {
          //
          // The resource requirement comes from the device itself.
          //
          DEBUG ((
            EFI_D_INFO, " [%02x|%02x|%02x:%02x]\n",
            Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,
            Resource->PciDev->FunctionNumber, Bar[Resource->Bar].Offset
            ));
        } else {
          //
          // The resource requirement comes from the subordinate devices.
          //
          DEBUG ((
            EFI_D_INFO, " [%02x|%02x|%02x:**]\n",
            Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,
            Resource->PciDev->FunctionNumber
            ));
        }
      } else {
        DEBUG ((EFI_D_INFO, " Padding:Length = 0x%lx;\tAlignment = 0x%lx\n", Resource->Length, Resource->Alignment));
      }
    }
  }
}
EFI_STATUS
DetermineDeviceAttribute (
  IN PCI_IO_DEVICE                      *PciIoDevice
  )
/*++

Routine Description:
 
  Determine the related attributes of all devices under a Root Bridge

Arguments:

Returns:

  None

--*/
{
  UINT16          Command;
  UINT16          BridgeControl;

  Command = 0;

  PciIoDevice->Supports |= EFI_PCI_DEVICE_ENABLE;
  PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;

  if (IS_PCI_VGA (&(PciIoDevice->Pci))){

    //
    // If the device is VGA, VGA related Attributes are supported
    //
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO ;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY   ;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_IO    ;
  }

  if(IS_ISA_BRIDGE(&(PciIoDevice->Pci)) || IS_INTEL_ISA_BRIDGE(&(PciIoDevice->Pci))) {
    //
    // If the devie is a ISA Bridge, set the two attributes
    //
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
  }

  if (IS_PCI_GFX (&(PciIoDevice->Pci))) {

    //
    // If the device is GFX, then only set the EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO
    // attribute
    //
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO    ;
  }


  //
  // If the device is IDE, IDE related attributes are supported
  //
  if (IS_PCI_IDE (&(PciIoDevice->Pci))) {
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO  ;
    PciIoDevice->Supports |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO  ;
  }

  PciReadCommandRegister(PciIoDevice, &Command);

  
  if (Command & EFI_PCI_COMMAND_IO_SPACE) {
    PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
  }

  if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {
    PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
  }

  if (Command & EFI_PCI_COMMAND_BUS_MASTER) {
    PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
  }

  if (IS_PCI_BRIDGE (&(PciIoDevice->Pci)) || 
      IS_CARDBUS_BRIDGE (&(PciIoDevice->Pci))){

    //
    // If it is a PPB, read the Bridge Control Register to determine
    // the relevant attributes
    //
    BridgeControl = 0;
    PciReadBridgeControlRegister(PciIoDevice, &BridgeControl);

    //
    // Determine whether the ISA bit is set
    // If ISA Enable on Bridge is set, the PPB
    // will block forwarding 0x100-0x3ff for each 1KB in the 
    // first 64KB I/O range.
    //
    if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
    } 

    //
    // Determine whether the VGA bit is set
    // If it is set, the bridge is set to decode VGA memory range
    // and palette register range
    //
    if (IS_PCI_VGA (&(PciIoDevice->Pci)) &&BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) {
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
    }

    //
    // if the palette snoop bit is set, then the brige is set to 
    // decode palette IO write
    //
    if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {
      PciIoDevice->Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
    }
  } 

  return EFI_SUCCESS;
}
EFI_STATUS
PciSearchDevice (
  IN  PCI_IO_DEVICE                         *Bridge,
  IN  PCI_TYPE00                            *Pci,
  IN  UINT8                                 Bus,
  IN  UINT8                                 Device,
  IN  UINT8                                 Func,
  OUT PCI_IO_DEVICE                         **PciDevice
  )
/*++

Routine Description:

  Search required device.

Arguments:

  Bridge     - A pointer to the PCI_IO_DEVICE.
  Pci        - A pointer to the PCI_TYPE00.
  Bus        - Bus number.
  Device     - Device number.
  Func       - Function number.
  PciDevice  - The Required pci device.

Returns:

  Status code.

--*/
{
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = NULL;

  if (!IS_PCI_BRIDGE (Pci)) {

    if (IS_CARDBUS_BRIDGE (Pci)) {
      PciIoDevice = GatherP2CInfo (
                      Bridge->PciRootBridgeIo,
                      Pci,
                      Bus,
                      Device,
                      Func
                      );
      if ((PciIoDevice != NULL) && (gFullEnumeration == TRUE)) {
        InitializeP2C (PciIoDevice);
      }
    } else {

      //
      // Create private data for Pci Device
      //
      PciIoDevice = GatherDeviceInfo (
                      Bridge->PciRootBridgeIo,
                      Pci,
                      Bus,
                      Device,
                      Func
                      );

    }

  } else {

    //
    // Create private data for PPB
    //
    PciIoDevice = GatherPPBInfo (
                    Bridge->PciRootBridgeIo,
                    Pci,
                    Bus,
                    Device,
                    Func
                    );

    //
    // Special initialization for PPB including making the PPB quiet
    //
    if ((PciIoDevice != NULL) && (gFullEnumeration == TRUE)) {
      InitializePPB (PciIoDevice);
    }
  }

  if (!PciIoDevice) {
    return EFI_OUT_OF_RESOURCES;
  }
  
  //
  // Create a device path for this PCI device and store it into its private data
  //
  CreatePciDevicePath(
    Bridge->DevicePath,
    PciIoDevice 
    );
  
  //
  // Detect this function has option rom
  //
  if (gFullEnumeration) {

    if (!IS_CARDBUS_BRIDGE (Pci)) {

      GetOpRomInfo (PciIoDevice);

    }

    ResetPowerManagementFeature (PciIoDevice);
    
  } 
  else {
    PciRomGetRomResourceFromPciOptionRomTable (
      &gPciBusDriverBinding,
      PciIoDevice->PciRootBridgeIo,
      PciIoDevice
      );
  }

 
  //
  // Insert it into a global tree for future reference
  //
  InsertPciDevice (Bridge, PciIoDevice);

  //
  // Determine PCI device attributes
  //
  DetermineDeviceAttribute (PciIoDevice);

  if (PciDevice != NULL) {
    *PciDevice = PciIoDevice;
  }

  return EFI_SUCCESS;
}
EFI_STATUS
PciPciDeviceInfoCollector (
  IN PCI_IO_DEVICE                      *Bridge,
  UINT8                                 StartBusNumber
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
{
  EFI_STATUS          Status;
  PCI_TYPE00          Pci;
  UINT8               Device;
  UINT8               Func;
  UINT8               SecBus;
  PCI_IO_DEVICE       *PciIoDevice;
  EFI_PCI_IO_PROTOCOL *PciIo;

  Status  = EFI_SUCCESS;
  SecBus  = 0;

  for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {

    for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {

      //
      // Check to see whether PCI device is present
      //

      Status = PciDevicePresent (
                Bridge->PciRootBridgeIo,
                &Pci,
                (UINT8) StartBusNumber,
                (UINT8) Device,
                (UINT8) Func
                );

      if (!EFI_ERROR (Status)) {

        //
        // Collect all the information about the PCI device discovered
        //
        Status = PciSearchDevice (
                  Bridge,
                  &Pci,
                  (UINT8) StartBusNumber,
                  Device,
                  Func,
                  &PciIoDevice
                  );

        //
        // Recursively scan PCI busses on the other side of PCI-PCI bridges
        //
        //

        if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {

          //
          // If it is PPB, we need to get the secondary bus to continue the enumeration
          //
          PciIo   = &(PciIoDevice->PciIo);

          Status  = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x19, 1, &SecBus);

          if (EFI_ERROR (Status)) {
            return Status;
          }
              
          //
          // Deep enumerate the next level bus
          //
          Status = PciPciDeviceInfoCollector (
                    PciIoDevice,
                    (UINT8) (SecBus)
                    );

        }

        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
EFIAPI
InitializePcatPciRootBridge (
  IN EFI_HANDLE       ImageHandle,
  IN EFI_SYSTEM_TABLE *SystemTable
  )
/*++

Routine Description:
  Initializes the PCI Root Bridge Controller

Arguments:
  ImageHandle -
  SystemTable -
    
Returns:
    None

--*/
{
  EFI_STATUS                     Status;
  PCAT_PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
  UINTN                          PciSegmentIndex;
  UINTN                          PciRootBridgeIndex;
  UINTN                          PrimaryBusIndex;
  UINTN                          NumberOfPciRootBridges;
  UINTN                          NumberOfPciDevices;
  UINTN                          Device;
  UINTN                          Function;
  UINT16                         VendorId;
  PCI_TYPE02                     PciConfigurationHeader;
  UINT64                         Address;
  UINT64                         Value;
  UINT64                         Base;
  UINT64                         Limit;

  //
  // Initialize gCpuIo now since the chipset init code requires it.
  //
  Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **)&gCpuIo);
  ASSERT_EFI_ERROR (Status);

  //
  // Initialize variables required to search all PCI segments for PCI devices
  //
  PciSegmentIndex        = 0;
  PciRootBridgeIndex     = 0;
  NumberOfPciRootBridges = 0;
  PrimaryBusIndex        = 0;

  while (PciSegmentIndex <= PCI_MAX_SEGMENT) {

    PrivateData = NULL;
    Status = gBS->AllocatePool(
                    EfiBootServicesData,
                    sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE),
                    (VOID **)&PrivateData
                    );
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    ZeroMem (PrivateData, sizeof (PCAT_PCI_ROOT_BRIDGE_INSTANCE));

    //
    // Initialize the signature of the private data structure
    //
    PrivateData->Signature  = PCAT_PCI_ROOT_BRIDGE_SIGNATURE;
    PrivateData->Handle     = NULL;
    PrivateData->DevicePath = NULL;
    InitializeListHead (&PrivateData->MapInfo);

    //
    // Initialize the PCI root bridge number and the bus range for that root bridge
    //
    PrivateData->RootBridgeNumber = (UINT32)PciRootBridgeIndex;
    PrivateData->PrimaryBus       = (UINT32)PrimaryBusIndex;
    PrivateData->SubordinateBus   = (UINT32)PrimaryBusIndex;

    PrivateData->IoBase      = 0xffffffff;
    PrivateData->MemBase     = 0xffffffff;
    PrivateData->Mem32Base   = 0xffffffffffffffffULL;
    PrivateData->Pmem32Base  = 0xffffffffffffffffULL;
    PrivateData->Mem64Base   = 0xffffffffffffffffULL;
    PrivateData->Pmem64Base  = 0xffffffffffffffffULL;

    //
    // The default mechanism for performing PCI Configuration cycles is to 
    // use the I/O ports at 0xCF8 and 0xCFC.  This is only used for IA-32.
    // IPF uses SAL calls to perform PCI COnfiguration cycles
    //
    PrivateData->PciAddress  = 0xCF8;
    PrivateData->PciData     = 0xCFC;

    //
    // Get the physical I/O base for performing PCI I/O cycles
    // For IA-32, this is always 0, because IA-32 has IN and OUT instructions
    // For IPF, a SAL call is made to retrieve the base address for PCI I/O cycles
    //
    Status = PcatRootBridgeIoGetIoPortMapping (
               &PrivateData->PhysicalIoBase, 
               &PrivateData->PhysicalMemoryBase
               );
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    //
    // Get PCI Express Base Address
    //
    PrivateData->PciExpressBaseAddress = GetPciExpressBaseAddressForRootBridge (PciSegmentIndex, PciRootBridgeIndex);
 /*   if (PrivateData->PciExpressBaseAddress != 0) {
      DEBUG ((EFI_D_ERROR, "PCIE Base - 0x%lx\n", PrivateData->PciExpressBaseAddress));
    }
*/
    //
    // Create a lock for performing PCI Configuration cycles
    //
    EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL);

    //
    // Initialize the attributes for this PCI root bridge
    //
    PrivateData->Attributes  = 0;

    //
    // Build the EFI Device Path Protocol instance for this PCI Root Bridge
    //
    Status = PcatRootBridgeDevicePathConstructor (&PrivateData->DevicePath, PciRootBridgeIndex, (BOOLEAN)((PrivateData->PciExpressBaseAddress != 0) ? TRUE : FALSE));
    if (EFI_ERROR (Status)) {
      goto Done;
    }

    //
    // Build the PCI Root Bridge I/O Protocol instance for this PCI Root Bridge
    //
    Status = PcatRootBridgeIoConstructor (&PrivateData->Io, PciSegmentIndex);
    if (EFI_ERROR (Status)) {
      goto Done;
    }
    
    //
    // Scan all the PCI devices on the primary bus of the PCI root bridge
    //
    for (Device = 0, NumberOfPciDevices = 0; Device <= PCI_MAX_DEVICE; Device++) {
    
      for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {

        //
        // Compute the PCI configuration address of the PCI device to probe
        //
        Address = EFI_PCI_ADDRESS (PrimaryBusIndex, Device, Function, 0);

        //
        // Read the Vendor ID from the PCI Configuration Header
        //
        Status = PrivateData->Io.Pci.Read (
                                       &PrivateData->Io, 
                                       EfiPciWidthUint16, 
                                       Address, 
                                       sizeof (VendorId) / sizeof (UINT16), 
                                       &VendorId
                                       );
        if ((EFI_ERROR (Status)) || ((VendorId == 0xffff) && (Function == 0))) {
          //
          // If the PCI Configuration Read fails, or a PCI device does not exist, then 
          // skip this entire PCI device
          //
          break;
        }
        if (VendorId == 0xffff) {
          //
          // If PCI function != 0, VendorId == 0xFFFF, we continue to search PCI function.
          //
          continue;
        }

        //
        // Read the entire PCI Configuration Header
        //
        Status = PrivateData->Io.Pci.Read (
                                       &PrivateData->Io, 
                                       EfiPciWidthUint16, 
                                       Address, 
                                       sizeof (PciConfigurationHeader) / sizeof (UINT16), 
                                       &PciConfigurationHeader
                                       );
        if (EFI_ERROR (Status)) {
          //
          // If the entire PCI Configuration Header can not be read, then skip this entire PCI device
          //
          break;
        }


        //
        // Increment the number of PCI device found on the primary bus of the PCI root bridge
        //
        NumberOfPciDevices++;

        //
        // Look for devices with the VGA Palette Snoop enabled in the COMMAND register of the PCI Config Header
        //
        if (PciConfigurationHeader.Hdr.Command & 0x20) {
          PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
        }

        //
        // If the device is a PCI-PCI Bridge, then look at the Subordinate Bus Number
        //
        if (IS_PCI_BRIDGE(&PciConfigurationHeader)) {
          //
          // Get the Bus range that the PPB is decoding
          //
          if (PciConfigurationHeader.Bridge.P2PBridge.SubordinateBus > PrivateData->SubordinateBus) {
            //
            // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's
            // current subordinate bus number, then update the PCI root bridge's subordinate bus number 
            //
            PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.P2PBridge.SubordinateBus;
          }

          //
          // Get the I/O range that the PPB is decoding
          //
          Value = PciConfigurationHeader.Bridge.P2PBridge.IoBase & 0x0f;
          Base  = ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoBase & 0xf0) << 8;
          Limit = (((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoLimit & 0xf0) << 8) | 0x0fff;
          if (Value == 0x01) {
            Base  |= ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoBaseUpper16 << 16);
            Limit |= ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.IoLimitUpper16 << 16);
          }
          if (Base < Limit) {
            if (PrivateData->IoBase > Base) {
              PrivateData->IoBase = Base;
            }
            if (PrivateData->IoLimit < Limit) {
              PrivateData->IoLimit = Limit;
            }
          }

          //
          // Get the Memory range that the PPB is decoding
          //
          Base  = ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.MemoryBase & 0xfff0) << 16;
          Limit = (((UINT32)PciConfigurationHeader.Bridge.P2PBridge.MemoryLimit & 0xfff0) << 16) | 0xfffff;
          if (Base < Limit) {
            if (PrivateData->MemBase > Base) {
              PrivateData->MemBase = Base;
            }
            if (PrivateData->MemLimit < Limit) {
              PrivateData->MemLimit = Limit;
            }
            if (PrivateData->Mem32Base > Base) {
              PrivateData->Mem32Base = Base;
            }
            if (PrivateData->Mem32Limit < Limit) {
              PrivateData->Mem32Limit = Limit;
            }
          }

          //
          // Get the Prefetchable Memory range that the PPB is decoding
          //
          Value = PciConfigurationHeader.Bridge.P2PBridge.PrefetchableMemoryBase & 0x0f;
          Base  = ((UINT32)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableMemoryBase & 0xfff0) << 16;
          Limit = (((UINT32)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableMemoryLimit & 0xfff0) << 16) | 0xffffff;
          if (Value == 0x01) {
            Base  |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableBaseUpper32,32);
            Limit |= LShiftU64((UINT64)PciConfigurationHeader.Bridge.P2PBridge.PrefetchableLimitUpper32,32);
          }
          if (Base < Limit) {
            if (PrivateData->MemBase > Base) {
              PrivateData->MemBase = Base;
            }
            if (PrivateData->MemLimit < Limit) {
              PrivateData->MemLimit = Limit;
            }
            if (Value == 0x00) {
              if (PrivateData->Pmem32Base > Base) {
                PrivateData->Pmem32Base = Base;
              }
              if (PrivateData->Pmem32Limit < Limit) {
                PrivateData->Pmem32Limit = Limit;
              }
            }
            if (Value == 0x01) {
              if (PrivateData->Pmem64Base > Base) {
                PrivateData->Pmem64Base = Base;
              }
              if (PrivateData->Pmem64Limit < Limit) {
                PrivateData->Pmem64Limit = Limit;
              }
            }
          }

          //
          // Look at the PPB Configuration for legacy decoding attributes
          //
          if (PciConfigurationHeader.Bridge.P2PBridge.BridgeControl & 0x04) {
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;
          }
          if (PciConfigurationHeader.Bridge.P2PBridge.BridgeControl & 0x08) {
           // PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          }

        } else if (IS_CARDBUS_BRIDGE(&PciConfigurationHeader)) {
          //
          // Get the Bus range that the PPB is decoding
          //
          if (PciConfigurationHeader.Bridge.CardBridge.SubordinateBusNumber > PrivateData->SubordinateBus) {
            //
            // If the suborinate bus number of the PCI-PCI bridge is greater than the PCI root bridge's
            // current subordinate bus number, then update the PCI root bridge's subordinate bus number 
            //
            PrivateData->SubordinateBus = PciConfigurationHeader.Bridge.CardBridge.SubordinateBusNumber;
          }
          
          //
          // Get the I/O range that the PPB is decoding
          //
          Base  = PciConfigurationHeader.Bridge.CardBridge.IoBase0;
          Limit = PciConfigurationHeader.Bridge.CardBridge.IoLimit0;
          if (Base < Limit) {
            if (PrivateData->IoBase > Base) {
              PrivateData->IoBase = Base;
            }
            if (PrivateData->IoLimit < Limit) {
              PrivateData->IoLimit = Limit;
            }
          }
          
          //
          // Get the Memory range that the PPB is decoding
          //
          Base  = PciConfigurationHeader.Bridge.CardBridge.MemoryBase0;
          Limit = PciConfigurationHeader.Bridge.CardBridge.MemoryLimit0;
          if (Base < Limit) {
            if (PrivateData->MemBase > Base) {
              PrivateData->MemBase = Base;
            }
            if (PrivateData->MemLimit < Limit) {
              PrivateData->MemLimit = Limit;
            }
            if (PrivateData->Mem32Base > Base) {
              PrivateData->Mem32Base = Base;
            }
            if (PrivateData->Mem32Limit < Limit) {
              PrivateData->Mem32Limit = Limit;
            }
          }
          
        } else 
          {
          //
          // Parse the BARs of the PCI device to determine what I/O Ranges,
          // Memory Ranges, and Prefetchable Memory Ranges the device is decoding
          //
          if ((PciConfigurationHeader.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) {
            Status = PcatPciRootBridgeParseBars (
                       PrivateData, 
                       PciConfigurationHeader.Hdr.Command,
                       PrimaryBusIndex, 
                       Device, 
                       Function
                       );
          }

          //
          // See if the PCI device is an IDE controller
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x01 &&
              PciConfigurationHeader.Hdr.ClassCode[1] == 0x01    ) {
            if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x80) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
            }
            if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x01) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO;
            }
            if (PciConfigurationHeader.Hdr.ClassCode[0] & 0x04) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO;
            }
          }

          //
          // See if the PCI device is a legacy VGA controller
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x00 &&
              PciConfigurationHeader.Hdr.ClassCode[1] == 0x01    ) {
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          }

          //
          // See if the PCI device is a standard VGA controller
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x03 &&
              PciConfigurationHeader.Hdr.ClassCode[1] == 0x00    ) {
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY;
            PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO;
          }

          //
          // See if the PCI Device is a PCI - ISA or PCI - EISA 
          // or ISA_POSITIVIE_DECODE Bridge device
          //
          if (PciConfigurationHeader.Hdr.ClassCode[2] == 0x06) {
            if (PciConfigurationHeader.Hdr.ClassCode[1] == 0x01 ||
                PciConfigurationHeader.Hdr.ClassCode[1] == 0x02 || 
                PciConfigurationHeader.Hdr.ClassCode[1] == 0x80 ) {
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO;
              PrivateData->Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO;

              if (PrivateData->MemBase > 0xa0000) {
                PrivateData->MemBase = 0xa0000;
              }
              if (PrivateData->MemLimit < 0xbffff) {
               PrivateData->MemLimit = 0xbffff;
             }
            }
          }
        }

        //
        // If this device is not a multi function device, then skip the rest of this PCI device
        //
        if (Function == 0 && !(PciConfigurationHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) {
          break;
        }
      }
    }

    //
    // After scanning all the PCI devices on the PCI root bridge's primary bus, update the 
    // Primary Bus Number for the next PCI root bridge to be this PCI root bridge's subordinate
    // bus number + 1.
    //
    PrimaryBusIndex = PrivateData->SubordinateBus + 1;

    //
    // If at least one PCI device was found on the primary bus of this PCI root bridge, then the PCI root bridge
    // exists.
    //
    if (NumberOfPciDevices > 0) {

      //
      // Adjust the I/O range used for bounds checking for the legacy decoding attributed
      //
      if (PrivateData->Attributes & 0x7f) {
        PrivateData->IoBase = 0;
        if (PrivateData->IoLimit < 0xffff) {
          PrivateData->IoLimit = 0xffff;
        }
      }

      //
      // Adjust the Memory range used for bounds checking for the legacy decoding attributed
      //
      if (PrivateData->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) {
        if (PrivateData->MemBase > 0xa0000) {
          PrivateData->MemBase = 0xa0000;
        }
        if (PrivateData->MemLimit < 0xbffff) {
          PrivateData->MemLimit = 0xbffff;
        }
      }

      //
      // Build ACPI descriptors for the resources on the PCI Root Bridge
      //
      Status = ConstructConfiguration(PrivateData);
      ASSERT_EFI_ERROR (Status);

      //
      // Create the handle for this PCI Root Bridge 
      //
      Status = gBS->InstallMultipleProtocolInterfaces (
                     &PrivateData->Handle,              
                     &gEfiDevicePathProtocolGuid,
                     PrivateData->DevicePath,
                     &gEfiPciRootBridgeIoProtocolGuid,
                     &PrivateData->Io,
                     NULL
                     );
      ASSERT_EFI_ERROR (Status);

      //
      // Contruct DeviceIoProtocol
      //
      Status = DeviceIoConstructor (
                 PrivateData->Handle,
                 &PrivateData->Io,
                 PrivateData->DevicePath,
                 (UINT16)PrivateData->PrimaryBus,
                 (UINT16)PrivateData->SubordinateBus
                 );
      ASSERT_EFI_ERROR (Status);
#if 0 //patch by nms42
      //
      // Scan this PCI Root Bridge for PCI Option ROMs and add them to the PCI Option ROM Table
      //
      Status = ScanPciRootBridgeForRoms(&PrivateData->Io);
#endif
      //
      // Increment the index for the next PCI Root Bridge
      //
      PciRootBridgeIndex++;

    } else {

      //
      // If no PCI Root Bridges were found on the current PCI segment, then exit
      //
      if (NumberOfPciRootBridges == 0) {
        Status = EFI_SUCCESS;
        goto Done;
      }

    }

    //
    // If the PrimaryBusIndex is greater than the maximum allowable PCI bus number, then
    // the PCI Segment Number is incremented, and the next segment is searched starting at Bus #0
    // Otherwise, the search is continued on the next PCI Root Bridge
    //
    if (PrimaryBusIndex > PCI_MAX_BUS) {
      PciSegmentIndex++;
      NumberOfPciRootBridges = 0;
      PrimaryBusIndex = 0;
    } else {
      NumberOfPciRootBridges++;
    }

  }

  return EFI_SUCCESS;

Done:
  //
  // Clean up memory allocated for the PCI Root Bridge that was searched but not created.
  //
  if (PrivateData) {
    if (PrivateData->DevicePath) {
      gBS->FreePool(PrivateData->DevicePath);
    }
    gBS->FreePool (PrivateData);
  }

  //
  // If no PCI Root Bridges were discovered, then return the error condition from scanning the
  // first PCI Root Bridge
  //
  if (PciRootBridgeIndex == 0) {
    return Status;
  }

  return EFI_SUCCESS;
}