/*++ | |
Copyright (c) 2005 - 2012, Intel Corporation. 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. | |
Module Name: | |
PcatPciRootBridgeIo.c | |
Abstract: | |
EFI PC AT PCI Root Bridge Io Protocol | |
Revision History | |
--*/ | |
#include "PcatPciRootBridge.h" | |
// | |
// Protocol Member Function Prototypes | |
// | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPollMem ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINT64 Mask, | |
IN UINT64 Value, | |
IN UINT64 Delay, | |
OUT UINT64 *Result | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPollIo ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINT64 Mask, | |
IN UINT64 Value, | |
IN UINT64 Delay, | |
OUT UINT64 *Result | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMemRead ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMemWrite ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoCopyMem ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 DestAddress, | |
IN UINT64 SrcAddress, | |
IN UINTN Count | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPciRead ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPciWrite ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMap ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, | |
IN VOID *HostAddress, | |
IN OUT UINTN *NumberOfBytes, | |
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
OUT VOID **Mapping | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoUnmap ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN VOID *Mapping | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoAllocateBuffer ( | |
IN EFI_PCI_ROOT_BRIDGE_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 | |
PcatRootBridgeIoFreeBuffer ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN UINTN Pages, | |
OUT VOID *HostAddress | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoFlush ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoGetAttributes ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
OUT UINT64 *Supported, | |
OUT UINT64 *Attributes | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoSetAttributes ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN UINT64 Attributes, | |
IN OUT UINT64 *ResourceBase, | |
IN OUT UINT64 *ResourceLength | |
); | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoConfiguration ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
OUT VOID **Resources | |
); | |
// | |
// Private Function Prototypes | |
// | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMemRW ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINTN Count, | |
IN BOOLEAN InStrideFlag, | |
IN PTR In, | |
IN BOOLEAN OutStrideFlag, | |
OUT PTR Out | |
); | |
EFI_STATUS | |
PcatRootBridgeIoConstructor ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol, | |
IN UINTN SegmentNumber | |
) | |
/*++ | |
Routine Description: | |
Contruct the Pci Root Bridge Io protocol | |
Arguments: | |
Protocol - protocol to initialize | |
Returns: | |
None | |
--*/ | |
{ | |
Protocol->ParentHandle = NULL; | |
Protocol->PollMem = PcatRootBridgeIoPollMem; | |
Protocol->PollIo = PcatRootBridgeIoPollIo; | |
Protocol->Mem.Read = PcatRootBridgeIoMemRead; | |
Protocol->Mem.Write = PcatRootBridgeIoMemWrite; | |
Protocol->Io.Read = PcatRootBridgeIoIoRead; | |
Protocol->Io.Write = PcatRootBridgeIoIoWrite; | |
Protocol->CopyMem = PcatRootBridgeIoCopyMem; | |
Protocol->Pci.Read = PcatRootBridgeIoPciRead; | |
Protocol->Pci.Write = PcatRootBridgeIoPciWrite; | |
Protocol->Map = PcatRootBridgeIoMap; | |
Protocol->Unmap = PcatRootBridgeIoUnmap; | |
Protocol->AllocateBuffer = PcatRootBridgeIoAllocateBuffer; | |
Protocol->FreeBuffer = PcatRootBridgeIoFreeBuffer; | |
Protocol->Flush = PcatRootBridgeIoFlush; | |
Protocol->GetAttributes = PcatRootBridgeIoGetAttributes; | |
Protocol->SetAttributes = PcatRootBridgeIoSetAttributes; | |
Protocol->Configuration = PcatRootBridgeIoConfiguration; | |
Protocol->SegmentNumber = (UINT32)SegmentNumber; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPollMem ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINT64 Mask, | |
IN UINT64 Value, | |
IN UINT64 Delay, | |
OUT UINT64 *Result | |
) | |
{ | |
EFI_STATUS Status; | |
UINT64 NumberOfTicks; | |
UINT32 Remainder; | |
if (Result == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((UINT32)Width > EfiPciWidthUint64) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// No matter what, always do a single poll. | |
// | |
Status = This->Mem.Read (This, Width, Address, 1, Result); | |
if ( EFI_ERROR(Status) ) { | |
return Status; | |
} | |
if ( (*Result & Mask) == Value ) { | |
return EFI_SUCCESS; | |
} | |
if (Delay == 0) { | |
return EFI_SUCCESS; | |
} else { | |
NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); | |
if ( Remainder !=0 ) { | |
NumberOfTicks += 1; | |
} | |
NumberOfTicks += 1; | |
while ( NumberOfTicks ) { | |
gBS->Stall (10); | |
Status = This->Mem.Read (This, Width, Address, 1, Result); | |
if ( EFI_ERROR(Status) ) { | |
return Status; | |
} | |
if ( (*Result & Mask) == Value ) { | |
return EFI_SUCCESS; | |
} | |
NumberOfTicks -= 1; | |
} | |
} | |
return EFI_TIMEOUT; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPollIo ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINT64 Mask, | |
IN UINT64 Value, | |
IN UINT64 Delay, | |
OUT UINT64 *Result | |
) | |
{ | |
EFI_STATUS Status; | |
UINT64 NumberOfTicks; | |
UINT32 Remainder; | |
if (Result == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if ((UINT32)Width > EfiPciWidthUint64) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// No matter what, always do a single poll. | |
// | |
Status = This->Io.Read (This, Width, Address, 1, Result); | |
if ( EFI_ERROR(Status) ) { | |
return Status; | |
} | |
if ( (*Result & Mask) == Value ) { | |
return EFI_SUCCESS; | |
} | |
if (Delay == 0) { | |
return EFI_SUCCESS; | |
} else { | |
NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder); | |
if ( Remainder !=0 ) { | |
NumberOfTicks += 1; | |
} | |
NumberOfTicks += 1; | |
while ( NumberOfTicks ) { | |
gBS->Stall(10); | |
Status = This->Io.Read (This, Width, Address, 1, Result); | |
if ( EFI_ERROR(Status) ) { | |
return Status; | |
} | |
if ( (*Result & Mask) == Value ) { | |
return EFI_SUCCESS; | |
} | |
NumberOfTicks -= 1; | |
} | |
} | |
return EFI_TIMEOUT; | |
} | |
BOOLEAN | |
PcatRootBridgeMemAddressValid ( | |
IN PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData, | |
IN UINT64 Address | |
) | |
{ | |
if ((Address >= PrivateData->PciExpressBaseAddress) && (Address < PrivateData->PciExpressBaseAddress + 0x10000000)) { | |
return TRUE; | |
} | |
if ((Address >= PrivateData->MemBase) && (Address < PrivateData->MemLimit)) { | |
return TRUE; | |
} | |
return FALSE; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMemRead ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
) | |
{ | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
UINTN AlignMask; | |
PTR In; | |
PTR Out; | |
if ( Buffer == NULL ) { | |
return EFI_INVALID_PARAMETER; | |
} | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
AlignMask = (1 << (Width & 0x03)) - 1; | |
if (Address & AlignMask) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Address += PrivateData->PhysicalMemoryBase; | |
In.buf = Buffer; | |
Out.buf = (VOID *)(UINTN) Address; | |
if ((UINT32)Width <= EfiPciWidthUint64) { | |
return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); | |
} | |
if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { | |
return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); | |
} | |
if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { | |
return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); | |
} | |
return EFI_INVALID_PARAMETER; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMemWrite ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
) | |
{ | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
UINTN AlignMask; | |
PTR In; | |
PTR Out; | |
if ( Buffer == NULL ) { | |
return EFI_INVALID_PARAMETER; | |
} | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
AlignMask = (1 << (Width & 0x03)) - 1; | |
if (Address & AlignMask) { | |
return EFI_INVALID_PARAMETER; | |
} | |
Address += PrivateData->PhysicalMemoryBase; | |
In.buf = (VOID *)(UINTN) Address; | |
Out.buf = Buffer; | |
if ((UINT32)Width <= EfiPciWidthUint64) { | |
return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out); | |
} | |
if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { | |
return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out); | |
} | |
if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { | |
return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out); | |
} | |
return EFI_INVALID_PARAMETER; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoCopyMem ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 DestAddress, | |
IN UINT64 SrcAddress, | |
IN UINTN Count | |
) | |
{ | |
EFI_STATUS Status; | |
BOOLEAN Direction; | |
UINTN Stride; | |
UINTN Index; | |
UINT64 Result; | |
if ((UINT32)Width > EfiPciWidthUint64) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (DestAddress == SrcAddress) { | |
return EFI_SUCCESS; | |
} | |
Stride = (UINTN)1 << Width; | |
Direction = TRUE; | |
if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) { | |
Direction = FALSE; | |
SrcAddress = SrcAddress + (Count-1) * Stride; | |
DestAddress = DestAddress + (Count-1) * Stride; | |
} | |
for (Index = 0;Index < Count;Index++) { | |
Status = PcatRootBridgeIoMemRead ( | |
This, | |
Width, | |
SrcAddress, | |
1, | |
&Result | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
Status = PcatRootBridgeIoMemWrite ( | |
This, | |
Width, | |
DestAddress, | |
1, | |
&Result | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
if (Direction) { | |
SrcAddress += Stride; | |
DestAddress += Stride; | |
} else { | |
SrcAddress -= Stride; | |
DestAddress -= Stride; | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPciRead ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
) | |
{ | |
if (Buffer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
return PcatRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoPciWrite ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINT64 Address, | |
IN UINTN Count, | |
IN OUT VOID *Buffer | |
) | |
{ | |
if (Buffer == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
return PcatRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMap ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation, | |
IN VOID *HostAddress, | |
IN OUT UINTN *NumberOfBytes, | |
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, | |
OUT VOID **Mapping | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PHYSICAL_ADDRESS PhysicalAddress; | |
MAP_INFO *MapInfo; | |
MAP_INFO_INSTANCE *MapInstance; | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
if ( HostAddress == NULL || NumberOfBytes == NULL || | |
DeviceAddress == NULL || Mapping == NULL ) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Perform a fence operation to make sure all memory operations are flushed | |
// | |
MemoryFence(); | |
// | |
// Initialize the return values to their defaults | |
// | |
*Mapping = NULL; | |
// | |
// Make sure that Operation is valid | |
// | |
if ((UINT32)Operation >= EfiPciOperationMaximum) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Most PCAT like chipsets can not handle performing DMA above 4GB. | |
// If any part of the DMA transfer being mapped is above 4GB, then | |
// map the DMA transfer to a buffer below 4GB. | |
// | |
PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress; | |
if ((PhysicalAddress + *NumberOfBytes) > 0x100000000ULL) { | |
// | |
// Common Buffer operations can not be remapped. If the common buffer | |
// if above 4GB, then it is not possible to generate a mapping, so return | |
// an error. | |
// | |
if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Allocate a MAP_INFO structure to remember the mapping when Unmap() is | |
// called later. | |
// | |
Status = gBS->AllocatePool ( | |
EfiBootServicesData, | |
sizeof(MAP_INFO), | |
(VOID **)&MapInfo | |
); | |
if (EFI_ERROR (Status)) { | |
*NumberOfBytes = 0; | |
return Status; | |
} | |
// | |
// Return a pointer to the MAP_INFO structure in Mapping | |
// | |
*Mapping = MapInfo; | |
// | |
// Initialize the MAP_INFO structure | |
// | |
MapInfo->Operation = Operation; | |
MapInfo->NumberOfBytes = *NumberOfBytes; | |
MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES(*NumberOfBytes); | |
MapInfo->HostAddress = PhysicalAddress; | |
MapInfo->MappedHostAddress = 0x00000000ffffffff; | |
// | |
// Allocate a buffer below 4GB to map the transfer to. | |
// | |
Status = gBS->AllocatePages ( | |
AllocateMaxAddress, | |
EfiBootServicesData, | |
MapInfo->NumberOfPages, | |
&MapInfo->MappedHostAddress | |
); | |
if (EFI_ERROR(Status)) { | |
gBS->FreePool (MapInfo); | |
*NumberOfBytes = 0; | |
return Status; | |
} | |
// | |
// If this is a read operation from the Bus Master's point of view, | |
// then copy the contents of the real buffer into the mapped buffer | |
// so the Bus Master can read the contents of the real buffer. | |
// | |
if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) { | |
CopyMem ( | |
(VOID *)(UINTN)MapInfo->MappedHostAddress, | |
(VOID *)(UINTN)MapInfo->HostAddress, | |
MapInfo->NumberOfBytes | |
); | |
} | |
Status =gBS->AllocatePool ( | |
EfiBootServicesData, | |
sizeof(MAP_INFO_INSTANCE), | |
(VOID **)&MapInstance | |
); | |
if (EFI_ERROR(Status)) { | |
gBS->FreePages (MapInfo->MappedHostAddress,MapInfo->NumberOfPages); | |
gBS->FreePool (MapInfo); | |
*NumberOfBytes = 0; | |
return Status; | |
} | |
MapInstance->Map=MapInfo; | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
InsertTailList(&PrivateData->MapInfo,&MapInstance->Link); | |
// | |
// The DeviceAddress is the address of the maped buffer below 4GB | |
// | |
*DeviceAddress = MapInfo->MappedHostAddress; | |
} else { | |
// | |
// The transfer is below 4GB, so the DeviceAddress is simply the HostAddress | |
// | |
*DeviceAddress = PhysicalAddress; | |
} | |
// | |
// Perform a fence operation to make sure all memory operations are flushed | |
// | |
MemoryFence(); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoUnmap ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN VOID *Mapping | |
) | |
{ | |
MAP_INFO *MapInfo; | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
LIST_ENTRY *Link; | |
// | |
// Perform a fence operation to make sure all memory operations are flushed | |
// | |
MemoryFence(); | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
// | |
// See if the Map() operation associated with this Unmap() required a mapping buffer. | |
// If a mapping buffer was not required, then this function simply returns EFI_SUCCESS. | |
// | |
if (Mapping != NULL) { | |
// | |
// Get the MAP_INFO structure from Mapping | |
// | |
MapInfo = (MAP_INFO *)Mapping; | |
for (Link = PrivateData->MapInfo.ForwardLink; Link != &PrivateData->MapInfo; Link = Link->ForwardLink) { | |
if (((MAP_INFO_INSTANCE*)Link)->Map == MapInfo) | |
break; | |
} | |
if (Link == &PrivateData->MapInfo) { | |
return EFI_INVALID_PARAMETER; | |
} | |
RemoveEntryList(Link); | |
((MAP_INFO_INSTANCE*)Link)->Map = NULL; | |
gBS->FreePool((MAP_INFO_INSTANCE*)Link); | |
// | |
// If this is a write operation from the Bus Master's point of view, | |
// then copy the contents of the mapped buffer into the real buffer | |
// so the processor can read the contents of the real buffer. | |
// | |
if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) { | |
CopyMem ( | |
(VOID *)(UINTN)MapInfo->HostAddress, | |
(VOID *)(UINTN)MapInfo->MappedHostAddress, | |
MapInfo->NumberOfBytes | |
); | |
} | |
// | |
// Free the mapped buffer and the MAP_INFO structure. | |
// | |
gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages); | |
gBS->FreePool (Mapping); | |
} | |
// | |
// Perform a fence operation to make sure all memory operations are flushed | |
// | |
MemoryFence(); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoAllocateBuffer ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN EFI_ALLOCATE_TYPE Type, | |
IN EFI_MEMORY_TYPE MemoryType, | |
IN UINTN Pages, | |
OUT VOID **HostAddress, | |
IN UINT64 Attributes | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PHYSICAL_ADDRESS PhysicalAddress; | |
// | |
// Validate Attributes | |
// | |
if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Check for invalid inputs | |
// | |
if (HostAddress == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData | |
// | |
if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Limit allocations to memory below 4GB | |
// | |
PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(0xffffffff); | |
Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
*HostAddress = (VOID *)(UINTN)PhysicalAddress; | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoFreeBuffer ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN UINTN Pages, | |
OUT VOID *HostAddress | |
) | |
{ | |
if( HostAddress == NULL ){ | |
return EFI_INVALID_PARAMETER; | |
} | |
return gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Pages); | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoFlush ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This | |
) | |
{ | |
// | |
// Perform a fence operation to make sure all memory operations are flushed | |
// | |
MemoryFence(); | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoGetAttributes ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
OUT UINT64 *Supported, OPTIONAL | |
OUT UINT64 *Attributes | |
) | |
{ | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
if (Attributes == NULL && Supported == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Supported is an OPTIONAL parameter. See if it is NULL | |
// | |
if (Supported) { | |
// | |
// This is a generic driver for a PC-AT class system. It does not have any | |
// chipset specific knowlegde, so none of the attributes can be set or | |
// cleared. Any attempt to set attribute that are already set will succeed, | |
// and any attempt to set an attribute that is not supported will fail. | |
// | |
*Supported = PrivateData->Attributes; | |
} | |
// | |
// Set Attrbutes to the attributes detected when the PCI Root Bridge was initialized | |
// | |
if (Attributes) { | |
*Attributes = PrivateData->Attributes; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoSetAttributes ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
IN UINT64 Attributes, | |
IN OUT UINT64 *ResourceBase, | |
IN OUT UINT64 *ResourceLength | |
) | |
{ | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
// | |
// This is a generic driver for a PC-AT class system. It does not have any | |
// chipset specific knowlegde, so none of the attributes can be set or | |
// cleared. Any attempt to set attribute that are already set will succeed, | |
// and any attempt to set an attribute that is not supported will fail. | |
// | |
if (Attributes & (~PrivateData->Attributes)) { | |
return EFI_UNSUPPORTED; | |
} | |
return EFI_SUCCESS; | |
} | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoConfiguration ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, | |
OUT VOID **Resources | |
) | |
{ | |
PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; | |
PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); | |
*Resources = PrivateData->Configuration; | |
return EFI_SUCCESS; | |
} | |
// | |
// Internal function | |
// | |
EFI_STATUS | |
EFIAPI | |
PcatRootBridgeIoMemRW ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, | |
IN UINTN Count, | |
IN BOOLEAN InStrideFlag, | |
IN PTR In, | |
IN BOOLEAN OutStrideFlag, | |
OUT PTR Out | |
) | |
/*++ | |
Routine Description: | |
Private service to provide the memory read/write | |
Arguments: | |
Width of the Memory Access | |
Count of the number of accesses to perform | |
Returns: | |
Status | |
EFI_SUCCESS - Successful transaction | |
EFI_INVALID_PARAMETER - Unsupported width and address combination | |
--*/ | |
{ | |
UINTN Stride; | |
UINTN InStride; | |
UINTN OutStride; | |
Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03); | |
Stride = (UINTN)1 << Width; | |
InStride = InStrideFlag ? Stride : 0; | |
OutStride = OutStrideFlag ? Stride : 0; | |
// | |
// Loop for each iteration and move the data | |
// | |
switch (Width) { | |
case EfiPciWidthUint8: | |
for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { | |
MemoryFence(); | |
*In.ui8 = *Out.ui8; | |
MemoryFence(); | |
} | |
break; | |
case EfiPciWidthUint16: | |
for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { | |
MemoryFence(); | |
*In.ui16 = *Out.ui16; | |
MemoryFence(); | |
} | |
break; | |
case EfiPciWidthUint32: | |
for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) { | |
MemoryFence(); | |
*In.ui32 = *Out.ui32; | |
MemoryFence(); | |
} | |
break; | |
default: | |
return EFI_INVALID_PARAMETER; | |
} | |
return EFI_SUCCESS; | |
} | |