diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/tpm/tpm.c | 31 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 3 |
2 files changed, 30 insertions, 4 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 0d2e82f95577..7c3b3dcbfbc8 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -1337,7 +1337,7 @@ int tpm_pm_suspend(struct device *dev) | |||
1337 | { | 1337 | { |
1338 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1338 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1339 | struct tpm_cmd_t cmd; | 1339 | struct tpm_cmd_t cmd; |
1340 | int rc; | 1340 | int rc, try; |
1341 | 1341 | ||
1342 | u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; | 1342 | u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 }; |
1343 | 1343 | ||
@@ -1355,9 +1355,32 @@ int tpm_pm_suspend(struct device *dev) | |||
1355 | } | 1355 | } |
1356 | 1356 | ||
1357 | /* now do the actual savestate */ | 1357 | /* now do the actual savestate */ |
1358 | cmd.header.in = savestate_header; | 1358 | for (try = 0; try < TPM_RETRY; try++) { |
1359 | rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, | 1359 | cmd.header.in = savestate_header; |
1360 | "sending savestate before suspend"); | 1360 | rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL); |
1361 | |||
1362 | /* | ||
1363 | * If the TPM indicates that it is too busy to respond to | ||
1364 | * this command then retry before giving up. It can take | ||
1365 | * several seconds for this TPM to be ready. | ||
1366 | * | ||
1367 | * This can happen if the TPM has already been sent the | ||
1368 | * SaveState command before the driver has loaded. TCG 1.2 | ||
1369 | * specification states that any communication after SaveState | ||
1370 | * may cause the TPM to invalidate previously saved state. | ||
1371 | */ | ||
1372 | if (rc != TPM_WARN_RETRY) | ||
1373 | break; | ||
1374 | msleep(TPM_TIMEOUT_RETRY); | ||
1375 | } | ||
1376 | |||
1377 | if (rc) | ||
1378 | dev_err(chip->dev, | ||
1379 | "Error (%d) sending savestate before suspend\n", rc); | ||
1380 | else if (try > 0) | ||
1381 | dev_warn(chip->dev, "TPM savestate took %dms\n", | ||
1382 | try * TPM_TIMEOUT_RETRY); | ||
1383 | |||
1361 | return rc; | 1384 | return rc; |
1362 | } | 1385 | } |
1363 | EXPORT_SYMBOL_GPL(tpm_pm_suspend); | 1386 | EXPORT_SYMBOL_GPL(tpm_pm_suspend); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 81b52015f669..0770d1d79366 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -32,10 +32,12 @@ enum tpm_const { | |||
32 | TPM_MINOR = 224, /* officially assigned */ | 32 | TPM_MINOR = 224, /* officially assigned */ |
33 | TPM_BUFSIZE = 4096, | 33 | TPM_BUFSIZE = 4096, |
34 | TPM_NUM_DEVICES = 256, | 34 | TPM_NUM_DEVICES = 256, |
35 | TPM_RETRY = 50, /* 5 seconds */ | ||
35 | }; | 36 | }; |
36 | 37 | ||
37 | enum tpm_timeout { | 38 | enum tpm_timeout { |
38 | TPM_TIMEOUT = 5, /* msecs */ | 39 | TPM_TIMEOUT = 5, /* msecs */ |
40 | TPM_TIMEOUT_RETRY = 100 /* msecs */ | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | /* TPM addresses */ | 43 | /* TPM addresses */ |
@@ -44,6 +46,7 @@ enum tpm_addr { | |||
44 | TPM_ADDR = 0x4E, | 46 | TPM_ADDR = 0x4E, |
45 | }; | 47 | }; |
46 | 48 | ||
49 | #define TPM_WARN_RETRY 0x800 | ||
47 | #define TPM_WARN_DOING_SELFTEST 0x802 | 50 | #define TPM_WARN_DOING_SELFTEST 0x802 |
48 | #define TPM_ERR_DEACTIVATED 0x6 | 51 | #define TPM_ERR_DEACTIVATED 0x6 |
49 | #define TPM_ERR_DISABLED 0x7 | 52 | #define TPM_ERR_DISABLED 0x7 |