Update the UhciPei 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.
Cc: Jiewen Yao <jiewen.yao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Star Zeng <star.zeng@intel.com>
Reviewed-by: Jiewen Yao <jiewen.yao@intel.com>
--- /dev/null
+/** @file\r
+The DMA memory help functions.\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 "UhcPeim.h"\r
+\r
+/**\r
+ Provides the controller-specific addresses required to access system memory from a\r
+ DMA bus master.\r
+\r
+ @param IoMmu Pointer to IOMMU PPI.\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_PPI *IoMmu,\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 (IoMmu != NULL) {\r
+ Status = IoMmu->Map (\r
+ IoMmu,\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 = IoMmu->SetAttribute (\r
+ IoMmu,\r
+ *Mapping,\r
+ Attribute\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmu->Unmap (IoMmu, Mapping);\r
+ *Mapping = NULL;\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 IoMmu Pointer to IOMMU PPI.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+**/\r
+VOID\r
+IoMmuUnmap (\r
+ IN EDKII_IOMMU_PPI *IoMmu,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ if (IoMmu != NULL) {\r
+ IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+ IoMmu->Unmap (IoMmu, Mapping);\r
+ }\r
+}\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param IoMmu Pointer to IOMMU PPI.\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 EDKII_IOMMU_PPI *IoMmu,\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
+ *Mapping = NULL;\r
+\r
+ if (IoMmu != NULL) {\r
+ Status = IoMmu->AllocateBuffer (\r
+ IoMmu,\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 = IoMmu->Map (\r
+ IoMmu,\r
+ EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+ *HostAddress,\r
+ &NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
+ *HostAddress = NULL;\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Status = IoMmu->SetAttribute (\r
+ IoMmu,\r
+ *Mapping,\r
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ IoMmu->Unmap (IoMmu, *Mapping);\r
+ IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);\r
+ *Mapping = NULL;\r
+ *HostAddress = NULL;\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 IoMmu Pointer to IOMMU PPI.\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
+**/\r
+VOID\r
+IoMmuFreeBuffer (\r
+ IN EDKII_IOMMU_PPI *IoMmu,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress,\r
+ IN VOID *Mapping\r
+ )\r
+{\r
+ if (IoMmu != NULL) {\r
+ IoMmu->SetAttribute (IoMmu, Mapping, 0);\r
+ IoMmu->Unmap (IoMmu, Mapping);\r
+ IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);\r
+ }\r
+}\r
+\r
+/**\r
+ Initialize IOMMU.\r
+\r
+ @param IoMmu Pointer to pointer to IOMMU PPI.\r
+\r
+**/\r
+VOID\r
+IoMmuInit (\r
+ OUT EDKII_IOMMU_PPI **IoMmu\r
+ )\r
+{\r
+ *IoMmu = NULL;\r
+ PeiServicesLocatePpi (\r
+ &gEdkiiIoMmuPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **) IoMmu\r
+ );\r
+}\r
+\r
PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid\r
which is used to enable recovery function from USB Drivers.\r
\r
-Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved. <BR>\r
+Copyright (c) 2006 - 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
\r
#include "UhcPeim.h"\r
\r
+/**\r
+ Stop the host controller.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Timeout Max time allowed.\r
+\r
+ @retval EFI_SUCCESS The host controller is stopped.\r
+ @retval EFI_TIMEOUT Failed to stop the host controller.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciStopHc (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN UINTN Timeout\r
+ )\r
+{\r
+ UINT16 CommandContent;\r
+ UINT16 UsbSts;\r
+ UINTN Index;\r
+\r
+ CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD);\r
+ CommandContent &= USBCMD_RS;\r
+ USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent);\r
+\r
+ //\r
+ // ensure the HC is in halt status after send the stop command\r
+ // Timeout is in us unit.\r
+ //\r
+ for (Index = 0; Index < (Timeout / 50) + 1; Index++) {\r
+ UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS);\r
+\r
+ if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ MicroSecondDelay (50);\r
+ }\r
+\r
+ return EFI_TIMEOUT;\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
+UhcEndOfPei (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ USB_UHC_DEV *Uhc;\r
+\r
+ Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);\r
+\r
+ //\r
+ // Stop the Host Controller\r
+ //\r
+ UhciStopHc (Uhc, 1000 * 1000);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Initializes Usb Host Controller.\r
\r
\r
UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);\r
UhcDev->Signature = USB_UHC_DEV_SIGNATURE;\r
+ IoMmuInit (&UhcDev->IoMmu);\r
UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;\r
\r
//\r
continue;\r
}\r
\r
+ UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;\r
+ UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei;\r
+\r
+ PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList);\r
+\r
Index++;\r
}\r
\r
TD_STRUCT *PtrStatusTD;\r
EFI_STATUS Status;\r
UINT32 DataLen;\r
- UINT8 *PtrDataSource;\r
- UINT8 *Ptr;\r
UINT8 DataToggle;\r
+ UINT8 *RequestPhy;\r
+ VOID *RequestMap;\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
\r
UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ //\r
+ // Map the Request and data for bus master access,\r
+ // then create a list of TD for this transfer\r
+ //\r
+ Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ if (RequestMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, RequestMap);\r
+ }\r
+ return Status;\r
+ }\r
+\r
//\r
// generate Setup Stage TD\r
//\r
0,\r
DeviceSpeed,\r
(UINT8 *) Request,\r
+ RequestPhy,\r
(UINT8) sizeof (EFI_USB_DEVICE_REQUEST),\r
&PtrSetupTD\r
);\r
//\r
// Data Stage of Control Transfer\r
//\r
- switch (TransferDirection) {\r
-\r
- case EfiUsbDataIn:\r
- PktID = INPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- case EfiUsbDataOut:\r
- PktID = OUTPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- //\r
- // no data stage\r
- //\r
- case EfiUsbNoData:\r
- if (*DataLength != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- PktID = OUTPUT_PACKET_ID;\r
- PtrDataSource = NULL;\r
- DataLen = 0;\r
- Ptr = NULL;\r
- break;\r
\r
- default:\r
- return EFI_INVALID_PARAMETER;\r
+ if (TransferDirection == EfiUsbNoData) {\r
+ DataLen = 0;\r
+ } else {\r
+ DataLen = (UINT32) *DataLength;\r
}\r
\r
DataToggle = 1;\r
UhcDev,\r
DeviceAddress,\r
0,\r
- Ptr,\r
+ Data,\r
+ DataPhy,\r
PacketSize,\r
PktID,\r
DataToggle,\r
PtrPreTD = PtrTD;\r
\r
DataToggle ^= 1;\r
- Ptr += PacketSize;\r
+ Data = (VOID *) ((UINT8 *) Data + PacketSize);\r
+ DataPhy += PacketSize;\r
DataLen -= PacketSize;\r
}\r
\r
// if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
//\r
if (!IsStatusOK (UhcDev, StatusReg)) {\r
-\r
- ClearStatusReg (UhcDev, StatusReg);\r
*TransferResult |= EFI_USB_ERR_SYSTEM;\r
- return EFI_DEVICE_ERROR;\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ if (DataMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, DataMap);\r
+ }\r
+ if (RequestMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, RequestMap);\r
+ }\r
+\r
return Status;\r
}\r
\r
TD_STRUCT *PtrPreTD;\r
\r
UINT8 PktID;\r
- UINT8 *PtrDataSource;\r
- UINT8 *Ptr;\r
\r
BOOLEAN IsFirstTD;\r
\r
\r
UINT16 CommandContent;\r
\r
+ UINT8 *DataPhy;\r
+ VOID *DataMap;\r
+\r
UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);\r
\r
//\r
PtrFirstTD = NULL;\r
PtrPreTD = NULL;\r
DataLen = 0;\r
- Ptr = NULL;\r
\r
ShortPacketEnable = FALSE;\r
\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ //\r
+ // Map the source data buffer for bus master access,\r
+ // then create a list of TDs\r
+ //\r
if ((EndPointAddress & 0x80) != 0) {\r
TransferDirection = EfiUsbDataIn;\r
} else {\r
TransferDirection = EfiUsbDataOut;\r
}\r
\r
- switch (TransferDirection) {\r
+ Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);\r
\r
- case EfiUsbDataIn:\r
- ShortPacketEnable = TRUE;\r
- PktID = INPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- case EfiUsbDataOut:\r
- PktID = OUTPUT_PACKET_ID;\r
- PtrDataSource = Data;\r
- DataLen = (UINT32) *DataLength;\r
- Ptr = PtrDataSource;\r
- break;\r
-\r
- default:\r
- break;\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
}\r
\r
+ DataLen = (UINT32) *DataLength;\r
+\r
PtrQH = UhcDev->BulkQH;\r
\r
IsFirstTD = TRUE;\r
UhcDev,\r
DeviceAddress,\r
EndPointAddress,\r
- Ptr,\r
+ Data,\r
+ DataPhy,\r
PacketSize,\r
PktID,\r
*DataToggle,\r
PtrPreTD = PtrTD;\r
\r
*DataToggle ^= 1;\r
- Ptr += PacketSize;\r
+ Data = (VOID *) ((UINT8 *) Data + PacketSize);\r
+ DataPhy += PacketSize;\r
DataLen -= PacketSize;\r
}\r
//\r
// if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.\r
//\r
if (!IsStatusOK (UhcDev, StatusReg)) {\r
-\r
- ClearStatusReg (UhcDev, StatusReg);\r
*TransferResult |= EFI_USB_ERR_SYSTEM;\r
- return EFI_DEVICE_ERROR;\r
+ Status = EFI_DEVICE_ERROR;\r
}\r
\r
ClearStatusReg (UhcDev, StatusReg);\r
\r
+ if (DataMap != NULL) {\r
+ IoMmuUnmap (UhcDev->IoMmu, DataMap);\r
+ }\r
+\r
return Status;\r
}\r
\r
@param DevAddr Device address.\r
@param Endpoint Endpoint number.\r
@param DeviceSpeed Device Speed.\r
- @param DevRequest Device reuquest.\r
+ @param DevRequest CPU memory address of request structure buffer to transfer.\r
+ @param RequestPhy PCI memory address of request structure buffer to transfer.\r
@param RequestLen Request length.\r
@param PtrTD TD_STRUCT generated.\r
\r
IN UINT8 Endpoint,\r
IN UINT8 DeviceSpeed,\r
IN UINT8 *DevRequest,\r
+ IN UINT8 *RequestPhy,\r
IN UINT8 RequestLen,\r
OUT TD_STRUCT **PtrTD\r
)\r
\r
TdStruct->PtrTDBuffer = (UINT8 *) DevRequest;\r
TdStruct->TDBufferLength = RequestLen;\r
- SetTDDataBuffer (TdStruct);\r
+ //\r
+ // Set the beginning address of the buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy;\r
\r
*PtrTD = TdStruct;\r
\r
@param UhcDev The UHCI device.\r
@param DevAddr Device address.\r
@param Endpoint Endpoint number.\r
- @param PtrData Data buffer.\r
+ @param PtrData CPU memory address of user data buffer to transfer.\r
+ @param DataPhy PCI memory address of user data buffer to transfer.\r
@param Len Data length.\r
@param PktID PacketID.\r
@param Toggle Data toggle value.\r
IN UINT8 DevAddr,\r
IN UINT8 Endpoint,\r
IN UINT8 *PtrData,\r
+ IN UINT8 *DataPhy,\r
IN UINT8 Len,\r
IN UINT8 PktID,\r
IN UINT8 Toggle,\r
\r
TdStruct->PtrTDBuffer = (UINT8 *) PtrData;\r
TdStruct->TDBufferLength = Len;\r
- SetTDDataBuffer (TdStruct);\r
+ //\r
+ // Set the beginning address of the buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy;\r
\r
*PtrTD = TdStruct;\r
\r
\r
PtrTDStruct->PtrTDBuffer = NULL;\r
PtrTDStruct->TDBufferLength = 0;\r
- SetTDDataBuffer (PtrTDStruct);\r
+ //\r
+ // Set the beginning address of the buffer that will be used\r
+ // during the transaction.\r
+ //\r
+ PtrTDStruct->TDData.TDBufferPtr = 0;\r
\r
*PtrTD = PtrTDStruct;\r
\r
PtrTDStruct->TDData.TDTokenPID = PacketID;\r
}\r
\r
-/**\r
- Set the beginning address of the data buffer that will be used\r
- during the transaction.\r
-\r
- @param PtrTDStruct Place to store TD_STRUCT pointer.\r
-\r
-**/\r
-VOID\r
-SetTDDataBuffer (\r
- IN TD_STRUCT *PtrTDStruct\r
- )\r
-{\r
- //\r
- // Set the beginning address of the data buffer that will be used\r
- // during the transaction.\r
- //\r
- PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);\r
-}\r
-\r
/**\r
Detect whether the TD is active.\r
\r
)\r
{\r
EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS TempPtr;\r
+ UINT8 *TempPtr;\r
UINTN MemPages;\r
UINT8 *Ptr;\r
+ VOID *Mapping;\r
+ EFI_PHYSICAL_ADDRESS MappedAddr;\r
\r
//\r
// Memory Block uses MemoryBlockSizeInPages pages,\r
// memory management header and bit array use 1 page\r
//\r
MemPages = MemoryBlockSizeInPages + 1;\r
- Status = PeiServicesAllocatePages (\r
- EfiBootServicesData,\r
+ Status = IoMmuAllocateBuffer (\r
+ UhcDev->IoMmu,\r
MemPages,\r
- &TempPtr\r
+ (VOID **) &TempPtr,\r
+ &MappedAddr,\r
+ &Mapping\r
);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
\r
- Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+ Ptr = TempPtr;\r
\r
ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);\r
\r
//\r
// Memory block initial address\r
//\r
- Ptr = (UINT8 *) ((UINTN) TempPtr);\r
+ Ptr = TempPtr;\r
Ptr += EFI_PAGE_SIZE;\r
(*MemoryHeader)->MemoryBlockPtr = Ptr;\r
//\r
}\r
}\r
}\r
+\r
+/**\r
+ Map address of request structure buffer.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Request The user request buffer.\r
+ @param MappedAddr Mapped address of request.\r
+ @param Map Identificaion of this mapping to return.\r
+\r
+ @return EFI_SUCCESS Success.\r
+ @return EFI_DEVICE_ERROR Fail to map the user request.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN OUT VOID *Request,\r
+ OUT UINT8 **MappedAddr,\r
+ OUT VOID **Map\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Len;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Len = sizeof (EFI_USB_DEVICE_REQUEST);\r
+ Status = IoMmuMap (\r
+ Uhc->IoMmu,\r
+ EdkiiIoMmuOperationBusMasterRead,\r
+ Request,\r
+ &Len,\r
+ &PhyAddr,\r
+ Map\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Map address of user data buffer.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Direction Direction of the data transfer.\r
+ @param Data The user data buffer.\r
+ @param Len Length of the user data.\r
+ @param PktId Packet identificaion.\r
+ @param MappedAddr Mapped address to return.\r
+ @param Map Identificaion of this mapping to return.\r
+\r
+ @return EFI_SUCCESS Success.\r
+ @return EFI_DEVICE_ERROR Fail to map the user data.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN VOID *Data,\r
+ IN OUT UINTN *Len,\r
+ OUT UINT8 *PktId,\r
+ OUT UINT8 **MappedAddr,\r
+ OUT VOID **Map\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS PhyAddr;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ switch (Direction) {\r
+ case EfiUsbDataIn:\r
+ //\r
+ // BusMasterWrite means cpu read\r
+ //\r
+ *PktId = INPUT_PACKET_ID;\r
+ Status = IoMmuMap (\r
+ Uhc->IoMmu,\r
+ EdkiiIoMmuOperationBusMasterWrite,\r
+ Data,\r
+ Len,\r
+ &PhyAddr,\r
+ Map\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+ break;\r
+\r
+ case EfiUsbDataOut:\r
+ *PktId = OUTPUT_PACKET_ID;\r
+ Status = IoMmuMap (\r
+ Uhc->IoMmu,\r
+ EdkiiIoMmuOperationBusMasterRead,\r
+ Data,\r
+ Len,\r
+ &PhyAddr,\r
+ Map\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto EXIT;\r
+ }\r
+\r
+ *MappedAddr = (UINT8 *) (UINTN) PhyAddr;\r
+ break;\r
+\r
+ case EfiUsbNoData:\r
+ if ((Len != NULL) && (*Len != 0)) {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto EXIT;\r
+ }\r
+\r
+ *PktId = OUTPUT_PACKET_ID;\r
+ *MappedAddr = NULL;\r
+ *Map = NULL;\r
+ break;\r
+\r
+ default:\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+EXIT:\r
+ return Status;\r
+}\r
+\r
/** @file\r
Private Header file for Usb Host Controller PEIM\r
\r
-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2006 - 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
\r
#include <Ppi/UsbController.h>\r
#include <Ppi/UsbHostController.h>\r
+#include <Ppi/IoMmu.h>\r
+#include <Ppi/EndOfPeiPhase.h>\r
\r
#include <Library/DebugLib.h>\r
#include <Library/PeimEntryPoint.h>\r
typedef struct {\r
UINTN Signature;\r
PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;\r
+ EDKII_IOMMU_PPI *IoMmu;\r
EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+ //\r
+ // EndOfPei callback is used to stop the UHC DMA operation\r
+ // after exit PEI phase.\r
+ //\r
+ EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;\r
\r
UINT32 UsbHostControllerBaseAddress;\r
FRAMELIST_ENTRY *FrameListEntry;\r
} USB_UHC_DEV;\r
\r
#define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a) CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE)\r
+#define PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY(a) CR (a, USB_UHC_DEV, EndOfPeiNotifyList, USB_UHC_DEV_SIGNATURE)\r
\r
/**\r
Submits control transfer to a target USB device.\r
@param DevAddr Device address.\r
@param Endpoint Endpoint number.\r
@param DeviceSpeed Device Speed.\r
- @param DevRequest Device reuquest.\r
+ @param DevRequest CPU memory address of request structure buffer to transfer.\r
+ @param RequestPhy PCI memory address of request structure buffer to transfer.\r
@param RequestLen Request length.\r
@param PtrTD TD_STRUCT generated.\r
\r
IN UINT8 Endpoint,\r
IN UINT8 DeviceSpeed,\r
IN UINT8 *DevRequest,\r
+ IN UINT8 *RequestPhy,\r
IN UINT8 RequestLen,\r
OUT TD_STRUCT **PtrTD\r
);\r
@param UhcDev The UHCI device.\r
@param DevAddr Device address.\r
@param Endpoint Endpoint number.\r
- @param PtrData Data buffer.\r
+ @param PtrData CPU memory address of user data buffer to transfer.\r
+ @param DataPhy PCI memory address of user data buffer to transfer.\r
@param Len Data length.\r
@param PktID PacketID.\r
@param Toggle Data toggle value.\r
IN UINT8 DevAddr,\r
IN UINT8 Endpoint,\r
IN UINT8 *PtrData,\r
+ IN UINT8 *DataPhy,\r
IN UINT8 Len,\r
IN UINT8 PktID,\r
IN UINT8 Toggle,\r
IN MEMORY_MANAGE_HEADER *FreeMemoryHeader\r
);\r
\r
+/**\r
+ Map address of request structure buffer.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Request The user request buffer.\r
+ @param MappedAddr Mapped address of request.\r
+ @param Map Identificaion of this mapping to return.\r
+\r
+ @return EFI_SUCCESS Success.\r
+ @return EFI_DEVICE_ERROR Fail to map the user request.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserRequest (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN OUT VOID *Request,\r
+ OUT UINT8 **MappedAddr,\r
+ OUT VOID **Map\r
+ );\r
+\r
+/**\r
+ Map address of user data buffer.\r
+\r
+ @param Uhc The UHCI device.\r
+ @param Direction Direction of the data transfer.\r
+ @param Data The user data buffer.\r
+ @param Len Length of the user data.\r
+ @param PktId Packet identificaion.\r
+ @param MappedAddr Mapped address to return.\r
+ @param Map Identificaion of this mapping to return.\r
+\r
+ @return EFI_SUCCESS Success.\r
+ @return EFI_DEVICE_ERROR Fail to map the user data.\r
+\r
+**/\r
+EFI_STATUS\r
+UhciMapUserData (\r
+ IN USB_UHC_DEV *Uhc,\r
+ IN EFI_USB_DATA_DIRECTION Direction,\r
+ IN VOID *Data,\r
+ IN OUT UINTN *Len,\r
+ OUT UINT8 *PktId,\r
+ OUT UINT8 **MappedAddr,\r
+ OUT VOID **Map\r
+ );\r
+\r
+/**\r
+ Provides the controller-specific addresses required to access system memory from a\r
+ DMA bus master.\r
+\r
+ @param IoMmu Pointer to IOMMU PPI.\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_PPI *IoMmu,\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 IoMmu Pointer to IOMMU PPI.\r
+ @param Mapping The mapping value returned from Map().\r
+\r
+**/\r
+VOID\r
+IoMmuUnmap (\r
+ IN EDKII_IOMMU_PPI *IoMmu,\r
+ IN VOID *Mapping\r
+ );\r
+\r
+/**\r
+ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param IoMmu Pointer to IOMMU PPI.\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 EDKII_IOMMU_PPI *IoMmu,\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 IoMmu Pointer to IOMMU PPI.\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
+**/\r
+VOID\r
+IoMmuFreeBuffer (\r
+ IN EDKII_IOMMU_PPI *IoMmu,\r
+ IN UINTN Pages,\r
+ IN VOID *HostAddress,\r
+ IN VOID *Mapping\r
+ );\r
+\r
+/**\r
+ Initialize IOMMU.\r
+\r
+ @param IoMmu Pointer to pointer to IOMMU PPI.\r
+\r
+**/\r
+VOID\r
+IoMmuInit (\r
+ OUT EDKII_IOMMU_PPI **IoMmu\r
+ );\r
+\r
#endif\r
# It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used\r
# to enable recovery function from USB Drivers.\r
#\r
-# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+# Copyright (c) 2006 - 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
[Sources]\r
UhcPeim.c\r
UhcPeim.h\r
+ DmaMem.c\r
\r
\r
[Packages]\r
[Ppis]\r
gPeiUsbHostControllerPpiGuid ## PRODUCES\r
gPeiUsbControllerPpiGuid ## CONSUMES\r
+ gEdkiiIoMmuPpiGuid ## CONSUMES\r
+ gEfiEndOfPeiSignalPpiGuid ## CONSUMES\r
\r
\r
[Depex]\r