From: Stefan Berger <[email protected]>

This patch introduces a function that runs the TPM_ContinueSelfTest()
function and then polls the TPM to check whether it finished the selftest
and can receive new commands.

Signed-off-by: Stefan Berger <[email protected]>
Signed-off-by: Rajiv Andrade <[email protected]>
(cherry picked from commit 68d6e6713fcb2ea6278661aaaf5f1c9c821b3751)
---
 drivers/char/tpm/tpm.c     |   44 +++++++++++++++++++++++++++++++++++++++++---
 drivers/char/tpm/tpm.h     |    4 +++-
 drivers/char/tpm/tpm_tis.c |    9 +++++++--
 3 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index b9e36b6..50f20b7 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -630,7 +630,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;
@@ -640,7 +640,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)
@@ -735,7 +734,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;
@@ -815,6 +814,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 5d2be8a..e264de1 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 c7e5282..7786c2b 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -619,6 +619,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);
@@ -725,7 +731,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:
@@ -793,7 +798,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;
 }
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to