MdeModulePkg/UfsBlockIoPei: Support IoMmu

V2 changes:
Resource cleanup logic update in UfsEndOfPei().

V1 history:
Update the UfsBlockIoPei 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: Jiewen Yao <jiewen.yao@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Hao Wu <hao.a.wu@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
This commit is contained in:
Hao Wu
2017-10-18 13:37:56 +08:00
parent 0aa1794118
commit 44a0857ec6
7 changed files with 535 additions and 38 deletions

View File

@@ -422,6 +422,7 @@ UfsInitQueryRequestUpiu (
@param[in] Lun The Lun on which the SCSI command is executed.
@param[in] Packet The pointer to the UFS_SCSI_REQUEST_PACKET data structure.
@param[in] Trd The pointer to the UTP Transfer Request Descriptor.
@param[out] BufferMap A resulting value, if not NULL, to pass to IoMmuUnmap().
@retval EFI_SUCCESS The creation succeed.
@retval EFI_DEVICE_ERROR The creation failed.
@@ -430,10 +431,11 @@ UfsInitQueryRequestUpiu (
**/
EFI_STATUS
UfsCreateScsiCommandDesc (
IN UFS_PEIM_HC_PRIVATE_DATA *Private,
IN UINT8 Lun,
IN UFS_SCSI_REQUEST_PACKET *Packet,
IN UTP_TRD *Trd
IN UFS_PEIM_HC_PRIVATE_DATA *Private,
IN UINT8 Lun,
IN UFS_SCSI_REQUEST_PACKET *Packet,
IN UTP_TRD *Trd,
OUT VOID **BufferMap
)
{
UINT8 *CommandDesc;
@@ -444,21 +446,37 @@ UfsCreateScsiCommandDesc (
UTP_COMMAND_UPIU *CommandUpiu;
UTP_TR_PRD *PrdtBase;
UFS_DATA_DIRECTION DataDirection;
EFI_STATUS Status;
EDKII_IOMMU_OPERATION MapOp;
UINTN MapLength;
EFI_PHYSICAL_ADDRESS BufferPhyAddr;
ASSERT ((Private != NULL) && (Packet != NULL) && (Trd != NULL));
BufferPhyAddr = 0;
if (Packet->DataDirection == UfsDataIn) {
Buffer = Packet->InDataBuffer;
Length = Packet->InTransferLength;
Buffer = Packet->InDataBuffer;
Length = Packet->InTransferLength;
DataDirection = UfsDataIn;
MapOp = EdkiiIoMmuOperationBusMasterWrite;
} else {
Buffer = Packet->OutDataBuffer;
Length = Packet->OutTransferLength;
DataDirection = UfsDataOut;
MapOp = EdkiiIoMmuOperationBusMasterRead;
}
if (Length == 0) {
DataDirection = UfsNoData;
} else {
MapLength = Length;
Status = IoMmuMap (MapOp, Buffer, &MapLength, &BufferPhyAddr, BufferMap);
if (EFI_ERROR (Status) || (MapLength != Length)) {
DEBUG ((DEBUG_ERROR, "UfsCreateScsiCommandDesc: Fail to map data buffer.\n"));
return EFI_OUT_OF_RESOURCES;
}
}
PrdtNumber = (UINTN)DivU64x32 ((UINT64)Length + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD);
@@ -473,7 +491,7 @@ UfsCreateScsiCommandDesc (
PrdtBase = (UTP_TR_PRD*)(CommandDesc + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU)));
UfsInitCommandUpiu (CommandUpiu, Lun, Private->TaskTag++, Packet->Cdb, Packet->CdbLength, DataDirection, Length);
UfsInitUtpPrdt (PrdtBase, Buffer, Length);
UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)BufferPhyAddr, Length);
//
// Fill UTP_TRD associated fields
@@ -1286,6 +1304,7 @@ UfsExecScsiCmds (
UTP_RESPONSE_UPIU *Response;
UINT16 SenseDataLen;
UINT32 ResTranCount;
VOID *PacketBufferMap;
//
// Find out which slot of transfer request list is available.
@@ -1296,11 +1315,12 @@ UfsExecScsiCmds (
}
Trd = ((UTP_TRD*)Private->UtpTrlBase) + Slot;
PacketBufferMap = NULL;
//
// Fill transfer request descriptor to this slot.
//
Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd);
Status = UfsCreateScsiCommandDesc (Private, Lun, Packet, Trd, &PacketBufferMap);
if (EFI_ERROR (Status)) {
return Status;
}
@@ -1362,6 +1382,9 @@ UfsExecScsiCmds (
}
Exit:
if (PacketBufferMap != NULL) {
IoMmuUnmap (PacketBufferMap);
}
UfsStopExecCmd (Private, Slot);
UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);
@@ -1587,7 +1610,9 @@ UfsInitTaskManagementRequestList (
UINTN Address;
UINT32 Data;
UINT8 Nutmrs;
EFI_PHYSICAL_ADDRESS Buffer;
VOID *CmdDescHost;
EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
VOID *CmdDescMapping;
EFI_STATUS Status;
//
@@ -1601,28 +1626,29 @@ UfsInitTaskManagementRequestList (
// Allocate and initialize UTP Task Management Request List.
//
Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1);
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
Status = IoMmuAllocateBuffer (
EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD)),
&Buffer
&CmdDescHost,
&CmdDescPhyAddr,
&CmdDescMapping
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutmrs * sizeof (UTP_TMRD))));
//
// Program the UTP Task Management Request List Base Address and UTP Task Management
// Request List Base Address with a 64-bit address allocated at step 6.
//
Address = Private->UfsHcBase + UFS_HC_UTMRLBA_OFFSET;
MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
Address = Private->UfsHcBase + UFS_HC_UTMRLBAU_OFFSET;
MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
Private->UtpTmrlBase = (VOID*)(UINTN)Buffer;
MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
Private->UtpTmrlBase = (VOID*)(UINTN)CmdDescHost;
Private->Nutmrs = Nutmrs;
Private->TmrlMapping = CmdDescMapping;
//
// Enable the UTP Task Management Request List by setting the UTP Task Management
@@ -1651,7 +1677,9 @@ UfsInitTransferRequestList (
UINTN Address;
UINT32 Data;
UINT8 Nutrs;
EFI_PHYSICAL_ADDRESS Buffer;
VOID *CmdDescHost;
EFI_PHYSICAL_ADDRESS CmdDescPhyAddr;
VOID *CmdDescMapping;
EFI_STATUS Status;
//
@@ -1665,28 +1693,29 @@ UfsInitTransferRequestList (
// Allocate and initialize UTP Transfer Request List.
//
Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1);
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
Status = IoMmuAllocateBuffer (
EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD)),
&Buffer
&CmdDescHost,
&CmdDescPhyAddr,
&CmdDescMapping
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
ZeroMem ((VOID*)(UINTN)Buffer, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
ZeroMem (CmdDescHost, EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (Nutrs * sizeof (UTP_TRD))));
//
// Program the UTP Transfer Request List Base Address and UTP Transfer Request List
// Base Address with a 64-bit address allocated at step 8.
//
Address = Private->UfsHcBase + UFS_HC_UTRLBA_OFFSET;
MmioWrite32 (Address, (UINT32)(UINTN)Buffer);
MmioWrite32 (Address, (UINT32)(UINTN)CmdDescPhyAddr);
Address = Private->UfsHcBase + UFS_HC_UTRLBAU_OFFSET;
MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)Buffer, 32));
Private->UtpTrlBase = (VOID*)(UINTN)Buffer;
MmioWrite32 (Address, (UINT32)RShiftU64 ((UINT64)CmdDescPhyAddr, 32));
Private->UtpTrlBase = (VOID*)(UINTN)CmdDescHost;
Private->Nutrs = Nutrs;
Private->TrlMapping = CmdDescMapping;
//
// Enable the UTP Transfer Request List by setting the UTP Transfer Request List
@@ -1735,6 +1764,16 @@ UfsControllerInit (
Status = UfsInitTransferRequestList (Private);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "UfsDevicePei: Transfer list initialization Fails, Status = %r\n", Status));
if (Private->TmrlMapping != NULL) {
IoMmuFreeBuffer (
EFI_SIZE_TO_PAGES (Private->Nutmrs * sizeof (UTP_TMRD)),
Private->UtpTmrlBase,
Private->TmrlMapping
);
Private->TmrlMapping = NULL;
}
return Status;
}