/*++
 
Copyright (c) 2006, Intel Corporation                                                         
All rights reserved. This program and the accompanying materials                          
are licensed and made available under the terms and conditions of the BSD License         
which accompanies this distribution.  The full text of the license may be found at        
http://opensource.org/licenses/bsd-license.php                                            
                                                                                          
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             

Module Name:

  PciIo.c
  
Abstract:

  PCI I/O Abstraction Driver

Revision History

--*/

#include "pcibus.h"

//
// Internal use only
//
STATIC
EFI_STATUS
ReportErrorStatusCode (
  IN PCI_IO_DEVICE               *PciIoDevice,
  IN EFI_STATUS_CODE_VALUE       Code
  );

//
// PCI I/O Support Function Prototypes
//
//
//
// Pci Io Protocol Interface
//
static EFI_PCI_IO_PROTOCOL  PciIoInterface = {
  PciIoPollMem,
  PciIoPollIo,
  {
    PciIoMemRead,
    PciIoMemWrite
  },
  {
    PciIoIoRead,
    PciIoIoWrite
  },
  {
    PciIoConfigRead,
    PciIoConfigWrite
  },
  PciIoCopyMem,
  PciIoMap,
  PciIoUnmap,
  PciIoAllocateBuffer,
  PciIoFreeBuffer,
  PciIoFlush,
  PciIoGetLocation,
  PciIoAttributes,
  PciIoGetBarAttributes,
  PciIoSetBarAttributes,
  0,
  NULL
};

STATIC
EFI_STATUS
ReportErrorStatusCode (
  IN PCI_IO_DEVICE               *PciIoDevice,
  IN EFI_STATUS_CODE_VALUE       Code
  )
