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>
---
MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c | 249 ++++++++++++++++++++
MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c | 55 +++--
MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h | 9 +-
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c | 55 ++++-
MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h | 107 +++++++++
MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf | 3 +
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c | 47 +++-
MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h | 1 +
8 files changed, 492 insertions(+), 34 deletions(-)
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c b/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
new file mode 100644
index 0000000..6e2c1b5
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/XhciPei/DmaMem.c
@@ -0,0 +1,249 @@
+/** @file
+The DMA memory help function.
+
+Copyright (c) 2017, 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.
+
+**/
+
+#include "XhcPeim.h"
+
+EDKII_IOMMU_PPI *mIoMmu;
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINT64 Attribute;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Map (
+ mIoMmu,
+ Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ switch (Operation) {
+ case EdkiiIoMmuOperationBusMasterRead:
+ case EdkiiIoMmuOperationBusMasterRead64:
+ Attribute = EDKII_IOMMU_ACCESS_READ;
+ break;
+ case EdkiiIoMmuOperationBusMasterWrite:
+ case EdkiiIoMmuOperationBusMasterWrite64:
+ Attribute = EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:
+ Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
+ break;
+ default:
+ ASSERT(FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ Attribute
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
+ *Mapping = NULL;
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfBytes;
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;
+
+ *HostAddress = NULL;
+ *DeviceAddress = 0;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ EfiBootServicesData,
+ Pages,
+ HostAddress,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);
+ Status = mIoMmu->Map (
+ mIoMmu,
+ EdkiiIoMmuOperationBusMasterCommonBuffer,
+ *HostAddress,
+ &NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mIoMmu->SetAttribute (
+ mIoMmu,
+ *Mapping,
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ Pages,
+ &HostPhyAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ *HostAddress = (VOID *)(UINTN)HostPhyAddress;
+ *DeviceAddress = HostPhyAddress;
+ *Mapping = NULL;
+ }
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->SetAttribute (mIoMmu, Mapping, 0);
+ Status = mIoMmu->Unmap (mIoMmu, Mapping);
+ Status = mIoMmu->FreeBuffer (mIoMmu, Pages, HostAddress);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ )
+{
+ PeiServicesLocatePpi (
+ &gEdkiiIoMmuPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&mIoMmu
+ );
+}
+
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c b/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
index 6a3f3a5..5d0232c 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
+++ b/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.c
@@ -31,6 +31,9 @@ UsbHcAllocMemBlock (
)
{
USBHC_MEM_BLOCK *Block;
+ VOID *BufHost;
+ VOID *Mapping;
+ EFI_PHYSICAL_ADDRESS MappedAddr;
EFI_STATUS Status;
UINTN PageNumber;
EFI_PHYSICAL_ADDRESS TempPtr;
@@ -71,18 +74,20 @@ UsbHcAllocMemBlock (
Block->Bits = (UINT8 *) (UINTN) TempPtr;
- Status = PeiServicesAllocatePages (
- EfiBootServicesData,
+ Status = IoMmuAllocateBuffer (
Pages,
- &TempPtr
+ &BufHost,
+ &MappedAddr,
+ &Mapping
);
if (EFI_ERROR (Status)) {
return NULL;
}
- ZeroMem ((VOID *) (UINTN) TempPtr, EFI_PAGES_TO_SIZE (Pages));
+ ZeroMem ((VOID *) (UINTN) BufHost, EFI_PAGES_TO_SIZE (Pages));
- Block->BufHost = (UINT8 *) (UINTN) TempPtr;;
- Block->Buf = (UINT8 *) (UINTN) TempPtr;
+ Block->BufHost = (UINT8 *) (UINTN) BufHost;
+ Block->Buf = (UINT8 *) (UINTN) MappedAddr;
+ Block->Mapping = Mapping;
Block->Next = NULL;
return Block;
@@ -102,6 +107,9 @@ UsbHcFreeMemBlock (
)
{
ASSERT ((Pool != NULL) && (Block != NULL));
+
+ IoMmuFreeBuffer (EFI_SIZE_TO_PAGES (Block->BufLen), Block->BufHost, Block->Mapping);
+
//
// No free memory in PEI.
//
@@ -567,6 +575,7 @@ UsbHcFreeMem (
@param HostAddress The system memory address to map to the PCI controller.
@param DeviceAddress The resulting map address for the bus master PCI controller to
use to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
@retval EFI_SUCCESS Success to allocate aligned pages.
@retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
@@ -578,13 +587,16 @@ UsbHcAllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment,
OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
)
{
EFI_STATUS Status;
- EFI_PHYSICAL_ADDRESS Memory;
+ VOID *Memory;
UINTN AlignedMemory;
UINTN AlignmentMask;
+ EFI_PHYSICAL_ADDRESS DeviceMemory;
+ UINTN AlignedDeviceMemory;
UINTN RealPages;
//
@@ -611,32 +623,36 @@ UsbHcAllocateAlignedPages (
//
ASSERT (RealPages > Pages);
- Status = PeiServicesAllocatePages (
- EfiBootServicesData,
+ Status = IoMmuAllocateBuffer (
Pages,
- &Memory
+ &Memory,
+ &DeviceMemory,
+ Mapping
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;
+ AlignedDeviceMemory = ((UINTN) DeviceMemory + AlignmentMask) & ~AlignmentMask;
} else {
//
// Do not over-allocate pages in this case.
//
- Status = PeiServicesAllocatePages (
- EfiBootServicesData,
+ Status = IoMmuAllocateBuffer (
Pages,
- &Memory
+ &Memory,
+ &DeviceMemory,
+ Mapping
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
AlignedMemory = (UINTN) Memory;
+ AlignedDeviceMemory = (UINTN) DeviceMemory;
}
*HostAddress = (VOID *) AlignedMemory;
- *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedMemory;
+ *DeviceAddress = (EFI_PHYSICAL_ADDRESS) AlignedDeviceMemory;
return EFI_SUCCESS;
}
@@ -646,17 +662,18 @@ UsbHcAllocateAlignedPages (
@param HostAddress The system memory address to map to the PCI controller.
@param Pages The number of pages to free.
+ @param Mapping The mapping value returned from Map().
**/
VOID
UsbHcFreeAlignedPages (
IN VOID *HostAddress,
- IN UINTN Pages
+ IN UINTN Pages,
+ IN VOID *Mapping
)
{
ASSERT (Pages != 0);
- //
- // No free memory in PEI.
- //
+
+ IoMmuFreeBuffer (Pages, HostAddress, Mapping);
}
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h b/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
index c314e92..c315e6e 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
+++ b/MdeModulePkg/Bus/Pci/XhciPei/UsbHcMem.h
@@ -29,6 +29,7 @@ struct _USBHC_MEM_BLOCK {
UINT8 *Buf;
UINT8 *BufHost;
UINTN BufLen; // Memory size in bytes
+ VOID *Mapping;
USBHC_MEM_BLOCK *Next;
};
@@ -112,6 +113,7 @@ UsbHcGetHostAddrForPciAddr (
@param HostAddress The system memory address to map to the PCI controller.
@param DeviceAddress The resulting map address for the bus master PCI controller to
use to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
@retval EFI_SUCCESS Success to allocate aligned pages.
@retval EFI_INVALID_PARAMETER Pages or Alignment is not valid.
@@ -123,7 +125,8 @@ UsbHcAllocateAlignedPages (
IN UINTN Pages,
IN UINTN Alignment,
OUT VOID **HostAddress,
- OUT EFI_PHYSICAL_ADDRESS *DeviceAddress
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
);
/**
@@ -131,12 +134,14 @@ UsbHcAllocateAlignedPages (
@param HostAddress The system memory address to map to the PCI controller.
@param Pages The number of pages to free.
+ @param Mapping The mapping value returned from Map().
**/
VOID
UsbHcFreeAlignedPages (
IN VOID *HostAddress,
- IN UINTN Pages
+ IN UINTN Pages,
+ IN VOID *Mapping
);
#endif
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c b/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
index 38f0d21..99f69f7 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
+++ b/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.c
@@ -662,7 +662,8 @@ XhcPeiControlTransfer (
if (EFI_ERROR(RecoveryStatus)) {
DEBUG((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiDequeueTrbFromEndpoint failed\n"));
}
- goto FREE_URB;
+ XhcPeiFreeUrb (Xhc, Urb);
+ goto ON_EXIT;
} else {
if (*TransferResult == EFI_USB_NOERROR) {
Status = EFI_SUCCESS;
@@ -672,11 +673,17 @@ XhcPeiControlTransfer (
DEBUG ((EFI_D_ERROR, "XhcPeiControlTransfer: XhcPeiRecoverHaltedEndpoint failed\n"));
}
Status = EFI_DEVICE_ERROR;
- goto FREE_URB;
+ XhcPeiFreeUrb (Xhc, Urb);
+ goto ON_EXIT;
} else {
- goto FREE_URB;
+ XhcPeiFreeUrb (Xhc, Urb);
+ goto ON_EXIT;
}
}
+ //
+ // Unmap data before consume.
+ //
+ XhcPeiFreeUrb (Xhc, Urb);
//
// Hook Get_Descriptor request from UsbBus as we need evaluate context and configure endpoint.
@@ -704,7 +711,7 @@ XhcPeiControlTransfer (
Xhc->UsbDevContext[SlotId].ConfDesc = AllocateZeroPool (Xhc->UsbDevContext[SlotId].DevDesc.NumConfigurations * sizeof (EFI_USB_CONFIG_DESCRIPTOR *));
if (Xhc->UsbDevContext[SlotId].ConfDesc == NULL) {
Status = EFI_OUT_OF_RESOURCES;
- goto FREE_URB;
+ goto ON_EXIT;
}
if (Xhc->HcCParams.Data.Csz == 0) {
Status = XhcPeiEvaluateContext (Xhc, SlotId, MaxPacket0);
@@ -722,7 +729,7 @@ XhcPeiControlTransfer (
Xhc->UsbDevContext[SlotId].ConfDesc[Index] = AllocateZeroPool (*DataLength);
if (Xhc->UsbDevContext[SlotId].ConfDesc[Index] == NULL) {
Status = EFI_OUT_OF_RESOURCES;
- goto FREE_URB;
+ goto ON_EXIT;
}
CopyMem (Xhc->UsbDevContext[SlotId].ConfDesc[Index], Data, *DataLength);
}
@@ -844,9 +851,6 @@ XhcPeiControlTransfer (
*(UINT32 *) Data = *(UINT32 *) &PortStatus;
}
-FREE_URB:
- XhcPeiFreeUrb (Xhc, Urb);
-
ON_EXIT:
if (EFI_ERROR (Status)) {
@@ -1399,6 +1403,34 @@ XhcPeiGetRootHubPortStatus (
}
/**
+ One notified function to stop the Host Controller at the end of PEI
+
+ @param[in] PeiServices Pointer to PEI Services Table.
+ @param[in] NotifyDescriptor Pointer to the descriptor for the Notification event that
+ caused this function to execute.
+ @param[in] Ppi Pointer to the PPI data associated with this function.
+
+ @retval EFI_SUCCESS The function completes successfully
+ @retval others
+**/
+EFI_STATUS
+EFIAPI
+XhcEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ PEI_XHC_DEV *Xhc;
+
+ Xhc = PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(NotifyDescriptor);
+
+ XhcPeiHaltHC (Xhc, XHC_GENERIC_TIMEOUT);
+
+ return EFI_SUCCESS;
+}
+
+/**
@param FileHandle Handle of the file being invoked.
@param PeiServices Describes the list of possible PEI Services.
@@ -1429,6 +1461,8 @@ XhcPeimEntry (
return EFI_SUCCESS;
}
+ IoMmuInit ();
+
Status = PeiServicesLocatePpi (
&gPeiUsbControllerPpiGuid,
0,
@@ -1530,7 +1564,12 @@ XhcPeimEntry (
XhcDev->PpiDescriptor.Guid = &gPeiUsb2HostControllerPpiGuid;
XhcDev->PpiDescriptor.Ppi = &XhcDev->Usb2HostControllerPpi;
+ XhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
+ XhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
+ XhcDev->EndOfPeiNotifyList.Notify = XhcEndOfPei;
+
PeiServicesInstallPpi (&XhcDev->PpiDescriptor);
+ PeiServicesNotifyPpi (&XhcDev->EndOfPeiNotifyList);
Index++;
}
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h b/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
index 99f0396..e7a100f 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
+++ b/MdeModulePkg/Bus/Pci/XhciPei/XhcPeim.h
@@ -21,6 +21,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Ppi/UsbController.h>
#include <Ppi/Usb2HostController.h>
+#include <Ppi/IoMmu.h>
+#include <Ppi/EndOfPeiPhase.h>
#include <Library/DebugLib.h>
#include <Library/PeimEntryPoint.h>
@@ -153,6 +155,12 @@ struct _PEI_XHC_DEV {
USBHC_MEM_POOL *MemPool;
//
+ // EndOfPei callback is used to stop the XHC DMA operation
+ // after exit PEI phase.
+ //
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
+
+ //
// XHCI configuration data
//
UINT8 CapLength; ///< Capability Register Length
@@ -164,7 +172,9 @@ struct _PEI_XHC_DEV {
UINT32 PageSize;
UINT32 MaxScratchpadBufs;
UINT64 *ScratchBuf;
+ VOID *ScratchMap;
UINT64 *ScratchEntry;
+ UINTN *ScratchEntryMap;
UINT64 *DCBAA;
UINT32 MaxSlotsEn;
//
@@ -184,6 +194,7 @@ struct _PEI_XHC_DEV {
};
#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS(a) CR (a, PEI_XHC_DEV, Usb2HostControllerPpi, USB_XHC_DEV_SIGNATURE)
+#define PEI_RECOVERY_USB_XHC_DEV_FROM_THIS_NOTIFY(a) CR (a, PEI_XHC_DEV, EndOfPeiNotifyList, USB_XHC_DEV_SIGNATURE)
/**
Initialize the memory management pool for the host controller.
@@ -242,4 +253,100 @@ UsbHcFreeMem (
)
;
+
+/**
+ Initialize IOMMU.
+**/
+VOID
+IoMmuInit (
+ VOID
+ );
+
+/**
+ Provides the controller-specific addresses required to access system memory from a
+ DMA bus master.
+
+ @param Operation Indicates if the bus master is going to read or write to system memory.
+ @param HostAddress The system memory address to map to the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
+ that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+
+**/
+EFI_STATUS
+IoMmuMap (
+ IN EDKII_IOMMU_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+IoMmuUnmap (
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
+ OperationBusMasterCommonBuffer64 mapping.
+
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to
+ access the hosts HostAddress.
+ @param Mapping A resulting value to pass to Unmap().
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+EFI_STATUS
+IoMmuAllocateBuffer (
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+ @param Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
+ was not allocated with AllocateBuffer().
+
+**/
+EFI_STATUS
+IoMmuFreeBuffer (
+ IN UINTN Pages,
+ IN VOID *HostAddress,
+ IN VOID *Mapping
+ );
+
#endif
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf b/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
index dc65f28..f307ea7 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
+++ b/MdeModulePkg/Bus/Pci/XhciPei/XhciPei.inf
@@ -37,6 +37,7 @@
XhcPeim.h
XhciSched.c
UsbHcMem.c
+ DmaMem.c
XhciReg.h
XhciSched.h
UsbHcMem.h
@@ -56,6 +57,8 @@
[Ppis]
gPeiUsb2HostControllerPpiGuid ## PRODUCES
gPeiUsbControllerPpiGuid ## CONSUMES
+ gEdkiiIoMmuPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND gPeiUsbControllerPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c b/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
index 3dd2b89..e5aee49 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
+++ b/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.c
@@ -200,6 +200,8 @@ XhcPeiFreeUrb (
return;
}
+ IoMmuUnmap (Urb->DataMap);
+
FreePool (Urb);
}
@@ -227,6 +229,10 @@ XhcPeiCreateTransferTrb (
UINTN TotalLen;
UINTN Len;
UINTN TrbNum;
+ EDKII_IOMMU_OPERATION MapOp;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *Map;
+ EFI_STATUS Status;
SlotId = XhcPeiBusDevAddrToSlotId (Xhc, Urb->Ep.BusAddr);
if (SlotId == 0) {
@@ -249,7 +255,27 @@ XhcPeiCreateTransferTrb (
EPType = (UINT8) ((DEVICE_CONTEXT_64 *)OutputContext)->EP[Dci-1].EPType;
}
- Urb->DataPhy = Urb->Data;
+ //
+ // No need to remap.
+ //
+ if ((Urb->Data != NULL) && (Urb->DataMap == NULL)) {
+ if (((UINT8) (Urb->Ep.Direction)) == EfiUsbDataIn) {
+ MapOp = EdkiiIoMmuOperationBusMasterWrite;
+ } else {
+ MapOp = EdkiiIoMmuOperationBusMasterRead;
+ }
+
+ Len = Urb->DataLen;
+ Status = IoMmuMap (MapOp, Urb->Data, &Len, &PhyAddr, &Map);
+
+ if (EFI_ERROR (Status) || (Len != Urb->DataLen)) {
+ DEBUG ((DEBUG_ERROR, "XhcCreateTransferTrb: Fail to map Urb->Data.\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Urb->DataPhy = (VOID *) ((UINTN) PhyAddr);
+ Urb->DataMap = Map;
+ }
//
// Construct the TRB
@@ -2812,6 +2838,7 @@ XhcPeiInitSched (
UINT64 *ScratchEntry;
EFI_PHYSICAL_ADDRESS ScratchEntryPhy;
UINT32 Index;
+ UINTN *ScratchEntryMap;
EFI_STATUS Status;
//
@@ -2848,6 +2875,13 @@ XhcPeiInitSched (
ASSERT (MaxScratchpadBufs <= 1023);
if (MaxScratchpadBufs != 0) {
//
+ // Allocate the buffer to record the Mapping for each scratch buffer in order to Unmap them
+ //
+ ScratchEntryMap = AllocateZeroPool (sizeof (UINTN) * MaxScratchpadBufs);
+ ASSERT (ScratchEntryMap != NULL);
+ Xhc->ScratchEntryMap = ScratchEntryMap;
+
+ //
// Allocate the buffer to record the host address for each entry
//
ScratchEntry = AllocateZeroPool (sizeof (UINT64) * MaxScratchpadBufs);
@@ -2859,7 +2893,8 @@ XhcPeiInitSched (
EFI_SIZE_TO_PAGES (MaxScratchpadBufs * sizeof (UINT64)),
Xhc->PageSize,
(VOID **) &ScratchBuf,
- &ScratchPhy
+ &ScratchPhy,
+ &Xhc->ScratchMap
);
ASSERT_EFI_ERROR (Status);
@@ -2875,7 +2910,8 @@ XhcPeiInitSched (
EFI_SIZE_TO_PAGES (Xhc->PageSize),
Xhc->PageSize,
(VOID **) &ScratchEntry[Index],
- &ScratchEntryPhy
+ &ScratchEntryPhy,
+ (VOID **) &ScratchEntryMap[Index]
);
ASSERT_EFI_ERROR (Status);
ZeroMem ((VOID *) (UINTN) ScratchEntry[Index], Xhc->PageSize);
@@ -2967,12 +3003,13 @@ XhcPeiFreeSched (
//
// Free Scratchpad Buffers
//
- UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize));
+ UsbHcFreeAlignedPages ((VOID*) (UINTN) ScratchEntry[Index], EFI_SIZE_TO_PAGES (Xhc->PageSize), (VOID *) Xhc->ScratchEntryMap[Index]);
}
//
// Free Scratchpad Buffer Array
//
- UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)));
+ UsbHcFreeAlignedPages (Xhc->ScratchBuf, EFI_SIZE_TO_PAGES (Xhc->MaxScratchpadBufs * sizeof (UINT64)), Xhc->ScratchMap);
+ FreePool (Xhc->ScratchEntryMap);
FreePool (Xhc->ScratchEntry);
}
diff --git a/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h b/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h
index b3d4c45..faf2e63 100644
--- a/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h
+++ b/MdeModulePkg/Bus/Pci/XhciPei/XhciSched.h
@@ -170,6 +170,7 @@ typedef struct _URB {
VOID *Data;
UINTN DataLen;
VOID *DataPhy;
+ VOID *DataMap;
EFI_ASYNC_USB_TRANSFER_CALLBACK Callback;
VOID *Context;
//
--
2.7.4.windows.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.