/** @file\r
\r
- Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
Data = NULL;\r
}\r
\r
- if ( ((Opcode != UtpQueryFuncOpcodeSetFlag) && (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag))\r
- && ((DataSize == 0) || (Data == NULL)))\r
- {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if ( ((Opcode == UtpQueryFuncOpcodeSetFlag) || (Opcode == UtpQueryFuncOpcodeClrFlag) || (Opcode == UtpQueryFuncOpcodeTogFlag))\r
- && ((DataSize != 0) || (Data != NULL)))\r
+ if (((Opcode != UtpQueryFuncOpcodeRdFlag) && (Opcode != UtpQueryFuncOpcodeSetFlag) &&\r
+ (Opcode != UtpQueryFuncOpcodeClrFlag) && (Opcode != UtpQueryFuncOpcodeTogFlag)) &&\r
+ ((DataSize == 0) || (Data == NULL)))\r
{\r
return EFI_INVALID_PARAMETER;\r
}\r
}\r
\r
/**\r
- Read or write specified device descriptor of a UFS device.\r
+ Extracts return data from query response upiu.\r
\r
- @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
- @param[in] Read The boolean variable to show r/w direction.\r
- @param[in] DescId The ID of device descriptor.\r
- @param[in] Index The Index of device descriptor.\r
- @param[in] Selector The Selector of device descriptor.\r
- @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
- @param[in] DescSize The size of device descriptor buffer.\r
+ @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
+ @param[in] QueryResp Pointer to the query response.\r
\r
- @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
- @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
- @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+ @retval EFI_INVALID_PARAMETER Packet or QueryResp are empty or opcode is invalid.\r
+ @retval EFI_DEVICE_ERROR Data returned from device is invalid.\r
+ @retval EFI_SUCCESS Data extracted.\r
\r
**/\r
EFI_STATUS\r
-UfsRwDeviceDesc (\r
- IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
- IN BOOLEAN Read,\r
- IN UINT8 DescId,\r
- IN UINT8 Index,\r
- IN UINT8 Selector,\r
- IN OUT VOID *Descriptor,\r
- IN UINT32 DescSize\r
+UfsGetReturnDataFromQueryResponse (\r
+ IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet,\r
+ IN UTP_QUERY_RESP_UPIU *QueryResp\r
)\r
{\r
- EFI_STATUS Status;\r
- UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
- UINT8 Slot;\r
- UTP_TRD *Trd;\r
- UINTN Address;\r
- UTP_QUERY_RESP_UPIU *QueryResp;\r
- UINT8 *CmdDescBase;\r
- UINT32 CmdDescSize;\r
- UINT16 ReturnDataSize;\r
+ UINT16 ReturnDataSize;\r
\r
- ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+ ReturnDataSize = 0;\r
\r
- if (Read) {\r
- Packet.DataDirection = UfsDataIn;\r
- Packet.InDataBuffer = Descriptor;\r
- Packet.InTransferLength = DescSize;\r
- Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
- } else {\r
- Packet.DataDirection = UfsDataOut;\r
- Packet.OutDataBuffer = Descriptor;\r
- Packet.OutTransferLength = DescSize;\r
- Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
+ if ((Packet == NULL) || (QueryResp == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
}\r
\r
- Packet.DescId = DescId;\r
- Packet.Index = Index;\r
- Packet.Selector = Selector;\r
- Packet.Timeout = UFS_TIMEOUT;\r
+ switch (Packet->Opcode) {\r
+ case UtpQueryFuncOpcodeRdDesc:\r
+ ReturnDataSize = QueryResp->Tsf.Length;\r
+ SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));\r
+ //\r
+ // Make sure the hardware device does not return more data than expected.\r
+ //\r
+ if (ReturnDataSize > Packet->InTransferLength) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (Packet->InDataBuffer, (QueryResp + 1), ReturnDataSize);\r
+ Packet->InTransferLength = ReturnDataSize;\r
+ break;\r
+ case UtpQueryFuncOpcodeWrDesc:\r
+ ReturnDataSize = QueryResp->Tsf.Length;\r
+ SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));\r
+ Packet->OutTransferLength = ReturnDataSize;\r
+ break;\r
+ case UtpQueryFuncOpcodeRdFlag:\r
+ //\r
+ // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value\r
+ //\r
+ *((UINT8 *)(Packet->InDataBuffer)) = *((UINT8 *)&(QueryResp->Tsf.Value) + 3);\r
+ break;\r
+ case UtpQueryFuncOpcodeSetFlag:\r
+ case UtpQueryFuncOpcodeClrFlag:\r
+ case UtpQueryFuncOpcodeTogFlag:\r
+ //\r
+ // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value\r
+ //\r
+ *((UINT8 *)(Packet->OutDataBuffer)) = *((UINT8 *)&(QueryResp->Tsf.Value) + 3);\r
+ break;\r
+ default:\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Creates Transfer Request descriptor and sends Query Request to the device.\r
+\r
+ @param[in] Private Pointer to the UFS_PEIM_HC_PRIVATE_DATA.\r
+ @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
+\r
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
+ @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
+ combination to point to a type of UFS device descriptor.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsSendDmRequestRetry (\r
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
+ IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ UINT8 Slot;\r
+ EFI_STATUS Status;\r
+ UTP_TRD *Trd;\r
+ UINTN Address;\r
+ UTP_QUERY_RESP_UPIU *QueryResp;\r
+ UINT8 *CmdDescBase;\r
+ UINT32 CmdDescSize;\r
\r
//\r
// Find out which slot of transfer request list is available.\r
//\r
// Fill transfer request descriptor to this slot.\r
//\r
- Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
+ Status = UfsCreateDMCommandDesc (Private, Packet, Trd);\r
if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to create DM command descriptor\n"));\r
return Status;\r
}\r
\r
// Wait for the completion of the transfer request.\r
//\r
Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
- Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);\r
+ Status = UfsWaitMemSet (Address, (BIT0 << Slot), 0, Packet->Timeout);\r
if (EFI_ERROR (Status)) {\r
goto Exit;\r
}\r
\r
- if (QueryResp->QueryResp != 0) {\r
+ if ((Trd->Ocs != 0) || (QueryResp->QueryResp != UfsUtpQueryResponseSuccess)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to send query request, OCS = %X, QueryResp = %X\n", Trd->Ocs, QueryResp->QueryResp));\r
DumpQueryResponseResult (QueryResp->QueryResp);\r
Status = EFI_DEVICE_ERROR;\r
goto Exit;\r
}\r
\r
- if (Trd->Ocs == 0) {\r
- ReturnDataSize = QueryResp->Tsf.Length;\r
- SwapLittleEndianToBigEndian ((UINT8 *)&ReturnDataSize, sizeof (UINT16));\r
+ Status = UfsGetReturnDataFromQueryResponse (Packet, QueryResp);\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "Failed to get return data from query response\n"));\r
+ goto Exit;\r
+ }\r
\r
- if (Read) {\r
- //\r
- // Make sure the hardware device does not return more data than expected.\r
- //\r
- if (ReturnDataSize > Packet.InTransferLength) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
+Exit:\r
+ UfsStopExecCmd (Private, Slot);\r
+ UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
\r
- CopyMem (Packet.InDataBuffer, (QueryResp + 1), ReturnDataSize);\r
- Packet.InTransferLength = ReturnDataSize;\r
- } else {\r
- Packet.OutTransferLength = ReturnDataSize;\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Sends Query Request to the device. Query is sent until device responds correctly or counter runs out.\r
+\r
+ @param[in] Private Pointer to the UFS_PEIM_HC_PRIVATE_DATA.\r
+ @param[in, out] Packet Pointer to the UFS_DEVICE_MANAGEMENT_REQUEST_PACKET.\r
+\r
+ @retval EFI_SUCCESS The device responded correctly to the Query request.\r
+ @retval EFI_INVALID_PARAMETER The DescId, Index and Selector fields in Packet are invalid\r
+ combination to point to a type of UFS device descriptor.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while waiting for the response from the device.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of the operation.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsSendDmRequest (\r
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
+ IN OUT UFS_DEVICE_MANAGEMENT_REQUEST_PACKET *Packet\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 Retry;\r
+\r
+ Status = EFI_SUCCESS;\r
+\r
+ for (Retry = 0; Retry < 5; Retry++) {\r
+ Status = UfsSendDmRequestRetry (Private, Packet);\r
+ if (!EFI_ERROR (Status)) {\r
+ return EFI_SUCCESS;\r
}\r
+ }\r
+\r
+ DEBUG ((DEBUG_ERROR, "Failed to get response from the device after %d retries\n", Retry));\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Read or write specified device descriptor of a UFS device.\r
+\r
+ @param[in] Private The pointer to the UFS_PEIM_HC_PRIVATE_DATA data structure.\r
+ @param[in] Read The boolean variable to show r/w direction.\r
+ @param[in] DescId The ID of device descriptor.\r
+ @param[in] Index The Index of device descriptor.\r
+ @param[in] Selector The Selector of device descriptor.\r
+ @param[in, out] Descriptor The buffer of device descriptor to be read or written.\r
+ @param[in] DescSize The size of device descriptor buffer.\r
+\r
+ @retval EFI_SUCCESS The device descriptor was read/written successfully.\r
+ @retval EFI_DEVICE_ERROR A device error occurred while attempting to r/w the device descriptor.\r
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the completion of r/w the device descriptor.\r
+\r
+**/\r
+EFI_STATUS\r
+UfsRwDeviceDesc (\r
+ IN UFS_PEIM_HC_PRIVATE_DATA *Private,\r
+ IN BOOLEAN Read,\r
+ IN UINT8 DescId,\r
+ IN UINT8 Index,\r
+ IN UINT8 Selector,\r
+ IN OUT VOID *Descriptor,\r
+ IN UINT32 DescSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
+\r
+ ZeroMem (&Packet, sizeof (UFS_DEVICE_MANAGEMENT_REQUEST_PACKET));\r
+\r
+ if (Read) {\r
+ Packet.DataDirection = UfsDataIn;\r
+ Packet.InDataBuffer = Descriptor;\r
+ Packet.InTransferLength = DescSize;\r
+ Packet.Opcode = UtpQueryFuncOpcodeRdDesc;\r
} else {\r
- Status = EFI_DEVICE_ERROR;\r
+ Packet.DataDirection = UfsDataOut;\r
+ Packet.OutDataBuffer = Descriptor;\r
+ Packet.OutTransferLength = DescSize;\r
+ Packet.Opcode = UtpQueryFuncOpcodeWrDesc;\r
}\r
\r
-Exit:\r
- UfsStopExecCmd (Private, Slot);\r
- UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+ Packet.DescId = DescId;\r
+ Packet.Index = Index;\r
+ Packet.Selector = Selector;\r
+ Packet.Timeout = UFS_TIMEOUT;\r
\r
+ Status = UfsSendDmRequest (Private, &Packet);\r
return Status;\r
}\r
\r
{\r
EFI_STATUS Status;\r
UFS_DEVICE_MANAGEMENT_REQUEST_PACKET Packet;\r
- UINT8 Slot;\r
- UTP_TRD *Trd;\r
- UINTN Address;\r
- UTP_QUERY_RESP_UPIU *QueryResp;\r
- UINT8 *CmdDescBase;\r
- UINT32 CmdDescSize;\r
\r
if (Value == NULL) {\r
return EFI_INVALID_PARAMETER;\r
\r
if (Read) {\r
ASSERT (Value != NULL);\r
- Packet.DataDirection = UfsDataIn;\r
- Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
+ Packet.DataDirection = UfsDataIn;\r
+ Packet.InDataBuffer = (VOID *)Value;\r
+ Packet.InTransferLength = 0;\r
+ Packet.Opcode = UtpQueryFuncOpcodeRdFlag;\r
} else {\r
- Packet.DataDirection = UfsDataOut;\r
+ Packet.DataDirection = UfsDataOut;\r
+ Packet.OutDataBuffer = (VOID *)Value;\r
+ Packet.OutTransferLength = 0;\r
if (*Value == 1) {\r
Packet.Opcode = UtpQueryFuncOpcodeSetFlag;\r
} else if (*Value == 0) {\r
Packet.Selector = 0;\r
Packet.Timeout = UFS_TIMEOUT;\r
\r
- //\r
- // Find out which slot of transfer request list is available.\r
- //\r
- Status = UfsFindAvailableSlotInTrl (Private, &Slot);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Fill transfer request descriptor to this slot.\r
- //\r
- Trd = ((UTP_TRD *)Private->UtpTrlBase) + Slot;\r
- Status = UfsCreateDMCommandDesc (Private, &Packet, Trd);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Check the transfer request result.\r
- //\r
- CmdDescBase = (UINT8 *)(UINTN)(LShiftU64 ((UINT64)Trd->UcdBaU, 32) | LShiftU64 ((UINT64)Trd->UcdBa, 7));\r
- QueryResp = (UTP_QUERY_RESP_UPIU *)(CmdDescBase + Trd->RuO * sizeof (UINT32));\r
- CmdDescSize = Trd->RuO * sizeof (UINT32) + Trd->RuL * sizeof (UINT32);\r
-\r
- //\r
- // Start to execute the transfer request.\r
- //\r
- UfsStartExecCmd (Private, Slot);\r
-\r
- //\r
- // Wait for the completion of the transfer request.\r
- //\r
- Address = Private->UfsHcBase + UFS_HC_UTRLDBR_OFFSET;\r
- Status = UfsWaitMemSet (Address, BIT0 << Slot, 0, Packet.Timeout);\r
- if (EFI_ERROR (Status)) {\r
- goto Exit;\r
- }\r
-\r
- if (QueryResp->QueryResp != 0) {\r
- DumpQueryResponseResult (QueryResp->QueryResp);\r
- Status = EFI_DEVICE_ERROR;\r
- goto Exit;\r
- }\r
-\r
- if (Trd->Ocs == 0) {\r
- //\r
- // The 'FLAG VALUE' field is at byte offset 3 of QueryResp->Tsf.Value\r
- //\r
- *Value = *((UINT8 *)&(QueryResp->Tsf.Value) + 3);\r
- } else {\r
- Status = EFI_DEVICE_ERROR;\r
- }\r
-\r
-Exit:\r
- UfsStopExecCmd (Private, Slot);\r
- UfsPeimFreeMem (Private->Pool, CmdDescBase, CmdDescSize);\r
+ Status = UfsSendDmRequest (Private, &Packet);\r
\r
return Status;\r
}\r