/*++

Routine Description:

  report a error Status code of PCI bus driver controller

Arguments:
  
Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    Code - add argument and description to function comment
{
  return REPORT_STATUS_CODE_WITH_DEVICE_PATH (
          EFI_ERROR_CODE | EFI_ERROR_MINOR,
          Code,
          PciIoDevice->DevicePath
          );
}

EFI_STATUS
InitializePciIoInstance (
  PCI_IO_DEVICE  *PciIoDevice
  )
/*++

Routine Description:

  Initializes a PCI I/O Instance

Arguments:
  
Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  CopyMem (&PciIoDevice->PciIo, &PciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
  return EFI_SUCCESS;
}

EFI_STATUS
PciIoVerifyBarAccess (
  PCI_IO_DEVICE                   *PciIoDevice,
  UINT8                           BarIndex,
  PCI_BAR_TYPE                    Type,
  IN EFI_PCI_IO_PROTOCOL_WIDTH    Width,
  IN UINTN                        Count,
  UINT64                          *Offset
  )
/*++

Routine Description:

  Verifies access to a PCI Base Address Register (BAR)

Arguments:

Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Type - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  if (Width < 0 || Width >= EfiPciIoWidthMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
    return EFI_SUCCESS;
  }

  //
  // BarIndex 0-5 is legal
  //
  if (BarIndex >= PCI_MAX_BAR) {
    return EFI_INVALID_PARAMETER;
  }

  if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
    return EFI_INVALID_PARAMETER;
  }

  //
  // If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
  // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
  //
  if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
    Count = 1;
  }

  Width &= 0x03;

  if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
    return EFI_INVALID_PARAMETER;
  }

  *Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;

  return EFI_SUCCESS;
}

EFI_STATUS
PciIoVerifyConfigAccess (
  PCI_IO_DEVICE                 *PciIoDevice,
  IN EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN UINTN                      Count,
  IN UINT64                     *Offset
  )
/*++

Routine Description:

  Verifies access to a PCI Config Header

Arguments:

Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  UINT64  ExtendOffset;

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

  //
  // If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
  //
  Width &= 0x03;

  if (PciIoDevice->IsPciExp) {
    if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
      return EFI_UNSUPPORTED;
    }

    ExtendOffset  = LShiftU64 (*Offset, 32);
    *Offset       = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
    *Offset       = (*Offset) | ExtendOffset;

  } else {
    if ((*Offset + Count * (UINTN)(1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
      return EFI_UNSUPPORTED;
    }

    *Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
PciIoPollMem (
  IN  EFI_PCI_IO_PROTOCOL        *This,
  IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN  UINT8                      BarIndex,
  IN  UINT64                     Offset,
  IN  UINT64                     Mask,
  IN  UINT64                     Value,
  IN  UINT64                     Delay,
  OUT UINT64                     *Result
  )
/*++

Routine Description:

  Poll PCI Memmory

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Mask - add argument and description to function comment
// TODO:    Value - add argument and description to function comment
// TODO:    Delay - add argument and description to function comment
// TODO:    Result - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  if (Width > EfiPciIoWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }

  Status = PciIoDevice->PciRootBridgeIo->PollMem (
                                          PciIoDevice->PciRootBridgeIo,
                                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                          Offset,
                                          Mask,
                                          Value,
                                          Delay,
                                          Result
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoPollIo (
  IN  EFI_PCI_IO_PROTOCOL        *This,
  IN  EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN  UINT8                      BarIndex,
  IN  UINT64                     Offset,
  IN  UINT64                     Mask,
  IN  UINT64                     Value,
  IN  UINT64                     Delay,
  OUT UINT64                     *Result
  )
/*++

Routine Description:

  Poll PCI IO

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Mask - add argument and description to function comment
// TODO:    Value - add argument and description to function comment
// TODO:    Delay - add argument and description to function comment
// TODO:    Result - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  if (Width > EfiPciIoWidthUint64) {
    return EFI_INVALID_PARAMETER;
  }

  Status = PciIoDevice->PciRootBridgeIo->PollIo (
                                          PciIoDevice->PciRootBridgeIo,
                                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                          Offset,
                                          Mask,
                                          Value,
                                          Delay,
                                          Result
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoMemRead (
  IN     EFI_PCI_IO_PROTOCOL        *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN     UINT8                      BarIndex,
  IN     UINT64                     Offset,
  IN     UINTN                      Count,
  IN OUT VOID                       *Buffer
  )
/*++

Routine Description:

  Performs a PCI Memory Read Cycle

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
                                              PciIoDevice->PciRootBridgeIo,
                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                              Offset,
                                              Count,
                                              Buffer
                                              );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoMemWrite (
  IN     EFI_PCI_IO_PROTOCOL        *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN     UINT8                      BarIndex,
  IN     UINT64                     Offset,
  IN     UINTN                      Count,
  IN OUT VOID                       *Buffer
  )
/*++

Routine Description:

  Performs a PCI Memory Write Cycle

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
                                              PciIoDevice->PciRootBridgeIo,
                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                              Offset,
                                              Count,
                                              Buffer
                                              );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoIoRead (
  IN     EFI_PCI_IO_PROTOCOL        *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN     UINT8                      BarIndex,
  IN     UINT64                     Offset,
  IN     UINTN                      Count,
  IN OUT VOID                       *Buffer
  )
/*++

Routine Description:

  Performs a PCI I/O Read Cycle

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Status = PciIoDevice->PciRootBridgeIo->Io.Read (
                                              PciIoDevice->PciRootBridgeIo,
                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                              Offset,
                                              Count,
                                              Buffer
                                              );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoIoWrite (
  IN     EFI_PCI_IO_PROTOCOL        *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN     UINT8                      BarIndex,
  IN     UINT64                     Offset,
  IN     UINTN                      Count,
  IN OUT VOID                       *Buffer
  )
/*++

Routine Description:

  Performs a PCI I/O Write Cycle

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Status = PciIoDevice->PciRootBridgeIo->Io.Write (
                                              PciIoDevice->PciRootBridgeIo,
                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                              Offset,
                                              Count,
                                              Buffer
                                              );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoConfigRead (
  IN     EFI_PCI_IO_PROTOCOL        *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN     UINT32                     Offset,
  IN     UINTN                      Count,
  IN OUT VOID                       *Buffer
  )
/*++

Routine Description:

  Performs a PCI Configuration Read Cycle

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;
  UINT64        Address;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  Address     = Offset;
  Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
                                              PciIoDevice->PciRootBridgeIo,
                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                              Address,
                                              Count,
                                              Buffer
                                              );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_READ_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoConfigWrite (
  IN     EFI_PCI_IO_PROTOCOL        *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
  IN     UINT32                     Offset,
  IN     UINTN                      Count,
  IN OUT VOID                       *Buffer
  )
/*++

Routine Description:

  Performs a PCI Configuration Write Cycle

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    Buffer - add argument and description to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;
  UINT64        Address;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  Address     = Offset;
  Status      = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
  if (EFI_ERROR (Status)) {
    return Status;
  }

  Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
                                              PciIoDevice->PciRootBridgeIo,
                                              (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                              Address,
                                              Count,
                                              Buffer
                                              );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_WRITE_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoCopyMem (
  IN EFI_PCI_IO_PROTOCOL              *This,
  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
  IN     UINT8                        DestBarIndex,
  IN     UINT64                       DestOffset,
  IN     UINT8                        SrcBarIndex,
  IN     UINT64                       SrcOffset,
  IN     UINTN                        Count
  )
/*++

Routine Description:

  Copy PCI Memory

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Width - add argument and description to function comment
// TODO:    DestBarIndex - add argument and description to function comment
// TODO:    DestOffset - add argument and description to function comment
// TODO:    SrcBarIndex - add argument and description to function comment
// TODO:    SrcOffset - add argument and description to function comment
// TODO:    Count - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

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

  if (Width == EfiPciIoWidthFifoUint8  ||
      Width == EfiPciIoWidthFifoUint16 ||
      Width == EfiPciIoWidthFifoUint32 ||
      Width == EfiPciIoWidthFifoUint64 ||
      Width == EfiPciIoWidthFillUint8  ||
      Width == EfiPciIoWidthFillUint16 ||
      Width == EfiPciIoWidthFillUint32 ||
      Width == EfiPciIoWidthFillUint64) {
    return EFI_INVALID_PARAMETER;
  }

  Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  Status = PciIoDevice->PciRootBridgeIo->CopyMem (
                                          PciIoDevice->PciRootBridgeIo,
                                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
                                          DestOffset,
                                          SrcOffset,
                                          Count
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoMap (
  IN     EFI_PCI_IO_PROTOCOL            *This,
  IN     EFI_PCI_IO_PROTOCOL_OPERATION  Operation,
  IN     VOID                           *HostAddress,
  IN OUT UINTN                          *NumberOfBytes,
  OUT    EFI_PHYSICAL_ADDRESS           *DeviceAddress,
  OUT    VOID                           **Mapping
  )
/*++

Routine Description:

  Maps a memory region for DMA

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Operation - add argument and description to function comment
// TODO:    HostAddress - add argument and description to function comment
// TODO:    NumberOfBytes - add argument and description to function comment
// TODO:    DeviceAddress - add argument and description to function comment
// TODO:    Mapping - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  if (Operation < 0 || Operation >= EfiPciIoOperationMaximum) {
    return EFI_INVALID_PARAMETER;
  }

  if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {
    Operation = Operation + EfiPciOperationBusMasterRead64;
  }

  Status = PciIoDevice->PciRootBridgeIo->Map (
                                          PciIoDevice->PciRootBridgeIo,
                                          (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,
                                          HostAddress,
                                          NumberOfBytes,
                                          DeviceAddress,
                                          Mapping
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoUnmap (
  IN  EFI_PCI_IO_PROTOCOL  *This,
  IN  VOID                 *Mapping
  )
/*++

Routine Description:

  Unmaps a memory region for DMA

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Mapping - add argument and description to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  Status = PciIoDevice->PciRootBridgeIo->Unmap (
                                          PciIoDevice->PciRootBridgeIo,
                                          Mapping
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoAllocateBuffer (
  IN  EFI_PCI_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 a common buffer for DMA

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Type - add argument and description to function comment
// TODO:    MemoryType - add argument and description to function comment
// TODO:    Pages - add argument and description to function comment
// TODO:    HostAddress - add argument and description to function comment
// TODO:    Attributes - add argument and description to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  if (Attributes &
      (~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
    return EFI_UNSUPPORTED;
  }

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {
    Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
  }

  Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
                                          PciIoDevice->PciRootBridgeIo,
                                          Type,
                                          MemoryType,
                                          Pages,
                                          HostAddress,
                                          Attributes
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoFreeBuffer (
  IN  EFI_PCI_IO_PROTOCOL   *This,
  IN  UINTN                 Pages,
  IN  VOID                  *HostAddress
  )
/*++

Routine Description:

  Frees a common buffer 

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Pages - add argument and description to function comment
// TODO:    HostAddress - add argument and description to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
                                          PciIoDevice->PciRootBridgeIo,
                                          Pages,
                                          HostAddress
                                          );

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoFlush (
  IN  EFI_PCI_IO_PROTOCOL  *This
  )
/*++

Routine Description:

  Flushes a DMA buffer

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  Status = PciIoDevice->PciRootBridgeIo->Flush (
                                           PciIoDevice->PciRootBridgeIo
                                           );
  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoGetLocation (
  IN  EFI_PCI_IO_PROTOCOL  *This,
  OUT UINTN                *Segment,
  OUT UINTN                *Bus,
  OUT UINTN                *Device,
  OUT UINTN                *Function
  )
/*++

Routine Description:

  Gets a PCI device's current bus number, device number, and function number.

Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Segment - add argument and description to function comment
// TODO:    Bus - add argument and description to function comment
// TODO:    Device - add argument and description to function comment
// TODO:    Function - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  PCI_IO_DEVICE *PciIoDevice;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  *Segment  = PciIoDevice->PciRootBridgeIo->SegmentNumber;
  *Bus      = PciIoDevice->BusNumber;
  *Device   = PciIoDevice->DeviceNumber;
  *Function = PciIoDevice->FunctionNumber;

  return EFI_SUCCESS;
}

BOOLEAN
CheckBarType (
  IN PCI_IO_DEVICE       *PciIoDevice,
  UINT8                  BarIndex,
  PCI_BAR_TYPE           BarType
  )
/*++

Routine Description:

  Sets a PCI controllers attributes on a resource range

Arguments:

Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    BarType - add argument and description to function comment
{
  switch (BarType) {

  case PciBarTypeMem:

    if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32  &&
        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64    ) {
      return FALSE;
    }

    return TRUE;

  case PciBarTypeIo:
    if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
        PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
      return FALSE;
    }

    return TRUE;

  default:
    break;
  }

  return FALSE;
}

EFI_STATUS
ModifyRootBridgeAttributes (
  IN  PCI_IO_DEVICE                            *PciIoDevice,
  IN  UINT64                                   Attributes,
  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
  )
/*++

Routine Description:

  Set new attributes to a Root Bridge

Arguments:

Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    Attributes - add argument and description to function comment
// TODO:    Operation - add argument and description to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  UINT64      PciRootBridgeSupports;
  UINT64      PciRootBridgeAttributes;
  UINT64      NewPciRootBridgeAttributes;
  EFI_STATUS  Status;

  //
  // Get the current attributes of this PCI device's PCI Root Bridge
  //
  Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
                                          PciIoDevice->PciRootBridgeIo,
                                          &PciRootBridgeSupports,
                                          &PciRootBridgeAttributes
                                          );
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }
  
  //
  // Record the new attribute of the Root Bridge
  //
  if (Operation == EfiPciIoAttributeOperationEnable) {
    NewPciRootBridgeAttributes = PciRootBridgeAttributes | Attributes;
  } else {
    NewPciRootBridgeAttributes = PciRootBridgeAttributes & (~Attributes);
  }
 
  //
  // Call the PCI Root Bridge to attempt to modify the attributes
  //
  if (NewPciRootBridgeAttributes ^ PciRootBridgeAttributes) {

    Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
                                            PciIoDevice->PciRootBridgeIo,
                                            NewPciRootBridgeAttributes,
                                            NULL,
                                            NULL
                                            );
    if (EFI_ERROR (Status)) {
      //
      // The PCI Root Bridge could not modify the attributes, so return the error.
      //
      return EFI_UNSUPPORTED;
    }
  }
    
  //
  // Also update the attributes for this Root Bridge structure
  //
  PciIoDevice->Attributes = NewPciRootBridgeAttributes;
  return EFI_SUCCESS;

}

EFI_STATUS
SupportPaletteSnoopAttributes (
  IN  PCI_IO_DEVICE                            *PciIoDevice,
  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation
  )
/*++

Routine Description:

  Check whether this device can be enable/disable to snoop

Arguments:

Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    Operation - add argument and description to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  PCI_IO_DEVICE *Temp;
  UINT16        VGACommand;

  //
  // Snoop attribute can be only modified by GFX
  //
  if (!IS_PCI_GFX (&PciIoDevice->Pci)) {
    return EFI_UNSUPPORTED;
  }

  //
  // Get the boot VGA on the same segement
  //
  Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);

  if (!Temp) {
    //
    // If there is no VGA device on the segement, set
    // this graphics card to decode the palette range
    //
    return EFI_SUCCESS;
  }
  
  //
  // Check these two agents are on the same path
  //
  if (!PciDevicesOnTheSamePath (Temp, PciIoDevice)) {
    //
    // they are not on the same path, so snoop can be enabled or disabled
    //
    return EFI_SUCCESS;
  }
  //
  // Check if they are on the same bus
  //
  if (Temp->Parent == PciIoDevice->Parent) {

    PciReadCommandRegister (Temp, &VGACommand);

    //
    // If they are on the same bus, either one can
    // be set to snoop, the other set to decode
    //
    if (VGACommand & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {
      //
      // VGA has set to snoop, so GFX can be only set to disable snoop
      //
      if (Operation == EfiPciIoAttributeOperationEnable) {
        return EFI_UNSUPPORTED;
      }
    } else {
      //
      // VGA has disabled to snoop, so GFX can be only enabled
      //
      if (Operation == EfiPciIoAttributeOperationDisable) {
        return EFI_UNSUPPORTED;
      }
    }

    return EFI_SUCCESS;
  }
  
  //
  // If they are on  the same path but on the different bus
  // The first agent is set to snoop, the second one set to
  // decode
  //
            
  if (Temp->BusNumber > PciIoDevice->BusNumber) {
    //
    // GFX should be set to decode
    //
    if (Operation == EfiPciIoAttributeOperationDisable) {
      PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
      Temp->Attributes |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
    } else {
      return EFI_UNSUPPORTED;
    }

  } else {
    //
    // GFX should be set to snoop
    //
    if (Operation == EfiPciIoAttributeOperationEnable) {
      PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
      Temp->Attributes &= (~EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
    } else {
      return EFI_UNSUPPORTED;
    }

  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
PciIoAttributes (
  IN EFI_PCI_IO_PROTOCOL                       * This,
  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
  IN  UINT64                                   Attributes,
  OUT UINT64                                   *Result OPTIONAL
  )
/*++

Routine Description:


Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Operation - add argument and description to function comment
// TODO:    Attributes - add argument and description to function comment
// TODO:    Result - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
{
  EFI_STATUS    Status;

  PCI_IO_DEVICE *PciIoDevice;
  PCI_IO_DEVICE *UpStreamBridge;
  PCI_IO_DEVICE *Temp;

  UINT64        Supports;
  UINT64        UpStreamAttributes;
  UINT16        BridgeControl;
  UINT16        Command;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  switch (Operation) {
  case EfiPciIoAttributeOperationGet:
    if (Result == NULL) {
      return EFI_INVALID_PARAMETER;
    }

    *Result = PciIoDevice->Attributes;
    return EFI_SUCCESS;

  case EfiPciIoAttributeOperationSupported:
    if (Result == NULL) {
      return EFI_INVALID_PARAMETER;
    }

    *Result = PciIoDevice->Supports;
    return EFI_SUCCESS;

  case EfiPciIoAttributeOperationSet:
    Status = PciIoDevice->PciIo.Attributes (
                                  &(PciIoDevice->PciIo),
                                  EfiPciIoAttributeOperationEnable,
                                  Attributes,
                                  NULL
                                  );
    if (EFI_ERROR (Status)) {
      return EFI_UNSUPPORTED;
    }

    Status = PciIoDevice->PciIo.Attributes (
                                  &(PciIoDevice->PciIo),
                                  EfiPciIoAttributeOperationDisable,
                                  (~Attributes) & (PciIoDevice->Supports),
                                  NULL
                                  );
    if (EFI_ERROR (Status)) {
      return EFI_UNSUPPORTED;
    }

    return EFI_SUCCESS;

  case EfiPciIoAttributeOperationEnable:
  case EfiPciIoAttributeOperationDisable:
    break;

  default:
    return EFI_INVALID_PARAMETER;
  }
  //
  // Just a trick for ENABLE attribute
  //
  if ((Attributes & EFI_PCI_DEVICE_ENABLE) == EFI_PCI_DEVICE_ENABLE) {
    Attributes &= (PciIoDevice->Supports);

    //
    // Raise the EFI_P_PC_ENABLE Status code
    //
    REPORT_STATUS_CODE_WITH_DEVICE_PATH (
      EFI_PROGRESS_CODE,
      EFI_IO_BUS_PCI | EFI_P_PC_ENABLE,
      PciIoDevice->DevicePath
      );
  }

  //
  // If no attributes can be supported, then return.
  // Otherwise, set the attributes that it can support.
  //
  Supports = (PciIoDevice->Supports) & Attributes;
  if (Supports != Attributes) {
    return EFI_UNSUPPORTED;
  }
   
  //
  // For Root Bridge, just call RootBridgeIo to set attributes;
  //
  if (!PciIoDevice->Parent) {
    Status = ModifyRootBridgeAttributes (PciIoDevice, Attributes, Operation);
    return Status;
  }

  Command       = 0;
  BridgeControl = 0;

  //
  // For PPB & P2C, set relevant attribute bits
  //
  if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {

    if (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
      BridgeControl |= EFI_PCI_BRIDGE_CONTROL_VGA;
    }

    if (Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) {
      BridgeControl |= EFI_PCI_BRIDGE_CONTROL_ISA;
    }

    if (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) {
      Command |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
    }

  } else {
    //
    // Do with the attributes on VGA
    //
    if ((Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) || 
        (IS_PCI_VGA(&PciIoDevice->Pci) && 
         ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) || 
          (Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY)))) {
      //
      // Check if a VGA has been enabled before enabling a new one
      //
      if (Operation == EfiPciIoAttributeOperationEnable) {
        //
        // Check if there have been an active VGA device on the same segment
        //
        Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
        if (Temp && Temp != PciIoDevice) {
          //
          // An active VGA has been detected, so can not enable another
          //
          return EFI_UNSUPPORTED;
        }
      }
    }
    
    //
    // Do with the attributes on GFX
    //
    if (Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) {

      if (Operation == EfiPciIoAttributeOperationEnable) {
        //
        // Check if snoop can be enabled in current configuration
        //
        Status = SupportPaletteSnoopAttributes (PciIoDevice, Operation);

        if (EFI_ERROR (Status)) {
        
          //
          // Enable operation is forbidden, so mask the bit in attributes
          // so as to keep consistent with the actual Status
          //
          // Attributes &= (~EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
          //
          //
          //
          return EFI_UNSUPPORTED;

        }
      }

      //
      // It can be supported, so get ready to set the bit
      //
      Command |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
    }
  }

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

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

  if (Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) {
    Command |= EFI_PCI_COMMAND_BUS_MASTER;
  }
  //
  // The upstream bridge should be also set to revelant attribute
  // expect for IO, Mem and BusMaster
  //
  UpStreamAttributes = Attributes & 
                       (~(EFI_PCI_IO_ATTRIBUTE_IO     |
                          EFI_PCI_IO_ATTRIBUTE_MEMORY |
                          EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
                          )
                        );
  UpStreamBridge = PciIoDevice->Parent;

  if (Operation == EfiPciIoAttributeOperationEnable) {
    //
    // Enable relevant attributes to command register and bridge control register
    //
    Status = PciEnableCommandRegister (PciIoDevice, Command);
    if (BridgeControl) {
      Status = PciEnableBridgeControlRegister (PciIoDevice, BridgeControl);
    }

    PciIoDevice->Attributes |= Attributes;

    //
    // Enable attributes of the upstream bridge
    //
    Status = UpStreamBridge->PciIo.Attributes (
                                    &(UpStreamBridge->PciIo),
                                    EfiPciIoAttributeOperationEnable,
                                    UpStreamAttributes,
                                    NULL
                                    );
  } else {
    
    //
    // Disable relevant attributes to command register and bridge control register
    //
    Status = PciDisableCommandRegister (PciIoDevice, Command);
    if (BridgeControl) {
      Status = PciDisableBridgeControlRegister (PciIoDevice, BridgeControl);
    }

    PciIoDevice->Attributes &= (~Attributes);
    Status = EFI_SUCCESS;

  }

  if (EFI_ERROR (Status)) {
    ReportErrorStatusCode (PciIoDevice, EFI_IO_BUS_PCI | EFI_IOB_EC_CONTROLLER_ERROR);
  }

  return Status;
}

EFI_STATUS
EFIAPI
PciIoGetBarAttributes (
  IN EFI_PCI_IO_PROTOCOL             * This,
  IN  UINT8                          BarIndex,
  OUT UINT64                         *Supports, OPTIONAL
  OUT VOID                           **Resources OPTIONAL
  )
/*++

Routine Description:


Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Supports - add argument and description to function comment
// TODO:    Resources - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_OUT_OF_RESOURCES - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{

  UINT8                             *Configuration;
  UINT8                             NumConfig;
  PCI_IO_DEVICE                     *PciIoDevice;
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
  EFI_ACPI_END_TAG_DESCRIPTOR       *PtrEnd;

  NumConfig   = 0;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  if (Supports == NULL && Resources == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (BarIndex >= PCI_MAX_BAR) {
    return EFI_UNSUPPORTED;
  }

  //
  // This driver does not support modifications to the WRITE_COMBINE or
  // CACHED attributes for BAR ranges.
  //
  if (Supports != NULL) {
    *Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
  }

  if (Resources != NULL) {

    if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeUnknown) {
      NumConfig = 1;
    }

    Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
    if (Configuration == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }

    ZeroMem (
      Configuration,
      sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * NumConfig + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
      );

    Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;

    if (NumConfig == 1) {
      Ptr->Desc         = ACPI_ADDRESS_SPACE_DESCRIPTOR;
      Ptr->Len          = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;

      Ptr->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
      Ptr->AddrLen      = PciIoDevice->PciBar[BarIndex].Length;
      Ptr->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;

      switch (PciIoDevice->PciBar[BarIndex].BarType) {
      case PciBarTypeIo16:
      case PciBarTypeIo32:
        //
        // Io
        //
        Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
        break;

      case PciBarTypeMem32:
        //
        // Mem
        //
        Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
        //
        // 32 bit
        //
        Ptr->AddrSpaceGranularity = 32;
        break;

      case PciBarTypePMem32:
        //
        // Mem
        //
        Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
        //
        // prefechable
        //
        Ptr->SpecificFlag = 0x6;
        //
        // 32 bit
        //
        Ptr->AddrSpaceGranularity = 32;
        break;

      case PciBarTypeMem64:
        //
        // Mem
        //
        Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
        //
        // 64 bit
        //
        Ptr->AddrSpaceGranularity = 64;
        break;

      case PciBarTypePMem64:
        //
        // Mem
        //
        Ptr->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
        //
        // prefechable
        //
        Ptr->SpecificFlag = 0x6;
        //
        // 64 bit
        //
        Ptr->AddrSpaceGranularity = 64;
        break;

      default:
        break;
      }

      Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) ((UINT8 *) Ptr + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR));
    }
    
    //
    // put the checksum
    //
    PtrEnd            = (EFI_ACPI_END_TAG_DESCRIPTOR *) ((UINT8 *) Ptr);
    PtrEnd->Desc      = ACPI_END_TAG_DESCRIPTOR;
    PtrEnd->Checksum  = 0;

    *Resources        = Configuration;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
EFIAPI
PciIoSetBarAttributes (
  IN EFI_PCI_IO_PROTOCOL              *This,
  IN     UINT64                       Attributes,
  IN     UINT8                        BarIndex,
  IN OUT UINT64                       *Offset,
  IN OUT UINT64                       *Length
  )
/*++

Routine Description:


Arguments:

Returns:

  None

--*/
// TODO:    This - add argument and description to function comment
// TODO:    Attributes - add argument and description to function comment
// TODO:    BarIndex - add argument and description to function comment
// TODO:    Offset - add argument and description to function comment
// TODO:    Length - add argument and description to function comment
// TODO:    EFI_INVALID_PARAMETER - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_UNSUPPORTED - add return value to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  EFI_STATUS    Status;
  PCI_IO_DEVICE *PciIoDevice;
  UINT64        NonRelativeOffset;
  UINT64        Supports;

  PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);

  //
  // Make sure Offset and Length are not NULL
  //
  if (Offset == NULL || Length == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
    return EFI_UNSUPPORTED;
  }
  //
  // This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
  // If Attributes is not 0, then return EFI_UNSUPPORTED.
  //
  Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;

  if (Attributes != (Attributes & Supports)) {
    return EFI_UNSUPPORTED;
  }
  //
  // Attributes must be supported.  Make sure the BAR range describd by BarIndex, Offset, and
  // Length are valid for this PCI device.
  //
  NonRelativeOffset = *Offset;
  Status = PciIoVerifyBarAccess (
            PciIoDevice,
            BarIndex,
            PciBarTypeMem,
            EfiPciIoWidthUint8,
            (UINT32) *Length,
            &NonRelativeOffset
            );
  if (EFI_ERROR (Status)) {
    return EFI_UNSUPPORTED;
  }

  return EFI_SUCCESS;
}

