Refine the codes to compare the definition 'SIZE_4GB' with type EFI_PHYSICAL_ADDRESS. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
		
			
				
	
	
		
			1503 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1503 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
 | 
						|
  Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
 | 
						|
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "NonDiscoverablePciDeviceIo.h"
 | 
						|
 | 
						|
#include <Library/DxeServicesTableLib.h>
 | 
						|
 | 
						|
#include <IndustryStandard/Acpi.h>
 | 
						|
 | 
						|
#include <Protocol/PciRootBridgeIo.h>
 | 
						|
 | 
						|
typedef struct {
 | 
						|
  EFI_PHYSICAL_ADDRESS            AllocAddress;
 | 
						|
  VOID                            *HostAddress;
 | 
						|
  EFI_PCI_IO_PROTOCOL_OPERATION   Operation;
 | 
						|
  UINTN                           NumberOfBytes;
 | 
						|
} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;
 | 
						|
 | 
						|
/**
 | 
						|
  Get the resource associated with BAR number 'BarIndex'.
 | 
						|
 | 
						|
  @param  Dev           Point to the NON_DISCOVERABLE_PCI_DEVICE instance.
 | 
						|
  @param  BarIndex      The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                        base address for the memory operation to perform.
 | 
						|
  @param  Descriptor    Points to the address space descriptor
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
GetBarResource (
 | 
						|
  IN  NON_DISCOVERABLE_PCI_DEVICE         *Dev,
 | 
						|
  IN  UINT8                               BarIndex,
 | 
						|
  OUT EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   **Descriptor
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
 | 
						|
 | 
						|
  if (BarIndex < Dev->BarOffset) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  BarIndex -= (UINT8)Dev->BarOffset;
 | 
						|
 | 
						|
  for (Desc = Dev->Device->Resources;
 | 
						|
       Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
 | 
						|
       Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
 | 
						|
 | 
						|
    if (BarIndex == 0) {
 | 
						|
      *Descriptor = Desc;
 | 
						|
      return EFI_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    BarIndex -= 1;
 | 
						|
  }
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
 | 
						|
  satisfied or after a defined duration.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory operation to perform.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory operation.
 | 
						|
  @param  Mask                  Mask used for the polling criteria.
 | 
						|
  @param  Value                 The comparison value used for the polling exit criteria.
 | 
						|
  @param  Delay                 The number of 100 ns units to poll.
 | 
						|
  @param  Result                Pointer to the last value read from the memory location.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is
 | 
						|
  satisfied or after a defined duration.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory operation to perform.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory operation.
 | 
						|
  @param  Mask                  Mask used for the polling criteria.
 | 
						|
  @param  Value                 The comparison value used for the polling exit criteria.
 | 
						|
  @param  Delay                 The number of 100 ns units to poll.
 | 
						|
  @param  Result                Pointer to the last value read from the memory location.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
 | 
						|
 | 
						|
  @param  Width         Signifies the width of the memory or I/O operations.
 | 
						|
  @param  Count         The number of memory or I/O operations to perform.
 | 
						|
  @param  DstStride     The stride of the destination buffer.
 | 
						|
  @param  Dst           For read operations, the destination buffer to store the results. For write
 | 
						|
                        operations, the destination buffer to write data to.
 | 
						|
  @param  SrcStride     The stride of the source buffer.
 | 
						|
  @param  Src           For read operations, the source buffer to read data from. For write
 | 
						|
                        operations, the source buffer to write data from.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The data was read from or written to the PCI controller.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoMemRW (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL_WIDTH   Width,
 | 
						|
  IN  UINTN                       Count,
 | 
						|
  IN  UINTN                       DstStride,
 | 
						|
  IN  VOID                        *Dst,
 | 
						|
  IN  UINTN                       SrcStride,
 | 
						|
  OUT CONST VOID                  *Src
 | 
						|
  )
 | 
						|
{
 | 
						|
  volatile UINT8             *Dst8;
 | 
						|
  volatile UINT16            *Dst16;
 | 
						|
  volatile UINT32            *Dst32;
 | 
						|
  volatile CONST UINT8       *Src8;
 | 
						|
  volatile CONST UINT16      *Src16;
 | 
						|
  volatile CONST UINT32      *Src32;
 | 
						|
 | 
						|
  //
 | 
						|
  // Loop for each iteration and move the data
 | 
						|
  //
 | 
						|
  switch (Width & 0x3) {
 | 
						|
  case EfiPciWidthUint8:
 | 
						|
    Dst8 = (UINT8 *)Dst;
 | 
						|
    Src8 = (UINT8 *)Src;
 | 
						|
    for (;Count > 0; Count--, Dst8 += DstStride, Src8 += SrcStride) {
 | 
						|
      *Dst8 = *Src8;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case EfiPciWidthUint16:
 | 
						|
    Dst16 = (UINT16 *)Dst;
 | 
						|
    Src16 = (UINT16 *)Src;
 | 
						|
    for (;Count > 0; Count--, Dst16 += DstStride, Src16 += SrcStride) {
 | 
						|
      *Dst16 = *Src16;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  case EfiPciWidthUint32:
 | 
						|
    Dst32 = (UINT32 *)Dst;
 | 
						|
    Src32 = (UINT32 *)Src;
 | 
						|
    for (;Count > 0; Count--, Dst32 += DstStride, Src32 += SrcStride) {
 | 
						|
      *Dst32 = *Src32;
 | 
						|
    }
 | 
						|
    break;
 | 
						|
  default:
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory or I/O operation to perform.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
 | 
						|
  @param  Count                 The number of memory or I/O operations to perform.
 | 
						|
  @param  Buffer                For read operations, the destination buffer to store the results. For write
 | 
						|
                                operations, the source buffer to write data from.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
 | 
						|
  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
 | 
						|
  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
 | 
						|
                                valid for the PCI BAR specified by BarIndex.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE         *Dev;
 | 
						|
  UINTN                               AlignMask;
 | 
						|
  VOID                                *Address;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Only allow accesses to the BARs we emulate
 | 
						|
  //
 | 
						|
  Status = GetBarResource (Dev, BarIndex, &Desc);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
 | 
						|
  AlignMask = (1 << (Width & 0x03)) - 1;
 | 
						|
  if ((UINTN)Address & AlignMask) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (Width) {
 | 
						|
  case EfiPciIoWidthUint8:
 | 
						|
  case EfiPciIoWidthUint16:
 | 
						|
  case EfiPciIoWidthUint32:
 | 
						|
  case EfiPciIoWidthUint64:
 | 
						|
    return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
 | 
						|
 | 
						|
  case EfiPciIoWidthFifoUint8:
 | 
						|
  case EfiPciIoWidthFifoUint16:
 | 
						|
  case EfiPciIoWidthFifoUint32:
 | 
						|
  case EfiPciIoWidthFifoUint64:
 | 
						|
    return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);
 | 
						|
 | 
						|
  case EfiPciIoWidthFillUint8:
 | 
						|
  case EfiPciIoWidthFillUint16:
 | 
						|
  case EfiPciIoWidthFillUint32:
 | 
						|
  case EfiPciIoWidthFillUint64:
 | 
						|
    return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);
 | 
						|
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory or I/O operation to perform.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
 | 
						|
  @param  Count                 The number of memory or I/O operations to perform.
 | 
						|
  @param  Buffer                For read operations, the destination buffer to store the results. For write
 | 
						|
                                operations, the source buffer to write data from.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
 | 
						|
  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
 | 
						|
  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
 | 
						|
                                valid for the PCI BAR specified by BarIndex.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE         *Dev;
 | 
						|
  UINTN                               AlignMask;
 | 
						|
  VOID                                *Address;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
 | 
						|
  EFI_STATUS                          Status;
 | 
						|
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  //
 | 
						|
  // Only allow accesses to the BARs we emulate
 | 
						|
  //
 | 
						|
  Status = GetBarResource (Dev, BarIndex, &Desc);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Offset + (Count << (Width & 0x3)) > Desc->AddrLen) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Address = (VOID *)(UINTN)(Desc->AddrRangeMin + Offset);
 | 
						|
  AlignMask = (1 << (Width & 0x03)) - 1;
 | 
						|
  if ((UINTN)Address & AlignMask) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (Width) {
 | 
						|
  case EfiPciIoWidthUint8:
 | 
						|
  case EfiPciIoWidthUint16:
 | 
						|
  case EfiPciIoWidthUint32:
 | 
						|
  case EfiPciIoWidthUint64:
 | 
						|
    return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
 | 
						|
 | 
						|
  case EfiPciIoWidthFifoUint8:
 | 
						|
  case EfiPciIoWidthFifoUint16:
 | 
						|
  case EfiPciIoWidthFifoUint32:
 | 
						|
  case EfiPciIoWidthFifoUint64:
 | 
						|
    return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);
 | 
						|
 | 
						|
  case EfiPciIoWidthFillUint8:
 | 
						|
  case EfiPciIoWidthFillUint16:
 | 
						|
  case EfiPciIoWidthFillUint32:
 | 
						|
  case EfiPciIoWidthFillUint64:
 | 
						|
    return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);
 | 
						|
 | 
						|
  default:
 | 
						|
    break;
 | 
						|
  }
 | 
						|
  return EFI_INVALID_PARAMETER;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory or I/O operation to perform.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
 | 
						|
  @param  Count                 The number of memory or I/O operations to perform.
 | 
						|
  @param  Buffer                For read operations, the destination buffer to store the results. For write
 | 
						|
                                operations, the source buffer to write data from.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory or I/O operation to perform.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
 | 
						|
  @param  Count                 The number of memory or I/O operations to perform.
 | 
						|
  @param  Buffer                For read operations, the destination buffer to store the results. For write
 | 
						|
                                operations, the source buffer to write data from.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI config space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
 | 
						|
  @param  Count                 The number of memory or I/O operations to perform.
 | 
						|
  @param  Buffer                For read operations, the destination buffer to store the results. For write
 | 
						|
                                operations, the source buffer to write data from.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoPciRead (
 | 
						|
  IN     EFI_PCI_IO_PROTOCOL        *This,
 | 
						|
  IN     EFI_PCI_IO_PROTOCOL_WIDTH  Width,
 | 
						|
  IN     UINT32                     Offset,
 | 
						|
  IN     UINTN                      Count,
 | 
						|
  IN OUT VOID                       *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
 | 
						|
  VOID                          *Address;
 | 
						|
  UINTN                         Length;
 | 
						|
 | 
						|
  if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
  Address = (UINT8 *)&Dev->ConfigSpace + Offset;
 | 
						|
  Length = Count << ((UINTN)Width & 0x3);
 | 
						|
 | 
						|
  if (Offset + Length > sizeof (Dev->ConfigSpace)) {
 | 
						|
    //
 | 
						|
    // Read all zeroes for config space accesses beyond the first
 | 
						|
    // 64 bytes
 | 
						|
    //
 | 
						|
    Length -= sizeof (Dev->ConfigSpace) - Offset;
 | 
						|
    ZeroMem ((UINT8 *)Buffer + sizeof (Dev->ConfigSpace) - Offset, Length);
 | 
						|
 | 
						|
    Count -= Length >> ((UINTN)Width & 0x3);
 | 
						|
  }
 | 
						|
  return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enable a PCI driver to access PCI config space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory or I/O operations.
 | 
						|
  @param  Offset                The offset within the selected BAR to start the memory or I/O operation.
 | 
						|
  @param  Count                 The number of memory or I/O operations to perform.
 | 
						|
  @param  Buffer                For read operations, the destination buffer to store the results. For write
 | 
						|
                                operations, the source buffer to write data from
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The data was read from or written to the PCI controller.
 | 
						|
  @retval EFI_UNSUPPORTED       The address range specified by Offset, Width, and Count is not
 | 
						|
                                valid for the PCI BAR specified by BarIndex.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoPciWrite (
 | 
						|
  IN EFI_PCI_IO_PROTOCOL              *This,
 | 
						|
  IN     EFI_PCI_IO_PROTOCOL_WIDTH    Width,
 | 
						|
  IN     UINT32                       Offset,
 | 
						|
  IN     UINTN                        Count,
 | 
						|
  IN OUT VOID                         *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
 | 
						|
  VOID                          *Address;
 | 
						|
 | 
						|
  if (Width < 0 || Width >= EfiPciIoWidthMaximum || Buffer == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
  Address = (UINT8 *)&Dev->ConfigSpace + Offset;
 | 
						|
 | 
						|
  if (Offset + (Count << ((UINTN)Width & 0x3)) > sizeof (Dev->ConfigSpace)) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Enables a PCI driver to copy one region of PCI memory space to another region of PCI
 | 
						|
  memory space.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Width                 Signifies the width of the memory operations.
 | 
						|
  @param  DestBarIndex          The BAR index in the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory operation to perform.
 | 
						|
  @param  DestOffset            The destination offset within the BAR specified by DestBarIndex to
 | 
						|
                                start the memory writes for the copy operation.
 | 
						|
  @param  SrcBarIndex           The BAR index in the standard PCI Configuration header to use as the
 | 
						|
                                base address for the memory operation to perform.
 | 
						|
  @param  SrcOffset             The source offset within the BAR specified by SrcBarIndex to start
 | 
						|
                                the memory reads for the copy operation.
 | 
						|
  @param  Count                 The number of memory operations to perform. Bytes moved is Width
 | 
						|
                                size * Count, starting at DestOffset and SrcOffset.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Provides the PCI controller-specific addresses needed to access system memory.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Operation             Indicates if the bus master is going to read or write to system memory.
 | 
						|
  @param  HostAddress           The system memory address to map to the PCI controller.
 | 
						|
  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
 | 
						|
                                that were mapped.
 | 
						|
  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
 | 
						|
                                access the hosts HostAddress.
 | 
						|
  @param  Mapping               A resulting value to pass to Unmap().
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
 | 
						|
  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
 | 
						|
  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoherentPciIoMap (
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE           *Dev;
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
 | 
						|
 | 
						|
  //
 | 
						|
  // If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA
 | 
						|
  // addressing, we need to allocate a bounce buffer and copy over the data.
 | 
						|
  //
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
  if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
 | 
						|
      (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {
 | 
						|
 | 
						|
    //
 | 
						|
    // Bounce buffering is not possible for consistent mappings
 | 
						|
    //
 | 
						|
    if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
 | 
						|
      return EFI_UNSUPPORTED;
 | 
						|
    }
 | 
						|
 | 
						|
    MapInfo = AllocatePool (sizeof *MapInfo);
 | 
						|
    if (MapInfo == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    MapInfo->AllocAddress = MAX_UINT32;
 | 
						|
    MapInfo->HostAddress = HostAddress;
 | 
						|
    MapInfo->Operation = Operation;
 | 
						|
    MapInfo->NumberOfBytes = *NumberOfBytes;
 | 
						|
 | 
						|
    Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData,
 | 
						|
                    EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
 | 
						|
                    &MapInfo->AllocAddress);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // If we fail here, it is likely because the system has no memory below
 | 
						|
      // 4 GB to begin with. There is not much we can do about that other than
 | 
						|
      // fail the map request.
 | 
						|
      //
 | 
						|
      FreePool (MapInfo);
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
    if (Operation == EfiPciIoOperationBusMasterRead) {
 | 
						|
      gBS->CopyMem ((VOID *)(UINTN)MapInfo->AllocAddress, HostAddress,
 | 
						|
             *NumberOfBytes);
 | 
						|
    }
 | 
						|
    *DeviceAddress = MapInfo->AllocAddress;
 | 
						|
    *Mapping = MapInfo;
 | 
						|
  } else {
 | 
						|
    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
 | 
						|
    *Mapping = NULL;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Completes the Map() operation and releases any corresponding resources.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Mapping               The mapping value returned from Map().
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The range was unmapped.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoherentPciIoUnmap (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL          *This,
 | 
						|
  IN  VOID                         *Mapping
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
 | 
						|
 | 
						|
  MapInfo = Mapping;
 | 
						|
  if (MapInfo != NULL) {
 | 
						|
    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
 | 
						|
      gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
 | 
						|
             MapInfo->NumberOfBytes);
 | 
						|
    }
 | 
						|
    gBS->FreePages (MapInfo->AllocAddress,
 | 
						|
           EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes));
 | 
						|
    FreePool (MapInfo);
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocates pages.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Type                  This parameter is not used and must be ignored.
 | 
						|
  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
 | 
						|
                                EfiRuntimeServicesData.
 | 
						|
  @param  Pages                 The number of pages to allocate.
 | 
						|
  @param  HostAddress           A pointer to store the base system memory address of the
 | 
						|
                                allocated range.
 | 
						|
  @param  Attributes            The requested bit mask of attributes for the allocated range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were allocated.
 | 
						|
  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
 | 
						|
                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoherentPciIoAllocateBuffer (
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE       *Dev;
 | 
						|
  EFI_PHYSICAL_ADDRESS              AllocAddress;
 | 
						|
  EFI_ALLOCATE_TYPE                 AllocType;
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
 | 
						|
  if ((Attributes & ~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
 | 
						|
                      EFI_PCI_ATTRIBUTE_MEMORY_CACHED)) != 0) {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Allocate below 4 GB if the dual address cycle attribute has not
 | 
						|
  // been set. If the system has no memory available below 4 GB, there
 | 
						|
  // is little we can do except propagate the error.
 | 
						|
  //
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
  if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
 | 
						|
    AllocAddress = MAX_UINT32;
 | 
						|
    AllocType = AllocateMaxAddress;
 | 
						|
  } else {
 | 
						|
    AllocType = AllocateAnyPages;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->AllocatePages (AllocType, MemoryType, Pages, &AllocAddress);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    *HostAddress = (VOID *)(UINTN)AllocAddress;
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Pages                 The number of pages to free.
 | 
						|
  @param  HostAddress           The base system memory address of the allocated range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were freed.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
CoherentPciIoFreeBuffer (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL         *This,
 | 
						|
  IN  UINTN                       Pages,
 | 
						|
  IN  VOID                        *HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  FreePages (HostAddress, Pages);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Pages                 The number of pages to free.
 | 
						|
  @param  HostAddress           The base system memory address of the allocated range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were freed.
 | 
						|
  @retval others                The operation contain some errors.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
NonCoherentPciIoFreeBuffer (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL         *This,
 | 
						|
  IN  UINTN                       Pages,
 | 
						|
  IN  VOID                        *HostAddress
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE                   *Dev;
 | 
						|
  LIST_ENTRY                                    *Entry;
 | 
						|
  EFI_STATUS                                    Status;
 | 
						|
  NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION   *Alloc;
 | 
						|
  BOOLEAN                                       Found;
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  Found = FALSE;
 | 
						|
  Alloc = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Find the uncached allocation list entry associated
 | 
						|
  // with this allocation
 | 
						|
  //
 | 
						|
  for (Entry = Dev->UncachedAllocationList.ForwardLink;
 | 
						|
       Entry != &Dev->UncachedAllocationList;
 | 
						|
       Entry = Entry->ForwardLink) {
 | 
						|
 | 
						|
    Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);
 | 
						|
    if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {
 | 
						|
      //
 | 
						|
      // We are freeing the exact allocation we were given
 | 
						|
      // before by AllocateBuffer()
 | 
						|
      //
 | 
						|
      Found = TRUE;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Found) {
 | 
						|
    ASSERT_EFI_ERROR (EFI_NOT_FOUND);
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  RemoveEntryList (&Alloc->List);
 | 
						|
 | 
						|
  Status = gDS->SetMemorySpaceAttributes (
 | 
						|
                  (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
 | 
						|
                  EFI_PAGES_TO_SIZE (Pages),
 | 
						|
                  Alloc->Attributes);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeAlloc;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If we fail to restore the original attributes, it is better to leak the
 | 
						|
  // memory than to return it to the heap
 | 
						|
  //
 | 
						|
  FreePages (HostAddress, Pages);
 | 
						|
 | 
						|
FreeAlloc:
 | 
						|
  FreePool (Alloc);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Allocates pages.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Type                  This parameter is not used and must be ignored.
 | 
						|
  @param  MemoryType            The type of memory to allocate, EfiBootServicesData or
 | 
						|
                                EfiRuntimeServicesData.
 | 
						|
  @param  Pages                 The number of pages to allocate.
 | 
						|
  @param  HostAddress           A pointer to store the base system memory address of the
 | 
						|
                                allocated range.
 | 
						|
  @param  Attributes            The requested bit mask of attributes for the allocated range.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The requested memory pages were allocated.
 | 
						|
  @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
 | 
						|
                                MEMORY_WRITE_COMBINE and MEMORY_CACHED.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
NonCoherentPciIoAllocateBuffer (
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE                 *Dev;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR             GcdDescriptor;
 | 
						|
  EFI_STATUS                                  Status;
 | 
						|
  UINT64                                      MemType;
 | 
						|
  NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;
 | 
						|
  VOID                                        *AllocAddress;
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,
 | 
						|
             &AllocAddress, Attributes);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gDS->GetMemorySpaceDescriptor (
 | 
						|
                  (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
 | 
						|
                  &GcdDescriptor);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto FreeBuffer;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {
 | 
						|
    Status = EFI_UNSUPPORTED;
 | 
						|
    goto FreeBuffer;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the preferred memory attributes
 | 
						|
  //
 | 
						|
  if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||
 | 
						|
      (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {
 | 
						|
    //
 | 
						|
    // Use write combining if it was requested, or if it is the only
 | 
						|
    // type supported by the region.
 | 
						|
    //
 | 
						|
    MemType = EFI_MEMORY_WC;
 | 
						|
  } else {
 | 
						|
    MemType = EFI_MEMORY_UC;
 | 
						|
  }
 | 
						|
 | 
						|
  Alloc = AllocatePool (sizeof *Alloc);
 | 
						|
  if (Alloc == NULL) {
 | 
						|
    goto FreeBuffer;
 | 
						|
  }
 | 
						|
 | 
						|
  Alloc->HostAddress = AllocAddress;
 | 
						|
  Alloc->NumPages = Pages;
 | 
						|
  Alloc->Attributes = GcdDescriptor.Attributes;
 | 
						|
 | 
						|
  //
 | 
						|
  // Record this allocation in the linked list, so we
 | 
						|
  // can restore the memory space attributes later
 | 
						|
  //
 | 
						|
  InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);
 | 
						|
 | 
						|
  Status = gDS->SetMemorySpaceAttributes (
 | 
						|
                  (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
 | 
						|
                  EFI_PAGES_TO_SIZE (Pages),
 | 
						|
                  MemType);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto RemoveList;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = mCpu->FlushDataCache (
 | 
						|
                   mCpu,
 | 
						|
                   (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,
 | 
						|
                   EFI_PAGES_TO_SIZE (Pages),
 | 
						|
                   EfiCpuFlushTypeInvalidate);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto RemoveList;
 | 
						|
  }
 | 
						|
 | 
						|
  *HostAddress = AllocAddress;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
RemoveList:
 | 
						|
  RemoveEntryList (&Alloc->List);
 | 
						|
  FreePool (Alloc);
 | 
						|
 | 
						|
FreeBuffer:
 | 
						|
  CoherentPciIoFreeBuffer (This, Pages, AllocAddress);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Provides the PCI controller-specific addresses needed to access system memory.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Operation             Indicates if the bus master is going to read or write to system memory.
 | 
						|
  @param  HostAddress           The system memory address to map to the PCI controller.
 | 
						|
  @param  NumberOfBytes         On input the number of bytes to map. On output the number of bytes
 | 
						|
                                that were mapped.
 | 
						|
  @param  DeviceAddress         The resulting map address for the bus master PCI controller to use to
 | 
						|
                                access the hosts HostAddress.
 | 
						|
  @param  Mapping               A resulting value to pass to Unmap().
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
 | 
						|
  @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
 | 
						|
  @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
NonCoherentPciIoMap (
 | 
						|
  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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE           *Dev;
 | 
						|
  EFI_STATUS                            Status;
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
 | 
						|
  UINTN                                 AlignMask;
 | 
						|
  VOID                                  *AllocAddress;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR       GcdDescriptor;
 | 
						|
  BOOLEAN                               Bounce;
 | 
						|
 | 
						|
  MapInfo = AllocatePool (sizeof *MapInfo);
 | 
						|
  if (MapInfo == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  MapInfo->HostAddress = HostAddress;
 | 
						|
  MapInfo->Operation = Operation;
 | 
						|
  MapInfo->NumberOfBytes = *NumberOfBytes;
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  //
 | 
						|
  // If this device does not support 64-bit DMA addressing, we need to allocate
 | 
						|
  // a bounce buffer and copy over the data in case HostAddress >= 4 GB.
 | 
						|
  //
 | 
						|
  Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&
 | 
						|
            (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);
 | 
						|
 | 
						|
  if (!Bounce) {
 | 
						|
    switch (Operation) {
 | 
						|
    case EfiPciIoOperationBusMasterRead:
 | 
						|
    case EfiPciIoOperationBusMasterWrite:
 | 
						|
      //
 | 
						|
      // For streaming DMA, it is sufficient if the buffer is aligned to
 | 
						|
      // the CPUs DMA buffer alignment.
 | 
						|
      //
 | 
						|
      AlignMask = mCpu->DmaBufferAlignment - 1;
 | 
						|
      if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      // fall through
 | 
						|
 | 
						|
    case EfiPciIoOperationBusMasterCommonBuffer:
 | 
						|
      //
 | 
						|
      // Check whether the host address refers to an uncached mapping.
 | 
						|
      //
 | 
						|
      Status = gDS->GetMemorySpaceDescriptor (
 | 
						|
                      (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
 | 
						|
                      &GcdDescriptor);
 | 
						|
      if (EFI_ERROR (Status) ||
 | 
						|
          (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {
 | 
						|
        Bounce = TRUE;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      ASSERT (FALSE);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (Bounce) {
 | 
						|
    if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {
 | 
						|
      Status = EFI_DEVICE_ERROR;
 | 
						|
      goto FreeMapInfo;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,
 | 
						|
               EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
 | 
						|
               &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto FreeMapInfo;
 | 
						|
    }
 | 
						|
    MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;
 | 
						|
    if (Operation == EfiPciIoOperationBusMasterRead) {
 | 
						|
      gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);
 | 
						|
    }
 | 
						|
    *DeviceAddress = MapInfo->AllocAddress;
 | 
						|
  } else {
 | 
						|
    MapInfo->AllocAddress = 0;
 | 
						|
    *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
 | 
						|
 | 
						|
    //
 | 
						|
    // We are not using a bounce buffer: the mapping is sufficiently
 | 
						|
    // aligned to allow us to simply flush the caches. Note that cleaning
 | 
						|
    // the caches is necessary for both data directions:
 | 
						|
    // - for bus master read, we want the latest data to be present
 | 
						|
    //   in main memory
 | 
						|
    // - for bus master write, we don't want any stale dirty cachelines that
 | 
						|
    //   may be written back unexpectedly, and clobber the data written to
 | 
						|
    //   main memory by the device.
 | 
						|
    //
 | 
						|
    mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,
 | 
						|
            *NumberOfBytes, EfiCpuFlushTypeWriteBack);
 | 
						|
  }
 | 
						|
 | 
						|
  *Mapping = MapInfo;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
FreeMapInfo:
 | 
						|
  FreePool (MapInfo);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Completes the Map() operation and releases any corresponding resources.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Mapping               The mapping value returned from Map().
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The range was unmapped.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
NonCoherentPciIoUnmap (
 | 
						|
  IN  EFI_PCI_IO_PROTOCOL          *This,
 | 
						|
  IN  VOID                         *Mapping
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO  *MapInfo;
 | 
						|
 | 
						|
  if (Mapping == NULL) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  MapInfo = Mapping;
 | 
						|
  if (MapInfo->AllocAddress != 0) {
 | 
						|
    //
 | 
						|
    // We are using a bounce buffer: copy back the data if necessary,
 | 
						|
    // and free the buffer.
 | 
						|
    //
 | 
						|
    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
 | 
						|
      gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,
 | 
						|
             MapInfo->NumberOfBytes);
 | 
						|
    }
 | 
						|
    NonCoherentPciIoFreeBuffer (This,
 | 
						|
      EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),
 | 
						|
      (VOID *)(UINTN)MapInfo->AllocAddress);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // We are *not* using a bounce buffer: if this is a bus master write,
 | 
						|
    // we have to invalidate the caches so the CPU will see the uncached
 | 
						|
    // data written by the device.
 | 
						|
    //
 | 
						|
    if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {
 | 
						|
      mCpu->FlushDataCache (mCpu,
 | 
						|
              (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,
 | 
						|
              MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  FreePool (MapInfo);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Flushes all PCI posted write transactions from a PCI host bridge to system memory.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoFlush (
 | 
						|
  IN EFI_PCI_IO_PROTOCOL          *This
 | 
						|
  )
 | 
						|
{
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Retrieves this PCI controller's current PCI bus number, device number, and function number.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  SegmentNumber         The PCI controller's current PCI segment number.
 | 
						|
  @param  BusNumber             The PCI controller's current PCI bus number.
 | 
						|
  @param  DeviceNumber          The PCI controller's current PCI device number.
 | 
						|
  @param  FunctionNumber        The PCI controller's current PCI function number.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The PCI controller location was returned.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoGetLocation (
 | 
						|
  IN   EFI_PCI_IO_PROTOCOL  *This,
 | 
						|
  OUT  UINTN                *SegmentNumber,
 | 
						|
  OUT  UINTN                *BusNumber,
 | 
						|
  OUT  UINTN                *DeviceNumber,
 | 
						|
  OUT  UINTN                *FunctionNumber
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (SegmentNumber == NULL ||
 | 
						|
      BusNumber == NULL ||
 | 
						|
      DeviceNumber == NULL ||
 | 
						|
      FunctionNumber == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *SegmentNumber  = 0;
 | 
						|
  *BusNumber      = 0xff;
 | 
						|
  *DeviceNumber   = 0;
 | 
						|
  *FunctionNumber = 0;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Performs an operation on the attributes that this PCI controller supports. The operations include
 | 
						|
  getting the set of supported attributes, retrieving the current attributes, setting the current
 | 
						|
  attributes, enabling attributes, and disabling attributes.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Operation             The operation to perform on the attributes for this PCI controller.
 | 
						|
  @param  Attributes            The mask of attributes that are used for Set, Enable, and Disable
 | 
						|
                                operations.
 | 
						|
  @param  Result                A pointer to the result mask of attributes that are returned for the Get
 | 
						|
                                and Supported operations.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The operation on the PCI controller's attributes was completed.
 | 
						|
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
 | 
						|
  @retval EFI_UNSUPPORTED       one or more of the bits set in
 | 
						|
                                Attributes are not supported by this PCI controller or one of
 | 
						|
                                its parent bridges when Operation is Set, Enable or Disable.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE   *Dev;
 | 
						|
  BOOLEAN                       Enable;
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  Enable = FALSE;
 | 
						|
  switch (Operation) {
 | 
						|
  case EfiPciIoAttributeOperationGet:
 | 
						|
    if (Result == NULL) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    *Result = Dev->Attributes;
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciIoAttributeOperationSupported:
 | 
						|
    if (Result == NULL) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciIoAttributeOperationEnable:
 | 
						|
    Attributes |= Dev->Attributes;
 | 
						|
  case EfiPciIoAttributeOperationSet:
 | 
						|
    Enable = ((~Dev->Attributes & Attributes) & EFI_PCI_DEVICE_ENABLE) != 0;
 | 
						|
    Dev->Attributes = Attributes;
 | 
						|
    break;
 | 
						|
 | 
						|
  case EfiPciIoAttributeOperationDisable:
 | 
						|
    Dev->Attributes &= ~Attributes;
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  };
 | 
						|
 | 
						|
  //
 | 
						|
  // If we're setting any of the EFI_PCI_DEVICE_ENABLE bits, perform
 | 
						|
  // the device specific initialization now.
 | 
						|
  //
 | 
						|
  if (Enable && !Dev->Enabled && Dev->Device->Initialize != NULL) {
 | 
						|
    Dev->Device->Initialize (Dev->Device);
 | 
						|
    Dev->Enabled = TRUE;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Gets the attributes that this PCI controller supports setting on a BAR using
 | 
						|
  SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for resource range. The legal range for this field is 0..5.
 | 
						|
  @param  Supports              A pointer to the mask of attributes that this PCI controller supports
 | 
						|
                                setting for this BAR with SetBarAttributes().
 | 
						|
  @param  Resources             A pointer to the ACPI 2.0 resource descriptors that describe the current
 | 
						|
                                configuration of this BAR of the PCI controller.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           If Supports is not NULL, then the attributes that the PCI
 | 
						|
                                controller supports are returned in Supports. If Resources
 | 
						|
                                is not NULL, then the ACPI 2.0 resource descriptors that the PCI
 | 
						|
                                controller is currently using are returned in Resources.
 | 
						|
  @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
 | 
						|
  @retval EFI_UNSUPPORTED       BarIndex not valid for this PCI controller.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  There are not enough resources available to allocate
 | 
						|
                                Resources.
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoGetBarAttributes (
 | 
						|
  IN EFI_PCI_IO_PROTOCOL             *This,
 | 
						|
  IN  UINT8                          BarIndex,
 | 
						|
  OUT UINT64                         *Supports OPTIONAL,
 | 
						|
  OUT VOID                           **Resources OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE       *Dev;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
 | 
						|
  EFI_ACPI_END_TAG_DESCRIPTOR       *End;
 | 
						|
  EFI_STATUS                        Status;
 | 
						|
 | 
						|
  if (Supports == NULL && Resources == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);
 | 
						|
 | 
						|
  Status = GetBarResource (Dev, BarIndex, &BarDesc);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Don't expose any configurable attributes for our emulated BAR
 | 
						|
  //
 | 
						|
  if (Supports != NULL) {
 | 
						|
    *Supports = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Resources != NULL) {
 | 
						|
    Descriptor = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
 | 
						|
                               sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
 | 
						|
    if (Descriptor == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    CopyMem (Descriptor, BarDesc, sizeof *Descriptor);
 | 
						|
 | 
						|
    End           = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
 | 
						|
    End->Desc     = ACPI_END_TAG_DESCRIPTOR;
 | 
						|
    End->Checksum = 0;
 | 
						|
 | 
						|
    *Resources = Descriptor;
 | 
						|
  }
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Sets the attributes for a range of a BAR on a PCI controller.
 | 
						|
 | 
						|
  @param  This                  A pointer to the EFI_PCI_IO_PROTOCOL instance.
 | 
						|
  @param  Attributes            The mask of attributes to set for the resource range specified by
 | 
						|
                                BarIndex, Offset, and Length.
 | 
						|
  @param  BarIndex              The BAR index of the standard PCI Configuration header to use as the
 | 
						|
                                base address for resource range. The legal range for this field is 0..5.
 | 
						|
  @param  Offset                A pointer to the BAR relative base address of the resource range to be
 | 
						|
                                modified by the attributes specified by Attributes.
 | 
						|
  @param  Length                A pointer to the length of the resource range to be modified by the
 | 
						|
                                attributes specified by Attributes.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PciIoSetBarAttributes (
 | 
						|
  IN     EFI_PCI_IO_PROTOCOL          *This,
 | 
						|
  IN     UINT64                       Attributes,
 | 
						|
  IN     UINT8                        BarIndex,
 | 
						|
  IN OUT UINT64                       *Offset,
 | 
						|
  IN OUT UINT64                       *Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  ASSERT (FALSE);
 | 
						|
  return EFI_UNSUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
STATIC CONST EFI_PCI_IO_PROTOCOL PciIoTemplate =
 | 
						|
{
 | 
						|
  PciIoPollMem,
 | 
						|
  PciIoPollIo,
 | 
						|
  { PciIoMemRead, PciIoMemWrite },
 | 
						|
  { PciIoIoRead,  PciIoIoWrite },
 | 
						|
  { PciIoPciRead, PciIoPciWrite },
 | 
						|
  PciIoCopyMem,
 | 
						|
  CoherentPciIoMap,
 | 
						|
  CoherentPciIoUnmap,
 | 
						|
  CoherentPciIoAllocateBuffer,
 | 
						|
  CoherentPciIoFreeBuffer,
 | 
						|
  PciIoFlush,
 | 
						|
  PciIoGetLocation,
 | 
						|
  PciIoAttributes,
 | 
						|
  PciIoGetBarAttributes,
 | 
						|
  PciIoSetBarAttributes,
 | 
						|
  0,
 | 
						|
  0
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize PciIo Protocol.
 | 
						|
 | 
						|
  @param  Dev      Point to NON_DISCOVERABLE_PCI_DEVICE instance.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
InitializePciIoProtocol (
 | 
						|
  NON_DISCOVERABLE_PCI_DEVICE     *Dev
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR   *Desc;
 | 
						|
  INTN                                Idx;
 | 
						|
 | 
						|
  InitializeListHead (&Dev->UncachedAllocationList);
 | 
						|
 | 
						|
  Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;
 | 
						|
  Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;
 | 
						|
 | 
						|
  // Copy protocol structure
 | 
						|
  CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);
 | 
						|
 | 
						|
  if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {
 | 
						|
    Dev->PciIo.AllocateBuffer   = NonCoherentPciIoAllocateBuffer;
 | 
						|
    Dev->PciIo.FreeBuffer       = NonCoherentPciIoFreeBuffer;
 | 
						|
    Dev->PciIo.Map              = NonCoherentPciIoMap;
 | 
						|
    Dev->PciIo.Unmap            = NonCoherentPciIoUnmap;
 | 
						|
  }
 | 
						|
 | 
						|
  if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
 | 
						|
    Dev->BarOffset = 5;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableEhciDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_EHCI;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableNvmeDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x2; // PCI_IF_NVMHCI
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = 0x8; // PCI_CLASS_MASS_STORAGE_NVM
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableOhciDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_OHCI;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableSdhciDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_SUBCLASS_SD_HOST_CONTROLLER;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SYSTEM_PERIPHERAL;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableXhciDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_XHCI;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableUhciDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_UHCI;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_SERIAL_USB;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_SERIAL;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else if (CompareGuid (Dev->Device->Type,
 | 
						|
                          &gEdkiiNonDiscoverableUfsDeviceGuid)) {
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[0] = 0x0; // don't care
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[1] = 0x9; // UFS controller subclass;
 | 
						|
    Dev->ConfigSpace.Hdr.ClassCode[2] = PCI_CLASS_MASS_STORAGE;
 | 
						|
    Dev->BarOffset = 0;
 | 
						|
  } else {
 | 
						|
    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Iterate over the resources to populate the virtual BARs
 | 
						|
  //
 | 
						|
  Idx = Dev->BarOffset;
 | 
						|
  for (Desc = Dev->Device->Resources, Dev->BarCount = 0;
 | 
						|
       Desc->Desc != ACPI_END_TAG_DESCRIPTOR;
 | 
						|
       Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {
 | 
						|
 | 
						|
    ASSERT (Desc->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR);
 | 
						|
    ASSERT (Desc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM);
 | 
						|
 | 
						|
    if (Idx >= PCI_MAX_BARS ||
 | 
						|
        (Idx == PCI_MAX_BARS - 1 && Desc->AddrSpaceGranularity == 64)) {
 | 
						|
      DEBUG ((DEBUG_ERROR,
 | 
						|
        "%a: resource count exceeds number of emulated BARs\n",
 | 
						|
        __FUNCTION__));
 | 
						|
      ASSERT (FALSE);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Dev->ConfigSpace.Device.Bar[Idx] = (UINT32)Desc->AddrRangeMin;
 | 
						|
    Dev->BarCount++;
 | 
						|
 | 
						|
    if (Desc->AddrSpaceGranularity == 64) {
 | 
						|
      Dev->ConfigSpace.Device.Bar[Idx] |= 0x4;
 | 
						|
      Dev->ConfigSpace.Device.Bar[++Idx] = (UINT32)RShiftU64 (
 | 
						|
                                                     Desc->AddrRangeMin, 32);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |