/** @file

Copyright (c) 2006 - 2008, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution.  The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php

THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

**/

#include "PciBus.h"
#include "PciResourceSupport.h"
#include "PciCommand.h"

/**
  The function is used to skip VGA range
  
  @param Start    address including VGA range
  @param Length   length of VGA range.
  
  @retval EFI_SUCCESS success.
**/
EFI_STATUS
SkipVGAAperture (
  OUT UINT64   *Start,
  IN  UINT64   Length
  )
{
  UINT64  Original;
  UINT64  Mask;
  UINT64  StartOffset;
  UINT64  LimitOffset;

  //
  // For legacy VGA, bit 10 to bit 15 is not decoded
  //
  Mask        = 0x3FF;

  Original    = *Start;
  StartOffset = Original & Mask;
  LimitOffset = ((*Start) + Length - 1) & Mask;
  if (LimitOffset >= VGABASE1) {
    *Start = *Start - StartOffset + VGALIMIT2 + 1;
  }

  return EFI_SUCCESS;
}

/**
  This function is used to skip ISA aliasing aperture.
  
  @param Start    address including ISA aliasing aperture.
  @param Length   length of ISA aliasing aperture.
  
  @retval EFI_SUCCESS success.
**/
EFI_STATUS
SkipIsaAliasAperture (
  OUT UINT64   *Start,
  IN  UINT64   Length
  )
{

  UINT64  Original;
  UINT64  Mask;
  UINT64  StartOffset;
  UINT64  LimitOffset;

  //
  // For legacy ISA, bit 10 to bit 15 is not decoded
  //
  Mask        = 0x3FF;

  Original    = *Start;
  StartOffset = Original & Mask;
  LimitOffset = ((*Start) + Length - 1) & Mask;

  if (LimitOffset >= ISABASE) {
    *Start = *Start - StartOffset + ISALIMIT + 1;
  }

  return EFI_SUCCESS;
}