EFI_STATUS
UpStreamBridgesAttributes (
  IN  PCI_IO_DEVICE                            *PciIoDevice,
  IN  EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION  Operation,
  IN  UINT64                                   Attributes
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
// TODO:    PciIoDevice - add argument and description to function comment
// TODO:    Operation - add argument and description to function comment
// TODO:    Attributes - add argument and description to function comment
// TODO:    EFI_SUCCESS - add return value to function comment
{
  PCI_IO_DEVICE       *Parent;
  EFI_PCI_IO_PROTOCOL *PciIo;

  Parent = PciIoDevice->Parent;

  while (Parent && IS_PCI_BRIDGE (&Parent->Pci)) {

    //
    // Get the PciIo Protocol
    //
    PciIo = &Parent->PciIo;

    PciIo->Attributes (PciIo, Operation, Attributes, NULL);

    Parent = Parent->Parent;
  }

  return EFI_SUCCESS;
}

BOOLEAN
PciDevicesOnTheSamePath (
  IN PCI_IO_DEVICE        *PciDevice1,
  IN PCI_IO_DEVICE        *PciDevice2
  )
/*++

Routine Description:

Arguments:

Returns:

  None

--*/
// TODO:    PciDevice1 - add argument and description to function comment
// TODO:    PciDevice2 - add argument and description to function comment
{

  if (PciDevice1->Parent == PciDevice2->Parent) {
    return TRUE;
  }

  if (PciDevice1->BusNumber > PciDevice2->BusNumber) {
    return PciDeviceExisted (PciDevice1->Parent, PciDevice2);
  }

  return PciDeviceExisted (PciDevice2->Parent, PciDevice1);
}
