From 8727e644ea9c53d066f2f289766920b7380dff83 Mon Sep 17 00:00:00 2001 From: Vadim Bendebury Date: Thu, 16 Nov 2017 21:00:41 -0800 Subject: spi/tpm: claim locality just once during boot All coreboot stages using TPM start with the same sequence: check if locality is claimed, if so, release it by writing 'active locality' bit, then try claiming it. This is actually not a proper procedure: section "5.5.2.3.1 Command Aborts" of "TCG PC Client Platform TPM Profile (PTP) Specification Level 00 Revision 00.430 Family 2" lists overwriting active locality status bit as a means of triggering TPM command abort. On top of that, none of the coreboot stages releases locality, it is enough to claim it once when device starts booting. In fact, locality being active when the device is in verstage is most likely due to delayed TPM reset processing by the Cr50 TPM: reset is an asynchronous event, and is processed once current command processing completes. The proper procedure is to wait if locality is active until it is released (which will happen when Cr50 processes reset) and then proceed to claim it. This needs to happen only during verstage, other stages using TPM are guaranteed has been claimed earlier. BRANCH=gru BUG=b:65867313 TEST=the new autotest triggering EC reset during key generation process does not cause boot failures on Fizz device any more. Below are times verstage had to wait: TPM ready after 3132 ms TPM ready after 22120 ms TPM ready after 4936 ms TPM ready after 6445 ms TPM ready after 11798 ms TPM ready after 27421 ms TPM ready after 4582 ms TPM ready after 7532 ms TPM ready after 27920 ms TPM ready after 3539 ms TPM ready after 12557 ms TPM ready after 6773 ms TPM ready after 1631 ms TPM ready after 197 ms TPM ready after 24330 ms TPM ready after 3241 ms Change-Id: Iaee04f009bcde03712483e5e03de4a3441ea32b1 Signed-off-by: Vadim Bendebury Reviewed-on: https://review.coreboot.org/22489 Tested-by: build bot (Jenkins) Reviewed-by: Philipp Deppenwiese Reviewed-by: Julius Werner Reviewed-by: Furquan Shaikh --- src/drivers/spi/tpm/tpm.c | 69 ++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 27 deletions(-) (limited to 'src/drivers/spi') diff --git a/src/drivers/spi/tpm/tpm.c b/src/drivers/spi/tpm/tpm.c index c09462e783..356c0fe3f7 100644 --- a/src/drivers/spi/tpm/tpm.c +++ b/src/drivers/spi/tpm/tpm.c @@ -346,37 +346,48 @@ static int tpm2_claim_locality(void) uint8_t access; struct stopwatch sw; - access = tpm2_read_access_reg(); /* - * If active locality is set (maybe reset line is not connected?), - * release the locality and try again. + * Locality is released by TPM reset. + * + * If locality is taken at this point, this could be due to the fact + * that the TPM is performing a long operation and has not processed + * reset request yet. We'll wait up to CR50_TIMEOUT_INIT_MS and see if + * it releases locality when reset is processed. */ - if (access & TPM_ACCESS_ACTIVE_LOCALITY) { - tpm2_write_access_reg(TPM_ACCESS_ACTIVE_LOCALITY); + stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_INIT_MS); + do { access = tpm2_read_access_reg(); - } + if (access & TPM_ACCESS_ACTIVE_LOCALITY) { + /* + * Don't bombard the chip with traffic, let it keep + * processing the command. + */ + mdelay(2); + continue; + } - /* - * If cr50 is doing a long crypto operation, it can take up to - * 30 seconds to get a valid status value back - */ - stopwatch_init_msecs_expire(&sw, CR50_TIMEOUT_INIT_MS); - while (!stopwatch_expired(&sw) && access != TPM_ACCESS_VALID) + /* + * Ok, the locality is free, TPM must be reset, let's claim + * it. + */ + + tpm2_write_access_reg(TPM_ACCESS_REQUEST_USE); access = tpm2_read_access_reg(); - if (access != TPM_ACCESS_VALID) { - printk(BIOS_ERR, "Invalid reset status: %#x\n", access); - return 0; - } + if (access != (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { + break; + } - tpm2_write_access_reg(TPM_ACCESS_REQUEST_USE); - access = tpm2_read_access_reg(); - if (access != (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) { - printk(BIOS_ERR, "Failed to claim locality 0, status: %#x\n", - access); - return 0; - } + printk(BIOS_INFO, "TPM ready after %ld ms\n", + stopwatch_duration_msecs(&sw)); - return 1; + return 1; + } while (!stopwatch_expired(&sw)); + + printk(BIOS_ERR, + "Failed to claim locality 0 after %ld ms, status: %#x\n", + stopwatch_duration_msecs(&sw), access); + + return 0; } /* Device/vendor ID values of the TPM devices this driver supports. */ @@ -426,9 +437,13 @@ int tpm2_init(struct spi_slave *spi_if) printk(BIOS_INFO, " done!\n"); - /* Claim locality 0. */ - if (!tpm2_claim_locality()) - return -1; + if (ENV_VERSTAGE || ENV_BOOTBLOCK) + /* + * Claim locality 0, do it only during the first + * initialization after reset. + */ + if (!tpm2_claim_locality()) + return -1; read_tpm_sts(&status); if ((status & TPM_STS_FAMILY_MASK) != TPM_STS_FAMILY_TPM_2_0) { -- cgit v1.2.3