/**
  This function inserts a resource node into the resource list.
  The resource list is sorted in descend order.

  @param Bridge  PCI resource node for bridge.
  @param ResNode Resource node want to be inserted.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
InsertResourceNode (
  PCI_RESOURCE_NODE *Bridge,
  PCI_RESOURCE_NODE *ResNode
  )
{
  LIST_ENTRY        *CurrentLink;
  PCI_RESOURCE_NODE *Temp;
  UINT64            ResNodeAlignRest;
  UINT64            TempAlignRest;

  InsertHeadList (&Bridge->ChildList, &ResNode->Link);

  CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;
  while (CurrentLink != &Bridge->ChildList) {
    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (ResNode->Alignment > Temp->Alignment) {
      break;
    } else if (ResNode->Alignment == Temp->Alignment) {
      ResNodeAlignRest  = ResNode->Length & ResNode->Alignment;
      TempAlignRest     = Temp->Length & Temp->Alignment;
      if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {
        break;
      }
    }

    SwapListEntries (&ResNode->Link, CurrentLink);

    CurrentLink = ResNode->Link.ForwardLink;
  }

  return EFI_SUCCESS;
}

/**

Routine Description:

  This routine is used to merge two different resource tree in need of
  resoure degradation. For example, if a upstream PPB doesn't support,
  prefetchable memory decoding, the PCI bus driver will choose to call this function
  to merge prefectchable memory resource list into normal memory list.

  If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
  type.

  @param Dst        Point to destination resource tree.
  @param Res        Point to source resource tree.
  @param TypeMerge  If the TypeMerge is TRUE, Res resource type is changed to the type of 
                    destination resource type.
                    
                    
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
MergeResourceTree (
  PCI_RESOURCE_NODE *Dst,
  PCI_RESOURCE_NODE *Res,
  BOOLEAN           TypeMerge
  )
{

  LIST_ENTRY        *CurrentLink;
  PCI_RESOURCE_NODE *Temp;

  while (!IsListEmpty (&Res->ChildList)) {
    CurrentLink = Res->ChildList.ForwardLink;

    Temp        = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (TypeMerge) {
      Temp->ResType = Dst->ResType;
    }

    RemoveEntryList (CurrentLink);
    InsertResourceNode (Dst, Temp);

  }

  return EFI_SUCCESS;
}

/**
  This function is used to calculate the IO16 aperture
  for a bridge.

  @param Bridge PCI resource node for bridge.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
CalculateApertureIo16 (
  IN PCI_RESOURCE_NODE *Bridge
  )
{

  UINT64            Aperture;
  LIST_ENTRY        *CurrentLink;
  PCI_RESOURCE_NODE *Node;
  UINT64            Offset;
  BOOLEAN           IsaEnable;
  BOOLEAN           VGAEnable;

  //
  // Always assume there is ISA device and VGA device on the platform
  // will be customized later
  //
  IsaEnable = FALSE;
  VGAEnable = FALSE;

  if (FeaturePcdGet (PcdPciIsaEnable)){
    IsaEnable = TRUE;
  }

  if (FeaturePcdGet (PcdPciVgaEnable)){
    VGAEnable = TRUE;
  }

  Aperture = 0;

  if (Bridge == NULL) {
    return EFI_SUCCESS;
  }

  CurrentLink = Bridge->ChildList.ForwardLink;

  //
  // Assume the bridge is aligned
  //
  while (CurrentLink != &Bridge->ChildList) {

    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);

    //
    // Consider the aperture alignment
    //
    Offset = Aperture & (Node->Alignment);

    if (Offset != 0) {

      Aperture = Aperture + (Node->Alignment + 1) - Offset;

    }

    //
    // IsaEnable and VGAEnable can not be implemented now.
    // If both of them are enabled, then the IO resource would
    // become too limited to meet the requirement of most of devices.
    //

    if (IsaEnable || VGAEnable) {
      if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
        //
        // Check if there is need to support ISA/VGA decoding
        // If so, we need to avoid isa/vga aliasing range
        //
        if (IsaEnable) {
          SkipIsaAliasAperture (
            &Aperture,
            Node->Length               
            );
          Offset = Aperture & (Node->Alignment);
          if (Offset != 0) {
            Aperture = Aperture + (Node->Alignment + 1) - Offset;
          }
        } else if (VGAEnable) {
          SkipVGAAperture (
            &Aperture,
            Node->Length
            );
          Offset = Aperture & (Node->Alignment);
          if (Offset != 0) {
            Aperture = Aperture + (Node->Alignment + 1) - Offset;
          }
        }
      }
    }

    Node->Offset = Aperture;

    //
    // Increment aperture by the length of node
    //
    Aperture += Node->Length;

    CurrentLink = CurrentLink->ForwardLink;
  }

  //
  // At last, adjust the aperture with the bridge's
  // alignment
  //
  Offset = Aperture & (Bridge->Alignment);

  if (Offset != 0) {
    Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
  }

  Bridge->Length = Aperture;
  //
  // At last, adjust the bridge's alignment to the first child's alignment
  // if the bridge has at least one child
  //
  CurrentLink = Bridge->ChildList.ForwardLink;
  if (CurrentLink != &Bridge->ChildList) {
    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
    if (Node->Alignment > Bridge->Alignment) {
      Bridge->Alignment = Node->Alignment;
    }
  }

  return EFI_SUCCESS;
}

/**
  This function is used to calculate the resource aperture
  for a given bridge device.

  @param Bridge Give bridge device.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
CalculateResourceAperture (
  IN PCI_RESOURCE_NODE *Bridge
  )
{
  UINT64            Aperture;
  LIST_ENTRY        *CurrentLink;
  PCI_RESOURCE_NODE *Node;

  UINT64            Offset;

  Aperture = 0;

  if (Bridge == NULL) {
    return EFI_SUCCESS;
  }

  if (Bridge->ResType == PciBarTypeIo16) {
    return CalculateApertureIo16 (Bridge);
  }

  CurrentLink = Bridge->ChildList.ForwardLink;

  //
  // Assume the bridge is aligned
  //
  while (CurrentLink != &Bridge->ChildList) {

    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);

    //
    // Apply padding resource if available
    //
        
    Offset = Aperture & (Node->Alignment);

    if (Offset != 0) {

      Aperture = Aperture + (Node->Alignment + 1) - Offset;

    }

    //
    // Recode current aperture as a offset
    // this offset will be used in future real allocation
    //
    Node->Offset = Aperture;

    //
    // Increment aperture by the length of node
    //
    Aperture += Node->Length;

    //
    // Consider the aperture alignment
    //
    
    CurrentLink = CurrentLink->ForwardLink;
  }

  //
  // At last, adjust the aperture with the bridge's
  // alignment
  //
  Offset = Aperture & (Bridge->Alignment);
  if (Offset != 0) {
    Aperture = Aperture + (Bridge->Alignment + 1) - Offset;
  }

  //
  // If the bridge has already padded the resource and the
  // amount of padded resource is larger, then keep the
  // padded resource
  //
  if (Bridge->Length < Aperture) {
    Bridge->Length = Aperture;
  }
  
  //
  // At last, adjust the bridge's alignment to the first child's alignment
  // if the bridge has at least one child
  //
  CurrentLink = Bridge->ChildList.ForwardLink;
  if (CurrentLink != &Bridge->ChildList) {
    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
    if (Node->Alignment > Bridge->Alignment) {
      Bridge->Alignment = Node->Alignment;
    }
  }

  return EFI_SUCCESS;
}

/**
  Get IO/Memory resource infor for given PCI device.
  
  @param PciDev     Pci device instance.
  @param IoNode     Resource info node for IO .
  @param Mem32Node  Resource info node for 32-bit memory.
  @param PMem32Node Resource info node for 32-bit PMemory.
  @param Mem64Node  Resource info node for 64-bit memory.
  @param PMem64Node Resource info node for 64-bit PMemory.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
GetResourceFromDevice (
  PCI_IO_DEVICE     *PciDev,
  PCI_RESOURCE_NODE *IoNode,
  PCI_RESOURCE_NODE *Mem32Node,
  PCI_RESOURCE_NODE *PMem32Node,
  PCI_RESOURCE_NODE *Mem64Node,
  PCI_RESOURCE_NODE *PMem64Node
  )
{

  UINT8             Index;
  PCI_RESOURCE_NODE *Node;
  BOOLEAN           ResourceRequested;

  Node              = NULL;
  ResourceRequested = FALSE;

  for (Index = 0; Index < PCI_MAX_BAR; Index++) {

    switch ((PciDev->PciBar)[Index].BarType) {

    case PciBarTypeMem32:

      Node = CreateResourceNode (
              PciDev,
              (PciDev->PciBar)[Index].Length,
              (PciDev->PciBar)[Index].Alignment,
              Index,
              PciBarTypeMem32,
              PciResUsageTypical
              );

      InsertResourceNode (
        Mem32Node,
        Node
        );

      ResourceRequested = TRUE;
      break;

    case PciBarTypeMem64:

      Node = CreateResourceNode (
              PciDev,
              (PciDev->PciBar)[Index].Length,
              (PciDev->PciBar)[Index].Alignment,
              Index,
              PciBarTypeMem64,
              PciResUsageTypical
              );

      InsertResourceNode (
        Mem64Node,
        Node
        );

      ResourceRequested = TRUE;
      break;

    case PciBarTypePMem64:

      Node = CreateResourceNode (
              PciDev,
              (PciDev->PciBar)[Index].Length,
              (PciDev->PciBar)[Index].Alignment,
              Index,
              PciBarTypePMem64,
              PciResUsageTypical
              );

      InsertResourceNode (
        PMem64Node,
        Node
        );

      ResourceRequested = TRUE;
      break;

    case PciBarTypePMem32:

      Node = CreateResourceNode (
              PciDev,
              (PciDev->PciBar)[Index].Length,
              (PciDev->PciBar)[Index].Alignment,
              Index,
              PciBarTypePMem32,
              PciResUsageTypical
              );

      InsertResourceNode (
        PMem32Node,
        Node
        );
      ResourceRequested = TRUE;
      break;

    case PciBarTypeIo16:
    case PciBarTypeIo32:

      Node = CreateResourceNode (
              PciDev,
              (PciDev->PciBar)[Index].Length,
              (PciDev->PciBar)[Index].Alignment,
              Index,
              PciBarTypeIo16,
              PciResUsageTypical
              );

      InsertResourceNode (
        IoNode,
        Node
        );
      ResourceRequested = TRUE;
      break;

    case PciBarTypeUnknown:
      break;

    default:
      break;
    }
  }

  //
  // If there is no resource requested from this device,
  // then we indicate this device has been allocated naturally.
  //
  if (!ResourceRequested) {
    PciDev->Allocated = TRUE;
  }

  return EFI_SUCCESS;
}

/**
  This function is used to create a resource node.

  @param PciDev       Pci device instance.
  @param Length       Length of Io/Memory resource.
  @param Alignment    Alignment of resource.
  @param Bar          Bar index.
  @param ResType      Type of resource: IO/Memory.
  @param ResUsage     Resource usage.
**/
PCI_RESOURCE_NODE *
CreateResourceNode (
  IN PCI_IO_DEVICE         *PciDev,
  IN UINT64                Length,
  IN UINT64                Alignment,
  IN UINT8                 Bar,
  IN PCI_BAR_TYPE          ResType,
  IN PCI_RESOURCE_USAGE    ResUsage
  )
{
  PCI_RESOURCE_NODE *Node;

  Node    = NULL;

  Node    = AllocatePool (sizeof (PCI_RESOURCE_NODE));
  ASSERT (Node != NULL);
  if (Node == NULL) {
    return NULL;
  }

  ZeroMem (Node, sizeof (PCI_RESOURCE_NODE));

  Node->Signature     = PCI_RESOURCE_SIGNATURE;
  Node->PciDev        = PciDev;
  Node->Length        = Length;
  Node->Alignment     = Alignment;
  Node->Bar           = Bar;
  Node->ResType       = ResType;
  Node->Reserved      = FALSE;
  Node->ResourceUsage = ResUsage;
  InitializeListHead (&Node->ChildList);
  return Node;
}

