mirror of https://github.com/acidanthera/audk.git
1215 lines
43 KiB
C
1215 lines
43 KiB
C
/** @file
|
|
Module produces Device I/O on top of PCI Root Bridge I/O for Segment 0 only.
|
|
This is a valid assumption because many of the EFI 1.02/EFI 1.10 systems that may have provided
|
|
Device I/O were single segment platforms. The goal of the ECP is to provide compatibility with the
|
|
drivers/apps that may have used Device I/O.
|
|
|
|
Device I/O is on list of deprecated protocols for UEFI 2.0 and later.
|
|
This module module layers Device I/O on top of PCI Root Bridge I/O (Segment 0)
|
|
Use if:
|
|
There are no R8.x modules present that produces Device I/O
|
|
EFI drivers included that consume Device I/O
|
|
Platform required to support EFI drivers that consume Device I/O
|
|
Platform required to support EFI applications that consume Device I/O
|
|
|
|
Copyright (c) 2008 Intel Corporation. <BR>
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
|
|
#include <PiDxe.h>
|
|
#include <IndustryStandard/Pci22.h>
|
|
#include <Protocol/DeviceIo.h>
|
|
#include <Protocol/PciRootBridgeIo.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiDriverEntryPoint.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
|
|
|
|
/**
|
|
Perform reading memory mapped I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The destination buffer to store results.
|
|
|
|
@retval EFI_SUCCESS The data was read from the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoMemRead (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
);
|
|
|
|
|
|
/**
|
|
Perform writing memory mapped I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The source buffer of data to be written.
|
|
|
|
@retval EFI_SUCCESS The data was written to the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoMemWrite (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
);
|
|
|
|
/**
|
|
Perform reading I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The destination buffer to store results.
|
|
|
|
@retval EFI_SUCCESS The data was read from the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoIoRead (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
);
|
|
|
|
/**
|
|
Perform writing I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The source buffer of data to be written.
|
|
|
|
@retval EFI_SUCCESS The data was written to the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoIoWrite (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
);
|
|
|
|
/**
|
|
Perform reading PCI configuration space of device
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The destination buffer to store results.
|
|
|
|
@retval EFI_SUCCESS The data was read from the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoPciRead (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
);
|
|
|
|
/**
|
|
Perform writing PCI configuration space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The source buffer of data to be written.
|
|
|
|
@retval EFI_SUCCESS The data was written to the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoPciWrite (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
);
|
|
|
|
/**
|
|
Provides an EFI Device Path for a PCI device with the given PCI configuration space address.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Address The PCI configuration space address of the device
|
|
whose Device Path is going to be returned.
|
|
@param PciDevicePath A pointer to the pointer for the EFI Device Path
|
|
for PciAddress. Memory for the Device Path is
|
|
allocated from the pool.
|
|
|
|
@retval EFI_SUCCESS The PciDevicePath returns a pointer to a valid EFI
|
|
Device Path.
|
|
@retval EFI_UNSUPPORTED The PciAddress does not map to a valid EFI Device
|
|
Path.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
of resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoPciDevicePath (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN UINT64 Address,
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath
|
|
);
|
|
|
|
/**
|
|
Provides the device-specific addresses needed to access system memory.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE 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 device.
|
|
@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
|
|
device 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_INVALID_PARAMETER The Operation or HostAddress is undefined.
|
|
@retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
|
|
buffer.
|
|
@retval EFI_DEVICE_ERROR The system hardware could not map the requested
|
|
address.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
of resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoMap (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_OPERATION_TYPE Operation,
|
|
IN EFI_PHYSICAL_ADDRESS *HostAddress,
|
|
IN OUT UINTN *NumberOfBytes,
|
|
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
|
|
OUT VOID **Mapping
|
|
);
|
|
|
|
/**
|
|
Completes the Map() operation and releases any corresponding resources.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Mapping The mapping value returned from Map().
|
|
|
|
@retval EFI_SUCCESS The range was unmapped.
|
|
@retval EFI_DEVICE_ERROR The data was not committed to the target system
|
|
memory.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoUnmap (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN VOID *Mapping
|
|
);
|
|
|
|
/**
|
|
Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Type The type allocation to perform.
|
|
@param MemoryType The type of memory to allocate,
|
|
EfiBootServicesData or EfiRuntimeServicesData.
|
|
@param Pages The number of pages to allocate.
|
|
@param PhysicalAddress A pointer to store the base address of the
|
|
allocated range.
|
|
|
|
@retval EFI_SUCCESS The requested memory pages were allocated.
|
|
@retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
|
|
@retval EFI_INVALID_PARAMETER The requested memory type is invalid.
|
|
@retval EFI_UNSUPPORTED The requested PhysicalAddress is not supported on
|
|
this platform.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoAllocateBuffer (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_ALLOCATE_TYPE Type,
|
|
IN EFI_MEMORY_TYPE MemoryType,
|
|
IN UINTN Pages,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress
|
|
);
|
|
|
|
/**
|
|
Flushes any posted write data to the device.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
|
|
@retval EFI_SUCCESS The buffers were flushed.
|
|
@retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware
|
|
error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoFlush (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This
|
|
);
|
|
|
|
/**
|
|
Frees pages that were allocated with AllocateBuffer().
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Pages The number of pages to free.
|
|
@param HostAddress The base address of the range to free.
|
|
|
|
@retval EFI_SUCCESS The requested memory pages were freed.
|
|
@retval EFI_NOT_FOUND The requested memory pages were not allocated with
|
|
AllocateBuffer().
|
|
@retval EFI_INVALID_PARAMETER HostAddress is not page aligned or Pages is
|
|
invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoFreeBuffer (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN UINTN Pages,
|
|
IN EFI_PHYSICAL_ADDRESS HostAddress
|
|
);
|
|
|
|
|
|
#define DEVICE_IO_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('D', 'e', 'I', 'O')
|
|
|
|
typedef struct {
|
|
UINTN Signature;
|
|
EFI_DEVICE_IO_PROTOCOL DeviceIo;
|
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
UINT16 PrimaryBus;
|
|
UINT16 SubordinateBus;
|
|
} DEVICE_IO_PRIVATE_DATA;
|
|
|
|
#define DEVICE_IO_PRIVATE_DATA_FROM_THIS(a) CR (a, DEVICE_IO_PRIVATE_DATA, DeviceIo, DEVICE_IO_PRIVATE_DATA_SIGNATURE)
|
|
|
|
#define MAX_COMMON_BUFFER 0x00000000FFFFFFFF
|
|
|
|
|
|
EFI_EVENT mPciRootBridgeIoRegistration;
|
|
|
|
//
|
|
// Device Io Volume Protocol template
|
|
//
|
|
DEVICE_IO_PRIVATE_DATA gDeviceIoPrivateDataTemplate = {
|
|
DEVICE_IO_PRIVATE_DATA_SIGNATURE,
|
|
{
|
|
{
|
|
DeviceIoMemRead,
|
|
DeviceIoMemWrite
|
|
},
|
|
{
|
|
DeviceIoIoRead,
|
|
DeviceIoIoWrite
|
|
},
|
|
{
|
|
DeviceIoPciRead,
|
|
DeviceIoPciWrite,
|
|
},
|
|
DeviceIoMap,
|
|
DeviceIoPciDevicePath,
|
|
DeviceIoUnmap,
|
|
DeviceIoAllocateBuffer,
|
|
DeviceIoFlush,
|
|
DeviceIoFreeBuffer
|
|
},
|
|
NULL, // PciRootBridgeIo
|
|
NULL, // DevicePath
|
|
0, // PrimaryBus
|
|
255 // SubordinateBus
|
|
};
|
|
|
|
VOID
|
|
EFIAPI
|
|
PciRootBridgeIoNotificationEvent (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN BufferSize;
|
|
EFI_HANDLE Handle;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
EFI_DEVICE_IO_PROTOCOL *DeviceIo;
|
|
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
|
|
|
|
while (TRUE) {
|
|
BufferSize = sizeof (Handle);
|
|
Status = gBS->LocateHandle (
|
|
ByRegisterNotify,
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
mPciRootBridgeIoRegistration,
|
|
&BufferSize,
|
|
&Handle
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//
|
|
// Exit Path of While Loop....
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Skip this handle if the Device Io Protocol is already installed
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiDeviceIoProtocolGuid,
|
|
(VOID **)&DeviceIo
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Retrieve the Pci Root Bridge IO Protocol
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
(VOID **)&PciRootBridgeIo
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
//
|
|
// We only install Device IO for PCI bus in Segment 0.
|
|
// See the file description at @file for details.
|
|
//
|
|
if (PciRootBridgeIo->SegmentNumber != 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Allocate private data structure
|
|
//
|
|
Private = AllocateCopyPool (sizeof (DEVICE_IO_PRIVATE_DATA), &gDeviceIoPrivateDataTemplate);
|
|
if (Private == NULL) {
|
|
continue;
|
|
}
|
|
|
|
Status = gBS->HandleProtocol (
|
|
Handle,
|
|
&gEfiDevicePathProtocolGuid,
|
|
(VOID **) &Private->DevicePath
|
|
);
|
|
|
|
//
|
|
// Install Device Io onto same handle
|
|
//
|
|
Status = gBS->InstallMultipleProtocolInterfaces (
|
|
&Handle,
|
|
&gEfiDeviceIoProtocolGuid,
|
|
&Private->DeviceIo,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
|
|
/**
|
|
The user Entry Point for DXE driver. The user code starts with this function
|
|
as the real entry point for the image goes into a library that calls this
|
|
function.
|
|
|
|
@param[in] ImageHandle The firmware allocated handle for the EFI image.
|
|
@param[in] SystemTable A pointer to the EFI System Table.
|
|
|
|
@retval EFI_SUCCESS The entry point is executed successfully.
|
|
@retval other Some error occurs when executing this entry point.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InitializeDeviceIo (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gEfiPciRootBridgeIoProtocolGuid,
|
|
TPL_CALLBACK,
|
|
PciRootBridgeIoNotificationEvent,
|
|
NULL,
|
|
&mPciRootBridgeIoRegistration
|
|
);
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Perform reading memory mapped I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The destination buffer to store results.
|
|
|
|
@retval EFI_SUCCESS The data was read from the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoMemRead (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Width > MMIO_COPY_UINT64) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (Width >= MMIO_COPY_UINT8) {
|
|
Width = (EFI_IO_WIDTH) (Width - MMIO_COPY_UINT8);
|
|
Status = Private->PciRootBridgeIo->CopyMem (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
(UINT64) (UINTN) Buffer,
|
|
Address,
|
|
Count
|
|
);
|
|
} else {
|
|
Status = Private->PciRootBridgeIo->Mem.Read (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
Count,
|
|
Buffer
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
Perform writing memory mapped I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The source buffer of data to be written.
|
|
|
|
@retval EFI_SUCCESS The data was written to the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoMemWrite (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Width > MMIO_COPY_UINT64) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
if (Width >= MMIO_COPY_UINT8) {
|
|
Width = (EFI_IO_WIDTH) (Width - MMIO_COPY_UINT8);
|
|
Status = Private->PciRootBridgeIo->CopyMem (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
(UINT64) (UINTN) Buffer,
|
|
Count
|
|
);
|
|
} else {
|
|
Status = Private->PciRootBridgeIo->Mem.Write (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
Count,
|
|
Buffer
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Perform reading I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The destination buffer to store results.
|
|
|
|
@retval EFI_SUCCESS The data was read from the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoIoRead (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Width >= MMIO_COPY_UINT8) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = Private->PciRootBridgeIo->Io.Read (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
Count,
|
|
Buffer
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Perform writing I/O space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The source buffer of data to be written.
|
|
|
|
@retval EFI_SUCCESS The data was written to the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoIoWrite (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Width >= MMIO_COPY_UINT8) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = Private->PciRootBridgeIo->Io.Write (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
Count,
|
|
Buffer
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Perform reading PCI configuration space of device
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The destination buffer to store results.
|
|
|
|
@retval EFI_SUCCESS The data was read from the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoPciRead (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Width < 0 || Width >= MMIO_COPY_UINT8) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = Private->PciRootBridgeIo->Pci.Read (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
Count,
|
|
Buffer
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Perform writing PCI configuration space of device.
|
|
|
|
@param This A pointer to EFI_DEVICE_IO protocol instance.
|
|
@param Width Width of I/O operations.
|
|
@param Address The base address of I/O operations.
|
|
@param Count The number of I/O operations to perform. Bytes
|
|
moves is Width size * Count, starting at Address.
|
|
@param Buffer The source buffer of data to be written.
|
|
|
|
@retval EFI_SUCCESS The data was written to the device.
|
|
@retval EFI_INVALID_PARAMETER Width is invalid.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of
|
|
resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoPciWrite (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_WIDTH Width,
|
|
IN UINT64 Address,
|
|
IN UINTN Count,
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Width < 0 || Width >= MMIO_COPY_UINT8) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
Status = Private->PciRootBridgeIo->Pci.Write (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
|
|
Address,
|
|
Count,
|
|
Buffer
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Append a PCI device path node to another device path.
|
|
|
|
@param Private A pointer to DEVICE_IO_PRIVATE_DATA instance.
|
|
@param Bus PCI bus number of the device.
|
|
@param Device PCI device number of the device.
|
|
@param Function PCI function number of the device.
|
|
@param DevicePath Original device path which will be appended a PCI
|
|
device path node.
|
|
@param BridgePrimaryBus Primary bus number of the bridge.
|
|
@param BridgeSubordinateBus Subordinate bus number of the bridge.
|
|
|
|
@return Pointer to the appended PCI device path.
|
|
|
|
**/
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
AppendPciDevicePath (
|
|
IN DEVICE_IO_PRIVATE_DATA *Private,
|
|
IN UINT8 Bus,
|
|
IN UINT8 Device,
|
|
IN UINT8 Function,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
|
IN OUT UINT16 *BridgePrimaryBus,
|
|
IN OUT UINT16 *BridgeSubordinateBus
|
|
)
|
|
{
|
|
UINT16 ThisBus;
|
|
UINT8 ThisDevice;
|
|
UINT8 ThisFunc;
|
|
UINT64 Address;
|
|
PCI_TYPE01 PciBridge;
|
|
PCI_TYPE01 *PciPtr;
|
|
EFI_DEVICE_PATH_PROTOCOL *ReturnDevicePath;
|
|
PCI_DEVICE_PATH PciNode;
|
|
|
|
PciPtr = &PciBridge;
|
|
for (ThisBus = *BridgePrimaryBus; ThisBus <= *BridgeSubordinateBus; ThisBus++) {
|
|
for (ThisDevice = 0; ThisDevice <= PCI_MAX_DEVICE; ThisDevice++) {
|
|
for (ThisFunc = 0; ThisFunc <= PCI_MAX_FUNC; ThisFunc++) {
|
|
Address = EFI_PCI_ADDRESS (ThisBus, ThisDevice, ThisFunc, 0);
|
|
ZeroMem (PciPtr, sizeof (PCI_TYPE01));
|
|
Private->DeviceIo.Pci.Read (
|
|
&Private->DeviceIo,
|
|
IO_UINT32,
|
|
Address,
|
|
1,
|
|
&(PciPtr->Hdr.VendorId)
|
|
);
|
|
if ((PciPtr->Hdr.VendorId == 0xffff) && (ThisFunc == 0)) {
|
|
break;
|
|
}
|
|
if (PciPtr->Hdr.VendorId == 0xffff) {
|
|
continue;
|
|
} else {
|
|
Private->DeviceIo.Pci.Read (
|
|
&Private->DeviceIo,
|
|
IO_UINT32,
|
|
Address,
|
|
sizeof (PCI_TYPE01) / sizeof (UINT32),
|
|
PciPtr
|
|
);
|
|
if (IS_PCI_BRIDGE (PciPtr)) {
|
|
if (Bus >= PciPtr->Bridge.SecondaryBus && Bus <= PciPtr->Bridge.SubordinateBus) {
|
|
|
|
PciNode.Header.Type = HARDWARE_DEVICE_PATH;
|
|
PciNode.Header.SubType = HW_PCI_DP;
|
|
SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
|
|
|
|
PciNode.Device = ThisDevice;
|
|
PciNode.Function = ThisFunc;
|
|
ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header);
|
|
|
|
*BridgePrimaryBus = PciPtr->Bridge.SecondaryBus;
|
|
*BridgeSubordinateBus = PciPtr->Bridge.SubordinateBus;
|
|
return ReturnDevicePath;
|
|
}
|
|
}
|
|
if (ThisFunc == 0 && !(PciPtr->Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION)) {
|
|
//
|
|
// Skip sub functions, this is not a multi function device
|
|
//
|
|
ThisFunc = 8;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ZeroMem (&PciNode, sizeof (PciNode));
|
|
PciNode.Header.Type = HARDWARE_DEVICE_PATH;
|
|
PciNode.Header.SubType = HW_PCI_DP;
|
|
SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
|
|
PciNode.Device = Device;
|
|
PciNode.Function = Function;
|
|
|
|
ReturnDevicePath = AppendDevicePathNode (DevicePath, &PciNode.Header);
|
|
|
|
*BridgePrimaryBus = 0xffff;
|
|
*BridgeSubordinateBus = 0xffff;
|
|
return ReturnDevicePath;
|
|
}
|
|
|
|
|
|
/**
|
|
Provides an EFI Device Path for a PCI device with the given PCI configuration space address.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Address The PCI configuration space address of the device
|
|
whose Device Path is going to be returned.
|
|
@param PciDevicePath A pointer to the pointer for the EFI Device Path
|
|
for PciAddress. Memory for the Device Path is
|
|
allocated from the pool.
|
|
|
|
@retval EFI_SUCCESS The PciDevicePath returns a pointer to a valid EFI
|
|
Device Path.
|
|
@retval EFI_UNSUPPORTED The PciAddress does not map to a valid EFI Device
|
|
Path.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
of resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoPciDevicePath (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN UINT64 Address,
|
|
IN OUT EFI_DEVICE_PATH_PROTOCOL **PciDevicePath
|
|
)
|
|
{
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
UINT16 PrimaryBus;
|
|
UINT16 SubordinateBus;
|
|
UINT8 Bus;
|
|
UINT8 Device;
|
|
UINT8 Func;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Bus = (UINT8) (((UINT32) Address >> 24) & 0xff);
|
|
Device = (UINT8) (((UINT32) Address >> 16) & 0xff);
|
|
Func = (UINT8) (((UINT32) Address >> 8) & 0xff);
|
|
|
|
if (Bus < Private->PrimaryBus || Bus > Private->SubordinateBus) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
*PciDevicePath = Private->DevicePath;
|
|
PrimaryBus = Private->PrimaryBus;
|
|
SubordinateBus = Private->SubordinateBus;
|
|
do {
|
|
*PciDevicePath = AppendPciDevicePath (
|
|
Private,
|
|
Bus,
|
|
Device,
|
|
Func,
|
|
*PciDevicePath,
|
|
&PrimaryBus,
|
|
&SubordinateBus
|
|
);
|
|
if (*PciDevicePath == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
} while (PrimaryBus != 0xffff);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Provides the device-specific addresses needed to access system memory.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE 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 device.
|
|
@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
|
|
device 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_INVALID_PARAMETER The Operation or HostAddress is undefined.
|
|
@retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common
|
|
buffer.
|
|
@retval EFI_DEVICE_ERROR The system hardware could not map the requested
|
|
address.
|
|
@retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack
|
|
of resources.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoMap (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_IO_OPERATION_TYPE Operation,
|
|
IN EFI_PHYSICAL_ADDRESS *HostAddress,
|
|
IN OUT UINTN *NumberOfBytes,
|
|
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
|
|
OUT VOID **Mapping
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (Operation < 0 || Operation > EfiBusMasterCommonBuffer) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (((UINTN) (*HostAddress) != (*HostAddress)) && Operation == EfiBusMasterCommonBuffer) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = Private->PciRootBridgeIo->Map (
|
|
Private->PciRootBridgeIo,
|
|
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,
|
|
(VOID *) (UINTN) (*HostAddress),
|
|
NumberOfBytes,
|
|
DeviceAddress,
|
|
Mapping
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Completes the Map() operation and releases any corresponding resources.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Mapping The mapping value returned from Map().
|
|
|
|
@retval EFI_SUCCESS The range was unmapped.
|
|
@retval EFI_DEVICE_ERROR The data was not committed to the target system
|
|
memory.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoUnmap (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN VOID *Mapping
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Status = Private->PciRootBridgeIo->Unmap (
|
|
Private->PciRootBridgeIo,
|
|
Mapping
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Allocates pages that are suitable for an EFIBusMasterCommonBuffer mapping.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Type The type allocation to perform.
|
|
@param MemoryType The type of memory to allocate,
|
|
EfiBootServicesData or EfiRuntimeServicesData.
|
|
@param Pages The number of pages to allocate.
|
|
@param PhysicalAddress A pointer to store the base address of the
|
|
allocated range.
|
|
|
|
@retval EFI_SUCCESS The requested memory pages were allocated.
|
|
@retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
|
|
@retval EFI_INVALID_PARAMETER The requested memory type is invalid.
|
|
@retval EFI_UNSUPPORTED The requested PhysicalAddress is not supported on
|
|
this platform.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoAllocateBuffer (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN EFI_ALLOCATE_TYPE Type,
|
|
IN EFI_MEMORY_TYPE MemoryType,
|
|
IN UINTN Pages,
|
|
IN OUT EFI_PHYSICAL_ADDRESS *PhysicalAddress
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_PHYSICAL_ADDRESS HostAddress;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
VOID *HostAddress2;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
HostAddress = *PhysicalAddress;
|
|
|
|
if ((MemoryType != EfiBootServicesData) && (MemoryType != EfiRuntimeServicesData)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Type >= MaxAllocateType) || (Type < AllocateAnyPages)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if ((Type == AllocateAddress) && (HostAddress + EFI_PAGES_TO_SIZE (Pages) - 1 > MAX_COMMON_BUFFER)) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if ((AllocateAnyPages == Type) || (AllocateMaxAddress == Type && HostAddress > MAX_COMMON_BUFFER)) {
|
|
Type = AllocateMaxAddress;
|
|
HostAddress = MAX_COMMON_BUFFER;
|
|
}
|
|
|
|
HostAddress2 = (VOID *) (UINTN) (HostAddress);
|
|
Status = Private->PciRootBridgeIo->AllocateBuffer (
|
|
Private->PciRootBridgeIo,
|
|
Type,
|
|
MemoryType,
|
|
Pages,
|
|
&HostAddress2,
|
|
EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE |
|
|
EFI_PCI_ATTRIBUTE_MEMORY_CACHED
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
|
|
*PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress2;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
Flushes any posted write data to the device.
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
|
|
@retval EFI_SUCCESS The buffers were flushed.
|
|
@retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware
|
|
error.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoFlush (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
Status = Private->PciRootBridgeIo->Flush (Private->PciRootBridgeIo);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Frees pages that were allocated with AllocateBuffer().
|
|
|
|
@param This A pointer to the EFI_DEVICE_IO_INTERFACE instance.
|
|
@param Pages The number of pages to free.
|
|
@param HostAddress The base address of the range to free.
|
|
|
|
@retval EFI_SUCCESS The requested memory pages were freed.
|
|
@retval EFI_NOT_FOUND The requested memory pages were not allocated with
|
|
AllocateBuffer().
|
|
@retval EFI_INVALID_PARAMETER HostAddress is not page aligned or Pages is
|
|
invalid.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
DeviceIoFreeBuffer (
|
|
IN EFI_DEVICE_IO_PROTOCOL *This,
|
|
IN UINTN Pages,
|
|
IN EFI_PHYSICAL_ADDRESS HostAddress
|
|
)
|
|
{
|
|
DEVICE_IO_PRIVATE_DATA *Private;
|
|
|
|
Private = DEVICE_IO_PRIVATE_DATA_FROM_THIS (This);
|
|
|
|
if (((HostAddress & EFI_PAGE_MASK) != 0) || (Pages <= 0)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
return Private->PciRootBridgeIo->FreeBuffer (
|
|
Private->PciRootBridgeIo,
|
|
Pages,
|
|
(VOID *) (UINTN) HostAddress
|
|
);
|
|
|
|
}
|
|
|