/** @file
IIO PCI Root Bridge Io Protocol code. Generic enough to work for all IIOs.
Does not support configuration accesses to the extended PCI Express registers yet.

Copyright (c) 2013-2015 Intel Corporation.

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.


**/

#include "PciRootBridge.h"

//
// Define PCI express offse
//
#define PCIE_OFF(Bus, Device, Function, Register) \
    ((UINT64) ((UINTN) (Bus << 20) + (UINTN) (Device << 15) + (UINTN) (Function << 12) + (UINTN) (Register)))

//
// Pci Root Bridge Io Module Variables
//
EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
EFI_CPU_IO2_PROTOCOL        *mCpuIo;

EFI_STATUS
SimpleIioRootBridgeConstructor (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *Protocol,
  IN EFI_HANDLE                            HostBridgeHandle,
  IN PCI_ROOT_BRIDGE_RESOURCE_APERTURE     *ResAperture,
  UINT64                                   AllocAttributes
  )
/*++

Routine Description:

  Construct the Pci Root Bridge Io protocol.

Arguments:

  Protocol          -  Protocol to initialize.
  HostBridgeHandle  -  Handle to the HostBridge.
  ResAperture       -  Resource apperture of the root bridge.
  AllocAttributes   -  Attribute of resouce allocated.

Returns:

  EFI_SUCCESS  -  Success.
  Others       -  Fail.

--*/
{
  EFI_STATUS                Status;
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
  PCI_RESOURCE_TYPE         Index;
  UINT32                    HecBase;
  UINT32                    HecSize;

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (Protocol);

  //
  // Initialize the apertures with default values
  //
  CopyMem (
    &PrivateData->Aperture,
    ResAperture,
    sizeof (PCI_ROOT_BRIDGE_RESOURCE_APERTURE)
    );

  for (Index = TypeIo; Index < TypeMax; Index++) {
    PrivateData->ResAllocNode[Index].Type   = Index;
    PrivateData->ResAllocNode[Index].Base   = 0;
    PrivateData->ResAllocNode[Index].Length = 0;
    PrivateData->ResAllocNode[Index].Status = ResNone;
  }

  EfiInitializeLock (&PrivateData->PciLock, TPL_HIGH_LEVEL);
  PrivateData->PciAddress             = 0xCF8;
  PrivateData->PciData                = 0xCFC;

  PrivateData->RootBridgeAllocAttrib  = AllocAttributes;
  PrivateData->Attributes             = 0;
  PrivateData->Supports = EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO |
    EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |
    EFI_PCI_ATTRIBUTE_ISA_IO_16         |
    EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 |
    EFI_PCI_ATTRIBUTE_VGA_MEMORY |
    EFI_PCI_ATTRIBUTE_VGA_IO_16;

  //
  // Don't support BASE above 4GB currently
  // Position to bit 39:28
  //
  HecBase = (UINT32) PcdGet64 (PcdPciExpressBaseAddress);
  HecSize = (UINT32) PcdGet64 (PcdPciExpressSize);

  ASSERT ((HecBase & (HecSize - 1)) == 0);
  ASSERT (HecBase != 0);

  PrivateData->HecBase            = HecBase;
  PrivateData->HecLen             = HecSize;

  PrivateData->BusNumberAssigned  = FALSE;
  PrivateData->BusScanCount       = 0;

  Protocol->ParentHandle          = HostBridgeHandle;

  Protocol->PollMem               = RootBridgeIoPollMem;
  Protocol->PollIo                = RootBridgeIoPollIo;

  Protocol->Mem.Read              = RootBridgeIoMemRead;
  Protocol->Mem.Write             = RootBridgeIoMemWrite;

  Protocol->Io.Read               = RootBridgeIoIoRead;
  Protocol->Io.Write              = RootBridgeIoIoWrite;

  Protocol->CopyMem               = RootBridgeIoCopyMem;

  Protocol->Pci.Read              = RootBridgeIoPciRead;
  Protocol->Pci.Write             = RootBridgeIoPciWrite;

  Protocol->Map                   = RootBridgeIoMap;
  Protocol->Unmap                 = RootBridgeIoUnmap;

  Protocol->AllocateBuffer        = RootBridgeIoAllocateBuffer;
  Protocol->FreeBuffer            = RootBridgeIoFreeBuffer;

  Protocol->Flush                 = RootBridgeIoFlush;

  Protocol->GetAttributes         = RootBridgeIoGetAttributes;
  Protocol->SetAttributes         = RootBridgeIoSetAttributes;

  Protocol->Configuration         = RootBridgeIoConfiguration;

  Protocol->SegmentNumber         = 0;

  Status                          = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);
  ASSERT_EFI_ERROR (Status);

  Status = gBS->LocateProtocol (
                  &gEfiCpuIo2ProtocolGuid,
                  NULL,
                  (VOID **) &mCpuIo
                  );
  ASSERT_EFI_ERROR (Status);

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoPollMem (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN  UINT64                                 Address,
  IN  UINT64                                 Mask,
  IN  UINT64                                 Value,
  IN  UINT64                                 Delay,
  OUT UINT64                                 *Result
  )
