X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=MdeModulePkg%2FBus%2FUfs%2FUfsPassThruDxe%2FUfsPassThruHci.c;h=74be3efc411b05b28133a0f970be94b64f2ae7dd;hb=a71272ed7a37e6f6bc1d32f3e72addc63196d933;hp=4b93821f38aa7abe54b73766ba6eceb5c4a62639;hpb=9d510e61fceee7b92955ef9a3c20343752d8ce3f;p=mirror_edk2.git diff --git a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c index 4b93821f38..74be3efc41 100644 --- a/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c +++ b/MdeModulePkg/Bus/Ufs/UfsPassThruDxe/UfsPassThruHci.c @@ -2,7 +2,7 @@ UfsPassThruDxe driver is used to produce EFI_EXT_SCSI_PASS_THRU protocol interface for upper layer application to execute UFS-supported SCSI cmds. - Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2014 - 2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -394,17 +394,13 @@ UfsInitUtpPrdt ( UINT8 *Remaining; UINTN PrdtNumber; - if ((BufferSize & (BIT0 | BIT1)) != 0) { - BufferSize &= ~(BIT0 | BIT1); - DEBUG ((DEBUG_WARN, "UfsInitUtpPrdt: The BufferSize [%d] is not dword-aligned!\n", BufferSize)); - } + ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0); + ASSERT ((BufferSize & (BIT1 | BIT0)) == 0); if (BufferSize == 0) { return EFI_SUCCESS; } - ASSERT (((UINTN)Buffer & (BIT0 | BIT1)) == 0); - RemainingLen = BufferSize; Remaining = Buffer; PrdtNumber = (UINTN)DivU64x32 ((UINT64)BufferSize + UFS_MAX_DATA_LEN_PER_PRD - 1, UFS_MAX_DATA_LEN_PER_PRD); @@ -735,7 +731,7 @@ UfsFindAvailableSlotInTrl ( return Status; } - Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1); + Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1); for (Index = 0; Index < Nutrs; Index++) { if ((Data & (BIT0 << Index)) == 0) { @@ -1317,6 +1313,143 @@ Exit: return Status; } +/** + Cleanup data buffers after data transfer. This function + also takes care to copy all data to user memory pool for + unaligned data transfers. + + @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA + @param[in] TransReq Pointer to the transfer request +**/ +VOID +UfsReconcileDataTransferBuffer ( + IN UFS_PASS_THRU_PRIVATE_DATA *Private, + IN UFS_PASS_THRU_TRANS_REQ *TransReq + ) +{ + if (TransReq->DataBufMapping != NULL) { + Private->UfsHostController->Unmap ( + Private->UfsHostController, + TransReq->DataBufMapping + ); + } + + // + // Check if unaligned transfer was performed. If it was and we read + // data from device copy memory to user data buffers before cleanup. + // The assumption is if auxiliary aligned data buffer is not NULL then + // unaligned transfer has been performed. + // + if (TransReq->AlignedDataBuf != NULL) { + if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { + CopyMem (TransReq->Packet->InDataBuffer, TransReq->AlignedDataBuf, TransReq->Packet->InTransferLength); + } + // + // Wipe out the transfer buffer in case it contains sensitive data. + // + ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize); + FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize)); + TransReq->AlignedDataBuf = NULL; + } +} + +/** + Prepare data buffer for transfer. + + @param[in] Private Pointer to the UFS_PASS_THRU_PRIVATE_DATA + @param[in, out] TransReq Pointer to the transfer request + + @retval EFI_DEVICE_ERROR Failed to prepare buffer for transfer + @retval EFI_SUCCESS Buffer ready for transfer +**/ +EFI_STATUS +UfsPrepareDataTransferBuffer ( + IN UFS_PASS_THRU_PRIVATE_DATA *Private, + IN OUT UFS_PASS_THRU_TRANS_REQ *TransReq + ) +{ + EFI_STATUS Status; + VOID *DataBuf; + UINT32 DataLen; + UINTN MapLength; + EFI_PHYSICAL_ADDRESS DataBufPhyAddr; + EDKII_UFS_HOST_CONTROLLER_OPERATION Flag; + UTP_TR_PRD *PrdtBase; + + DataBufPhyAddr = 0; + DataBuf = NULL; + + // + // For unaligned data transfers we allocate auxiliary DWORD aligned memory pool. + // When command is finished auxiliary memory pool is copied into actual user memory. + // This is requiered to assure data transfer safety(DWORD alignment required by UFS spec.) + // + if (TransReq->Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { + if (((UINTN)TransReq->Packet->InDataBuffer % 4 != 0) || (TransReq->Packet->InTransferLength % 4 != 0)) { + DataLen = TransReq->Packet->InTransferLength + (4 - (TransReq->Packet->InTransferLength % 4)); + DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4); + if (DataBuf == NULL) { + return EFI_DEVICE_ERROR; + } + ZeroMem (DataBuf, DataLen); + TransReq->AlignedDataBuf = DataBuf; + TransReq->AlignedDataBufSize = DataLen; + } else { + DataLen = TransReq->Packet->InTransferLength; + DataBuf = TransReq->Packet->InDataBuffer; + } + Flag = EdkiiUfsHcOperationBusMasterWrite; + } else { + if (((UINTN)TransReq->Packet->OutDataBuffer % 4 != 0) || (TransReq->Packet->OutTransferLength % 4 != 0)) { + DataLen = TransReq->Packet->OutTransferLength + (4 - (TransReq->Packet->OutTransferLength % 4)); + DataBuf = AllocateAlignedPages (EFI_SIZE_TO_PAGES (DataLen), 4); + if (DataBuf == NULL) { + return EFI_DEVICE_ERROR; + } + CopyMem (DataBuf, TransReq->Packet->OutDataBuffer, TransReq->Packet->OutTransferLength); + TransReq->AlignedDataBuf = DataBuf; + TransReq->AlignedDataBufSize = DataLen; + } else { + DataLen = TransReq->Packet->OutTransferLength; + DataBuf = TransReq->Packet->OutDataBuffer; + } + Flag = EdkiiUfsHcOperationBusMasterRead; + } + + if (DataLen != 0) { + MapLength = DataLen; + Status = Private->UfsHostController->Map ( + Private->UfsHostController, + Flag, + DataBuf, + &MapLength, + &DataBufPhyAddr, + &TransReq->DataBufMapping + ); + + if (EFI_ERROR (Status) || (DataLen != MapLength)) { + if (TransReq->AlignedDataBuf != NULL) { + // + // Wipe out the transfer buffer in case it contains sensitive data. + // + ZeroMem (TransReq->AlignedDataBuf, TransReq->AlignedDataBufSize); + FreeAlignedPages (TransReq->AlignedDataBuf, EFI_SIZE_TO_PAGES (TransReq->AlignedDataBufSize)); + TransReq->AlignedDataBuf = NULL; + } + return EFI_DEVICE_ERROR; + } + } + + // + // Fill PRDT table of Command UPIU for executed SCSI cmd. + // + PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))); + ASSERT (PrdtBase != NULL); + UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen); + + return EFI_SUCCESS; +} + /** Sends a UFS-supported SCSI Request Packet to a UFS device that is attached to the UFS host controller. @@ -1353,24 +1486,19 @@ UfsExecScsiCmds ( UTP_RESPONSE_UPIU *Response; UINT16 SenseDataLen; UINT32 ResTranCount; - VOID *DataBuf; - EFI_PHYSICAL_ADDRESS DataBufPhyAddr; - UINT32 DataLen; - UINTN MapLength; - EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; - EDKII_UFS_HOST_CONTROLLER_OPERATION Flag; - UTP_TR_PRD *PrdtBase; EFI_TPL OldTpl; UFS_PASS_THRU_TRANS_REQ *TransReq; + EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; - TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ)); + TransReq = AllocateZeroPool (sizeof (UFS_PASS_THRU_TRANS_REQ)); if (TransReq == NULL) { return EFI_OUT_OF_RESOURCES; } TransReq->Signature = UFS_PASS_THRU_TRANS_REQ_SIG; TransReq->TimeoutRemain = Packet->Timeout; - DataBufPhyAddr = 0; + TransReq->Packet = Packet; + UfsHc = Private->UfsHostController; // // Find out which slot of transfer request list is available. @@ -1399,44 +1527,16 @@ UfsExecScsiCmds ( TransReq->CmdDescSize = TransReq->Trd->PrdtO * sizeof (UINT32) + TransReq->Trd->PrdtL * sizeof (UTP_TR_PRD); - if (Packet->DataDirection == EFI_EXT_SCSI_DATA_DIRECTION_READ) { - DataBuf = Packet->InDataBuffer; - DataLen = Packet->InTransferLength; - Flag = EdkiiUfsHcOperationBusMasterWrite; - } else { - DataBuf = Packet->OutDataBuffer; - DataLen = Packet->OutTransferLength; - Flag = EdkiiUfsHcOperationBusMasterRead; - } - - if (DataLen != 0) { - MapLength = DataLen; - Status = UfsHc->Map ( - UfsHc, - Flag, - DataBuf, - &MapLength, - &DataBufPhyAddr, - &TransReq->DataBufMapping - ); - - if (EFI_ERROR (Status) || (DataLen != MapLength)) { - goto Exit1; - } + Status = UfsPrepareDataTransferBuffer (Private, TransReq); + if (EFI_ERROR (Status)) { + goto Exit1; } - // - // Fill PRDT table of Command UPIU for executed SCSI cmd. - // - PrdtBase = (UTP_TR_PRD*)((UINT8*)TransReq->CmdDescHost + ROUNDUP8 (sizeof (UTP_COMMAND_UPIU)) + ROUNDUP8 (sizeof (UTP_RESPONSE_UPIU))); - ASSERT (PrdtBase != NULL); - UfsInitUtpPrdt (PrdtBase, (VOID*)(UINTN)DataBufPhyAddr, DataLen); // // Insert the async SCSI cmd to the Async I/O list // if (Event != NULL) { OldTpl = gBS->RaiseTPL (TPL_NOTIFY); - TransReq->Packet = Packet; TransReq->CallerEvent = Event; InsertTailList (&Private->Queue, &TransReq->TransferList); gBS->RestoreTPL (OldTpl); @@ -1515,9 +1615,7 @@ Exit: UfsStopExecCmd (Private, TransReq->Slot); - if (TransReq->DataBufMapping != NULL) { - UfsHc->Unmap (UfsHc, TransReq->DataBufMapping); - } + UfsReconcileDataTransferBuffer (Private, TransReq); Exit1: if (TransReq->CmdDescMapping != NULL) { @@ -1532,28 +1630,20 @@ Exit1: return Status; } - /** - Sent UIC DME_LINKSTARTUP command to start the link startup procedure. + Send UIC command. - @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure. - @param[in] UicOpcode The opcode of the UIC command. - @param[in] Arg1 The value for 1st argument of the UIC command. - @param[in] Arg2 The value for 2nd argument of the UIC command. - @param[in] Arg3 The value for 3rd argument of the UIC command. + @param[in] Private The pointer to the UFS_PASS_THRU_PRIVATE_DATA data structure. + @param[in, out] UicCommand UIC command descriptor. On exit contains UIC command results. @return EFI_SUCCESS Successfully execute this UIC command and detect attached UFS device. @return EFI_DEVICE_ERROR Fail to execute this UIC command and detect attached UFS device. - @return EFI_NOT_FOUND The presence of the UFS device isn't detected. **/ EFI_STATUS UfsExecUicCommands ( IN UFS_PASS_THRU_PRIVATE_DATA *Private, - IN UINT8 UicOpcode, - IN UINT32 Arg1, - IN UINT32 Arg2, - IN UINT32 Arg3 + IN OUT EDKII_UIC_COMMAND *UicCommand ) { EFI_STATUS Status; @@ -1579,17 +1669,17 @@ UfsExecUicCommands ( // only after all the UIC command argument registers (UICCMDARG1, UICCMDARG2 and UICCMDARG3) // are set. // - Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, Arg1); + Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG1_OFFSET, UicCommand->Arg1); if (EFI_ERROR (Status)) { return Status; } - Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, Arg2); + Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG2_OFFSET, UicCommand->Arg2); if (EFI_ERROR (Status)) { return Status; } - Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, Arg3); + Status = UfsMmioWrite32 (Private, UFS_HC_UCMD_ARG3_OFFSET, UicCommand->Arg3); if (EFI_ERROR (Status)) { return Status; } @@ -1602,7 +1692,7 @@ UfsExecUicCommands ( return Status; } - Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, (UINT32)UicOpcode); + Status = UfsMmioWrite32 (Private, UFS_HC_UIC_CMD_OFFSET, UicCommand->Opcode); if (EFI_ERROR (Status)) { return Status; } @@ -1616,37 +1706,23 @@ UfsExecUicCommands ( return Status; } - if (UicOpcode != UfsUicDmeReset) { - Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &Data); + if (UicCommand->Opcode != UfsUicDmeReset) { + Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG2_OFFSET, &UicCommand->Arg2); if (EFI_ERROR (Status)) { return Status; } - if ((Data & 0xFF) != 0) { + Status = UfsMmioRead32 (Private, UFS_HC_UCMD_ARG3_OFFSET, &UicCommand->Arg3); + if (EFI_ERROR (Status)) { + return Status; + } + if ((UicCommand->Arg2 & 0xFF) != 0) { DEBUG_CODE_BEGIN(); - DumpUicCmdExecResult (UicOpcode, (UINT8)(Data & 0xFF)); + DumpUicCmdExecResult ((UINT8)UicCommand->Opcode, (UINT8)(UicCommand->Arg2 & 0xFF)); DEBUG_CODE_END(); return EFI_DEVICE_ERROR; } } - // - // Check value of HCS.DP and make sure that there is a device attached to the Link. - // - Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data); - if (EFI_ERROR (Status)) { - return Status; - } - - if ((Data & UFS_HC_HCS_DP) == 0) { - Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT); - if (EFI_ERROR (Status)) { - return EFI_DEVICE_ERROR; - } - return EFI_NOT_FOUND; - } - - DEBUG ((DEBUG_INFO, "UfsPassThruDxe: found a attached UFS device\n")); - return EFI_SUCCESS; } @@ -1678,7 +1754,7 @@ UfsAllocateAlignCommonBuffer ( BOOLEAN Is32BitAddr; EDKII_UFS_HOST_CONTROLLER_PROTOCOL *UfsHc; - if ((Private->Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) { + if ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_64ADDR) == UFS_HC_CAP_64ADDR) { Is32BitAddr = FALSE; } else { Is32BitAddr = TRUE; @@ -1820,31 +1896,41 @@ UfsDeviceDetection ( IN UFS_PASS_THRU_PRIVATE_DATA *Private ) { - UINTN Retry; - EFI_STATUS Status; + UINTN Retry; + EFI_STATUS Status; + UINT32 Data; + EDKII_UIC_COMMAND LinkStartupCommand; // // Start UFS device detection. // Try up to 3 times for establishing data link with device. // for (Retry = 0; Retry < 3; Retry++) { - Status = UfsExecUicCommands (Private, UfsUicDmeLinkStartup, 0, 0, 0); - if (!EFI_ERROR (Status)) { - break; + LinkStartupCommand.Opcode = UfsUicDmeLinkStartup; + LinkStartupCommand.Arg1 = 0; + LinkStartupCommand.Arg2 = 0; + LinkStartupCommand.Arg3 = 0; + Status = UfsExecUicCommands (Private, &LinkStartupCommand); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; } - if (Status == EFI_NOT_FOUND) { - continue; + Status = UfsMmioRead32 (Private, UFS_HC_STATUS_OFFSET, &Data); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; } - return EFI_DEVICE_ERROR; - } - - if (Retry == 3) { - return EFI_NOT_FOUND; + if ((Data & UFS_HC_HCS_DP) == 0) { + Status = UfsWaitMemSet (Private, UFS_HC_IS_OFFSET, UFS_HC_IS_ULSS, UFS_HC_IS_ULSS, UFS_TIMEOUT); + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + } else { + return EFI_SUCCESS; + } } - return EFI_SUCCESS; + return EFI_NOT_FOUND; } /** @@ -1861,7 +1947,6 @@ UfsInitTaskManagementRequestList ( IN UFS_PASS_THRU_PRIVATE_DATA *Private ) { - UINT32 Data; UINT8 Nutmrs; VOID *CmdDescHost; EFI_PHYSICAL_ADDRESS CmdDescPhyAddr; @@ -1875,17 +1960,10 @@ UfsInitTaskManagementRequestList ( CmdDescMapping = NULL; CmdDescPhyAddr = 0; - Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data); - if (EFI_ERROR (Status)) { - return Status; - } - - Private->Capabilities = Data; - // // Allocate and initialize UTP Task Management Request List. // - Nutmrs = (UINT8) (RShiftU64 ((Private->Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1); + Nutmrs = (UINT8) (RShiftU64 ((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTMRS), 16) + 1); Status = UfsAllocateAlignCommonBuffer (Private, Nutmrs * sizeof (UTP_TMRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping); if (EFI_ERROR (Status)) { return Status; @@ -1934,7 +2012,6 @@ UfsInitTransferRequestList ( IN UFS_PASS_THRU_PRIVATE_DATA *Private ) { - UINT32 Data; UINT8 Nutrs; VOID *CmdDescHost; EFI_PHYSICAL_ADDRESS CmdDescPhyAddr; @@ -1948,17 +2025,10 @@ UfsInitTransferRequestList ( CmdDescMapping = NULL; CmdDescPhyAddr = 0; - Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data); - if (EFI_ERROR (Status)) { - return Status; - } - - Private->Capabilities = Data; - // // Allocate and initialize UTP Transfer Request List. // - Nutrs = (UINT8)((Private->Capabilities & UFS_HC_CAP_NUTRS) + 1); + Nutrs = (UINT8)((Private->UfsHcInfo.Capabilities & UFS_HC_CAP_NUTRS) + 1); Status = UfsAllocateAlignCommonBuffer (Private, Nutrs * sizeof (UTP_TRD), &CmdDescHost, &CmdDescPhyAddr, &CmdDescMapping); if (EFI_ERROR (Status)) { return Status; @@ -2100,7 +2170,6 @@ UfsControllerStop ( return EFI_SUCCESS; } - /** Internal helper function which will signal the caller event and clean up resources. @@ -2132,9 +2201,7 @@ SignalCallerEvent ( UfsStopExecCmd (Private, TransReq->Slot); - if (TransReq->DataBufMapping != NULL) { - UfsHc->Unmap (UfsHc, TransReq->DataBufMapping); - } + UfsReconcileDataTransferBuffer (Private, TransReq); if (TransReq->CmdDescMapping != NULL) { UfsHc->Unmap (UfsHc, TransReq->CmdDescMapping); @@ -2283,3 +2350,36 @@ ProcessAsyncTaskList ( } } +/** + Initializes UfsHcInfo field in private data. + + @param[in] Private Pointer to host controller private data. + + @retval EFI_SUCCESS UfsHcInfo initialized successfully. + @retval Others Failed to initalize UfsHcInfo. +**/ +EFI_STATUS +GetUfsHcInfo ( + IN UFS_PASS_THRU_PRIVATE_DATA *Private + ) +{ + UINT32 Data; + EFI_STATUS Status; + + Status = UfsMmioRead32 (Private, UFS_HC_VER_OFFSET, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->UfsHcInfo.Version = Data; + + Status = UfsMmioRead32 (Private, UFS_HC_CAP_OFFSET, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + + Private->UfsHcInfo.Capabilities = Data; + + return EFI_SUCCESS; +} +