Skip to content

Commit f16a0d0

Browse files
tpmlib/tis.c: work around poor TPM implementations
Release versions of SKL hanged in tis_send(), while versions with serial output worked, most likely thanks to increased delay between DRTM sequence and next TPM command. Apparently, some TPMs don't properly handle setting STS.commandReady when all of the following conditions are met: - TPM has recently finished DRTM sequence (internal work may still be happening at that point, there is no way to be sure), - TPM just transitioned to Idle state (e.g. by changing locality), - STS.commandReady is written periodically before TPM reports it is in Ready state. When all of the above applies, STS.commandReady is always read as 0, as if the TPM restarted transition from Idle to Ready each time it is asked to do so. To work around this, set this bit once and keep checking in a loop until TIMEOUT_B (2 seconds). Well behaving TPM must be able to enter Ready state before that time, if it doesn't, error is returned. Signed-off-by: Krystian Hebel <[email protected]>
1 parent 75f3f0f commit f16a0d0

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

tpmlib/tis.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,28 @@ size_t tis_send(struct tpmbuff *buf)
8080
u8 status, *buf_ptr;
8181
u32 burstcnt = 0;
8282
u32 count = 0;
83+
int i;
8384

8485
if (locality > TPM_MAX_LOCALITY)
8586
return 0;
8687

87-
for (status = 0; (status & STS_COMMAND_READY) == 0; ) {
88-
tpm_write8(STS_COMMAND_READY, STS(locality));
88+
/*
89+
* TPM may go directly to Ready if time since entering Idle < TIMEOUT_B
90+
* (2 seconds). Some TPMs (e.g. Infineon SLB 9665) don't like having
91+
* STS_COMMAND_READY set during that time and immediately checked, which
92+
* results in bit never being set. To work around this, check status once
93+
* before delaying and don't keep setting STS_COMMAND_READY in a loop.
94+
*/
95+
tpm_write8(STS_COMMAND_READY, STS(locality));
96+
status = tpm_read8(STS(locality));
97+
for (i = 0; (status & STS_COMMAND_READY) == 0 && i < 200; i++) {
98+
tpm_mdelay(10);
8999
status = tpm_read8(STS(locality));
90100
}
91101

102+
if ((status & STS_COMMAND_READY) == 0)
103+
return 0;
104+
92105
buf_ptr = buf->head;
93106

94107
/* send all but the last byte */

0 commit comments

Comments
 (0)