/*++

Routine Description:

  Poll an address in memory mapped space until an exit condition is met
  or a timeout occurs.

Arguments:

  This     -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Width    -  Width of the memory operation.
  Address  -  The base address of the memory operation.
  Mask     -  Mask used for polling criteria.
  Value    -  Comparison value used for polling exit criteria.
  Delay    -  Number of 100ns units to poll.
  Result   -  Pointer to the last value read from memory location.

Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_TIMEOUT            -  Delay expired before a match occurred.
  EFI_OUT_OF_RESOURCES   -  Fail due to lack of resources.

--*/
{
  EFI_STATUS  Status;
  UINT64      NumberOfTicks;
  UINT32       Remainder;

  if (Result == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 || Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // No matter what, always do a single poll.
  //
  Status = This->Mem.Read (
                      This,
                      Width,
                      Address,
                      1,
                      Result
                      );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  if ((*Result & Mask) == Value) {
    return EFI_SUCCESS;
  }

  if (Delay != 0) {
    //
    // Determine the proper # of metronome ticks to wait for polling the
    // location.  The nuber of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
    // The "+1" to account for the possibility of the first tick being short
    // because we started in the middle of a tick.
    //
    // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
    // protocol definition is updated.
    //
    NumberOfTicks = DivU64x32Remainder (
                      Delay,
                      (UINT32) mMetronome->TickPeriod,
                      &Remainder
                      );
    if (Remainder != 0) {
      NumberOfTicks += 1;
    }

    NumberOfTicks += 1;

    while (NumberOfTicks) {

      mMetronome->WaitForTick (mMetronome, 1);

      Status = This->Mem.Read (
                          This,
                          Width,
                          Address,
                          1,
                          Result
                          );
      if (EFI_ERROR (Status)) {
        return Status;
      }

      if ((*Result & Mask) == Value) {
        return EFI_SUCCESS;
      }

      NumberOfTicks -= 1;
    }
  }

  return EFI_TIMEOUT;
}

EFI_STATUS
EFIAPI
RootBridgeIoPollIo (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN  UINT64                                 Address,
  IN  UINT64                                 Mask,
  IN  UINT64                                 Value,
  IN  UINT64                                 Delay,
  OUT UINT64                                 *Result
  )
/*++

Routine Description:

  Poll an address in I/O space until an exit condition is met
  or a timeout occurs.

Arguments:

  This     -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Width    -  Width of I/O operation.
  Address  -  The base address of the I/O operation.
  Mask     -  Mask used for polling criteria.
  Value    -  Comparison value used for polling exit criteria.
  Delay    -  Number of 100ns units to poll.
  Result   -  Pointer to the last value read from memory location.

Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_TIMEOUT            -  Delay expired before a match occurred.
  EFI_OUT_OF_RESOURCES   -  Fail due to lack of resources.

--*/
{
  EFI_STATUS  Status;
  UINT64      NumberOfTicks;
  UINT32       Remainder;

  //
  // No matter what, always do a single poll.
  //
  if (Result == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 || Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }

  Status = This->Io.Read (
                      This,
                      Width,
                      Address,
                      1,
                      Result
                      );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  if ((*Result & Mask) == Value) {
    return EFI_SUCCESS;
  }

  if (Delay != 0) {
    //
    // Determine the proper # of metronome ticks to wait for polling the
    // location.  The number of ticks is Roundup (Delay / mMetronome->TickPeriod)+1
    // The "+1" to account for the possibility of the first tick being short
    // because we started in the middle of a tick.
    //
    NumberOfTicks = DivU64x32Remainder (
                      Delay,
                      (UINT32) mMetronome->TickPeriod,
                      &Remainder
                      );
    if (Remainder != 0) {
      NumberOfTicks += 1;
    }

    NumberOfTicks += 1;

    while (NumberOfTicks) {

      mMetronome->WaitForTick (mMetronome, 1);

      Status = This->Io.Read (
                          This,
                          Width,
                          Address,
                          1,
                          Result
                          );
      if (EFI_ERROR (Status)) {
        return Status;
      }

      if ((*Result & Mask) == Value) {
        return EFI_SUCCESS;
      }

      NumberOfTicks -= 1;
    }
  }

  return EFI_TIMEOUT;
}

EFI_STATUS
EFIAPI
RootBridgeIoMemRead (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN     UINT64                                 Address,
  IN     UINTN                                  Count,
  IN OUT VOID                                   *Buffer
  )
/*++

Routine Description:

  Allow read from memory mapped I/O space.

Arguments:

  This     -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Width    -  The width of memory operation.
  Address  -  Base address of the memory operation.
  Count    -  Number of memory opeartion to perform.
  Buffer   -  The destination buffer to store data.

Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_OUT_OF_RESOURCES   -  Fail due to lack of resources.

--*/
{
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 ||
      Width == EfiPciWidthUint64 ||
      Width == EfiPciWidthFifoUint64 ||
      Width == EfiPciWidthFillUint64 ||
      Width >= EfiPciWidthMaximum
      ) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);
  //
  // Check memory access limit
  //
  if (PrivateData->Aperture.Mem64Limit > PrivateData->Aperture.Mem64Base) {
      if (Address > PrivateData->Aperture.Mem64Limit) {
        return EFI_INVALID_PARAMETER;
      }
  } else {
      if (Address > PrivateData->Aperture.Mem32Limit) {
        return EFI_INVALID_PARAMETER;
      }
  }

  return mCpuIo->Mem.Read (
                      mCpuIo,
                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
                      Address,
                      Count,
                      Buffer
                      );
}

