aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2015-01-29 00:43:47 -0500
committerPeter Huewe <peterhuewe@gmx.de>2015-02-15 10:56:49 -0500
commit74d6b3ceaa17d111220c3f09f50f901bf955d7c8 (patch)
tree8460d16593728245a56f8f270b4f107df0dba020
parent04f81f0154e4bf002be6f4d85668ce1257efa4d9 (diff)
tpm: fix suspend/resume paths for TPM 2.0
Fixed suspend/resume paths for TPM 2.0 and consolidated all the associated code to the tpm_pm_suspend() and tpm_pm_resume() functions. Resume path should be handled by the firmware, i.e. Startup(CLEAR) for hibernate and Startup(STATE) for suspend. There might be some non-PC embedded devices in the future where Startup() is not the handled by the FW but fixing the code for those IMHO should be postponed until there is hardware available to test the fixes although extra Startup in the driver code is essentially a NOP. Added Shutdown(CLEAR) to the remove paths of TIS and CRB drivers. Changed tpm2_shutdown() to a void function because there isn't much you can do except print an error message if this fails with a system error. Fixes: aec04cbdf723 ("tpm: TPM 2.0 FIFO Interface") Fixes: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface") [phuewe: both did send TPM_Shutdown on resume which 'disables' the TPM and did not send TPM2_Shutdown on teardown which leads some TPM2.0 to believe there was an attack (no TPM2_Shutdown = no orderly shutdown = attack)] Reported-by: Peter Hüwe <PeterHuewe@gmx.de> Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Tested-by: Scot Doyle <lkml14@scotdoyle.com> Reviewed-by: Peter Huewe <peterhuewe@gmx.de> Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
-rw-r--r--drivers/char/tpm/tpm-interface.c6
-rw-r--r--drivers/char/tpm/tpm.h2
-rw-r--r--drivers/char/tpm/tpm2-cmd.c19
-rw-r--r--drivers/char/tpm/tpm_crb.c20
-rw-r--r--drivers/char/tpm/tpm_tis.c26
5 files changed, 34 insertions, 39 deletions
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index bf53a3771da5..e85d3416d899 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -901,8 +901,10 @@ int tpm_pm_suspend(struct device *dev)
901 if (chip == NULL) 901 if (chip == NULL)
902 return -ENODEV; 902 return -ENODEV;
903 903
904 if (chip->flags & TPM_CHIP_FLAG_TPM2) 904 if (chip->flags & TPM_CHIP_FLAG_TPM2) {
905 return tpm2_shutdown(chip, TPM2_SU_CLEAR); 905 tpm2_shutdown(chip, TPM2_SU_STATE);
906 return 0;
907 }
906 908
907 /* for buggy tpm, flush pcrs with extend to selected dummy */ 909 /* for buggy tpm, flush pcrs with extend to selected dummy */
908 if (tpm_suspend_pcr) { 910 if (tpm_suspend_pcr) {
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 7b0727c5e803..a2ce3797e3e0 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -432,7 +432,7 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
432 u32 *value, const char *desc); 432 u32 *value, const char *desc);
433 433
434extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); 434extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
435extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); 435extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
436extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); 436extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
437extern int tpm2_do_selftest(struct tpm_chip *chip); 437extern int tpm2_do_selftest(struct tpm_chip *chip);
438extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet); 438extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index 1abe6502219f..f2f38a5ee632 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -456,20 +456,23 @@ static const struct tpm_input_header tpm2_shutdown_header = {
456 * @chip: TPM chip to use. 456 * @chip: TPM chip to use.
457 * @shutdown_type shutdown type. The value is either 457 * @shutdown_type shutdown type. The value is either
458 * TPM_SU_CLEAR or TPM_SU_STATE. 458 * TPM_SU_CLEAR or TPM_SU_STATE.
459 *
460 * 0 is returned when the operation is successful. If a negative number is
461 * returned it remarks a POSIX error code. If a positive number is returned
462 * it remarks a TPM error.
463 */ 459 */
464int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) 460void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
465{ 461{
466 struct tpm2_cmd cmd; 462 struct tpm2_cmd cmd;
463 int rc;
467 464
468 cmd.header.in = tpm2_shutdown_header; 465 cmd.header.in = tpm2_shutdown_header;
469
470 cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); 466 cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
471 return tpm_transmit_cmd(chip, &cmd, sizeof(cmd), 467
472 "stopping the TPM"); 468 rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM");
469
470 /* In places where shutdown command is sent there's no much we can do
471 * except print the error code on a system failure.
472 */
473 if (rc < 0)
474 dev_warn(chip->pdev, "transmit returned %d while stopping the TPM",
475 rc);
473} 476}
474EXPORT_SYMBOL_GPL(tpm2_shutdown); 477EXPORT_SYMBOL_GPL(tpm2_shutdown);
475 478
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 3dd23cfae4fe..b26ceee3585e 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -95,21 +95,7 @@ struct crb_priv {
95 u8 __iomem *rsp; 95 u8 __iomem *rsp;
96}; 96};
97 97
98#ifdef CONFIG_PM_SLEEP 98static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume);
99static int crb_resume(struct device *dev)
100{
101 int rc;
102 struct tpm_chip *chip = dev_get_drvdata(dev);
103
104 rc = tpm2_shutdown(chip, TPM2_SU_STATE);
105 if (!rc)
106 rc = tpm2_do_selftest(chip);
107
108 return rc;
109}
110#endif
111
112static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume);
113 99
114static u8 crb_status(struct tpm_chip *chip) 100static u8 crb_status(struct tpm_chip *chip)
115{ 101{
@@ -326,6 +312,10 @@ static int crb_acpi_remove(struct acpi_device *device)
326 struct tpm_chip *chip = dev_get_drvdata(dev); 312 struct tpm_chip *chip = dev_get_drvdata(dev);
327 313
328 tpm_chip_unregister(chip); 314 tpm_chip_unregister(chip);
315
316 if (chip->flags & TPM_CHIP_FLAG_TPM2)
317 tpm2_shutdown(chip, TPM2_SU_CLEAR);
318
329 return 0; 319 return 0;
330} 320}
331 321
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 6725bef7cb96..e12b3ab215cf 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -588,6 +588,9 @@ MODULE_PARM_DESC(interrupts, "Enable interrupts");
588 588
589static void tpm_tis_remove(struct tpm_chip *chip) 589static void tpm_tis_remove(struct tpm_chip *chip)
590{ 590{
591 if (chip->flags & TPM_CHIP_FLAG_TPM2)
592 tpm2_shutdown(chip, TPM2_SU_CLEAR);
593
591 iowrite32(~TPM_GLOBAL_INT_ENABLE & 594 iowrite32(~TPM_GLOBAL_INT_ENABLE &
592 ioread32(chip->vendor.iobase + 595 ioread32(chip->vendor.iobase +
593 TPM_INT_ENABLE(chip->vendor. 596 TPM_INT_ENABLE(chip->vendor.
@@ -865,25 +868,22 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
865static int tpm_tis_resume(struct device *dev) 868static int tpm_tis_resume(struct device *dev)
866{ 869{
867 struct tpm_chip *chip = dev_get_drvdata(dev); 870 struct tpm_chip *chip = dev_get_drvdata(dev);
868 int ret = 0; 871 int ret;
869 872
870 if (chip->vendor.irq) 873 if (chip->vendor.irq)
871 tpm_tis_reenable_interrupts(chip); 874 tpm_tis_reenable_interrupts(chip);
872 875
873 if (chip->flags & TPM_CHIP_FLAG_TPM2) { 876 ret = tpm_pm_resume(dev);
874 /* NOP if firmware properly does this. */ 877 if (ret)
875 tpm2_startup(chip, TPM2_SU_STATE); 878 return ret;
876 879
877 ret = tpm2_shutdown(chip, TPM2_SU_STATE); 880 /* TPM 1.2 requires self-test on resume. This function actually returns
878 if (!ret) 881 * an error code but for unknown reason it isn't handled.
879 ret = tpm2_do_selftest(chip); 882 */
880 } else { 883 if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
881 ret = tpm_pm_resume(dev); 884 tpm_do_selftest(chip);
882 if (!ret)
883 tpm_do_selftest(chip);
884 }
885 885
886 return ret; 886 return 0;
887} 887}
888#endif 888#endif
889 889