MdeModulePkg UhciPei: Support IoMmu

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>
This commit is contained in:
Star Zeng 2017-11-20 15:44:39 +08:00
parent c34a5aab53
commit 8284b1791e
4 changed files with 719 additions and 99 deletions

View File

@ -0,0 +1,251 @@
/** @file
The DMA memory help functions.
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 "UhcPeim.h"
/**
Provides the controller-specific addresses required to access system memory from a
DMA bus master.
@param IoMmu Pointer to IOMMU PPI.
@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_PPI *IoMmu,
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 (IoMmu != NULL) {
Status = IoMmu->Map (
IoMmu,
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 = IoMmu->SetAttribute (
IoMmu,
*Mapping,
Attribute
);
if (EFI_ERROR (Status)) {
IoMmu->Unmap (IoMmu, Mapping);
*Mapping = NULL;
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 IoMmu Pointer to IOMMU PPI.
@param Mapping The mapping value returned from Map().
**/
VOID
IoMmuUnmap (
IN EDKII_IOMMU_PPI *IoMmu,
IN VOID *Mapping
)
{
if (IoMmu != NULL) {
IoMmu->SetAttribute (IoMmu, Mapping, 0);
IoMmu->Unmap (IoMmu, Mapping);
}
}
/**
Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
OperationBusMasterCommonBuffer64 mapping.
@param IoMmu Pointer to IOMMU PPI.
@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 EDKII_IOMMU_PPI *IoMmu,
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;
*Mapping = NULL;
if (IoMmu != NULL) {
Status = IoMmu->AllocateBuffer (
IoMmu,
EfiBootServicesData,
Pages,
HostAddress,
0
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
Status = IoMmu->Map (
IoMmu,
EdkiiIoMmuOperationBusMasterCommonBuffer,
*HostAddress,
&NumberOfBytes,
DeviceAddress,
Mapping
);
if (EFI_ERROR (Status)) {
IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
*HostAddress = NULL;
return EFI_OUT_OF_RESOURCES;
}
Status = IoMmu->SetAttribute (
IoMmu,
*Mapping,
EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
);
if (EFI_ERROR (Status)) {
IoMmu->Unmap (IoMmu, *Mapping);
IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
*Mapping = NULL;
*HostAddress = NULL;
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 IoMmu Pointer to IOMMU PPI.
@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().
**/
VOID
IoMmuFreeBuffer (
IN EDKII_IOMMU_PPI *IoMmu,
IN UINTN Pages,
IN VOID *HostAddress,
IN VOID *Mapping
)
{
if (IoMmu != NULL) {
IoMmu->SetAttribute (IoMmu, Mapping, 0);
IoMmu->Unmap (IoMmu, Mapping);
IoMmu->FreeBuffer (IoMmu, Pages, HostAddress);
}
}
/**
Initialize IOMMU.
@param IoMmu Pointer to pointer to IOMMU PPI.
**/
VOID
IoMmuInit (
OUT EDKII_IOMMU_PPI **IoMmu
)
{
*IoMmu = NULL;
PeiServicesLocatePpi (
&gEdkiiIoMmuPpiGuid,
0,
NULL,
(VOID **) IoMmu
);
}

View File