EFI_STATUS
EFIAPI
RootBridgeIoMemWrite (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN     UINT64                                 Address,
  IN     UINTN                                  Count,
  IN OUT VOID                                   *Buffer
  )
/*++

Routine Description:

  Allow write to memory mapped I/O space.

Arguments:

  This     -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Width    -  The width of memory operation.
  Address  -  Base address of the memory operation.
  Count    -  Number of memory opeartion to perform.
  Buffer   -  The source buffer to write data from.

Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_OUT_OF_RESOURCES   -  Fail due to lack of resources.

--*/
{
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;

  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 ||
      Width == EfiPciWidthUint64 ||
      Width == EfiPciWidthFifoUint64 ||
      Width == EfiPciWidthFillUint64 ||
      Width >= EfiPciWidthMaximum
      ) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  //
  // Check memory access limit
  //
  if (PrivateData->Aperture.Mem64Limit > PrivateData->Aperture.Mem64Base) {
      if (Address > PrivateData->Aperture.Mem64Limit) {
        return EFI_INVALID_PARAMETER;
      }
  } else {
      if (Address > PrivateData->Aperture.Mem32Limit) {
        return EFI_INVALID_PARAMETER;
      }
  }

  return mCpuIo->Mem.Write (
                      mCpuIo,
                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
                      Address,
                      Count,
                      Buffer
                      );
}

EFI_STATUS
EFIAPI
RootBridgeIoIoRead (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN     UINT64                                 Address,
  IN     UINTN                                  Count,
  IN OUT VOID                                   *Buffer
  )
/*++

Routine Description:

  Enable a PCI driver to read PCI controller registers in the
  PCI root bridge I/O space.

Arguments:

  This     -  A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
  Width    -  Signifies the width of the memory operation.
  Address  -  The base address of the I/O operation.
  Count    -  The number of I/O operations to perform.
  Buffer   -  The destination buffer to store the results.

Returns:

  EFI_SUCCESS            -  The data was read from the PCI root bridge.
  EFI_INVALID_PARAMETER  -  Invalid parameters found.
  EFI_OUT_OF_RESOURCES   -  The request could not be completed due to a lack of
                            resources.
--*/
{

  UINTN                     AlignMask;
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;

  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 ||
      Width == EfiPciWidthUint64 ||
      Width == EfiPciWidthFifoUint64 ||
      Width == EfiPciWidthFillUint64 ||
      Width >= EfiPciWidthMaximum
      ) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  //
  // AlignMask = (1 << Width) - 1;
  //
  AlignMask = (1 << (Width & 0x03)) - 1;

  //
  // check Io access limit
  //
  if (Address > PrivateData->Aperture.IoLimit) {
    return EFI_INVALID_PARAMETER;
  }

  if (Address & AlignMask) {
    return EFI_INVALID_PARAMETER;
  }

  return mCpuIo->Io.Read (
                      mCpuIo,
                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
                      Address,
                      Count,
                      Buffer
                      );

}

EFI_STATUS
EFIAPI
RootBridgeIoIoWrite (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL          *This,
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
  IN     UINT64                                   Address,
  IN     UINTN                                    Count,
  IN OUT VOID                                     *Buffer
  )
