/** @file\r
PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.\r
\r
-Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>\r
Copyright (c), Microsoft Corporation.\r
SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
//\r
#define TPMCMDBUFLENGTH 0x500\r
\r
+//\r
+// Max retry count according to Spec TCG PC Client Device Driver Design Principles\r
+// for TPM2.0, Version 1.1, Revision 0.04, Section 7.2.1\r
+//\r
+#define RETRY_CNT_MAX 3\r
+\r
/**\r
Check whether TPM PTP register exist.\r
\r
UINT32 TpmOutSize;\r
UINT16 Data16;\r
UINT32 Data32;\r
+ UINT8 RetryCnt;\r
\r
DEBUG_CODE_BEGIN ();\r
UINTN DebugSize;\r
DEBUG_CODE_END ();\r
TpmOutSize = 0;\r
\r
- //\r
- // STEP 0:\r
- // if CapCRbIdelByPass == 0, enforce Idle state before sending command\r
- //\r
- if ((GetCachedIdleByPass () == 0) && ((MmioRead32 ((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0)) {\r
+ RetryCnt = 0;\r
+ while (TRUE) {\r
+ //\r
+ // STEP 0:\r
+ // if CapCRbIdelByPass == 0, enforce Idle state before sending command\r
+ //\r
+ if ((GetCachedIdleByPass () == 0) && ((MmioRead32 ((UINTN)&CrbReg->CrbControlStatus) & PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE) == 0)) {\r
+ Status = PtpCrbWaitRegisterBits (\r
+ &CrbReg->CrbControlStatus,\r
+ PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+ 0,\r
+ PTP_TIMEOUT_C\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ RetryCnt++;\r
+ if (RetryCnt < RETRY_CNT_MAX) {\r
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+ continue;\r
+ } else {\r
+ //\r
+ // Try to goIdle to recover TPM\r
+ //\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto GoIdle_Exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // STEP 1:\r
+ // Ready is any time the TPM is ready to receive a command, following a write\r
+ // of 1 by software to Request.cmdReady, as indicated by the Status field\r
+ // being cleared to 0.\r
+ //\r
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);\r
Status = PtpCrbWaitRegisterBits (\r
- &CrbReg->CrbControlStatus,\r
- PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+ &CrbReg->CrbControlRequest,\r
0,\r
+ PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,\r
PTP_TIMEOUT_C\r
);\r
if (EFI_ERROR (Status)) {\r
- //\r
- // Try to goIdle to recover TPM\r
- //\r
- Status = EFI_DEVICE_ERROR;\r
- goto GoIdle_Exit;\r
+ RetryCnt++;\r
+ if (RetryCnt < RETRY_CNT_MAX) {\r
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+ continue;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto GoIdle_Exit;\r
+ }\r
}\r
- }\r
\r
- //\r
- // STEP 1:\r
- // Ready is any time the TPM is ready to receive a command, following a write\r
- // of 1 by software to Request.cmdReady, as indicated by the Status field\r
- // being cleared to 0.\r
- //\r
- MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);\r
- Status = PtpCrbWaitRegisterBits (\r
- &CrbReg->CrbControlRequest,\r
- 0,\r
- PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,\r
- PTP_TIMEOUT_C\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto GoIdle_Exit;\r
- }\r
+ Status = PtpCrbWaitRegisterBits (\r
+ &CrbReg->CrbControlStatus,\r
+ 0,\r
+ PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
+ PTP_TIMEOUT_C\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ RetryCnt++;\r
+ if (RetryCnt < RETRY_CNT_MAX) {\r
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
+ continue;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ goto GoIdle_Exit;\r
+ }\r
+ }\r
\r
- Status = PtpCrbWaitRegisterBits (\r
- &CrbReg->CrbControlStatus,\r
- 0,\r
- PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
- PTP_TIMEOUT_C\r
- );\r
- if (EFI_ERROR (Status)) {\r
- Status = EFI_DEVICE_ERROR;\r
- goto GoIdle_Exit;\r
+ break;\r
}\r
\r
//\r
// Command completed, but buffer is not enough\r
//\r
Status = EFI_BUFFER_TOO_SMALL;\r
- goto GoReady_Exit;\r
+ goto GoIdle_Exit;\r
}\r
\r
*SizeOut = TpmOutSize;\r
DEBUG ((DEBUG_VERBOSE, "\n"));\r
DEBUG_CODE_END ();\r
\r
-GoReady_Exit:\r
- //\r
- // Goto Ready State if command is completed successfully and TPM support IdleBypass\r
- // If not supported. flow down to GoIdle\r
- //\r
- if (GetCachedIdleByPass () == 1) {\r
- MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);\r
- return Status;\r
- }\r
-\r
//\r
// Do not wait for state transition for TIMEOUT_C\r
// This function will try to wait 2 TIMEOUT_C at the beginning in next call.\r
//\r
MmioWrite32 ((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);\r
\r
- //\r
- // Only enforce Idle state transition if execution fails when CRBIdleBypass==1\r
- // Leave regular Idle delay at the beginning of next command execution\r
- //\r
- if (GetCachedIdleByPass () == 1) {\r
- Status = PtpCrbWaitRegisterBits (\r
- &CrbReg->CrbControlStatus,\r
- PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,\r
- 0,\r
- PTP_TIMEOUT_C\r
- );\r
- }\r
-\r
return Status;\r
}\r
\r