@ -2,7 +2,7 @@
PEIM to produce gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid
which is used to enable recovery function from USB Drivers.
Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved. <BR>
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved. <BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
@ -17,6 +17,78 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "UhcPeim.h"
/**
Stop the host controller.
@param Uhc The UHCI device.
@param Timeout Max time allowed.
@retval EFI_SUCCESS The host controller is stopped.
@retval EFI_TIMEOUT Failed to stop the host controller.
**/
EFI_STATUS
UhciStopHc (
IN USB_UHC_DEV *Uhc,
IN UINTN Timeout
)
{
UINT16 CommandContent;
UINT16 UsbSts;
UINTN Index;
CommandContent = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD);
CommandContent &= USBCMD_RS;
USBWritePortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBCMD, CommandContent);
//
// ensure the HC is in halt status after send the stop command
// Timeout is in us unit.
//
for (Index = 0; Index < (Timeout / 50) + 1; Index++) {
UsbSts = USBReadPortW (Uhc, Uhc->UsbHostControllerBaseAddress + USBSTS);
if ((UsbSts & USBSTS_HCH) == USBSTS_HCH) {
return EFI_SUCCESS;
}
MicroSecondDelay (50);
}
return EFI_TIMEOUT;
}
/**
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
UhcEndOfPei (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
)
{
USB_UHC_DEV *Uhc;
Uhc = PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY (NotifyDescriptor);
//
// Stop the Host Controller
//
UhciStopHc (Uhc, 1000 * 1000);
return EFI_SUCCESS;
}
/**
Initializes Usb Host Controller.
@ -98,6 +170,7 @@ UhcPeimEntry (
UhcDev = (USB_UHC_DEV *) ((UINTN) TempPtr);
UhcDev->Signature = USB_UHC_DEV_SIGNATURE;
IoMmuInit (&UhcDev->IoMmu);
UhcDev->UsbHostControllerBaseAddress = (UINT32) BaseAddress;
//
@ -133,6 +206,12 @@ UhcPeimEntry (
continue;
}
UhcDev->EndOfPeiNotifyList.Flags = (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
UhcDev->EndOfPeiNotifyList.Guid = &gEfiEndOfPeiSignalPpiGuid;
UhcDev->EndOfPeiNotifyList.Notify = UhcEndOfPei;
PeiServicesNotifyPpi (&UhcDev->EndOfPeiNotifyList);
Index++;
}
@ -190,9 +269,11 @@ UhcControlTransfer (
TD_STRUCT *PtrStatusTD;
EFI_STATUS Status;
UINT32 DataLen;
UINT8 *PtrDataSource;
UINT8 *Ptr;
UINT8 DataToggle;
UINT8 *RequestPhy;
VOID *RequestMap;
UINT8 *DataPhy;
VOID *DataMap;
UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
@ -216,6 +297,24 @@ UhcControlTransfer (
ClearStatusReg (UhcDev, StatusReg);
//
// Map the Request and data for bus master access,
// then create a list of TD for this transfer
//
Status = UhciMapUserRequest (UhcDev, Request, &RequestPhy, &RequestMap);
if (EFI_ERROR (Status)) {
return Status;
}
Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);
if (EFI_ERROR (Status)) {
if (RequestMap != NULL) {
IoMmuUnmap (UhcDev->IoMmu, RequestMap);
}
return Status;
}
//
// generate Setup Stage TD
//
@ -228,6 +327,7 @@ UhcControlTransfer (
0,
DeviceSpeed,
(UINT8 *) Request,
RequestPhy,
(UINT8) sizeof (EFI_USB_DEVICE_REQUEST),
&PtrSetupTD
);
@ -242,38 +342,11 @@ UhcControlTransfer (
//
// Data Stage of Control Transfer
//
switch (TransferDirection) {
case EfiUsbDataIn:
PktID = INPUT_PACKET_ID;
PtrDataSource = Data;
DataLen = (UINT32) *DataLength;
Ptr = PtrDataSource;
break;
case EfiUsbDataOut:
PktID = OUTPUT_PACKET_ID;
PtrDataSource = Data;
DataLen = (UINT32) *DataLength;
Ptr = PtrDataSource;
break;
//
// no data stage
//
case EfiUsbNoData:
if (*DataLength != 0) {
return EFI_INVALID_PARAMETER;
}
PktID = OUTPUT_PACKET_ID;
PtrDataSource = NULL;
DataLen = 0;
Ptr = NULL;
break;
default:
return EFI_INVALID_PARAMETER;
if (TransferDirection == EfiUsbNoData) {
DataLen = 0;
} else {
DataLen = (UINT32) *DataLength;
}
DataToggle = 1;
@ -297,7 +370,8 @@ UhcControlTransfer (
UhcDev,
DeviceAddress,
0,
Ptr,
Data,
DataPhy,
PacketSize,
PktID,
DataToggle,
@ -312,7 +386,8 @@ UhcControlTransfer (
PtrPreTD = PtrTD;
DataToggle ^= 1;
Ptr += PacketSize;
Data = (VOID *) ((UINT8 *) Data + PacketSize);
DataPhy += PacketSize;
DataLen -= PacketSize;
}
@ -365,14 +440,19 @@ UhcControlTransfer (
// if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
//
if (!IsStatusOK (UhcDev, StatusReg)) {
ClearStatusReg (UhcDev, StatusReg);
*TransferResult |= EFI_USB_ERR_SYSTEM;
return EFI_DEVICE_ERROR;
Status = EFI_DEVICE_ERROR;
}
ClearStatusReg (UhcDev, StatusReg);
if (DataMap != NULL) {
IoMmuUnmap (UhcDev->IoMmu, DataMap);
}
if (RequestMap != NULL) {
IoMmuUnmap (UhcDev->IoMmu, RequestMap);
}
return Status;
}
@ -431,8 +511,6 @@ UhcBulkTransfer (
TD_STRUCT *PtrPreTD;
UINT8 PktID;
UINT8 *PtrDataSource;
UINT8 *Ptr;
BOOLEAN IsFirstTD;
@ -444,6 +522,9 @@ UhcBulkTransfer (
UINT16 CommandContent;
UINT8 *DataPhy;
VOID *DataMap;
UhcDev = PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS (This);
//
@ -467,7 +548,6 @@ UhcBulkTransfer (
PtrFirstTD = NULL;
PtrPreTD = NULL;
DataLen = 0;
Ptr = NULL;
ShortPacketEnable = FALSE;
@ -495,33 +575,24 @@ UhcBulkTransfer (
ClearStatusReg (UhcDev, StatusReg);
//
// Map the source data buffer for bus master access,
// then create a list of TDs
//
if ((EndPointAddress & 0x80) != 0) {
TransferDirection = EfiUsbDataIn;
} else {
TransferDirection = EfiUsbDataOut;
}
switch (TransferDirection) {
Status = UhciMapUserData (UhcDev, TransferDirection, Data, DataLength, &PktID, &DataPhy, &DataMap);
case EfiUsbDataIn:
ShortPacketEnable = TRUE;
PktID = INPUT_PACKET_ID;
PtrDataSource = Data;
DataLen = (UINT32) *DataLength;
Ptr = PtrDataSource;
break;
case EfiUsbDataOut:
PktID = OUTPUT_PACKET_ID;
PtrDataSource = Data;
DataLen = (UINT32) *DataLength;
Ptr = PtrDataSource;
break;
default:
break;
if (EFI_ERROR (Status)) {
return Status;
}
DataLen = (UINT32) *DataLength;
PtrQH = UhcDev->BulkQH;
IsFirstTD = TRUE;
@ -540,7 +611,8 @@ UhcBulkTransfer (
UhcDev,
DeviceAddress,
EndPointAddress,
Ptr,
Data,
DataPhy,
PacketSize,
PktID,
*DataToggle,
@ -570,7 +642,8 @@ UhcBulkTransfer (
PtrPreTD = PtrTD;
*DataToggle ^= 1;
Ptr += PacketSize;
Data = (VOID *) ((UINT8 *) Data + PacketSize);
DataPhy += PacketSize;
DataLen -= PacketSize;
}
//
@ -604,14 +677,16 @@ UhcBulkTransfer (
// if has errors that cause host controller halt, then return EFI_DEVICE_ERROR directly.
//
if (!IsStatusOK (UhcDev, StatusReg)) {
ClearStatusReg (UhcDev, StatusReg);
*TransferResult |= EFI_USB_ERR_SYSTEM;
return EFI_DEVICE_ERROR;
Status = EFI_DEVICE_ERROR;
}
ClearStatusReg (UhcDev, StatusReg);
if (DataMap != NULL) {
IoMmuUnmap (UhcDev->IoMmu, DataMap);
}
return Status;
}
@ -1492,7 +1567,8 @@ CreateTD (
@param DevAddr Device address.
@param Endpoint Endpoint number.
@param DeviceSpeed Device Speed.
@param DevRequest Device reuquest.
@param DevRequest CPU memory address of request structure buffer to transfer.
@param RequestPhy PCI memory address of request structure buffer to transfer.
@param RequestLen Request length.
@param PtrTD TD_STRUCT generated.
@ -1507,6 +1583,7 @@ GenSetupStageTD (
IN UINT8 Endpoint,
IN UINT8 DeviceSpeed,
IN UINT8 *DevRequest,
IN UINT8 *RequestPhy,
IN UINT8 RequestLen,
OUT TD_STRUCT **PtrTD
)
@ -1583,7 +1660,11 @@ GenSetupStageTD (
TdStruct->PtrTDBuffer = (UINT8 *) DevRequest;
TdStruct->TDBufferLength = RequestLen;
SetTDDataBuffer (TdStruct);
//
// Set the beginning address of the buffer that will be used
// during the transaction.
//
TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) RequestPhy;
*PtrTD = TdStruct;
@ -1596,7 +1677,8 @@ GenSetupStageTD (
@param UhcDev The UHCI device.
@param DevAddr Device address.
@param Endpoint Endpoint number.
@param PtrData Data buffer.
@param PtrData CPU memory address of user data buffer to transfer.
@param DataPhy PCI memory address of user data buffer to transfer.
@param Len Data length.
@param PktID PacketID.
@param Toggle Data toggle value.
@ -1613,6 +1695,7 @@ GenDataTD (
IN UINT8 DevAddr,
IN UINT8 Endpoint,
IN UINT8 *PtrData,
IN UINT8 *DataPhy,
IN UINT8 Len,
IN UINT8 PktID,
IN UINT8 Toggle,
@ -1700,7 +1783,11 @@ GenDataTD (
TdStruct->PtrTDBuffer = (UINT8 *) PtrData;
TdStruct->TDBufferLength = Len;
SetTDDataBuffer (TdStruct);
//
// Set the beginning address of the buffer that will be used
// during the transaction.
//
TdStruct->TDData.TDBufferPtr = (UINT32) (UINTN) DataPhy;
*PtrTD = TdStruct;
@ -1803,7 +1890,11 @@ CreateStatusTD (
PtrTDStruct->PtrTDBuffer = NULL;
PtrTDStruct->TDBufferLength = 0;
SetTDDataBuffer (PtrTDStruct);
//
// Set the beginning address of the buffer that will be used
// during the transaction.
//
PtrTDStruct->TDData.TDBufferPtr = 0;
*PtrTD = PtrTDStruct;
@ -2173,25 +2264,6 @@ SetTDTokenPacketID (
PtrTDStruct->TDData.TDTokenPID = PacketID;
}
/**
Set the beginning address of the data buffer that will be used
during the transaction.
@param PtrTDStruct Place to store TD_STRUCT pointer.
**/
VOID
SetTDDataBuffer (
IN TD_STRUCT *PtrTDStruct
)
{
//
// Set the beginning address of the data buffer that will be used
// during the transaction.
//
PtrTDStruct->TDData.TDBufferPtr = (UINT32) (UINTN) (PtrTDStruct->PtrTDBuffer);
}
/**
Detect whether the TD is active.
@ -2773,25 +2845,29 @@ CreateMemoryBlock (
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS TempPtr;
UINT8 *TempPtr;
UINTN MemPages;
UINT8 *Ptr;
VOID *Mapping;
EFI_PHYSICAL_ADDRESS MappedAddr;
//
// Memory Block uses MemoryBlockSizeInPages pages,
// memory management header and bit array use 1 page
//
MemPages = MemoryBlockSizeInPages + 1;
Status = PeiServicesAllocatePages (
EfiBootServicesData,
Status = IoMmuAllocateBuffer (
UhcDev->IoMmu,
MemPages,
&TempPtr
(VOID **) &TempPtr,
&MappedAddr,
&Mapping
);
if (EFI_ERROR (Status)) {
return Status;
}
Ptr = (UINT8 *) ((UINTN) TempPtr);
Ptr = TempPtr;
ZeroMem (Ptr, MemPages * EFI_PAGE_SIZE);
@ -2810,7 +2886,7 @@ CreateMemoryBlock (
//
// Memory block initial address
//
Ptr = (UINT8 *) ((UINTN) TempPtr);
Ptr = TempPtr;
Ptr += EFI_PAGE_SIZE;
(*MemoryHeader)->MemoryBlockPtr = Ptr;
//
@ -3217,3 +3293,135 @@ DelinkMemoryBlock (
}
}
}
/**
Map address of request structure buffer.
@param Uhc The UHCI device.
@param Request The user request buffer.
@param MappedAddr Mapped address of request.
@param Map Identificaion of this mapping to return.
@return EFI_SUCCESS Success.
@return EFI_DEVICE_ERROR Fail to map the user request.
**/
EFI_STATUS
UhciMapUserRequest (
IN USB_UHC_DEV *Uhc,
IN OUT VOID *Request,
OUT UINT8 **MappedAddr,
OUT VOID **Map
)
{
EFI_STATUS Status;
UINTN Len;
EFI_PHYSICAL_ADDRESS PhyAddr;
Len = sizeof (EFI_USB_DEVICE_REQUEST);
Status = IoMmuMap (
Uhc->IoMmu,
EdkiiIoMmuOperationBusMasterRead,
Request,
&Len,
&PhyAddr,
Map
);
if (!EFI_ERROR (Status)) {
*MappedAddr = (UINT8 *) (UINTN) PhyAddr;
}
return Status;
}
/**
Map address of user data buffer.
@param Uhc The UHCI device.
@param Direction Direction of the data transfer.
@param Data The user data buffer.
@param Len Length of the user data.
@param PktId Packet identificaion.
@param MappedAddr Mapped address to return.
@param Map Identificaion of this mapping to return.
@return EFI_SUCCESS Success.
@return EFI_DEVICE_ERROR Fail to map the user data.
**/
EFI_STATUS
UhciMapUserData (
IN USB_UHC_DEV *Uhc,
IN EFI_USB_DATA_DIRECTION Direction,
IN VOID *Data,
IN OUT UINTN *Len,
OUT UINT8 *PktId,
OUT UINT8 **MappedAddr,
OUT VOID **Map
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS PhyAddr;
Status = EFI_SUCCESS;
switch (Direction) {
case EfiUsbDataIn:
//
// BusMasterWrite means cpu read
//
*PktId = INPUT_PACKET_ID;
Status = IoMmuMap (
Uhc->IoMmu,
EdkiiIoMmuOperationBusMasterWrite,
Data,
Len,
&PhyAddr,
Map
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
*MappedAddr = (UINT8 *) (UINTN) PhyAddr;
break;
case EfiUsbDataOut:
*PktId = OUTPUT_PACKET_ID;
Status = IoMmuMap (
Uhc->IoMmu,
EdkiiIoMmuOperationBusMasterRead,
Data,
Len,
&PhyAddr,
Map
);
if (EFI_ERROR (Status)) {
goto EXIT;
}
*MappedAddr = (UINT8 *) (UINTN) PhyAddr;
break;
case EfiUsbNoData:
if ((Len != NULL) && (*Len != 0)) {
Status = EFI_INVALID_PARAMETER;
goto EXIT;
}
*PktId = OUTPUT_PACKET_ID;
*MappedAddr = NULL;
*Map = NULL;
break;
default:
Status = EFI_INVALID_PARAMETER;
}
EXIT:
return Status;
}

View File

@ -1,7 +1,7 @@
/** @file
Private Header file for Usb Host Controller PEIM
Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions
@ -22,6 +22,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Ppi/UsbController.h>
#include <Ppi/UsbHostController.h>
#include <Ppi/IoMmu.h>
#include <Ppi/EndOfPeiPhase.h>
#include <Library/DebugLib.h>
#include <Library/PeimEntryPoint.h>
@ -177,7 +179,13 @@ struct _MEMORY_MANAGE_HEADER {
typedef struct {
UINTN Signature;
PEI_USB_HOST_CONTROLLER_PPI UsbHostControllerPpi;
EDKII_IOMMU_PPI *IoMmu;
EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
//
// EndOfPei callback is used to stop the UHC DMA operation
// after exit PEI phase.
//
EFI_PEI_NOTIFY_DESCRIPTOR EndOfPeiNotifyList;
UINT32 UsbHostControllerBaseAddress;
FRAMELIST_ENTRY *FrameListEntry;
@ -191,6 +199,7 @@ typedef struct {
} USB_UHC_DEV;
#define PEI_RECOVERY_USB_UHC_DEV_FROM_UHCI_THIS(a) CR (a, USB_UHC_DEV, UsbHostControllerPpi, USB_UHC_DEV_SIGNATURE)
#define PEI_RECOVERY_USB_UHC_DEV_FROM_THIS_NOTIFY(a) CR (a, USB_UHC_DEV, EndOfPeiNotifyList, USB_UHC_DEV_SIGNATURE)
/**
Submits control transfer to a target USB device.
@ -654,7 +663,8 @@ CreateTD (
@param DevAddr Device address.
@param Endpoint Endpoint number.
@param DeviceSpeed Device Speed.
@param DevRequest Device reuquest.
@param DevRequest CPU memory address of request structure buffer to transfer.
@param RequestPhy PCI memory address of request structure buffer to transfer.
@param RequestLen Request length.
@param PtrTD TD_STRUCT generated.
@ -669,6 +679,7 @@ GenSetupStageTD (
IN UINT8 Endpoint,
IN UINT8 DeviceSpeed,
IN UINT8 *DevRequest,
IN UINT8 *RequestPhy,
IN UINT8 RequestLen,
OUT TD_STRUCT **PtrTD
);
@ -679,7 +690,8 @@ GenSetupStageTD (
@param UhcDev The UHCI device.
@param DevAddr Device address.
@param Endpoint Endpoint number.
@param PtrData Data buffer.
@param PtrData CPU memory address of user data buffer to transfer.
@param DataPhy PCI memory address of user data buffer to transfer.
@param Len Data length.
@param PktID PacketID.
@param Toggle Data toggle value.
@ -696,6 +708,7 @@ GenDataTD (
IN UINT8 DevAddr,
IN UINT8 Endpoint,
IN UINT8 *PtrData,
IN UINT8 *DataPhy,
IN UINT8 Len,
IN UINT8 PktID,
IN UINT8 Toggle,
@ -1330,4 +1343,149 @@ DelinkMemoryBlock (
IN MEMORY_MANAGE_HEADER *FreeMemoryHeader
);
/**
Map address of request structure buffer.
@param Uhc The UHCI device.
@param Request The user request buffer.
@param MappedAddr Mapped address of request.
@param Map Identificaion of this mapping to return.
@return EFI_SUCCESS Success.
@return EFI_DEVICE_ERROR Fail to map the user request.
**/
EFI_STATUS
UhciMapUserRequest (
IN USB_UHC_DEV *Uhc,
IN OUT VOID *Request,
OUT UINT8 **MappedAddr,
OUT VOID **Map
);
/**
Map address of user data buffer.
@param Uhc The UHCI device.
@param Direction Direction of the data transfer.
@param Data The user data buffer.
@param Len Length of the user data.
@param PktId Packet identificaion.
@param MappedAddr Mapped address to return.
@param Map Identificaion of this mapping to return.
@return EFI_SUCCESS Success.
@return EFI_DEVICE_ERROR Fail to map the user data.
**/
EFI_STATUS
UhciMapUserData (
IN USB_UHC_DEV *Uhc,
IN EFI_USB_DATA_DIRECTION Direction,
IN VOID *Data,
IN OUT UINTN *Len,
OUT UINT8 *PktId,
OUT UINT8 **MappedAddr,
OUT VOID **Map
);
/**
Provides the controller-specific addresses required to access system memory from a
DMA bus master.
@param IoMmu Pointer to IOMMU PPI.
@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_PPI *IoMmu,
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 IoMmu Pointer to IOMMU PPI.
@param Mapping The mapping value returned from Map().
**/
VOID
IoMmuUnmap (
IN EDKII_IOMMU_PPI *IoMmu,
IN VOID *Mapping
);
/**
Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
OperationBusMasterCommonBuffer64 mapping.
@param IoMmu Pointer to IOMMU PPI.
@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 EDKII_IOMMU_PPI *IoMmu,
IN UINTN Pages,
OUT VOID **HostAddress,
OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
OUT VOID **Mapping
);
/**
Frees memory that was allocated with AllocateBuffer().
@param IoMmu Pointer to IOMMU PPI.
@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().
**/
VOID
IoMmuFreeBuffer (
IN EDKII_IOMMU_PPI *IoMmu,
IN UINTN Pages,
IN VOID *HostAddress,
IN VOID *Mapping
);
/**
Initialize IOMMU.
@param IoMmu Pointer to pointer to IOMMU PPI.
**/
VOID
IoMmuInit (
OUT EDKII_IOMMU_PPI **IoMmu
);
#endif

View File

@ -4,7 +4,7 @@
# It produces gPeiUsbHostControllerPpiGuid based on gPeiUsbControllerPpiGuid which is used
# to enable recovery function from USB Drivers.
#
# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
# Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions
@ -36,6 +36,7 @@
[Sources]
UhcPeim.c
UhcPeim.h
DmaMem.c
[Packages]
@ -55,6 +56,8 @@
[Ppis]
gPeiUsbHostControllerPpiGuid ## PRODUCES
gPeiUsbControllerPpiGuid ## CONSUMES
gEdkiiIoMmuPpiGuid ## CONSUMES
gEfiEndOfPeiSignalPpiGuid ## CONSUMES
[Depex]