\r
#include "NonDiscoverablePciDeviceIo.h"\r
\r
+#include <Library/DxeServicesTableLib.h>\r
+\r
#include <IndustryStandard/Acpi.h>\r
\r
#include <Protocol/PciRootBridgeIo.h>\r
UINTN NumberOfBytes;\r
} NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO;\r
\r
-//\r
-// Get the resource associated with BAR number 'BarIndex'.\r
-//\r
+/**\r
+ Get the resource associated with BAR number 'BarIndex'.\r
+\r
+ @param Dev Point to the NON_DISCOVERABLE_PCI_DEVICE instance.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory operation to perform.\r
+ @param Descriptor Points to the address space descriptor\r
+**/\r
STATIC\r
EFI_STATUS\r
GetBarResource (\r
\r
BarIndex -= (UINT8)Dev->BarOffset;\r
\r
+ if (BarIndex >= Dev->BarCount) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
for (Desc = Dev->Device->Resources;\r
Desc->Desc != ACPI_END_TAG_DESCRIPTOR;\r
Desc = (VOID *)((UINT8 *)Desc + Desc->Len + 3)) {\r
return EFI_NOT_FOUND;\r
}\r
\r
+/**\r
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is\r
+ satisfied or after a defined duration.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory operation to perform.\r
+ @param Offset The offset within the selected BAR to start the memory operation.\r
+ @param Mask Mask used for the polling criteria.\r
+ @param Value The comparison value used for the polling exit criteria.\r
+ @param Delay The number of 100 ns units to poll.\r
+ @param Result Pointer to the last value read from the memory location.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Reads from the memory space of a PCI controller. Returns either when the polling exit criteria is\r
+ satisfied or after a defined duration.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory operation to perform.\r
+ @param Offset The offset within the selected BAR to start the memory operation.\r
+ @param Mask Mask used for the polling criteria.\r
+ @param Value The comparison value used for the polling exit criteria.\r
+ @param Delay The number of 100 ns units to poll.\r
+ @param Result Pointer to the last value read from the memory location.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
+\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param DstStride The stride of the destination buffer.\r
+ @param Dst For read operations, the destination buffer to store the results. For write\r
+ operations, the destination buffer to write data to.\r
+ @param SrcStride The stride of the source buffer.\r
+ @param Src For read operations, the source buffer to read data from. For write\r
+ operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory or I/O operation to perform.\r
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param Buffer For read operations, the destination buffer to store the results. For write\r
+ operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not\r
+ valid for the PCI BAR specified by BarIndex.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
}\r
\r
switch (Width) {\r
- case EfiPciWidthUint8:\r
- case EfiPciWidthUint16:\r
- case EfiPciWidthUint32:\r
- case EfiPciWidthUint64:\r
+ case EfiPciIoWidthUint8:\r
+ case EfiPciIoWidthUint16:\r
+ case EfiPciIoWidthUint32:\r
+ case EfiPciIoWidthUint64:\r
return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
\r
- case EfiPciWidthFifoUint8:\r
- case EfiPciWidthFifoUint16:\r
- case EfiPciWidthFifoUint32:\r
- case EfiPciWidthFifoUint64:\r
+ case EfiPciIoWidthFifoUint8:\r
+ case EfiPciIoWidthFifoUint16:\r
+ case EfiPciIoWidthFifoUint32:\r
+ case EfiPciIoWidthFifoUint64:\r
return PciIoMemRW (Width, Count, 1, Buffer, 0, Address);\r
\r
- case EfiPciWidthFillUint8:\r
- case EfiPciWidthFillUint16:\r
- case EfiPciWidthFillUint32:\r
- case EfiPciWidthFillUint64:\r
+ case EfiPciIoWidthFillUint8:\r
+ case EfiPciIoWidthFillUint16:\r
+ case EfiPciIoWidthFillUint32:\r
+ case EfiPciIoWidthFillUint64:\r
return PciIoMemRW (Width, Count, 0, Buffer, 1, Address);\r
\r
default:\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory or I/O operation to perform.\r
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param Buffer For read operations, the destination buffer to store the results. For write\r
+ operations, the source buffer to write data from.\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not\r
+ valid for the PCI BAR specified by BarIndex.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
}\r
\r
switch (Width) {\r
- case EfiPciWidthUint8:\r
- case EfiPciWidthUint16:\r
- case EfiPciWidthUint32:\r
- case EfiPciWidthUint64:\r
+ case EfiPciIoWidthUint8:\r
+ case EfiPciIoWidthUint16:\r
+ case EfiPciIoWidthUint32:\r
+ case EfiPciIoWidthUint64:\r
return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
\r
- case EfiPciWidthFifoUint8:\r
- case EfiPciWidthFifoUint16:\r
- case EfiPciWidthFifoUint32:\r
- case EfiPciWidthFifoUint64:\r
+ case EfiPciIoWidthFifoUint8:\r
+ case EfiPciIoWidthFifoUint16:\r
+ case EfiPciIoWidthFifoUint32:\r
+ case EfiPciIoWidthFifoUint64:\r
return PciIoMemRW (Width, Count, 0, Address, 1, Buffer);\r
\r
- case EfiPciWidthFillUint8:\r
- case EfiPciWidthFillUint16:\r
- case EfiPciWidthFillUint32:\r
- case EfiPciWidthFillUint64:\r
+ case EfiPciIoWidthFillUint8:\r
+ case EfiPciIoWidthFillUint16:\r
+ case EfiPciIoWidthFillUint32:\r
+ case EfiPciIoWidthFillUint64:\r
return PciIoMemRW (Width, Count, 1, Address, 0, Buffer);\r
\r
default:\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory or I/O operation to perform.\r
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param Buffer For read operations, the destination buffer to store the results. For write\r
+ operations, the source buffer to write data from.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI controller registers in the PCI memory or I/O space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for the memory or I/O operation to perform.\r
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param Buffer For read operations, the destination buffer to store the results. For write\r
+ operations, the source buffer to write data from.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI config space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param Buffer For read operations, the destination buffer to store the results. For write\r
+ operations, the source buffer to write data from.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
Address = (UINT8 *)&Dev->ConfigSpace + Offset;\r
Length = Count << ((UINTN)Width & 0x3);\r
\r
+ if (Offset >= sizeof (Dev->ConfigSpace)) {\r
+ ZeroMem (Buffer, Length);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
if (Offset + Length > sizeof (Dev->ConfigSpace)) {\r
//\r
// Read all zeroes for config space accesses beyond the first\r
return PciIoMemRW (Width, Count, 1, Buffer, 1, Address);\r
}\r
\r
+/**\r
+ Enable a PCI driver to access PCI config space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory or I/O operations.\r
+ @param Offset The offset within the selected BAR to start the memory or I/O operation.\r
+ @param Count The number of memory or I/O operations to perform.\r
+ @param Buffer For read operations, the destination buffer to store the results. For write\r
+ operations, the source buffer to write data from\r
+\r
+ @retval EFI_SUCCESS The data was read from or written to the PCI controller.\r
+ @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not\r
+ valid for the PCI BAR specified by BarIndex.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return PciIoMemRW (Width, Count, 1, Address, 1, Buffer);\r
}\r
\r
+/**\r
+ Enables a PCI driver to copy one region of PCI memory space to another region of PCI\r
+ memory space.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Width Signifies the width of the memory operations.\r
+ @param DestBarIndex The BAR index in the standard PCI Configuration header to use as the\r
+ base address for the memory operation to perform.\r
+ @param DestOffset The destination offset within the BAR specified by DestBarIndex to\r
+ start the memory writes for the copy operation.\r
+ @param SrcBarIndex The BAR index in the standard PCI Configuration header to use as the\r
+ base address for the memory operation to perform.\r
+ @param SrcOffset The source offset within the BAR specified by SrcBarIndex to start\r
+ the memory reads for the copy operation.\r
+ @param Count The number of memory operations to perform. Bytes moved is Width\r
+ size * Count, starting at DestOffset and SrcOffset.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_UNSUPPORTED;\r
}\r
\r
+/**\r
+ Provides the PCI controller-specific addresses needed to access system memory.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Operation Indicates if the bus master is going to read or write to system memory.\r
+ @param HostAddress The system memory address to map to the PCI controller.\r
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
+ that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
+ access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
EFI_STATUS Status;\r
NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
\r
+ if (Operation != EfiPciIoOperationBusMasterRead &&\r
+ Operation != EfiPciIoOperationBusMasterWrite &&\r
+ Operation != EfiPciIoOperationBusMasterCommonBuffer) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (HostAddress == NULL ||\r
+ NumberOfBytes == NULL ||\r
+ DeviceAddress == NULL ||\r
+ Mapping == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
//\r
// If HostAddress exceeds 4 GB, and this device does not support 64-bit DMA\r
// addressing, we need to allocate a bounce buffer and copy over the data.\r
//\r
Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
if ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
- (UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB) {\r
\r
//\r
// Bounce buffering is not possible for consistent mappings\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Allocates pages.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Type This parameter is not used and must be ignored.\r
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
+ EfiRuntimeServicesData.\r
+ @param Pages The number of pages to allocate.\r
+ @param HostAddress A pointer to store the base system memory address of the\r
+ allocated range.\r
+ @param Attributes The requested bit mask of attributes for the allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_UNSUPPORTED;\r
}\r
\r
+ if ((MemoryType != EfiBootServicesData) &&\r
+ (MemoryType != EfiRuntimeServicesData)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
//\r
// Allocate below 4 GB if the dual address cycle attribute has not\r
// been set. If the system has no memory available below 4 GB, there\r
return Status;\r
}\r
\r
+/**\r
+ Frees memory that was allocated in function CoherentPciIoAllocateBuffer ().\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Frees memory that was allocated in function NonCoherentPciIoAllocateBuffer ().\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval others The operation contain some errors.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentPciIoFreeBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ LIST_ENTRY *Entry;\r
+ EFI_STATUS Status;\r
+ NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
+ BOOLEAN Found;\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ Found = FALSE;\r
+ Alloc = NULL;\r
+\r
+ //\r
+ // Find the uncached allocation list entry associated\r
+ // with this allocation\r
+ //\r
+ for (Entry = Dev->UncachedAllocationList.ForwardLink;\r
+ Entry != &Dev->UncachedAllocationList;\r
+ Entry = Entry->ForwardLink) {\r
+\r
+ Alloc = BASE_CR (Entry, NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION, List);\r
+ if (Alloc->HostAddress == HostAddress && Alloc->NumPages == Pages) {\r
+ //\r
+ // We are freeing the exact allocation we were given\r
+ // before by AllocateBuffer()\r
+ //\r
+ Found = TRUE;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (!Found) {\r
+ ASSERT_EFI_ERROR (EFI_NOT_FOUND);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ RemoveEntryList (&Alloc->List);\r
+\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
+ EFI_PAGES_TO_SIZE (Pages),\r
+ Alloc->Attributes);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeAlloc;\r
+ }\r
+\r
+ //\r
+ // If we fail to restore the original attributes, it is better to leak the\r
+ // memory than to return it to the heap\r
+ //\r
+ FreePages (HostAddress, Pages);\r
+\r
+FreeAlloc:\r
+ FreePool (Alloc);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Allocates pages.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Type This parameter is not used and must be ignored.\r
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
+ EfiRuntimeServicesData.\r
+ @param Pages The number of pages to allocate.\r
+ @param HostAddress A pointer to store the base system memory address of the\r
+ allocated range.\r
+ @param Attributes The requested bit mask of attributes for the allocated range.\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentPciIoAllocateBuffer (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_ALLOCATE_TYPE Type,\r
+ IN EFI_MEMORY_TYPE MemoryType,\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
+ EFI_STATUS Status;\r
+ UINT64 MemType;\r
+ NON_DISCOVERABLE_DEVICE_UNCACHED_ALLOCATION *Alloc;\r
+ VOID *AllocAddress;\r
+\r
+ if (HostAddress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ Status = CoherentPciIoAllocateBuffer (This, Type, MemoryType, Pages,\r
+ &AllocAddress, Attributes);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = gDS->GetMemorySpaceDescriptor (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
+ &GcdDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeBuffer;\r
+ }\r
+\r
+ if ((GcdDescriptor.Capabilities & (EFI_MEMORY_WC | EFI_MEMORY_UC)) == 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ goto FreeBuffer;\r
+ }\r
+\r
+ //\r
+ // Set the preferred memory attributes\r
+ //\r
+ if ((Attributes & EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE) != 0 ||\r
+ (GcdDescriptor.Capabilities & EFI_MEMORY_UC) == 0) {\r
+ //\r
+ // Use write combining if it was requested, or if it is the only\r
+ // type supported by the region.\r
+ //\r
+ MemType = EFI_MEMORY_WC;\r
+ } else {\r
+ MemType = EFI_MEMORY_UC;\r
+ }\r
+\r
+ Alloc = AllocatePool (sizeof *Alloc);\r
+ if (Alloc == NULL) {\r
+ goto FreeBuffer;\r
+ }\r
+\r
+ Alloc->HostAddress = AllocAddress;\r
+ Alloc->NumPages = Pages;\r
+ Alloc->Attributes = GcdDescriptor.Attributes;\r
+\r
+ //\r
+ // Record this allocation in the linked list, so we\r
+ // can restore the memory space attributes later\r
+ //\r
+ InsertHeadList (&Dev->UncachedAllocationList, &Alloc->List);\r
+\r
+ Status = gDS->SetMemorySpaceAttributes (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
+ EFI_PAGES_TO_SIZE (Pages),\r
+ MemType);\r
+ if (EFI_ERROR (Status)) {\r
+ goto RemoveList;\r
+ }\r
+\r
+ Status = mCpu->FlushDataCache (\r
+ mCpu,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress,\r
+ EFI_PAGES_TO_SIZE (Pages),\r
+ EfiCpuFlushTypeInvalidate);\r
+ if (EFI_ERROR (Status)) {\r
+ goto RemoveList;\r
+ }\r
+\r
+ *HostAddress = AllocAddress;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+RemoveList:\r
+ RemoveEntryList (&Alloc->List);\r
+ FreePool (Alloc);\r
+\r
+FreeBuffer:\r
+ CoherentPciIoFreeBuffer (This, Pages, AllocAddress);\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Provides the PCI controller-specific addresses needed to access system memory.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Operation Indicates if the bus master is going to read or write to system memory.\r
+ @param HostAddress The system memory address to map to the PCI controller.\r
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
+ that were mapped.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
+ access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentPciIoMap (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN EFI_PCI_IO_PROTOCOL_OPERATION Operation,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+ EFI_STATUS Status;\r
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
+ UINTN AlignMask;\r
+ VOID *AllocAddress;\r
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
+ BOOLEAN Bounce;\r
+\r
+ if (HostAddress == NULL ||\r
+ NumberOfBytes == NULL ||\r
+ DeviceAddress == NULL ||\r
+ Mapping == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Operation != EfiPciIoOperationBusMasterRead &&\r
+ Operation != EfiPciIoOperationBusMasterWrite &&\r
+ Operation != EfiPciIoOperationBusMasterCommonBuffer) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ MapInfo = AllocatePool (sizeof *MapInfo);\r
+ if (MapInfo == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ MapInfo->HostAddress = HostAddress;\r
+ MapInfo->Operation = Operation;\r
+ MapInfo->NumberOfBytes = *NumberOfBytes;\r
+\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ //\r
+ // If this device does not support 64-bit DMA addressing, we need to allocate\r
+ // a bounce buffer and copy over the data in case HostAddress >= 4 GB.\r
+ //\r
+ Bounce = ((Dev->Attributes & EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0 &&\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress + *NumberOfBytes > SIZE_4GB);\r
+\r
+ if (!Bounce) {\r
+ switch (Operation) {\r
+ case EfiPciIoOperationBusMasterRead:\r
+ case EfiPciIoOperationBusMasterWrite:\r
+ //\r
+ // For streaming DMA, it is sufficient if the buffer is aligned to\r
+ // the CPUs DMA buffer alignment.\r
+ //\r
+ AlignMask = mCpu->DmaBufferAlignment - 1;\r
+ if ((((UINTN) HostAddress | *NumberOfBytes) & AlignMask) == 0) {\r
+ break;\r
+ }\r
+ // fall through\r
+\r
+ case EfiPciIoOperationBusMasterCommonBuffer:\r
+ //\r
+ // Check whether the host address refers to an uncached mapping.\r
+ //\r
+ Status = gDS->GetMemorySpaceDescriptor (\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
+ &GcdDescriptor);\r
+ if (EFI_ERROR (Status) ||\r
+ (GcdDescriptor.Attributes & (EFI_MEMORY_WB|EFI_MEMORY_WT)) != 0) {\r
+ Bounce = TRUE;\r
+ }\r
+ break;\r
+\r
+ default:\r
+ ASSERT (FALSE);\r
+ }\r
+ }\r
+\r
+ if (Bounce) {\r
+ if (Operation == EfiPciIoOperationBusMasterCommonBuffer) {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto FreeMapInfo;\r
+ }\r
+\r
+ Status = NonCoherentPciIoAllocateBuffer (This, AllocateAnyPages,\r
+ EfiBootServicesData, EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
+ &AllocAddress, EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeMapInfo;\r
+ }\r
+ MapInfo->AllocAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocAddress;\r
+ if (Operation == EfiPciIoOperationBusMasterRead) {\r
+ gBS->CopyMem (AllocAddress, HostAddress, *NumberOfBytes);\r
+ }\r
+ *DeviceAddress = MapInfo->AllocAddress;\r
+ } else {\r
+ MapInfo->AllocAddress = 0;\r
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
+\r
+ //\r
+ // We are not using a bounce buffer: the mapping is sufficiently\r
+ // aligned to allow us to simply flush the caches. Note that cleaning\r
+ // the caches is necessary for both data directions:\r
+ // - for bus master read, we want the latest data to be present\r
+ // in main memory\r
+ // - for bus master write, we don't want any stale dirty cachelines that\r
+ // may be written back unexpectedly, and clobber the data written to\r
+ // main memory by the device.\r
+ //\r
+ mCpu->FlushDataCache (mCpu, (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
+ *NumberOfBytes, EfiCpuFlushTypeWriteBack);\r
+ }\r
+\r
+ *Mapping = MapInfo;\r
+ return EFI_SUCCESS;\r
+\r
+FreeMapInfo:\r
+ FreePool (MapInfo);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Mapping The mapping value returned from Map().\r
\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+EFIAPI\r
+NonCoherentPciIoUnmap (\r
+ IN EFI_PCI_IO_PROTOCOL *This,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ NON_DISCOVERABLE_PCI_DEVICE_MAP_INFO *MapInfo;\r
+\r
+ if (Mapping == NULL) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ MapInfo = Mapping;\r
+ if (MapInfo->AllocAddress != 0) {\r
+ //\r
+ // We are using a bounce buffer: copy back the data if necessary,\r
+ // and free the buffer.\r
+ //\r
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
+ gBS->CopyMem (MapInfo->HostAddress, (VOID *)(UINTN)MapInfo->AllocAddress,\r
+ MapInfo->NumberOfBytes);\r
+ }\r
+ NonCoherentPciIoFreeBuffer (This,\r
+ EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes),\r
+ (VOID *)(UINTN)MapInfo->AllocAddress);\r
+ } else {\r
+ //\r
+ // We are *not* using a bounce buffer: if this is a bus master write,\r
+ // we have to invalidate the caches so the CPU will see the uncached\r
+ // data written by the device.\r
+ //\r
+ if (MapInfo->Operation == EfiPciIoOperationBusMasterWrite) {\r
+ mCpu->FlushDataCache (mCpu,\r
+ (EFI_PHYSICAL_ADDRESS)(UINTN)MapInfo->HostAddress,\r
+ MapInfo->NumberOfBytes, EfiCpuFlushTypeInvalidate);\r
+ }\r
+ }\r
+ FreePool (MapInfo);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Flushes all PCI posted write transactions from a PCI host bridge to system memory.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Retrieves this PCI controller's current PCI bus number, device number, and function number.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param SegmentNumber The PCI controller's current PCI segment number.\r
+ @param BusNumber The PCI controller's current PCI bus number.\r
+ @param DeviceNumber The PCI controller's current PCI device number.\r
+ @param FunctionNumber The PCI controller's current PCI function number.\r
+\r
+ @retval EFI_SUCCESS The PCI controller location was returned.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
OUT UINTN *FunctionNumber\r
)\r
{\r
+ NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
+\r
if (SegmentNumber == NULL ||\r
BusNumber == NULL ||\r
DeviceNumber == NULL ||\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- *SegmentNumber = 0;\r
- *BusNumber = 0xff;\r
- *DeviceNumber = 0;\r
+ Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
+\r
+ *SegmentNumber = 0xff;\r
+ *BusNumber = Dev->UniqueId >> 5;\r
+ *DeviceNumber = Dev->UniqueId & 0x1f;\r
*FunctionNumber = 0;\r
\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Performs an operation on the attributes that this PCI controller supports. The operations include\r
+ getting the set of supported attributes, retrieving the current attributes, setting the current\r
+ attributes, enabling attributes, and disabling attributes.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Operation The operation to perform on the attributes for this PCI controller.\r
+ @param Attributes The mask of attributes that are used for Set, Enable, and Disable\r
+ operations.\r
+ @param Result A pointer to the result mask of attributes that are returned for the Get\r
+ and Supported operations.\r
+\r
+ @retval EFI_SUCCESS The operation on the PCI controller's attributes was completed.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_UNSUPPORTED one or more of the bits set in\r
+ Attributes are not supported by this PCI controller or one of\r
+ its parent bridges when Operation is Set, Enable or Disable.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
BOOLEAN Enable;\r
\r
+ #define DEV_SUPPORTED_ATTRIBUTES \\r
+ (EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE)\r
+\r
Dev = NON_DISCOVERABLE_PCI_DEVICE_FROM_PCI_IO(This);\r
\r
+ if ((Attributes & (~(DEV_SUPPORTED_ATTRIBUTES))) != 0) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
Enable = FALSE;\r
switch (Operation) {\r
case EfiPciIoAttributeOperationGet:\r
if (Result == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
- *Result = EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
+ *Result = DEV_SUPPORTED_ATTRIBUTES;\r
break;\r
\r
case EfiPciIoAttributeOperationEnable:\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Gets the attributes that this PCI controller supports setting on a BAR using\r
+ SetBarAttributes(), and retrieves the list of resource descriptors for a BAR.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for resource range. The legal range for this field is 0..5.\r
+ @param Supports A pointer to the mask of attributes that this PCI controller supports\r
+ setting for this BAR with SetBarAttributes().\r
+ @param Resources A pointer to the ACPI 2.0 resource descriptors that describe the current\r
+ configuration of this BAR of the PCI controller.\r
+\r
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes that the PCI\r
+ controller supports are returned in Supports. If Resources\r
+ is not NULL, then the ACPI 2.0 resource descriptors that the PCI\r
+ controller is currently using are returned in Resources.\r
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.\r
+ @retval EFI_UNSUPPORTED BarIndex not valid for this PCI controller.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to allocate\r
+ Resources.\r
+\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
)\r
{\r
NON_DISCOVERABLE_PCI_DEVICE *Dev;\r
- EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor, *BarDesc;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;\r
EFI_ACPI_END_TAG_DESCRIPTOR *End;\r
EFI_STATUS Status;\r
\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Sets the attributes for a range of a BAR on a PCI controller.\r
+\r
+ @param This A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
+ @param Attributes The mask of attributes to set for the resource range specified by\r
+ BarIndex, Offset, and Length.\r
+ @param BarIndex The BAR index of the standard PCI Configuration header to use as the\r
+ base address for resource range. The legal range for this field is 0..5.\r
+ @param Offset A pointer to the BAR relative base address of the resource range to be\r
+ modified by the attributes specified by Attributes.\r
+ @param Length A pointer to the length of the resource range to be modified by the\r
+ attributes specified by Attributes.\r
+**/\r
STATIC\r
EFI_STATUS\r
EFIAPI\r
0\r
};\r
\r
+/**\r
+ Initialize PciIo Protocol.\r
+\r
+ @param Dev Point to NON_DISCOVERABLE_PCI_DEVICE instance.\r
+\r
+**/\r
VOID\r
InitializePciIoProtocol (\r
NON_DISCOVERABLE_PCI_DEVICE *Dev\r
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;\r
INTN Idx;\r
\r
+ InitializeListHead (&Dev->UncachedAllocationList);\r
+\r
Dev->ConfigSpace.Hdr.VendorId = PCI_ID_VENDOR_UNKNOWN;\r
Dev->ConfigSpace.Hdr.DeviceId = PCI_ID_DEVICE_DONTCARE;\r
\r
// Copy protocol structure\r
CopyMem(&Dev->PciIo, &PciIoTemplate, sizeof PciIoTemplate);\r
\r
+ if (Dev->Device->DmaType == NonDiscoverableDeviceDmaTypeNonCoherent) {\r
+ Dev->PciIo.AllocateBuffer = NonCoherentPciIoAllocateBuffer;\r
+ Dev->PciIo.FreeBuffer = NonCoherentPciIoFreeBuffer;\r
+ Dev->PciIo.Map = NonCoherentPciIoMap;\r
+ Dev->PciIo.Unmap = NonCoherentPciIoUnmap;\r
+ }\r
+\r
if (CompareGuid (Dev->Device->Type, &gEdkiiNonDiscoverableAhciDeviceGuid)) {\r
Dev->ConfigSpace.Hdr.ClassCode[0] = PCI_IF_MASS_STORAGE_AHCI;\r
Dev->ConfigSpace.Hdr.ClassCode[1] = PCI_CLASS_MASS_STORAGE_SATADPA;\r