diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2017-11-16 21:00:41 -0800 |
---|---|---|
committer | Vadim Bendebury <vbendeb@chromium.org> | 2017-11-21 23:16:27 +0000 |
commit | 8727e644ea9c53d066f2f289766920b7380dff83 (patch) | |
tree | 7a477559ae0d72a0c511058f578abf2ae4ba1167 /src/drivers/spi/tpm/tpm.c | |
parent | 0d0408ad4f94430b04007c1d3eeb93312031cf2d (diff) | |
download | coreboot-8727e644ea9c53d066f2f289766920b7380dff83.tar.xz |
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 <vbendeb@chromium.org>
Reviewed-on: https://review.coreboot.org/22489
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Reviewed-by: Furquan Shaikh <furquan@google.com>
Diffstat (limited to 'src/drivers/spi/tpm/tpm.c')
-rw-r--r-- | src/drivers/spi/tpm/tpm.c | 69 |
1 files changed, 42 insertions, 27 deletions
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) { |