]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Bus/Ufs/UfsBlockIoPei/UfsHci.c
MdeModulePkg: Refactoring UFS DME request and fix timing problem
[mirror_edk2.git] / MdeModulePkg / Bus / Ufs / UfsBlockIoPei / UfsHci.c
index 2baa57593e1c035c59f264f0c6fb394a7a5e8ac3..409ea283f5131316b6541596641c11ad9cac28a7 100644 (file)
@@ -1,6 +1,6 @@
 /** @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
@@ -551,14 +551,9 @@ UfsCreateDMCommandDesc (
     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
@@ -747,60 +742,96 @@ UfsStopExecCmd (
 }\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
@@ -814,8 +845,9 @@ UfsRwDeviceDesc (
   //\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
@@ -835,43 +867,116 @@ UfsRwDeviceDesc (
   // 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
@@ -898,12 +1003,6 @@ UfsRwFlags (
 {\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
@@ -913,10 +1012,14 @@ UfsRwFlags (
 \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
@@ -931,62 +1034,7 @@ UfsRwFlags (
   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