/**
  This routine is used to extract resource request from
  device node list.

  @param Bridge     Pci device instance.
  @param IoNode     Resource info node for IO.
  @param Mem32Node  Resource info node for 32-bit memory.
  @param PMem32Node Resource info node for 32-bit PMemory.
  @param Mem64Node  Resource info node for 64-bit memory.
  @param PMem64Node Resource info node for 64-bit PMemory.

  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
CreateResourceMap (
  IN PCI_IO_DEVICE     *Bridge,
  IN PCI_RESOURCE_NODE *IoNode,
  IN PCI_RESOURCE_NODE *Mem32Node,
  IN PCI_RESOURCE_NODE *PMem32Node,
  IN PCI_RESOURCE_NODE *Mem64Node,
  IN PCI_RESOURCE_NODE *PMem64Node
  )
{
  PCI_IO_DEVICE     *Temp;
  PCI_RESOURCE_NODE *IoBridge;
  PCI_RESOURCE_NODE *Mem32Bridge;
  PCI_RESOURCE_NODE *PMem32Bridge;
  PCI_RESOURCE_NODE *Mem64Bridge;
  PCI_RESOURCE_NODE *PMem64Bridge;
  LIST_ENTRY        *CurrentLink;

  CurrentLink = Bridge->ChildList.ForwardLink;

  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);

    //
    // Create resource nodes for this device by scanning the
    // Bar array in the device private data
    // If the upstream bridge doesn't support this device,
    // no any resource node will be created for this device
    //
    GetResourceFromDevice (
      Temp,
      IoNode,
      Mem32Node,
      PMem32Node,
      Mem64Node,
      PMem64Node
      );

    if (IS_PCI_BRIDGE (&Temp->Pci)) {

      //
      // If the device has children, create a bridge resource node for this PPB
      // Note: For PPB, memory aperture is aligned with 1MB and IO aperture
      // is aligned with 4KB
      // This device is typically a bridge device like PPB and P2C
      //
      IoBridge = CreateResourceNode (
                  Temp,
                  0,
                  0xFFF,
                  PPB_IO_RANGE,
                  PciBarTypeIo16,
                  PciResUsageTypical
                  ); //0x1000 aligned
      
      Mem32Bridge = CreateResourceNode (
                      Temp,
                      0,
                      0xFFFFF,
                      PPB_MEM32_RANGE,
                      PciBarTypeMem32,
                      PciResUsageTypical
                      );

      PMem32Bridge = CreateResourceNode (
                      Temp,
                      0,
                      0xFFFFF,
                      PPB_PMEM32_RANGE,
                      PciBarTypePMem32,
                      PciResUsageTypical
                      );

      Mem64Bridge = CreateResourceNode (
                      Temp,
                      0,
                      0xFFFFF,
                      PPB_MEM64_RANGE,
                      PciBarTypeMem64,
                      PciResUsageTypical
                      );

      PMem64Bridge = CreateResourceNode (
                      Temp,
                      0,
                      0xFFFFF,
                      PPB_PMEM64_RANGE,
                      PciBarTypePMem64,
                      PciResUsageTypical
                      );

      //
      // Recursively create resouce map on this bridge
      //
      CreateResourceMap (
        Temp,
        IoBridge,
        Mem32Bridge,
        PMem32Bridge,
        Mem64Bridge,
        PMem64Bridge
        );

      if (ResourceRequestExisted (IoBridge)) {
        InsertResourceNode (
          IoNode,
          IoBridge
          );
      } else {
        gBS->FreePool (IoBridge);
        IoBridge = NULL;
      }

      //
      // If there is node under this resource bridge,
      // then calculate bridge's aperture of this type
      // and insert it into the respective resource tree.
      // If no, delete this resource bridge
      //
      if (ResourceRequestExisted (Mem32Bridge)) {
        InsertResourceNode (
          Mem32Node,
          Mem32Bridge
          );
      } else {
        gBS->FreePool (Mem32Bridge);
        Mem32Bridge = NULL;
      }

      //
      // If there is node under this resource bridge,
      // then calculate bridge's aperture of this type
      // and insert it into the respective resource tree.
      // If no, delete this resource bridge
      //
      if (ResourceRequestExisted (PMem32Bridge)) {
        InsertResourceNode (
          PMem32Node,
          PMem32Bridge
          );
      } else {
        gBS->FreePool (PMem32Bridge);
        PMem32Bridge = NULL;
      }

      //
      // If there is node under this resource bridge,
      // then calculate bridge's aperture of this type
      // and insert it into the respective resource tree.
      // If no, delete this resource bridge
      //
      if (ResourceRequestExisted (Mem64Bridge)) {
        InsertResourceNode (
          Mem64Node,
          Mem64Bridge
          );
      } else {
        gBS->FreePool (Mem64Bridge);
        Mem64Bridge = NULL;
      }

      //
      // If there is node under this resource bridge,
      // then calculate bridge's aperture of this type
      // and insert it into the respective resource tree.
      // If no, delete this resource bridge
      //
      if (ResourceRequestExisted (PMem64Bridge)) {
        InsertResourceNode (
          PMem64Node,
          PMem64Bridge
          );
      } else {
        gBS->FreePool (PMem64Bridge);
        PMem64Bridge = NULL;
      }

    }

    //
    // If it is P2C, apply hard coded resource padding
    //
    //
    if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
      ResourcePaddingForCardBusBridge (
        Temp,
        IoNode,
        Mem32Node,
        PMem32Node,
        Mem64Node,
        PMem64Node
        );
    }

    CurrentLink = CurrentLink->ForwardLink;
  }
  //
  //
  // To do some platform specific resource padding ...
  //
  ResourcePaddingPolicy (
    Bridge,
    IoNode,
    Mem32Node,
    PMem32Node,
    Mem64Node,
    PMem64Node
    );

  //
  // Degrade resource if necessary
  //
  DegradeResource (
    Bridge,
    Mem32Node,
    PMem32Node,
    Mem64Node,
    PMem64Node
    );

  //
  // Calculate resource aperture for this bridge device
  //
  CalculateResourceAperture (Mem32Node);
  CalculateResourceAperture (PMem32Node);
  CalculateResourceAperture (Mem64Node);
  CalculateResourceAperture (PMem64Node);
  CalculateResourceAperture (IoNode);

  return EFI_SUCCESS;

}

/**
  This function is used to do the resource padding for a specific platform.

  @param PciDev     Pci device instance.
  @param IoNode     Resource info node for IO.
  @param Mem32Node  Resource info node for 32-bit memory.
  @param PMem32Node Resource info node for 32-bit PMemory.
  @param Mem64Node  Resource info node for 64-bit memory.
  @param PMem64Node Resource info node for 64-bit PMemory.

  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
ResourcePaddingPolicy (
  PCI_IO_DEVICE     *PciDev,
  PCI_RESOURCE_NODE *IoNode,
  PCI_RESOURCE_NODE *Mem32Node,
  PCI_RESOURCE_NODE *PMem32Node,
  PCI_RESOURCE_NODE *Mem64Node,
  PCI_RESOURCE_NODE *PMem64Node
  )
{
  //
  // Create padding resource node
  //
  if (PciDev->ResourcePaddingDescriptors != NULL) {
    ApplyResourcePadding (
      PciDev,
      IoNode,
      Mem32Node,
      PMem32Node,
      Mem64Node,
      PMem64Node
      );
  }

  return EFI_SUCCESS;

}

/**
  This function is used to degrade resource if the upstream bridge 
  doesn't support certain resource. Degradation path is 
  PMEM64 -> MEM64  -> MEM32
  PMEM64 -> PMEM32 -> MEM32
  IO32   -> IO16.

  @param Bridge     Pci device instance.
  @param Mem32Node  Resource info node for 32-bit memory.
  @param PMem32Node Resource info node for 32-bit PMemory.
  @param Mem64Node  Resource info node for 64-bit memory.
  @param PMem64Node Resource info node for 64-bit PMemory.

  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
DegradeResource (
  IN PCI_IO_DEVICE     *Bridge,
  IN PCI_RESOURCE_NODE *Mem32Node,
  IN PCI_RESOURCE_NODE *PMem32Node,
  IN PCI_RESOURCE_NODE *Mem64Node,
  IN PCI_RESOURCE_NODE *PMem64Node
  )
{
  BOOLEAN              HasOprom;
  PCI_IO_DEVICE        *Temp;
  LIST_ENTRY           *CurrentLink;

  //
  // For RootBridge, PPB , P2C, go recursively to traverse all its children
  // to find if this bridge and downstream has OptionRom.
  // 
  HasOprom = FALSE;
  CurrentLink = Bridge->ChildList.ForwardLink;
  while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {

    Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
    if (Temp->RomSize != 0) {
      HasOprom = TRUE;
      break;
    }    
    CurrentLink = CurrentLink->ForwardLink;
  }  

  //
  // If bridge doesn't support Prefetchable
  // memory64, degrade it to Prefetchable memory32
  //
  if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
    MergeResourceTree (
      PMem32Node,
      PMem64Node,
      TRUE
      );
  } else {
    //
    // if no PMem32 request and no OptionRom request, still keep PMem64. Otherwise degrade to PMem32
    //
    if ((PMem32Node != NULL && (PMem32Node->Length != 0 && Bridge->Parent != NULL)) || HasOprom) { 
      //
      // Fixed the issue that there is no resource for 64-bit (above 4G)
      //
      MergeResourceTree (
        PMem32Node,
        PMem64Node,
        TRUE
        );
    }
  }


  //
  // If bridge doesn't support Mem64
  // degrade it to mem32
  //
  if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
    MergeResourceTree (
      Mem32Node,
      Mem64Node,
      TRUE
      );
  }

  //
  // If bridge doesn't support Pmem32
  // degrade it to mem32
  //
  if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
    MergeResourceTree (
      Mem32Node,
      PMem32Node,
      TRUE
      );
  }

  //
  // if bridge supports combined Pmem Mem decoding
  // merge these two type of resource
  //
  if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
    MergeResourceTree (
      Mem32Node,
      PMem32Node,
      FALSE
      );

    MergeResourceTree (
      Mem64Node,
      PMem64Node,
      FALSE
      );
  }

  return EFI_SUCCESS;
}

/**
  Test whether bridge device support decode resource
  
  @param Bridge    Bridge device instance.
  @param Decode    Decode type according to resource type.
  
  @return TRUE  bridge device support decode resource.
  @return FALSE bridge device don't support decode resource.
  
**/
BOOLEAN
BridgeSupportResourceDecode (
  IN PCI_IO_DEVICE *Bridge,
  IN UINT32        Decode
  )
{

  if (((Bridge->Decodes) & Decode) != 0) {
    return TRUE;
  }

  return FALSE;
}