/*++

Routine Description:

  Enable a PCI driver to write to PCI controller registers in the
  PCI root bridge I/O space.

Arguments:

  This     -  A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
  Width    -  Signifies the width of the memory operation.
  Address  -  The base address of the I/O operation.
  Count    -  The number of I/O operations to perform.
  Buffer   -  The source buffer to write data from.

Returns:

  EFI_SUCCESS            -  The data was written to the PCI root bridge.
  EFI_INVALID_PARAMETER  -  Invalid parameters found.
  EFI_OUT_OF_RESOURCES   -  The request could not be completed due to a lack of
                            resources.
--*/
{
  UINTN                     AlignMask;
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;

  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 ||
      Width == EfiPciWidthUint64 ||
      Width == EfiPciWidthFifoUint64 ||
      Width == EfiPciWidthFillUint64 ||
      Width >= EfiPciWidthMaximum
      ) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  //
  // AlignMask = (1 << Width) - 1;
  //
  AlignMask = (1 << (Width & 0x03)) - 1;

  //
  // Check Io access limit
  //
  if (Address > PrivateData->Aperture.IoLimit) {
    return EFI_INVALID_PARAMETER;
  }

  if (Address & AlignMask) {
    return EFI_INVALID_PARAMETER;
  }

  return mCpuIo->Io.Write (
                      mCpuIo,
                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
                      Address,
                      Count,
                      Buffer
                      );

}

EFI_STATUS
EFIAPI
RootBridgeIoCopyMem (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL           *This,
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH     Width,
  IN UINT64                                    DestAddress,
  IN UINT64                                    SrcAddress,
  IN UINTN                                     Count
  )
/*++

Routine Description:

  Copy one region of PCI root bridge memory space to be copied to
  another region of PCI root bridge memory space.

Arguments:

  This         -  A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Width        -  Signifies the width of the memory operation.
  DestAddress  -  Destination address of the memory operation.
  SrcAddress   -  Source address of the memory operation.
  Count        -  Number of memory operations to perform.

Returns:

  EFI_SUCCESS            -  The data was copied successfully.
  EFI_INVALID_PARAMETER  -  Invalid parameters found.
  EFI_OUT_OF_RESOURCES   -  The request could not be completed due to a lack of
                            resources.
--*/
{
  EFI_STATUS  Status;
  BOOLEAN     Direction;
  UINTN       Stride;
  UINTN       Index;
  UINT64      Result;

  if (Width < 0 || Width > EfiPciWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }

  if (DestAddress == SrcAddress) {
    return EFI_SUCCESS;
  }

  Stride    = (UINTN)1 << Width;

  Direction = TRUE;
  if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) {
    Direction   = FALSE;
    SrcAddress  = SrcAddress + (Count - 1) * Stride;
    DestAddress = DestAddress + (Count - 1) * Stride;
  }

  for (Index = 0; Index < Count; Index++) {
    Status = RootBridgeIoMemRead (
              This,
              Width,
              SrcAddress,
              1,
              &Result
              );
    if (EFI_ERROR (Status)) {
      return Status;
    }

    Status = RootBridgeIoMemWrite (
              This,
              Width,
              DestAddress,
              1,
              &Result
              );
    if (EFI_ERROR (Status)) {
      return Status;
    }

    if (Direction) {
      SrcAddress += Stride;
      DestAddress += Stride;
    } else {
      SrcAddress -= Stride;
      DestAddress -= Stride;
    }
  }

  return EFI_SUCCESS;
}

EFI_STATUS
RootBridgeIoPciRW (
  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
  )
/*++

Routine Description:

Arguments:

Returns:

--*/
{
  PCI_CONFIG_ACCESS_CF8             Pci;
  PCI_CONFIG_ACCESS_CF8             PciAligned;
  UINT32                            Stride;
  UINTN                             PciData;
  UINTN                             PciDataStride;
  PCI_ROOT_BRIDGE_INSTANCE         *PrivateData;

  if (Width >= EfiPciWidthMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);

  ASSERT (((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*)&UserAddress)->ExtendedRegister == 0x00);

  Stride = 1 << Width;

  Pci.Bits.Reg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Register;
  Pci.Bits.Func = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Function;
  Pci.Bits.Dev = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Device;
  Pci.Bits.Bus = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Bus;
  Pci.Bits.Reserved = 0;
  Pci.Bits.Enable = 1;

  //
  // PCI Configure access are all 32-bit aligned, but by accessing the
  //  CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types
  //  are possible on PCI.
  //
  // To read a byte of PCI configuration space you load 0xcf8 and
  //  read 0xcfc, 0xcfd, 0xcfe, 0xcff
  //
  PciDataStride = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Register & 0x03;

  while (Count) {
    PciAligned = Pci;
    PciAligned.Bits.Reg &= 0xfc;
    PciData = 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) + Stride;
    PciDataStride = (PciDataStride + Stride) % 4;
    Count -= 1;

    //
    // Only increment the PCI address if Width is not a FIFO.
    //
    if (Width >= EfiPciWidthUint8 && Width <= EfiPciWidthUint64) {
      Pci.Bits.Reg += Stride;
    }
  }
  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoPciRead (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL          *This,
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
  IN     UINT64                                   Address,
  IN     UINTN                                    Count,
  IN OUT VOID                                     *Buffer
  )
