diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 9bd4668e2855..2e12b3f98139 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -627,7 +627,7 @@ static struct tpm_input_header continue_selftest_header = { * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing * a TPM error code. */ -int tpm_continue_selftest(struct tpm_chip *chip) +static int tpm_continue_selftest(struct tpm_chip *chip) { int rc; struct tpm_cmd_t cmd; @@ -637,7 +637,6 @@ int tpm_continue_selftest(struct tpm_chip *chip) "continue selftest"); return rc; } -EXPORT_SYMBOL_GPL(tpm_continue_selftest); ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, char *buf) @@ -732,7 +731,7 @@ static struct tpm_input_header pcrread_header = { .ordinal = TPM_ORDINAL_PCRREAD }; -int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) +static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) { int rc; struct tpm_cmd_t cmd; @@ -812,6 +811,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) } EXPORT_SYMBOL_GPL(tpm_pcr_extend); +/** + * tpm_do_selftest - have the TPM continue its selftest and wait until it + * can receive further commands + * @chip: TPM chip to use + * + * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing + * a TPM error code. + */ +int tpm_do_selftest(struct tpm_chip *chip) +{ + int rc; + u8 digest[TPM_DIGEST_SIZE]; + unsigned int loops; + unsigned int delay_msec = 1000; + unsigned long duration; + + duration = tpm_calc_ordinal_duration(chip, + TPM_ORD_CONTINUE_SELFTEST); + + loops = jiffies_to_msecs(duration) / delay_msec; + + rc = tpm_continue_selftest(chip); + /* This may fail if there was no TPM driver during a suspend/resume + * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) + */ + if (rc) + return rc; + + do { + rc = __tpm_pcr_read(chip, 0, digest); + if (rc != TPM_WARN_DOING_SELFTEST) + return rc; + msleep(delay_msec); + } while (--loops > 0); + + return rc; +} +EXPORT_SYMBOL_GPL(tpm_do_selftest); + int tpm_send(u32 chip_num, void *cmd, size_t buflen) { struct tpm_chip *chip; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 5d2be8ae1b48..e264de16285f 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -38,6 +38,8 @@ enum tpm_addr { TPM_ADDR = 0x4E, }; +#define TPM_WARN_DOING_SELFTEST 0x802 + extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, char *); extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, @@ -281,7 +283,7 @@ ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); extern int tpm_get_timeouts(struct tpm_chip *); extern void tpm_gen_interrupt(struct tpm_chip *); -extern int tpm_continue_selftest(struct tpm_chip *); +extern int tpm_do_selftest(struct tpm_chip *); extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); extern struct tpm_chip* tpm_register_hardware(struct device *, const struct tpm_vendor_specific *); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 3f4051a7c5a7..d30d5c3c6c02 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -616,6 +616,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, /* get the timeouts before testing for irqs */ tpm_get_timeouts(chip); + if (tpm_do_selftest(chip)) { + dev_err(dev, "TPM self test failed\n"); + rc = -ENODEV; + goto out_err; + } + /* INTERRUPT Setup */ init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); @@ -722,7 +728,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, list_add(&chip->vendor.list, &tis_chips); spin_unlock(&tis_lock); - tpm_continue_selftest(chip); return 0; out_err: @@ -790,7 +795,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) ret = tpm_pm_resume(&dev->dev); if (!ret) - tpm_continue_selftest(chip); + tpm_do_selftest(chip); return ret; }