/**
  This function is used to program the resource allocated 
  for each resource node.

  
  @param Base     Base address of resource.
  @param Bridge   Bridge device instance.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
ProgramResource (
  IN UINT64            Base,
  IN PCI_RESOURCE_NODE *Bridge
  )
{
  LIST_ENTRY        *CurrentLink;
  PCI_RESOURCE_NODE *Node;
  EFI_STATUS        Status;

  if (Base == gAllOne) {
    return EFI_OUT_OF_RESOURCES;
  }

  CurrentLink = Bridge->ChildList.ForwardLink;

  while (CurrentLink != &Bridge->ChildList) {

    Node = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {

      if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
        ProgramP2C (Base, Node);
      } else {
        ProgramBar (Base, Node);
      }
    } else {
      Status = ProgramResource (Base + Node->Offset, Node);

      if (EFI_ERROR (Status)) {
        return Status;
      }

      ProgramPpbApperture (Base, Node);
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return EFI_SUCCESS;
}

/**
  Program Bar register.
  
  @param Base  Base address for resource.
  @param Node  Point to resoure node structure.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
ProgramBar (
  IN UINT64            Base,
  IN PCI_RESOURCE_NODE *Node
  )
{
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINT64              Address;
  UINT32              Address32;

  Address = 0;
  PciIo   = &(Node->PciDev->PciIo);

  Address = Base + Node->Offset;

  //
  // Indicate pci bus driver has allocated
  // resource for this device
  // It might be a temporary solution here since
  // pci device could have multiple bar
  //
  Node->PciDev->Allocated = TRUE;

  switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {

  case PciBarTypeIo16:
  case PciBarTypeIo32:
  case PciBarTypeMem32:
  case PciBarTypePMem32:

    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                (Node->PciDev->PciBar[Node->Bar]).Offset,
                1,
                &Address
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;

    break;

  case PciBarTypeMem64:
  case PciBarTypePMem64:

    Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);

    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                (Node->PciDev->PciBar[Node->Bar]).Offset,
                1,
                &Address32
                );

    Address32 = (UINT32) RShiftU64 (Address, 32);

    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
                1,
                &Address32
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;

    break;

  default:
    break;
  }

  return EFI_SUCCESS;
}

/**
  Program PPB apperture.
  
  @param Base  Base address for resource.
  @param Node  Point to resoure node structure.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
ProgramPpbApperture (
  IN UINT64            Base,
  IN PCI_RESOURCE_NODE *Node
  )
{
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINT64              Address;
  UINT32              Address32;

  Address = 0;
  //
  // if no device south of this PPB, return anyway
  // Apperture is set default in the initialization code
  //
  if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {
    //
    // For padding resource node, just ignore when programming
    //
    return EFI_SUCCESS;
  }

  PciIo   = &(Node->PciDev->PciIo);
  Address = Base + Node->Offset;

  //
  // Indicate the PPB resource has been allocated
  //
  Node->PciDev->Allocated = TRUE;

  switch (Node->Bar) {

  case PPB_BAR_0:
  case PPB_BAR_1:
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                (Node->PciDev->PciBar[Node->Bar]).Offset,
                1,
                &Address
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;

    break;

  case PPB_IO_RANGE:

    Address32 = ((UINT32) (Address)) >> 8;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint8,
                0x1C,
                1,
                &Address32
                );

    Address32 >>= 8;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint16,
                0x30,
                1,
                &Address32
                );

    Address32 = (UINT32) (Address + Node->Length - 1);
    Address32 = ((UINT32) (Address32)) >> 8;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint8,
                0x1D,
                1,
                &Address32
                );

    Address32 >>= 8;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint16,
                0x32,
                1,
                &Address32
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    break;

  case PPB_MEM32_RANGE:

    Address32 = ((UINT32) (Address)) >> 16;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint16,
                0x20,
                1,
                &Address32
                );

    Address32 = (UINT32) (Address + Node->Length - 1);
    Address32 = ((UINT32) (Address32)) >> 16;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint16,
                0x22,
                1,
                &Address32
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    break;

  case PPB_PMEM32_RANGE:
  case PPB_PMEM64_RANGE:

    Address32 = ((UINT32) (Address)) >> 16;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint16,
                0x24,
                1,
                &Address32
                );

    Address32 = (UINT32) (Address + Node->Length - 1);
    Address32 = ((UINT32) (Address32)) >> 16;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint16,
                0x26,
                1,
                &Address32
                );

    Address32 = (UINT32) RShiftU64 (Address, 32);
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x28,
                1,
                &Address32
                );

    Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x2C,
                1,
                &Address32
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    break;

  default:
    break;
  }

  return EFI_SUCCESS;
}

/**
  Program parent bridge for oprom.
  
  @param PciDevice      Pci deivce instance.
  @param OptionRomBase  Base address for oprom.
  @param Enable         Enable/Disable.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
ProgrameUpstreamBridgeForRom (
  IN PCI_IO_DEVICE   *PciDevice,
  IN UINT32          OptionRomBase,
  IN BOOLEAN         Enable
  )
{
  PCI_IO_DEVICE     *Parent;
  PCI_RESOURCE_NODE Node;
  //
  // For root bridge, just return.
  //
  Parent = PciDevice->Parent;
  ZeroMem (&Node, sizeof (Node));
  while (Parent != NULL) {
    if (!IS_PCI_BRIDGE (&Parent->Pci)) {
      break;
    }

    Node.PciDev     = Parent;
    Node.Length     = PciDevice->RomSize;
    Node.Alignment  = 0;
    Node.Bar        = PPB_MEM32_RANGE;
    Node.ResType    = PciBarTypeMem32;
    Node.Offset     = 0;

    //
    // Program PPB to only open a single <= 16<MB apperture
    //
    if (Enable) {
      ProgramPpbApperture (OptionRomBase, &Node);
      PciEnableCommandRegister (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
    } else {
      InitializePpb (Parent);
      PciDisableCommandRegister (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
    }

    Parent = Parent->Parent;
  }

  return EFI_SUCCESS;
}

/**
  Test whether resource exists for a bridge.
  
  @param Bridge  Point to resource node for a bridge.
  
  @return whether resource exists.
**/
BOOLEAN
ResourceRequestExisted (
  IN PCI_RESOURCE_NODE *Bridge
  )
{
  if (Bridge != NULL) {
    if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
      return TRUE;
    }
  }

  return FALSE;
}

