Update XHCI driver to consume IOMMU_PPI to allocate DMA buffer.
If no IOMMU_PPI exists, this driver still calls PEI service
to allocate DMA buffer, with assumption that DRAM==DMA.
This is a compatible change.
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
--- /dev/null
+/** @file\r
+The DMA memory help function.\r
+\r
+Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions\r
+of the BSD License which accompanies this distribution. The\r
+full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "XhcPeim.h"\r
+\r
+EDKII_IOMMU_PPI *mIoMmu;\r
+\r
+/**\r
+ Provides the controller-specific addresses required to access system memory from a\r
+ DMA bus master.\r
+\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
+EFI_STATUS\r
+IoMmuMap (\r
+ IN EDKII_IOMMU_OPERATION Operation,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 Attribute;\r
+\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->Map (\r
+ mIoMmu,\r
+ Operation,\r
+ HostAddress,\r
+ NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ switch (Operation) {\r
+ case EdkiiIoMmuOperationBusMasterRead:\r
+ case EdkiiIoMmuOperationBusMasterRead64:\r
+ Attribute = EDKII_IOMMU_ACCESS_READ;\r
+ break;\r
+ case EdkiiIoMmuOperationBusMasterWrite:\r
+ case EdkiiIoMmuOperationBusMasterWrite64:\r
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;\r
+ break;\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;\r
+ break;\r
+ default:\r
+ ASSERT(FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ Status = mIoMmu->SetAttribute (\r
+ mIoMmu,\r
+ *Mapping,\r
+ Attribute\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;\r
+ *Mapping = NULL;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
+**/\r
+EFI_STATUS\r
+IoMmuUnmap (\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);\r
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\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 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 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
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN NumberOfBytes;\r
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;\r
+\r
+ *HostAddress = NULL;\r
+ *DeviceAddress = 0;\r
+\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->AllocateBuffer (\r
+ mIoMmu,\r
+ EfiBootServicesData,\r
+ Pages,\r
+ HostAddress,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);\r
+ Status = mIoMmu->Map (\r
+ mIoMmu,\r
+ EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+ *HostAddress,\r
+ &NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Status = mIoMmu->SetAttribute (\r
+ mIoMmu,\r
+ *Mapping,\r
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ Pages,\r
+ &HostPhyAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;\r
+ *DeviceAddress = HostPhyAddress;\r
+ *Mapping = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Frees memory that was allocated with AllocateBuffer().\r
+\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated range.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+ was not allocated with AllocateBuffer().\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuFreeBuffer (\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);\r
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);\r
+ Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);\r
+ } else {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize IOMMU.\r
+**/\r
+VOID\r
+IoMmuInit (\r
+ VOID\r
+ )\r
+{\r
+ PeiServicesLocatePpi (\r
+ &gEdkiiIoMmuPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **)&mIoMmu\r
+ );\r
+}\r
+\r
)\r
{\r
USBHC_MEM_BLOCK *Block;\r
+ VOID *BufHost;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
EFI_STATUS Status;\r
UINTN PageNumber;\r
EFI_PHYSICAL_ADDRESS TempPtr;\r
\r
Block->Bits = (UINT8 *) (UINTN) TempPtr;\r
\r
- Status = PeiServicesAllocatePages (\r
- EfiBootServicesData,\r
+ Status = IoMmuAllocateBuffer (\r
Pages,\r
- &TempPtr\r
+ &BufHost,\r
+ &MappedAddr,\r
+ &Mapping\r
);\r
if (EFI_ERROR (Status)) {\r
return NULL;\r
}\r
- ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));\r
+ ZeroMem ((VOID *) (UINTN) BufHost, EFI_PAGES_TO_SIZE (Pages));\r
\r
- Block->BufHost = (UINT8 *) (UINTN) TempPtr;;\r
- Block->Buf = (UINT8 *) (UINTN) TempPtr;\r
+ Block->BufHost = (UINT8 *) (UINTN) BufHost;\r
+ Block->Buf = (UINT8 *) (UINTN) MappedAddr;\r
+ Block->Mapping = Mapping;\r
Block->Next = NULL;\r
\r
return Block;\r
)\r
{\r
ASSERT ((Pool != NULL) && (Block != NULL));\r
+\r
+ IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);\r
+\r
//\r
// No free memory in PEI.\r
//\r
@param HostAddress The system memory address to map to the PCI controller.\r
@param DeviceAddress The resulting map address for the bus master PCI controller to\r
use to access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
\r
@retval EFI_SUCCESS Success to allocate aligned pages.\r
@retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
IN UINTN Pages,\r
IN UINTN Alignment,\r
OUT VOID **HostAddress,\r
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS Memory;\r
+ VOID *Memory;\r
UINTN AlignedMemory;\r
UINTN AlignmentMask;\r
+ EFI_PHYSICAL_ADDRESS DeviceMemory;\r
+ UINTN AlignedDeviceMemory;\r
UINTN RealPages;\r
\r
//\r
//\r
ASSERT (RealPages > Pages);\r
\r
- Status = PeiServicesAllocatePages (\r
- EfiBootServicesData,\r
+ Status = IoMmuAllocateBuffer (\r
Pages,\r
- &Memory\r
+ &Memory,\r
+ &DeviceMemory,\r
+ Mapping\r
);\r
if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+ AlignedDeviceMemory = ((UINTN) DeviceMemory + AlignmentMask) & ~AlignmentMask;\r
} else {\r
//\r
// Do not over-allocate pages in this case.\r
//\r
- Status = PeiServicesAllocatePages (\r
- EfiBootServicesData,\r
+ Status = IoMmuAllocateBuffer (\r
Pages,\r
- &Memory\r
+ &Memory,\r
+ &DeviceMemory,\r
+ Mapping\r
);\r
if (EFI_ERROR (Status)) {\r
return EFI_OUT_OF_RESOURCES;\r
}\r
AlignedMemory = (UINTN) Memory;\r
+ AlignedDeviceMemory = (UINTN) DeviceMemory;\r
}\r
\r
*HostAddress = (VOID *) AlignedMemory;\r
- *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;\r
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedDeviceMemory;\r
\r
return EFI_SUCCESS;\r
}\r
\r
@param HostAddress The system memory address to map to the PCI controller.\r
@param Pages The number of pages to free.\r
+ @param Mapping The mapping value returned from Map().\r
\r
**/\r
VOID\r
UsbHcFreeAlignedPages (\r
IN VOID *HostAddress,\r
- IN UINTN Pages\r
+ IN UINTN Pages,\r
+ IN VOID *Mapping\r
)\r
{\r
ASSERT (Pages != 0);\r
- //\r
- // No free memory in PEI.\r
- //\r
+\r
+ IoMmuFreeBuffer (Pages, HostAddress, Mapping);\r
}\r
\r
UINT8 *Buf;\r
UINT8 *BufHost;\r
UINTN BufLen; // Memory size in bytes\r
+ VOID *Mapping;\r
USBHC_MEM_BLOCK *Next;\r
};\r
\r
@param HostAddress The system memory address to map to the PCI controller.\r
@param DeviceAddress The resulting map address for the bus master PCI controller to\r
use to access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
\r
@retval EFI_SUCCESS Success to allocate aligned pages.\r
@retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.\r
IN UINTN Pages,\r
IN UINTN Alignment,\r
OUT VOID **HostAddress,\r
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
);\r
\r
/**\r
\r
@param HostAddress The system memory address to map to the PCI controller.\r
@param Pages The number of pages to free.\r
+ @param Mapping The mapping value returned from Map().\r
\r
**/\r
VOID\r
UsbHcFreeAlignedPages (\r
IN VOID *HostAddress,\r
- IN UINTN Pages\r
+ IN UINTN Pages,\r
+ IN VOID *Mapping\r
);\r
\r
#endif\r
if (EFI_ERROR(RecoveryStatus)) {\r
DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));\r
}\r
- goto FREE_URB;\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
+ goto ON_EXIT;\r
} else {\r
if (*TransferResult == EFI_USB_NOERROR) {\r
Status = EFI_SUCCESS;\r
DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));\r
}\r
Status = EFI_DEVICE_ERROR;\r
- goto FREE_URB;\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
+ goto ON_EXIT;\r
} else {\r
- goto FREE_URB;\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
+ goto ON_EXIT;\r
}\r
}\r
+ //\r
+ // Unmap data before consume.\r
+ //\r
+ XhcPeiFreeUrb (Xhc, Urb);\r
\r
//\r
// Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.\r
Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));\r
if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
- goto FREE_URB;\r
+ goto ON_EXIT;\r
}\r
if (Xhc->HcCParams.Data.Csz == 0) {\r
Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);\r
Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);\r
if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {\r
Status = EFI_OUT_OF_RESOURCES;\r
- goto FREE_URB;\r
+ goto ON_EXIT;\r
}\r
CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);\r
}\r
*(UINT32 *) Data = *(UINT32 *) &PortStatus;\r
}\r
\r
-FREE_URB:\r
- XhcPeiFreeUrb (Xhc, Urb);\r
-\r
ON_EXIT:\r
\r
if (EFI_ERROR (Status)) {\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ One notified function to stop the Host Controller at the end of PEI\r
+\r
+ @param[in] PeiServices Pointer to PEI Services Table.\r
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that\r
+ caused this function to execute.\r
+ @param[in] Ppi Pointer to the PPI data associated with this function.\r
+\r
+ @retval EFI_SUCCESS The function completes successfully\r
+ @retval others\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+XhcEndOfPei (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ PEI_XHC_DEV *Xhc;\r
+\r
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(NotifyDescriptor);\r
+\r
+ XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
@param FileHandle Handle of the file being invoked.\r
@param PeiServices Describes the list of possible PEI Services.\r
return EFI_SUCCESS;\r
}\r
\r
+ IoMmuInit ();\r
+\r
Status = PeiServicesLocatePpi (\r
&gPeiUsbControllerPpiGuid,\r
0,\r
XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;\r
XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;\r
\r
+ XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;\r
+ XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;\r
+\r
PeiServicesInstallPpi (&XhcDev->PpiDescriptor);\r
+ PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);\r
\r
Index++;\r
}\r
\r
#include <Ppi/UsbController.h>\r
#include <Ppi/Usb2HostController.h>\r
+#include <Ppi/IoMmu.h>\r
+#include <Ppi/EndOfPeiPhase.h>\r
\r
#include <Library/DebugLib.h>\r
#include <Library/PeimEntryPoint.h>\r
UINT32 UsbHostControllerBaseAddress;\r
USBHC_MEM_POOL *MemPool;\r
\r
+ //\r
+ // EndOfPei callback is used to stop the XHC DMA operation\r
+ // after exit PEI phase.\r
+ //\r
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;\r
+\r
//\r
// XHCI configuration data\r
//\r
UINT32 PageSize;\r
UINT32 MaxScratchpadBufs;\r
UINT64 *ScratchBuf;\r
+ VOID *ScratchMap;\r
UINT64 *ScratchEntry;\r
+ UINTN *ScratchEntryMap;\r
UINT64 *DCBAA;\r
UINT32 MaxSlotsEn;\r
//\r
};\r
\r
#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)\r
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(a) CR (a, PEI_XHC_DEV, EndOfPeiNotifyList, USB_XHC_DEV_SIGNATURE)\r
\r
/**\r
Initialize the memory management pool for the host controller.\r
)\r
;\r
\r
+\r
+/**\r
+ Initialize IOMMU.\r
+**/\r
+VOID\r
+IoMmuInit (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Provides the controller-specific addresses required to access system memory from a\r
+ DMA bus master.\r
+\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
+EFI_STATUS\r
+IoMmuMap (\r
+ IN EDKII_IOMMU_OPERATION Operation,\r
+ IN VOID *HostAddress,\r
+ IN OUT UINTN *NumberOfBytes,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ );\r
+\r
+/**\r
+ Completes the Map() operation and releases any corresponding resources.\r
+\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The range was unmapped.\r
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
+**/\r
+EFI_STATUS\r
+IoMmuUnmap (\r
+ IN VOID *Mapping\r
+ );\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\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 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 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
+EFI_STATUS\r
+IoMmuAllocateBuffer (\r
+ IN UINTN Pages,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ );\r
+\r
+/**\r
+ Frees memory that was allocated with AllocateBuffer().\r
+\r
+ @param Pages The number of pages to free.\r
+ @param HostAddress The base system memory address of the allocated range.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were freed.\r
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
+ was not allocated with AllocateBuffer().\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuFreeBuffer (\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress,\r
+ IN VOID *Mapping\r
+ );\r
+\r
#endif\r
XhcPeim.h\r
XhciSched.c\r
UsbHcMem.c\r
+ DmaMem.c\r
XhciReg.h\r
XhciSched.h\r
UsbHcMem.h\r
[Ppis]\r
gPeiUsb2HostControllerPpiGuid ## PRODUCES\r
gPeiUsbControllerPpiGuid ## CONSUMES\r
+ gEdkiiIoMmuPpiGuid ## CONSUMES\r
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES\r
\r
[Depex]\r
gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
return;\r
}\r
\r
+ IoMmuUnmap (Urb->DataMap);\r
+\r
FreePool (Urb);\r
}\r
\r
UINTN TotalLen;\r
UINTN Len;\r
UINTN TrbNum;\r
+ EDKII_IOMMU_OPERATION MapOp;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+ VOID *Map;\r
+ EFI_STATUS Status;\r
\r
SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);\r
if (SlotId == 0) {\r
EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;\r
}\r
\r
- Urb->DataPhy = Urb->Data;\r
+ //\r
+ // No need to remap.\r
+ //\r
+ if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {\r
+ if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {\r
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;\r
+ } else {\r
+ MapOp = EdkiiIoMmuOperationBusMasterRead;\r
+ }\r
+\r
+ Len = Urb->DataLen;\r
+ Status = IoMmuMap (MapOp, Urb->Data, &Len, &PhyAddr, &Map);\r
+\r
+ if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {\r
+ DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);\r
+ Urb->DataMap = Map;\r
+ }\r
\r
//\r
// Construct the TRB\r
UINT64 *ScratchEntry;\r
EFI_PHYSICAL_ADDRESS ScratchEntryPhy;\r
UINT32 Index;\r
+ UINTN *ScratchEntryMap;\r
EFI_STATUS Status;\r
\r
//\r
Xhc->MaxScratchpadBufs = MaxScratchpadBufs;\r
ASSERT (MaxScratchpadBufs <= 1023);\r
if (MaxScratchpadBufs != 0) {\r
+ //\r
+ // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them\r
+ //\r
+ ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);\r
+ ASSERT (ScratchEntryMap != NULL);\r
+ Xhc->ScratchEntryMap = ScratchEntryMap;\r
+\r
//\r
// Allocate the buffer to record the host address for each entry\r
//\r
EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),\r
Xhc->PageSize,\r
(VOID **) &ScratchBuf,\r
- &ScratchPhy\r
+ &ScratchPhy,\r
+ &Xhc->ScratchMap\r
);\r
ASSERT_EFI_ERROR (Status);\r
\r
EFI_SIZE_TO_PAGES (Xhc->PageSize),\r
Xhc->PageSize,\r
(VOID **) &ScratchEntry[Index],\r
- &ScratchEntryPhy\r
+ &ScratchEntryPhy,\r
+ (VOID **) &ScratchEntryMap[Index]\r
);\r
ASSERT_EFI_ERROR (Status);\r
ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);\r
//\r
// Free Scratchpad Buffers\r
//\r
- UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));\r
+ UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);\r
}\r
//\r
// Free Scratchpad Buffer Array\r
//\r
- UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));\r
+ UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);\r
+ FreePool (Xhc->ScratchEntryMap);\r
FreePool (Xhc->ScratchEntry);\r
}\r
\r
VOID *Data;\r
UINTN DataLen;\r
VOID *DataPhy;\r
+ VOID *DataMap;\r
EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;\r
VOID *Context;\r
//\r