/*++

Routine Description:

  Allows read from PCI configuration space.

Arguments:

  This     -  A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
  Width    -  Signifies the width of the memory operation.
  Address  -  The address within the PCI configuration space
              for the PCI controller.
  Count    -  The number of PCI configuration operations
              to perform.
  Buffer   -  The destination buffer to store the results.

Returns:

  EFI_SUCCESS            -  The data was read from the PCI root bridge.
  EFI_INVALID_PARAMETER  -  Invalid parameters found.
  EFI_OUT_OF_RESOURCES   -  The request could not be completed due to a lack of
                            resources.
--*/
{
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
  UINT32                    PciBus;
  UINT32                    PciDev;
  UINT32                    PciFn;
  UINT32                    PciExtReg;
  UINT64                    ExtConfigAdd;

  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 ||
      Width == EfiPciWidthUint64 ||
      Width == EfiPciWidthFifoUint64 ||
      Width == EfiPciWidthFillUint64 ||
      Width >= EfiPciWidthMaximum
      ) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Read Pci configuration space
  //
  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  if (PrivateData->HecBase == 0) {
    return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
  }

  if (!((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister) {
    PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Register;
  } else {
    PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister & 0x0FFF;
  }

  PciBus        = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Bus;
  PciDev        = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Device;
  PciFn         = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Function;

  ExtConfigAdd  = (UINT64) PrivateData->HecBase + PCIE_OFF (PciBus, PciDev, PciFn, PciExtReg);

  return mCpuIo->Mem.Read (
                      mCpuIo,
                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
                      ExtConfigAdd,
                      Count,
                      Buffer
                      );
}

EFI_STATUS
EFIAPI
RootBridgeIoPciWrite (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL          *This,
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH    Width,
  IN UINT64                                   Address,
  IN UINTN                                    Count,
  IN OUT VOID                                 *Buffer
  )
/*++

Routine Description:

  Allows write to PCI configuration space.

Arguments:

  This     -  A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
  Width    -  Signifies the width of the memory operation.
  Address  -  The address within the PCI configuration space
              for the PCI controller.
  Count    -  The number of PCI configuration operations
              to perform.
  Buffer   -  The source buffer to get the results.

Returns:

  EFI_SUCCESS            -  The data was written to the PCI root bridge.
  EFI_INVALID_PARAMETER  -  Invalid parameters found.
  EFI_OUT_OF_RESOURCES   -  The request could not be completed due to a lack of
                            resources.
--*/
{
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
  UINT32                    PciBus;
  UINT32                    PciDev;
  UINT32                    PciFn;
  UINT32                    PciExtReg;
  UINT64                    ExtConfigAdd;

  if (Buffer == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (Width < 0 || Width >= EfiPciWidthMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // Write Pci configuration space
  //
  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  if (PrivateData->HecBase == 0) {
    return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
  }

  if (!((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister) {
    PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Register;
  } else {
    PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister & 0x0FFF;
  }

  PciBus        = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Bus;
  PciDev        = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Device;
  PciFn         = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Function;

  ExtConfigAdd  = (UINT64) PrivateData->HecBase + PCIE_OFF (PciBus, PciDev, PciFn, PciExtReg);

  return mCpuIo->Mem.Write (
                      mCpuIo,
                      (EFI_CPU_IO_PROTOCOL_WIDTH) Width,
                      ExtConfigAdd,
                      Count,
                      Buffer
                      );
}

EFI_STATUS
EFIAPI
RootBridgeIoMap (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL            *This,
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION  Operation,
  IN     VOID                                       *HostAddress,
  IN OUT UINTN                                      *NumberOfBytes,
  OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
  OUT    VOID                                       **Mapping
  )
/*++

Routine Description:

  Provides the PCI controller-specific address needed to access
  system memory for DMA.

Arguments:

  This           -  A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
  Operation      -  Indicate if the bus master is going to read or write
                    to system memory.
  HostAddress    -  The system memory address to map on the PCI controller.
  NumberOfBytes  -  On input the number of bytes to map.
                    On output the number of bytes that were mapped.
  DeviceAddress  -  The resulting map address for the bus master PCI
                    controller to use to access the system memory's HostAddress.
  Mapping        -  The value to pass to Unmap() when the bus master DMA
                    operation is complete.

Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameters found.
  EFI_UNSUPPORTED        -  The HostAddress cannot be mapped as a common
                            buffer.
  EFI_DEVICE_ERROR       -  The System hardware could not map the requested
                            address.
  EFI_OUT_OF_RESOURCES   -  The request could not be completed due to
                            lack of resources.

--*/
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PhysicalAddress;
  MAP_INFO              *MapInfo;

  if (NumberOfBytes == NULL || Mapping == NULL || DeviceAddress == NULL || HostAddress == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Initialize the return values to their defaults
  //
  *Mapping = NULL;

  //
  // Make sure that Operation is valid
  //
  if ((Operation < 0) || (Operation > EfiPciOperationBusMasterCommonBuffer64)) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Most PCAT like chipsets can not handle performing DMA above 4GB.
  // If any part of the DMA transfer being mapped is above 4GB, then
  // map the DMA transfer to a buffer below 4GB.
  //
  PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
  if ((PhysicalAddress +*NumberOfBytes) > 0x100000000ULL) {
    //
    // Common Buffer operations can not be remapped.  If the common buffer
    // if above 4GB, then it is not possible to generate a mapping, so return
    // an error.
    //
    if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) {
      return EFI_INVALID_PARAMETER;
    }
  }

  if ((PhysicalAddress + *NumberOfBytes) > (DMA_MEMORY_TOP+1)) {

    //
    // Common Buffer operations can not be remapped.
    //
    if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) {
      *DeviceAddress = PhysicalAddress;
      return EFI_SUCCESS;
    }
    //
    // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
    // called later.
    //
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    sizeof (MAP_INFO),
                    (VOID **) &MapInfo
                    );
    if (EFI_ERROR (Status)) {
      *NumberOfBytes = 0;
      return Status;
    }
    //
    // Return a pointer to the MAP_INFO structure in Mapping
    //
    *Mapping = MapInfo;

    //
    // Initialize the MAP_INFO structure
    //
    MapInfo->Operation          = Operation;
    MapInfo->NumberOfBytes      = *NumberOfBytes;
    MapInfo->NumberOfPages      = EFI_SIZE_TO_PAGES (*NumberOfBytes);
    MapInfo->HostAddress        = PhysicalAddress;
    MapInfo->MappedHostAddress  = DMA_MEMORY_TOP;

    //
    // Allocate a buffer below DMA_MEMORY_TOP to map the transfer to.
    //
    Status = gBS->AllocatePages (
                    AllocateMaxAddress,
                    EfiBootServicesData,
                    MapInfo->NumberOfPages,
                    &MapInfo->MappedHostAddress
                    );
    if (EFI_ERROR (Status)) {
      gBS->FreePool (MapInfo);
      *NumberOfBytes = 0;
      return Status;
    }
    //
    // If this is a read operation from the Bus Master's point of view,
    // then copy the contents of the real buffer into the mapped buffer
    // so the Bus Master can read the contents of the real buffer.
    //
    if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) {
      CopyMem (
        (VOID *) (UINTN) MapInfo->MappedHostAddress,
        (VOID *) (UINTN) MapInfo->HostAddress,
        MapInfo->NumberOfBytes
        );
    }
    //
    // The DeviceAddress is the address of the maped buffer below DMA_MEMORY_TOP
    //
    *DeviceAddress = MapInfo->MappedHostAddress;
  } else {
    //
    // The transfer is below DMA_MEMORY_TOP, so the DeviceAddress is simply the HostAddress
    //
    *DeviceAddress = PhysicalAddress;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoUnmap (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
  IN VOID                             *Mapping
  )
/*++

Routine Description:

  Completes the Map() operation and releases any corresponding resources.

Arguments:

  This     -  Pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Mapping  -  The value returned from Map() operation.

Returns:

  EFI_SUCCESS            -  The range was unmapped successfully.
  EFI_INVALID_PARAMETER  -  Mapping is not a value that was returned
                            by Map operation.
  EFI_DEVICE_ERROR       -  The data was not committed to the target
                            system memory.

--*/
{
  MAP_INFO  *MapInfo;

  //
  // See if the Map() operation associated with this Unmap() required a mapping buffer.
  // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS.
  //
  if (Mapping != NULL) {
    //
    // Get the MAP_INFO structure from Mapping
    //
    MapInfo = (MAP_INFO *) Mapping;

    //
    // If this is a write operation from the Bus Master's point of view,
    // then copy the contents of the mapped buffer into the real buffer
    // so the processor can read the contents of the real buffer.
    //
    if ((MapInfo->Operation == EfiPciOperationBusMasterWrite) ||
        (MapInfo->Operation == EfiPciOperationBusMasterWrite64)
        ) {
      CopyMem (
        (VOID *) (UINTN) MapInfo->HostAddress,
        (VOID *) (UINTN) MapInfo->MappedHostAddress,
        MapInfo->NumberOfBytes
        );
    }
    //
    // Free the mapped buffer and the MAP_INFO structure.
    //
    gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages);
    gBS->FreePool (Mapping);
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoAllocateBuffer (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
  IN  EFI_ALLOCATE_TYPE                Type,
  IN  EFI_MEMORY_TYPE                  MemoryType,
  IN  UINTN                            Pages,
  OUT VOID                             **HostAddress,
  IN  UINT64                           Attributes
  )
/*++

Routine Description:

  Allocates pages that are suitable for a common buffer mapping.

Arguments:

  This         -  Pointer to EFI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Type         -  Not used and can be ignored.
  MemoryType   -  Type of memory to allocate.
  Pages        -  Number of pages to allocate.
  HostAddress  -  Pointer to store the base system memory address
                  of the allocated range.
  Attributes   -  Requested bit mask of attributes of the allocated
                  range.

Returns:

  EFI_SUCCESS            -  The requested memory range were allocated.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_UNSUPPORTED        -  Attributes is unsupported.

--*/
{
  EFI_STATUS            Status;
  EFI_PHYSICAL_ADDRESS  PhysicalAddress;

  //
  // Validate Attributes
  //
  if ((Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
    return EFI_UNSUPPORTED;
  }
  //
  // Check for invalid inputs
  //
  if (HostAddress == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
  //
  if ((MemoryType != EfiBootServicesData) && (MemoryType != EfiRuntimeServicesData)) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Limit allocations to memory below DMA_MEMORY_TOP
  //
  PhysicalAddress = DMA_MEMORY_TOP;

  Status = gBS->AllocatePages (
                  AllocateMaxAddress,
                  MemoryType,
                  Pages,
                  &PhysicalAddress
                  );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  *HostAddress = (VOID *) (UINTN) PhysicalAddress;

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoFreeBuffer (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
  IN  UINTN                            Pages,
  OUT VOID                             *HostAddress
  )
/*++

Routine Description:

  Free memory allocated in AllocateBuffer.

Arguments:

  This         -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
                  instance.
  Pages        -  Number of pages to free.
  HostAddress  -  The base system memory address of the
                  allocated range.

Returns:

  EFI_SUCCESS            -  Requested memory pages were freed.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.

--*/
{
  return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
}

EFI_STATUS
EFIAPI
RootBridgeIoFlush (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL       *This
  )
/*++

Routine Description:

  Flushes all PCI posted write transactions from a PCI host
  bridge to system memory.

Arguments:

  This  - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.

Returns:

  EFI_SUCCESS       -  PCI posted write transactions were flushed
                       from PCI host bridge to system memory.
  EFI_DEVICE_ERROR  -  Fail due to hardware error.

--*/
{
  //
  // not supported yet
  //
  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoGetAttributes (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
  OUT UINT64                           *Supported,
  OUT UINT64                           *Attributes
  )
/*++

Routine Description:

  Get the attributes that a PCI root bridge supports and
  the attributes the PCI root bridge is currently using.

Arguments:

  This        -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
                 instance.
  Supports    -  A pointer to the mask of attributes that
                 this PCI root bridge supports.
  Attributes  -  A pointer to the mask of attributes that
                 this PCI root bridge is currently using.
Returns:

  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.

--*/

// GC_TODO:    Supported - add argument and description to function comment
//
// GC_TODO:    Supported - add argument and description to function comment
//
// GC_TODO:    Supported - add argument and description to function comment
//
{
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  if (Attributes == NULL && Supported == NULL) {
    return EFI_INVALID_PARAMETER;
  }
  //
  // Set the return value for Supported and Attributes
  //
  if (Supported) {
    *Supported = PrivateData->Supports;
  }

  if (Attributes) {
    *Attributes = PrivateData->Attributes;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoSetAttributes (
  IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
  IN     UINT64                           Attributes,
  IN OUT UINT64                           *ResourceBase,
  IN OUT UINT64                           *ResourceLength
  )
/*++

Routine Description:

  Sets the attributes for a resource range on a PCI root bridge.

Arguments:

  This            -  Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Attributes      -  The mask of attributes to set.
  ResourceBase    -  Pointer to the base address of the resource range
                     to be modified by the attributes specified by Attributes.
  ResourceLength  -  Pointer to the length of the resource range to be modified.

Returns:
  EFI_SUCCESS            -  Success.
  EFI_INVALID_PARAMETER  -  Invalid parameter found.
  EFI_OUT_OF_RESOURCES   -  Not enough resources to set the attributes upon.

--*/

//
// GC_TODO:    EFI_UNSUPPORTED - add return value to function comment
//
{
  PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;

  PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  if (Attributes != 0) {
    Attributes &= (PrivateData->Supports);
    if (Attributes == 0) {
      return EFI_UNSUPPORTED;
    }
  }

  if (Attributes == PrivateData->Attributes) {
    return EFI_SUCCESS;
  }
  //
  // It is just a trick for some attribute can only be enabled or disabled
  // otherwise it can impact on other devices
  //
  PrivateData->Attributes = Attributes;

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
RootBridgeIoConfiguration (
  IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
  OUT VOID                             **Resources
  )
/*++

Routine Description:

  Retrieves the current resource settings of this PCI root bridge
  in the form of a set of ACPI 2.0 resource descriptor.

Arguments:

  This       -  Pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
  Resources  -  Pointer to the ACPI 2.0 resource descriptor that
                describe the current configuration of this PCI root
                bridge.

Returns:

  EFI_SUCCESS      -  Success.
  EFI_UNSUPPORTED  -  Current configuration of the PCI root bridge
                      could not be retrieved.

--*/

//
// GC_TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
//
{
  EFI_STATUS                        Status;
  UINTN                             Idx;

  PCI_ROOT_BRIDGE_INSTANCE          *RbPrivateData;
  PCI_RES_NODE                      *ResAllocNode;
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Config;

  //
  // Get this instance of the Root Bridge.
  //
  RbPrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS (This);

  //
  // If the pointer is not NULL, it points to a buffer already allocated.
  //
  if (RbPrivateData->ConfigBuffer == NULL) {
    Status = gBS->AllocatePool (
                    EfiBootServicesData,
                    TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
                    &RbPrivateData->ConfigBuffer
                    );
    if (EFI_ERROR (Status)) {
      return EFI_OUT_OF_RESOURCES;
    }
  }

  Config = RbPrivateData->ConfigBuffer;

  ZeroMem (Config, TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));

  for (Idx = 0; Idx < TypeMax; Idx++) {

    ResAllocNode = &RbPrivateData->ResAllocNode[Idx];

    if (ResAllocNode->Status != ResAllocated) {
      continue;
    }

    switch (ResAllocNode->Type) {

    case TypeIo:
      Config->Desc          = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Config->Len           = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
      Config->ResType       = ACPI_ADDRESS_SPACE_TYPE_IO;
      Config->AddrRangeMin  = ResAllocNode->Base;
      Config->AddrRangeMax  = ResAllocNode->Base + ResAllocNode->Length - 1;
      Config->AddrLen       = ResAllocNode->Length;
      break;

    case TypeMem32:
      Config->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Config->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
      Config->ResType               = ACPI_ADDRESS_SPACE_TYPE_MEM;
      Config->AddrSpaceGranularity  = 32;
      Config->AddrRangeMin          = ResAllocNode->Base;
      Config->AddrRangeMax          = ResAllocNode->Base + ResAllocNode->Length - 1;
      Config->AddrLen               = ResAllocNode->Length;
      break;

    case TypePMem32:
      Config->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Config->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
      Config->ResType               = ACPI_ADDRESS_SPACE_TYPE_MEM;
      Config->SpecificFlag          = 6;
      Config->AddrSpaceGranularity  = 32;
      Config->AddrRangeMin          = ResAllocNode->Base;
      Config->AddrRangeMax          = ResAllocNode->Base + ResAllocNode->Length - 1;
      Config->AddrLen               = ResAllocNode->Length;
      break;

    case TypeMem64:
      Config->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Config->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
      Config->ResType               = ACPI_ADDRESS_SPACE_TYPE_MEM;
      Config->SpecificFlag          = 6;
      Config->AddrSpaceGranularity  = 64;
      Config->AddrRangeMin          = ResAllocNode->Base;
      Config->AddrRangeMax          = ResAllocNode->Base + ResAllocNode->Length - 1;
      Config->AddrLen               = ResAllocNode->Length;
      break;

    case TypePMem64:
      Config->Desc                  = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Config->Len                   = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
      Config->ResType               = ACPI_ADDRESS_SPACE_TYPE_MEM;
      Config->SpecificFlag          = 6;
      Config->AddrSpaceGranularity  = 64;
      Config->AddrRangeMin          = ResAllocNode->Base;
      Config->AddrRangeMax          = ResAllocNode->Base + ResAllocNode->Length - 1;
      Config->AddrLen               = ResAllocNode->Length;
      break;

    case TypeBus:
      Config->Desc          = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Config->Len           = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
      Config->ResType       = ACPI_ADDRESS_SPACE_TYPE_BUS;
      Config->AddrRangeMin  = ResAllocNode->Base;
      Config->AddrRangeMax  = ResAllocNode->Base + ResAllocNode->Length - 1;
      Config->AddrLen       = ResAllocNode->Length;
      break;

    default:
      break;
    }

    Config++;
  }
  //
  // Terminate the entries.
  //
  ((EFI_ACPI_END_TAG_DESCRIPTOR *) Config)->Desc      = ACPI_END_TAG_DESCRIPTOR;
  ((EFI_ACPI_END_TAG_DESCRIPTOR *) Config)->Checksum  = 0x0;

  *Resources = RbPrivateData->ConfigBuffer;
  return EFI_SUCCESS;
}