/**
  Initialize resource pool structure.
  
  @param ResourcePool Point to resource pool structure.
  @param ResourceType Type of resource.
**/
EFI_STATUS
InitializeResourcePool (
  PCI_RESOURCE_NODE   *ResourcePool,
  PCI_BAR_TYPE        ResourceType
  )
{

  ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
  ResourcePool->ResType   = ResourceType;
  ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
  InitializeListHead (&ResourcePool->ChildList);

  return EFI_SUCCESS;
}

/**
  Get all resource information for given Pci device.
  
  @param PciDev         Pci device instance.
  @param IoBridge       Io resource node.
  @param Mem32Bridge    32-bit memory node.
  @param PMem32Bridge   32-bit Pmemory node.
  @param Mem64Bridge    64-bit memory node.
  @param PMem64Bridge   64-bit PMemory node.
  @param IoPool         Link list header for Io resource.
  @param Mem32Pool      Link list header for 32-bit memory.
  @param PMem32Pool     Link list header for 32-bit Pmemory.
  @param Mem64Pool      Link list header for 64-bit memory.
  @param PMem64Pool     Link list header for 64-bit Pmemory.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
GetResourceMap (
  PCI_IO_DEVICE      *PciDev,
  PCI_RESOURCE_NODE  **IoBridge,
  PCI_RESOURCE_NODE  **Mem32Bridge,
  PCI_RESOURCE_NODE  **PMem32Bridge,
  PCI_RESOURCE_NODE  **Mem64Bridge,
  PCI_RESOURCE_NODE  **PMem64Bridge,
  PCI_RESOURCE_NODE  *IoPool,
  PCI_RESOURCE_NODE  *Mem32Pool,
  PCI_RESOURCE_NODE  *PMem32Pool,
  PCI_RESOURCE_NODE  *Mem64Pool,
  PCI_RESOURCE_NODE  *PMem64Pool
  )
{

  PCI_RESOURCE_NODE *Temp;
  LIST_ENTRY        *CurrentLink;

  CurrentLink = IoPool->ChildList.ForwardLink;

  //
  // Get Io resource map
  //
  while (CurrentLink != &IoPool->ChildList) {

    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (Temp->PciDev == PciDev) {
      *IoBridge = Temp;
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  //
  // Get Mem32 resource map
  //
  CurrentLink = Mem32Pool->ChildList.ForwardLink;

  while (CurrentLink != &Mem32Pool->ChildList) {

    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (Temp->PciDev == PciDev) {
      *Mem32Bridge = Temp;
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  //
  // Get Pmem32 resource map
  //
  CurrentLink = PMem32Pool->ChildList.ForwardLink;

  while (CurrentLink != &PMem32Pool->ChildList) {

    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (Temp->PciDev == PciDev) {
      *PMem32Bridge = Temp;
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  //
  // Get Mem64 resource map
  //
  CurrentLink = Mem64Pool->ChildList.ForwardLink;

  while (CurrentLink != &Mem64Pool->ChildList) {

    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (Temp->PciDev == PciDev) {
      *Mem64Bridge = Temp;
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  //
  // Get Pmem64 resource map
  //
  CurrentLink = PMem64Pool->ChildList.ForwardLink;

  while (CurrentLink != &PMem64Pool->ChildList) {

    Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);

    if (Temp->PciDev == PciDev) {
      *PMem64Bridge = Temp;
    }

    CurrentLink = CurrentLink->ForwardLink;
  }

  return EFI_SUCCESS;
}

/**
  Destory given resource tree.
  
  @param Bridge  root node of resource tree.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
DestroyResourceTree (
  IN PCI_RESOURCE_NODE *Bridge
  )
{
  PCI_RESOURCE_NODE *Temp;
  LIST_ENTRY        *CurrentLink;

  while (!IsListEmpty (&Bridge->ChildList)) {

    CurrentLink = Bridge->ChildList.ForwardLink;

    Temp        = RESOURCE_NODE_FROM_LINK (CurrentLink);

    RemoveEntryList (CurrentLink);

    if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
      DestroyResourceTree (Temp);
    }

    gBS->FreePool (Temp);
  }

  return EFI_SUCCESS;
}

/**
  Record the reserved resource and insert to reserved list.
  
  @param Base     Base address of reserved resourse.
  @param Length   Length of reserved resource. 
  @param ResType  Resource type.
  @param Bridge   Pci device instance.
**/
EFI_STATUS
RecordReservedResource (
  IN UINT64         Base,
  IN UINT64         Length,
  IN PCI_BAR_TYPE   ResType,
  IN PCI_IO_DEVICE  *Bridge
  )
{
  PCI_RESERVED_RESOURCE_LIST  *ReservedNode;

  ReservedNode = AllocatePool (sizeof (PCI_RESERVED_RESOURCE_LIST));
  if (ReservedNode == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  ReservedNode->Signature     = RESERVED_RESOURCE_SIGNATURE;
  ReservedNode->Node.Base     = Base;
  ReservedNode->Node.Length   = Length;
  ReservedNode->Node.ResType  = ResType;

  InsertTailList (&Bridge->ReservedResourceList, &(ReservedNode->Link));

  return EFI_SUCCESS;
}

/**
  Insert resource padding for P2C.
  
  @param PciDev     Pci device instance.
  @param IoNode     Resource info node for IO. 
  @param Mem32Node  Resource info node for 32-bit memory.
  @param PMem32Node Resource info node for 32-bit PMemory.
  @param Mem64Node  Resource info node for 64-bit memory.
  @param PMem64Node Resource info node for 64-bit PMemory.
  
  @retval EFI_SUCCESS Success.
**/
EFI_STATUS
ResourcePaddingForCardBusBridge (
  PCI_IO_DEVICE     *PciDev,
  PCI_RESOURCE_NODE *IoNode,
  PCI_RESOURCE_NODE *Mem32Node,
  PCI_RESOURCE_NODE *PMem32Node,
  PCI_RESOURCE_NODE *Mem64Node,
  PCI_RESOURCE_NODE *PMem64Node
  )
{
  PCI_RESOURCE_NODE *Node;

  Node = NULL;

  //
  // Memory Base/Limit Register 0
  // Bar 1 denodes memory range 0
  //
  Node = CreateResourceNode (
          PciDev,
          0x2000000,
          0x1ffffff,
          1,
          PciBarTypeMem32,
          PciResUsagePadding
          );

  InsertResourceNode (
    Mem32Node,
    Node
    );

  //
  // Memory Base/Limit Register 1
  // Bar 2 denodes memory range1
  //
  Node = CreateResourceNode (
          PciDev,
          0x2000000,
          0x1ffffff,
          2,
          PciBarTypePMem32,
          PciResUsagePadding
          );

  InsertResourceNode (
    PMem32Node,
    Node
    );

  //
  // Io Base/Limit
  // Bar 3 denodes io range 0
  //
  Node = CreateResourceNode (
          PciDev,
          0x100,
          0xff,
          3,
          PciBarTypeIo16,
          PciResUsagePadding
          );

  InsertResourceNode (
    IoNode,
    Node
    );

  //
  // Io Base/Limit
  // Bar 4 denodes io range 0
  //
  Node = CreateResourceNode (
          PciDev,
          0x100,
          0xff,
          4,
          PciBarTypeIo16,
          PciResUsagePadding
          );

  InsertResourceNode (
    IoNode,
    Node
    );

  return EFI_SUCCESS;
}

/**
  Program P2C register for given resource node
  
  @param Base    Base address of P2C device
  @param Node    Given resource node.
  
  @retval EFI_SUCCESS Success
**/
EFI_STATUS
ProgramP2C (
  IN UINT64            Base,
  IN PCI_RESOURCE_NODE *Node
  )
{
  EFI_PCI_IO_PROTOCOL *PciIo;
  UINT64              Address;
  UINT64              TempAddress;
  UINT16              BridgeControl;

  Address = 0;
  PciIo   = &(Node->PciDev->PciIo);

  Address = Base + Node->Offset;

  //
  // Indicate pci bus driver has allocated
  // resource for this device
  // It might be a temporary solution here since
  // pci device could have multiple bar
  //
  Node->PciDev->Allocated = TRUE;

  switch (Node->Bar) {

  case P2C_BAR_0:
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                (Node->PciDev->PciBar[Node->Bar]).Offset,
                1,
                &Address
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    break;

  case P2C_MEM_1:
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x1c,
                1,
                &Address
                );

    TempAddress = Address + Node->Length - 1;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x20,
                1,
                &TempAddress
                );

    if (Node->ResType == PciBarTypeMem32) {

      //
      // Set non-prefetchable bit
      //
      PciIoRead (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );

      BridgeControl &= 0xfeff;
      PciIoWrite (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );

    } else {

      //
      // Set pre-fetchable bit
      //
      PciIoRead (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );

      BridgeControl |= 0x0100;
      PciIoWrite (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );
    }

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;

    break;

  case P2C_MEM_2:
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x24,
                1,
                &Address
                );

    TempAddress = Address + Node->Length - 1;

    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x28,
                1,
                &TempAddress
                );

    if (Node->ResType == PciBarTypeMem32) {

      //
      // Set non-prefetchable bit
      //
      PciIoRead (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );

      BridgeControl &= 0xfdff;
      PciIoWrite (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );
    } else {

      //
      // Set pre-fetchable bit
      //
      PciIoRead (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );

      BridgeControl |= 0x0200;
      PciIoWrite (
                  PciIo,
                  EfiPciIoWidthUint16,
                  0x3e,
                  1,
                  &BridgeControl
                  );
    }

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;
    break;

  case P2C_IO_1:
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x2c,
                1,
                &Address
                );
    TempAddress = Address + Node->Length - 1;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x30,
                1,
                &TempAddress
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;

    break;

  case P2C_IO_2:
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x34,
                1,
                &Address
                );

    TempAddress = Address + Node->Length - 1;
    PciIoWrite (
                PciIo,
                EfiPciIoWidthUint32,
                0x38,
                1,
                &TempAddress
                );

    Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
    Node->PciDev->PciBar[Node->Bar].Length      = Node->Length;
    Node->PciDev->PciBar[Node->Bar].BarType     = Node->ResType;
    break;

  default:
    break;
  }

  return EFI_SUCCESS;
}

