BACKPORT: TPM: Retry SaveState command in suspend path
authorDuncan Laurie <dlaurie@chromium.org>
Mon, 22 Apr 2013 21:01:49 +0000 (14:01 -0700)
committerChromeBot <chrome-bot@google.com>
Tue, 23 Apr 2013 21:38:48 +0000 (14:38 -0700)
commita526ff4dd6922a53701f029b3a83d0e84fba7964
tree76b5fb06bd299548117b9390936d9d2a8d457634
parent1c80d4725af213093775cd2c86ff045fa1aed57a
BACKPORT: TPM: Retry SaveState command in suspend path

If the TPM has already been sent a SaveState command before the driver
is loaded it may have problems sending that same command again later.

This issue is seen with the Chromebook Pixel due to a firmware bug in
the legacy mode boot path which is sending the SaveState command
before booting the kernel.  More information is available at
http://crbug.com/203524

This change introduces a retry of the SaveState command in the suspend
path in order to work around this issue.  A future firmware update
should fix this but this is also a trivial workaround in the driver
that has no effect on systems that do not show this problem.

When this does happen the TPM responds with a non-fatal TPM_RETRY code
that is defined in the specification:

  The TPM is too busy to respond to the command immediately, but the
  command could be resubmitted at a later time.  The TPM MAY return
  TPM_RETRY for any command at any time.

It can take several seconds before the TPM will respond again.  I
measured a typical time between 3 and 4 seconds and the timeout is set
at a safe 7 seconds.  (note: upstream is 5 seconds right now)

It is also possible to reproduce this with commands via /dev/tpm0.
The bug linked above has a python script attached which can be used to
test for this problem.  I tested a variety of TPMs from Infineon,
Nuvoton, Atmel, and STMicro but was only able to reproduce this with
LPC and I2C TPMs from Infineon.

The TPM specification only loosely defines this behavior:

  TPM Main Level 2 Part 3 v1.2 r116, section 3.3. TPM_SaveState:
  The TPM MAY declare all preserved values invalid in response to any
  command other than TPM_Init.

  TCG PC Client BIOS Spec 1.21 section 8.3.1.
  After issuing a TPM_SaveState command, the OS SHOULD NOT issue TPM
  commands before transitioning to S3 without issuing another
  TPM_SaveState command.

  TCG PC Client TIS 1.21, section 4. Power Management:
  The TPM_SaveState command allows a Static OS to indicate to the TPM
  that the platform may enter a low power state where the TPM will be
  required to enter into the D3 power state.  The use of the term "may"
  is significant in that there is no requirement for the platform to
  actually enter the low power state after sending the TPM_SaveState
  command.  The software may, in fact, send subsequent commands after
  sending the TPM_SaveState command.

BUG=chrome-os-partner:18686
TEST=originally tested on pixel for crbug.com/203524

Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
(backported from commit 32d33b29ba077d6b45de35f2181e0a7411b162f4)

Change-Id: I023103b69e5253dc98b289c25853104a08f4787f
Reviewed-on: https://gerrit.chromium.org/gerrit/48812
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
Tested-by: Duncan Laurie <dlaurie@chromium.org>
Commit-Queue: Duncan Laurie <dlaurie@chromium.org>
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h