/*++
Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
PciIo.c
Abstract:
PCI I/O Abstraction Driver
Revision History
--*/
#include
#include
#include
#include "PciDeviceSupport.h"
#include "PciEnumerator.h"
#include "PciEnumeratorSupport.h"
#include "PciDriverOverride.h"
#include "PciRomTable.h"
#include "PciOptionRomSupport.h"
#include "PciPowerManagement.h"
//
// PCI I/O Support Function Prototypes
//
//
BOOLEAN
PciDevicesOnTheSamePath (
IN PCI_IO_DEVICE *PciDevice1,
IN PCI_IO_DEVICE *PciDevice2
);
EFI_STATUS
UpStreamBridgesAttributes (
IN PCI_IO_DEVICE *PciIoDevice,
IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
IN UINT64 Attributes
);
BOOLEAN
CheckBarType (
IN PCI_IO_DEVICE *PciIoDevice,
UINT8 BarIndex,
PCI_BAR_TYPE BarType
);
EFI_STATUS
SetBootVGA (
IN PCI_IO_DEVICE *PciIoDevice
);
EFI_STATUS
DisableBootVGA (
IN PCI_IO_DEVICE *PciIoDevice
);
EFI_STATUS
PciIoVerifyBarAccess (
PCI_IO_DEVICE *PciIoDevice,
UINT8 BarIndex,
PCI_BAR_TYPE Type,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINTN Count,
UINT64 *Offset
);
EFI_STATUS
PciIoVerifyConfigAccess (
PCI_IO_DEVICE *PciIoDevice,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINTN Count,
IN UINT64 *Offset
);
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
);
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
);
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
);
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
);
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
);
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
);
EFI_STATUS
EFIAPI
PciIoConfigRead (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT32 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
);
EFI_STATUS
EFIAPI
PciIoConfigWrite (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT32 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
);
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
);
EFI_STATUS
EFIAPI
PciIoMap (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
IN VOID *HostAddress,
IN OUT UINTN *NumberOfBytes,
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
OUT VOID **Mapping
);
EFI_STATUS
EFIAPI
PciIoUnmap (
IN EFI_PCI_IO_PROTOCOL *This,
IN VOID *Mapping
);
EFI_STATUS
EFIAPI
PciIoAllocateBuffer (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Pages,
OUT VOID **HostAddress,
IN UINT64 Attributes
);
EFI_STATUS
EFIAPI
PciIoFreeBuffer (
IN EFI_PCI_IO_PROTOCOL *This,
IN UINTN Pages,
IN VOID *HostAddress
);
EFI_STATUS
EFIAPI
PciIoFlush (
IN EFI_PCI_IO_PROTOCOL *This
);
EFI_STATUS
EFIAPI
PciIoGetLocation (
IN EFI_PCI_IO_PROTOCOL *This,
OUT UINTN *Segment,
OUT UINTN *Bus,
OUT UINTN *Device,
OUT UINTN *Function
);
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
);
EFI_STATUS
EFIAPI
PciIoGetBarAttributes(
IN EFI_PCI_IO_PROTOCOL *This,
IN UINT8 BarIndex,
OUT UINT64 *Supports, OPTIONAL
OUT VOID **Resources OPTIONAL
);
EFI_STATUS
EFIAPI
PciIoSetBarAttributes(
IN EFI_PCI_IO_PROTOCOL *This,
IN UINT64 Attributes,
IN UINT8 BarIndex,
IN OUT UINT64 *Offset,
IN OUT UINT64 *Length
);
//
// Pci Io Protocol Interface
//
EFI_PCI_IO_PROTOCOL PciIoInterface = {
PciIoPollMem,
PciIoPollIo,
{
PciIoMemRead,
PciIoMemWrite
},
{
PciIoIoRead,
PciIoIoWrite
},
{
PciIoConfigRead,
PciIoConfigWrite
},
PciIoCopyMem,
PciIoMap,
PciIoUnmap,
PciIoAllocateBuffer,
PciIoFreeBuffer,
PciIoFlush,
PciIoGetLocation,
PciIoAttributes,
PciIoGetBarAttributes,
PciIoSetBarAttributes,
0,
NULL
};
//EFI_STATUS
VOID
InitializePciIoInstance (
PCI_IO_DEVICE *PciIoDevice
)
/*++
Routine Description:
Initializes a PCI I/O Instance
Arguments:
Returns:
None
--*/
{
CopyMem(&PciIoDevice->PciIo, &PciIoInterface, sizeof (EFI_PCI_IO_PROTOCOL));
// return EFI_SUCCESS;
}
EFI_STATUS
PciIoVerifyBarAccess (
PCI_IO_DEVICE *PciIoDevice,
UINT8 BarIndex,
PCI_BAR_TYPE Type,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINTN Count,
UINT64 *Offset
)
/*++
Routine Description:
Verifies access to a PCI Base Address Register (BAR)
Arguments:
Returns:
None
--*/
{
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
if (BarIndex == EFI_PCI_IO_PASS_THROUGH_BAR) {
return EFI_SUCCESS;
}
//
// BarIndex 0-5 is legal
//
if (BarIndex >= PCI_MAX_BAR) {
return EFI_INVALID_PARAMETER;
}
if (!CheckBarType (PciIoDevice, BarIndex, Type)) {
return EFI_INVALID_PARAMETER;
}
//
// If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
// If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
//
if (Width >= EfiPciIoWidthFifoUint8 && Width <= EfiPciIoWidthFifoUint64) {
Count = 1;
}
Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PciIoDevice->PciBar[BarIndex].Length) {
return EFI_INVALID_PARAMETER;
}
*Offset = *Offset + PciIoDevice->PciBar[BarIndex].BaseAddress;
return EFI_SUCCESS;
}
EFI_STATUS
PciIoVerifyConfigAccess (
PCI_IO_DEVICE *PciIoDevice,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINTN Count,
IN UINT64 *Offset
)
/*++
Routine Description:
Verifies access to a PCI Config Header
Arguments:
Returns:
None
--*/
{
UINT64 ExtendOffset;
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
//
// If Width is EfiPciIoWidthFifoUintX then convert to EfiPciIoWidthUintX
// If Width is EfiPciIoWidthFillUintX then convert to EfiPciIoWidthUintX
//
Width = (EFI_PCI_IO_PROTOCOL_WIDTH) (Width & 0x03);
if (PciIoDevice->IsPciExp) {
if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PCI_EXP_MAX_CONFIG_OFFSET) {
return EFI_UNSUPPORTED;
}
ExtendOffset = LShiftU64 (*Offset, 32);
*Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
*Offset = (*Offset) | ExtendOffset;
} else {
if ((*Offset + Count * ((UINTN)1 << Width)) - 1 >= PCI_MAX_CONFIG_OFFSET) {
return EFI_UNSUPPORTED;
}
*Offset = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, *Offset);
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
PciIoPollMem (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 BarIndex,
IN UINT64 Offset,
IN UINT64 Mask,
IN UINT64 Value,
IN UINT64 Delay,
OUT UINT64 *Result
)
/*++
Routine Description:
Poll PCI Memmory
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, 1, &Offset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
if (Width > EfiPciIoWidthUint64) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoDevice->PciRootBridgeIo->PollMem (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Offset,
Mask,
Value,
Delay,
Result
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoPollIo (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 BarIndex,
IN UINT64 Offset,
IN UINT64 Mask,
IN UINT64 Value,
IN UINT64 Delay,
OUT UINT64 *Result
)
/*++
Routine Description:
Poll PCI IO
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width > EfiPciIoWidthUint64) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, 1, &Offset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoDevice->PciRootBridgeIo->PollIo (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Offset,
Mask,
Value,
Delay,
Result
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoMemRead (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 BarIndex,
IN UINT64 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
)
/*++
Routine Description:
Performs a PCI Memory Read Cycle
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
if (Buffer == NULL){
return EFI_INVALID_PARAMETER;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoDevice->PciRootBridgeIo->Mem.Read (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Offset,
Count,
Buffer
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoMemWrite (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 BarIndex,
IN UINT64 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
)
/*++
Routine Description:
Performs a PCI Memory Write Cycle
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
if (Buffer == NULL){
return EFI_INVALID_PARAMETER;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeMem, Width, Count, &Offset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoDevice->PciRootBridgeIo->Mem.Write (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Offset,
Count,
Buffer
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoIoRead (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 BarIndex,
IN UINT64 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
)
/*++
Routine Description:
Performs a PCI I/O Read Cycle
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
if (Buffer == NULL){
return EFI_INVALID_PARAMETER;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoDevice->PciRootBridgeIo->Io.Read (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Offset,
Count,
Buffer
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoIoWrite (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 BarIndex,
IN UINT64 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
)
/*++
Routine Description:
Performs a PCI I/O Write Cycle
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
if (Buffer == NULL){
return EFI_INVALID_PARAMETER;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, BarIndex, PciBarTypeIo, Width, Count, &Offset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoDevice->PciRootBridgeIo->Io.Write (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Offset,
Count,
Buffer
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoConfigRead (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT32 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
)
/*++
Routine Description:
Performs a PCI Configuration Read Cycle
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
UINT64 Address;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
Address = Offset;
Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
if (EFI_ERROR(Status)) {
return Status;
}
Status = PciIoDevice->PciRootBridgeIo->Pci.Read (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Address,
Count,
Buffer
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoConfigWrite (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT32 Offset,
IN UINTN Count,
IN OUT VOID *Buffer
)
/*++
Routine Description:
Performs a PCI Configuration Write Cycle
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
UINT64 Address;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
Address = Offset;
Status = PciIoVerifyConfigAccess (PciIoDevice, Width, Count, &Address);
if (EFI_ERROR(Status)) {
return Status;
}
Status = PciIoDevice->PciRootBridgeIo->Pci.Write (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
Address,
Count,
Buffer
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoCopyMem(
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
IN UINT8 DestBarIndex,
IN UINT64 DestOffset,
IN UINT8 SrcBarIndex,
IN UINT64 SrcOffset,
IN UINTN Count
)
/*++
Routine Description:
Copy PCI Memory
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Width >= EfiPciIoWidthMaximum) {
return EFI_INVALID_PARAMETER;
}
if (Width == EfiPciIoWidthFifoUint8 ||
Width == EfiPciIoWidthFifoUint16 ||
Width == EfiPciIoWidthFifoUint32 ||
Width == EfiPciIoWidthFifoUint64 ||
Width == EfiPciIoWidthFillUint8 ||
Width == EfiPciIoWidthFillUint16 ||
Width == EfiPciIoWidthFillUint32 ||
Width == EfiPciIoWidthFillUint64) {
return EFI_INVALID_PARAMETER;
}
Status = PciIoVerifyBarAccess (PciIoDevice, DestBarIndex, PciBarTypeMem, Width, Count, &DestOffset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoVerifyBarAccess (PciIoDevice, SrcBarIndex, PciBarTypeMem, Width, Count, &SrcOffset);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
Status = PciIoDevice->PciRootBridgeIo->CopyMem(
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
DestOffset,
SrcOffset,
Count
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoMap (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,
IN VOID *HostAddress,
IN OUT UINTN *NumberOfBytes,
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
OUT VOID **Mapping
)
/*++
Routine Description:
Maps a memory region for DMA
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if ((UINT32)Operation >= EfiPciIoOperationMaximum) {
return EFI_INVALID_PARAMETER;
}
if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL || Mapping == NULL) {
return EFI_INVALID_PARAMETER;
}
if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {
Operation = (EFI_PCI_IO_PROTOCOL_OPERATION) (Operation + EfiPciOperationBusMasterRead64);
}
Status = PciIoDevice->PciRootBridgeIo->Map (
PciIoDevice->PciRootBridgeIo,
(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) Operation,
HostAddress,
NumberOfBytes,
DeviceAddress,
Mapping
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoUnmap (
IN EFI_PCI_IO_PROTOCOL *This,
IN VOID *Mapping
)
/*++
Routine Description:
Unmaps a memory region for DMA
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
Status = PciIoDevice->PciRootBridgeIo->Unmap (
PciIoDevice->PciRootBridgeIo,
Mapping
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoAllocateBuffer (
IN EFI_PCI_IO_PROTOCOL *This,
IN EFI_ALLOCATE_TYPE Type,
IN EFI_MEMORY_TYPE MemoryType,
IN UINTN Pages,
OUT VOID **HostAddress,
IN UINT64 Attributes
)
/*++
Routine Description:
Allocates a common buffer for DMA
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
if (Attributes &
(~(EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_PCI_ATTRIBUTE_MEMORY_CACHED))) {
return EFI_UNSUPPORTED;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) {
Attributes |= EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
}
Status = PciIoDevice->PciRootBridgeIo->AllocateBuffer (
PciIoDevice->PciRootBridgeIo,
Type,
MemoryType,
Pages,
HostAddress,
Attributes
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoFreeBuffer (
IN EFI_PCI_IO_PROTOCOL *This,
IN UINTN Pages,
IN VOID *HostAddress
)
/*++
Routine Description:
Frees a common buffer
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
if( HostAddress == NULL ){
return EFI_INVALID_PARAMETER;
}
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
Status = PciIoDevice->PciRootBridgeIo->FreeBuffer (
PciIoDevice->PciRootBridgeIo,
Pages,
HostAddress
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoFlush (
IN EFI_PCI_IO_PROTOCOL *This
)
/*++
Routine Description:
Flushes a DMA buffer
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
UINT32 Register;
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
//
// If the device is behind a PCI-PCI Bridge, then perform a read cycles to the device to
// flush the posted write cycles through the PCI-PCI bridges
//
if (PciIoDevice->Parent != NULL) {
Status = This->Pci.Read (This, EfiPciIoWidthUint32, 0, 1, &Register);
}
//
// Call the PCI Root Bridge I/O Protocol to flush the posted write cycles through the chipset
//
Status = PciIoDevice->PciRootBridgeIo->Flush (
PciIoDevice->PciRootBridgeIo
);
return Status;
}
EFI_STATUS
EFIAPI
PciIoGetLocation (
IN EFI_PCI_IO_PROTOCOL *This,
OUT UINTN *Segment,
OUT UINTN *Bus,
OUT UINTN *Device,
OUT UINTN *Function
)
/*++
Routine Description:
Gets a PCI device's current bus number, device number, and function number.
Arguments:
Returns:
None
--*/
{
PCI_IO_DEVICE *PciIoDevice;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if (Segment == NULL || Bus == NULL || Device == NULL || Function == NULL) {
return EFI_INVALID_PARAMETER;
}
*Segment = PciIoDevice->PciRootBridgeIo->SegmentNumber;
*Bus = PciIoDevice->BusNumber;
*Device = PciIoDevice->DeviceNumber;
*Function = PciIoDevice->FunctionNumber;
return EFI_SUCCESS;
}
BOOLEAN
CheckBarType (
IN PCI_IO_DEVICE *PciIoDevice,
UINT8 BarIndex,
PCI_BAR_TYPE BarType
)
/*++
Routine Description:
Sets a PCI controllers attributes on a resource range
Arguments:
Returns:
None
--*/
{
switch (BarType) {
case PciBarTypeMem:
if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem32 &&
PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem32 &&
PciIoDevice->PciBar[BarIndex].BarType != PciBarTypePMem64 &&
PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeMem64 ) {
return FALSE;
}
return TRUE;
case PciBarTypeIo:
if (PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo32 &&
PciIoDevice->PciBar[BarIndex].BarType != PciBarTypeIo16){
return FALSE;
}
return TRUE;
default:
break;
}
return FALSE;
}
EFI_STATUS
EFIAPI
PciIoAttributes (
IN EFI_PCI_IO_PROTOCOL * This,
IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
IN UINT64 Attributes,
OUT UINT64 *Result OPTIONAL
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
PCI_IO_DEVICE *Temp;
UINT64 NewAttributes;
UINT64 PciRootBridgeSupports;
UINT64 PciRootBridgeAttributes;
UINT64 NewPciRootBridgeAttributes;
UINT64 NewUpStreamBridgeAttributes;
UINT64 ModifiedPciRootBridgeAttributes;
UINT16 EnableCommand;
UINT16 DisableCommand;
UINT16 EnableBridge;
UINT16 DisableBridge;
UINT16 Command;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
NewUpStreamBridgeAttributes = 0;
EnableCommand = 0;
DisableCommand = 0;
EnableBridge = 0;
DisableBridge = 0;
switch (Operation) {
case EfiPciIoAttributeOperationGet:
if (Result == NULL) {
return EFI_INVALID_PARAMETER;
}
*Result = PciIoDevice->Attributes;
return EFI_SUCCESS;
case EfiPciIoAttributeOperationSupported:
if (Result == NULL) {
return EFI_INVALID_PARAMETER;
}
*Result = PciIoDevice->Supports;
return EFI_SUCCESS;
case EfiPciIoAttributeOperationEnable:
if(Attributes & ~(PciIoDevice->Supports)) {
return EFI_UNSUPPORTED;
}
NewAttributes = PciIoDevice->Attributes | Attributes;
break;
case EfiPciIoAttributeOperationDisable:
if(Attributes & ~(PciIoDevice->Supports)) {
return EFI_UNSUPPORTED;
}
NewAttributes = PciIoDevice->Attributes & (~Attributes);
break;
case EfiPciIoAttributeOperationSet:
if(Attributes & ~(PciIoDevice->Supports)) {
return EFI_UNSUPPORTED;
}
NewAttributes = Attributes;
break;
default:
return EFI_INVALID_PARAMETER;
}
//
// If VGA_IO is set, then set VGA_MEMORY too. This driver can not enable them seperately.
//
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
NewAttributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
}
//
// If VGA_MEMORY is set, then set VGA_IO too. This driver can not enable them seperately.
//
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY) {
NewAttributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
}
//
// If the attributes are already set correctly, then just return EFI_SUCCESS;
//
if ((NewAttributes ^ PciIoDevice->Attributes) == 0) {
return EFI_SUCCESS;
}
//
// This driver takes care of EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_MEMORY, and
// EFI_PCI_IO_ATTRIBUTE_BUS_MASTER. Strip these 3 bits off the new attribute mask so
// a call to the PCI Root Bridge I/O Protocol can be made
//
if (!IS_PCI_BRIDGE(&PciIoDevice->Pci)) {
NewPciRootBridgeAttributes = NewAttributes & (~(EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE));
//
// Get the current attributes of this PCI device's PCI Root Bridge
//
Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
PciIoDevice->PciRootBridgeIo,
&PciRootBridgeSupports,
&PciRootBridgeAttributes
);
//
// Check to see if any of the PCI Root Bridge attributes are being modified
//
ModifiedPciRootBridgeAttributes = NewPciRootBridgeAttributes ^ PciRootBridgeAttributes;
if (ModifiedPciRootBridgeAttributes) {
//
// Check to see if the PCI Root Bridge supports modifiying the attributes that are changing
//
if ((ModifiedPciRootBridgeAttributes & PciRootBridgeSupports) != ModifiedPciRootBridgeAttributes) {
// return EFI_UNSUPPORTED;
}
//
// Call the PCI Root Bridge to attempt to modify the attributes
//
Status = PciIoDevice->PciRootBridgeIo->SetAttributes (
PciIoDevice->PciRootBridgeIo,
NewPciRootBridgeAttributes,
NULL,
NULL
);
if (EFI_ERROR(Status)) {
//
// The PCI Root Bridge could not modify the attributes, so return the error.
//
return Status;
}
}
}
if (IS_PCI_BRIDGE(&PciIoDevice->Pci)) {
//
// Check to see if an VGA related attributes are being set.
//
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
EnableBridge |= EFI_PCI_BRIDGE_CONTROL_VGA;
} else {
DisableBridge |= EFI_PCI_BRIDGE_CONTROL_VGA;
}
}
//
// Check to see if an VGA related attributes are being set.
// If ISA Enable on the PPB is set, the PPB will block the
// 0x100-0x3FF for each 1KB block in the first 64K I/O block
//
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_ISA_IO) {
DisableBridge |= EFI_PCI_BRIDGE_CONTROL_ISA;
} else {
EnableBridge |= EFI_PCI_BRIDGE_CONTROL_ISA;
}
}
//
// Check to see if an VGA related attributes are being set.
//
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) {
EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
} else {
DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
}
}
} else {
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_IO) {
//
//Check if there have been an active VGA device on the same segment
//
Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
if (Temp && Temp != PciIoDevice) {
return EFI_UNSUPPORTED;
}
}
}
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO)) {
if (IS_PCI_GFX(&PciIoDevice->Pci)) {
//
//Get the boot VGA on the same segement
//
Temp = ActiveVGADeviceOnTheSameSegment (PciIoDevice);
if (!Temp) {
//
// If there is no VGA device on the segement, set
// this graphics card to decode the palette range
//
DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
} else {
//
// Check these two agents are on the same path
//
if (PciDevicesOnTheSamePath(Temp, PciIoDevice)) {
//
// Check if they are on the same bus
//
if (Temp->Parent == PciIoDevice->Parent) {
PciReadCommandRegister (Temp, &Command);
//
// If they are on the same bus, either one can
// be set to snoop, the other set to decode
//
if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {
DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
} else {
EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
}
} else {
//
// If they are on the same path but on the different bus
// The first agent is set to snoop, the second one set to
// decode
//
if (Temp->BusNumber > PciIoDevice->BusNumber) {
PciEnableCommandRegister(Temp,EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
DisableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
} else {
PciDisableCommandRegister(Temp,EFI_PCI_COMMAND_VGA_PALETTE_SNOOP);
EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
}
}
} else {
EnableCommand |= EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
}
}
}
}
}
//
// Check to see of the I/O enable is being modified
//
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_IO) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_IO)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_IO) {
EnableCommand |= EFI_PCI_COMMAND_IO_SPACE;
} else {
DisableCommand |= EFI_PCI_COMMAND_IO_SPACE;
}
}
//
// Check to see of the Memory enable is being modified
//
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_MEMORY)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_MEMORY) {
EnableCommand |= EFI_PCI_COMMAND_MEMORY_SPACE;
} else {
DisableCommand |= EFI_PCI_COMMAND_MEMORY_SPACE;
}
}
//
// Check to see of the Bus Master enable is being modified
//
if ((NewAttributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) ^ (PciIoDevice->Attributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER)) {
if (NewAttributes & EFI_PCI_IO_ATTRIBUTE_BUS_MASTER) {
EnableCommand |= EFI_PCI_COMMAND_BUS_MASTER;
} else {
DisableCommand |= EFI_PCI_COMMAND_BUS_MASTER;
}
}
Status = EFI_SUCCESS;
if (EnableCommand) {
Status = PciEnableCommandRegister(PciIoDevice, EnableCommand);
}
if (DisableCommand) {
Status = PciDisableCommandRegister(PciIoDevice, DisableCommand);
}
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
if (EnableBridge) {
Status = PciEnableBridgeControlRegister(PciIoDevice, EnableBridge);
}
if (DisableBridge) {
Status = PciDisableBridgeControlRegister(PciIoDevice, DisableBridge);
}
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
//
// Set the upstream bridge attributes
//
if (Operation != EfiPciIoAttributeOperationGet && Operation != EfiPciIoAttributeOperationSupported) {
//
// EFI_PCI_IO_ATTRIBUTE_MEMORY, EFI_PCI_IO_ATTRIBUTE_IO, EFI_PCI_IO_ATTRIBUTE_BUS_MASTER
// EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE, EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED
// EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE will not effect to upstream bridge
//
NewUpStreamBridgeAttributes = Attributes & \
(~(EFI_PCI_IO_ATTRIBUTE_IO | \
EFI_PCI_IO_ATTRIBUTE_MEMORY | \
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER | \
EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | \
EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | \
EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE));
if (NewUpStreamBridgeAttributes){
UpStreamBridgesAttributes(PciIoDevice, Operation, NewUpStreamBridgeAttributes);
}
}
PciIoDevice->Attributes = NewAttributes;
return Status;
}
EFI_STATUS
EFIAPI
PciIoGetBarAttributes (
IN EFI_PCI_IO_PROTOCOL * This,
IN UINT8 BarIndex,
OUT UINT64 *Supports, OPTIONAL
OUT VOID **Resources OPTIONAL
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
UINT8 *Configuration;
PCI_IO_DEVICE *PciIoDevice;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *AddressSpace;
EFI_ACPI_END_TAG_DESCRIPTOR *End;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
if (Supports == NULL && Resources == NULL) {
return EFI_INVALID_PARAMETER;
}
if ((BarIndex >= PCI_MAX_BAR) || (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown)) {
return EFI_UNSUPPORTED;
}
//
// This driver does not support modifications to the WRITE_COMBINE or
// CACHED attributes for BAR ranges.
//
if (Supports != NULL) {
*Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
}
if (Resources != NULL) {
Configuration = AllocateZeroPool(sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
if (Configuration == NULL) {
return EFI_OUT_OF_RESOURCES;
}
AddressSpace = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
AddressSpace->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
AddressSpace->Len = (UINT16) (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3);
AddressSpace->AddrRangeMin = PciIoDevice->PciBar[BarIndex].BaseAddress;
AddressSpace->AddrLen = PciIoDevice->PciBar[BarIndex].Length;
AddressSpace->AddrRangeMax = PciIoDevice->PciBar[BarIndex].Alignment;
switch (PciIoDevice->PciBar[BarIndex].BarType) {
case PciBarTypeIo16:
case PciBarTypeIo32:
//
// Io
//
AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
break;
case PciBarTypeMem32:
//
// Mem
//
AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
//
// 32 bit
//
AddressSpace->AddrSpaceGranularity = 32;
break;
case PciBarTypePMem32:
//
// Mem
//
AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
//
// prefechable
//
AddressSpace->SpecificFlag = 0x6;
//
// 32 bit
//
AddressSpace->AddrSpaceGranularity = 32;
break;
case PciBarTypeMem64:
//
// Mem
//
AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
//
// 64 bit
//
AddressSpace->AddrSpaceGranularity = 64;
break;
case PciBarTypePMem64:
//
// Mem
//
AddressSpace->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
//
// prefechable
//
AddressSpace->SpecificFlag = 0x6;
//
// 64 bit
//
AddressSpace->AddrSpaceGranularity = 64;
break;
default:
break;
}
//
// put the checksum
//
End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (AddressSpace + 1);
End->Desc = ACPI_END_TAG_DESCRIPTOR;
End->Checksum = 0;
*Resources = Configuration;
}
return EFI_SUCCESS;
}
EFI_STATUS
EFIAPI
PciIoSetBarAttributes (
IN EFI_PCI_IO_PROTOCOL *This,
IN UINT64 Attributes,
IN UINT8 BarIndex,
IN OUT UINT64 *Offset,
IN OUT UINT64 *Length
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
EFI_STATUS Status;
PCI_IO_DEVICE *PciIoDevice;
UINT64 NonRelativeOffset;
UINT64 Supports;
PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (This);
//
// Make sure Offset and Length are not NULL
//
if (Offset == NULL || Length == NULL) {
return EFI_INVALID_PARAMETER;
}
if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeUnknown) {
return EFI_UNSUPPORTED;
}
//
// This driver does not support setting the WRITE_COMBINE or the CACHED attributes.
// If Attributes is not 0, then return EFI_UNSUPPORTED.
//
Supports = PciIoDevice->Supports & EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED & EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE;
if (Attributes != (Attributes & Supports)) {
return EFI_UNSUPPORTED;
}
//
// Attributes must be supported. Make sure the BAR range describd by BarIndex, Offset, and
// Length are valid for this PCI device.
//
NonRelativeOffset = *Offset;
Status = PciIoVerifyBarAccess (
PciIoDevice,
BarIndex,
PciBarTypeMem,
EfiPciIoWidthUint8,
(UINT32) *Length,
&NonRelativeOffset
);
if (EFI_ERROR(Status)) {
return EFI_UNSUPPORTED;
}
return EFI_SUCCESS;
}
EFI_STATUS
UpStreamBridgesAttributes (
IN PCI_IO_DEVICE *PciIoDevice,
IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation,
IN UINT64 Attributes
)
/*++
Routine Description:
Arguments:
Returns:
None
--*/
{
PCI_IO_DEVICE *Parent;
EFI_PCI_IO_PROTOCOL *PciIo;
Parent = PciIoDevice->Parent;
while (Parent && IS_PCI_BRIDGE (&Parent->Pci)) {
//
// Get the PciIo Protocol
//
PciIo = &Parent->PciIo;
PciIo->Attributes (PciIo, Operation, Attributes, NULL);
Parent = Parent->Parent;
}
return EFI_SUCCESS;
}
BOOLEAN
PciDevicesOnTheSamePath (
IN PCI_IO_DEVICE *PciDevice1,
IN PCI_IO_DEVICE *PciDevice2
)
/*++
Routine Description:
Arguments:
PciDevice1 - The pointer to the first PCI_IO_DEVICE.
PciDevice2 - The pointer to the second PCI_IO_DEVICE.
Returns:
TRUE - The two Pci devices are on the same path.
FALSE - The two Pci devices are not on the same path.
--*/
{
if (PciDevice1->Parent == PciDevice2->Parent) {
return TRUE;
}
return (BOOLEAN) ((PciDeviceExisted (PciDevice1->Parent, PciDevice2)|| PciDeviceExisted (PciDevice2->Parent, PciDevice1)));
}