/**
  Create padding resource node.
  
  @param PciDev     Pci device instance.
  @param IoNode     Resource info node for IO. 
  @param Mem32Node  Resource info node for 32-bit memory.
  @param PMem32Node Resource info node for 32-bit PMemory.
  @param Mem64Node  Resource info node for 64-bit memory.
  @param PMem64Node Resource info node for 64-bit PMemory.
  
  @retval EFI_SUCCESS Success.

**/
EFI_STATUS
ApplyResourcePadding (
  PCI_IO_DEVICE     *PciDev,
  PCI_RESOURCE_NODE *IoNode,
  PCI_RESOURCE_NODE *Mem32Node,
  PCI_RESOURCE_NODE *PMem32Node,
  PCI_RESOURCE_NODE *Mem64Node,
  PCI_RESOURCE_NODE *PMem64Node
  )
{
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
  PCI_RESOURCE_NODE                 *Node;
  UINT8                             DummyBarIndex;

  DummyBarIndex = 0;
  Ptr           = PciDev->ResourcePaddingDescriptors;

  while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {

    if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
      if (Ptr->AddrLen != 0) {

        Node = CreateResourceNode (
                PciDev,
                Ptr->AddrLen,
                Ptr->AddrRangeMax,
                DummyBarIndex,
                PciBarTypeIo16,
                PciResUsagePadding
                );
        InsertResourceNode (
          IoNode,
          Node
          );
      }

      Ptr++;
      continue;
    }

    if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {

      if (Ptr->AddrSpaceGranularity == 32) {

        //
        // prefechable
        //
        if (Ptr->SpecificFlag == 0x6) {
          if (Ptr->AddrLen != 0) {
            Node = CreateResourceNode (
                    PciDev,
                    Ptr->AddrLen,
                    Ptr->AddrRangeMax,
                    DummyBarIndex,
                    PciBarTypePMem32,
                    PciResUsagePadding
                    );
            InsertResourceNode (
              PMem32Node,
              Node
              );
          }

          Ptr++;
          continue;
        }

        //
        // Non-prefechable
        //
        if (Ptr->SpecificFlag == 0) {
          if (Ptr->AddrLen != 0) {
            Node = CreateResourceNode (
                    PciDev,
                    Ptr->AddrLen,
                    Ptr->AddrRangeMax,
                    DummyBarIndex,
                    PciBarTypeMem32,
                    PciResUsagePadding
                    );
            InsertResourceNode (
              Mem32Node,
              Node
              );
          }

          Ptr++;
          continue;
        }
      }

      if (Ptr->AddrSpaceGranularity == 64) {

        //
        // prefechable
        //
        if (Ptr->SpecificFlag == 0x6) {
          if (Ptr->AddrLen != 0) {
            Node = CreateResourceNode (
                    PciDev,
                    Ptr->AddrLen,
                    Ptr->AddrRangeMax,
                    DummyBarIndex,
                    PciBarTypePMem64,
                    PciResUsagePadding
                    );
            InsertResourceNode (
              PMem64Node,
              Node
              );
          }

          Ptr++;
          continue;
        }

        //
        // Non-prefechable
        //
        if (Ptr->SpecificFlag == 0) {
          if (Ptr->AddrLen != 0) {
            Node = CreateResourceNode (
                    PciDev,
                    Ptr->AddrLen,
                    Ptr->AddrRangeMax,
                    DummyBarIndex,
                    PciBarTypeMem64,
                    PciResUsagePadding
                    );
            InsertResourceNode (
              Mem64Node,
              Node
              );
          }

          Ptr++;
          continue;
        }
      }
    }

    Ptr++;
  }

  return EFI_SUCCESS;
}

/**
  Get padding resource for PPB.
  Light PCI bus driver woundn't support hotplug root device
  So no need to pad resource for them.

  @param   PciIoDevice Pci device instance.
**/
VOID
GetResourcePaddingPpb (
  IN  PCI_IO_DEVICE                  *PciIoDevice
  )
{
  if (gPciHotPlugInit != NULL) {
    if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
      GetResourcePaddingForHpb (PciIoDevice);
    }
  }
}

