Commit 68d6e671 authored by Stefan Berger's avatar Stefan Berger Committed by Rajiv Andrade

tpm: Introduce function to poll for result of self test

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: default avatarStefan Berger <stefanb@linux.vnet.ibm.com>
parent d97c6ade
...@@ -627,7 +627,7 @@ static struct tpm_input_header continue_selftest_header = { ...@@ -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 * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
* a TPM error code. * a TPM error code.
*/ */
int tpm_continue_selftest(struct tpm_chip *chip) static int tpm_continue_selftest(struct tpm_chip *chip)
{ {
int rc; int rc;
struct tpm_cmd_t cmd; struct tpm_cmd_t cmd;
...@@ -637,7 +637,6 @@ int tpm_continue_selftest(struct tpm_chip *chip) ...@@ -637,7 +637,6 @@ int tpm_continue_selftest(struct tpm_chip *chip)
"continue selftest"); "continue selftest");
return rc; return rc;
} }
EXPORT_SYMBOL_GPL(tpm_continue_selftest);
ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr,
char *buf) char *buf)
...@@ -732,7 +731,7 @@ static struct tpm_input_header pcrread_header = { ...@@ -732,7 +731,7 @@ static struct tpm_input_header pcrread_header = {
.ordinal = TPM_ORDINAL_PCRREAD .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; int rc;
struct tpm_cmd_t cmd; struct tpm_cmd_t cmd;
...@@ -812,6 +811,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) ...@@ -812,6 +811,45 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
} }
EXPORT_SYMBOL_GPL(tpm_pcr_extend); 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) int tpm_send(u32 chip_num, void *cmd, size_t buflen)
{ {
struct tpm_chip *chip; struct tpm_chip *chip;
......
...@@ -38,6 +38,8 @@ enum tpm_addr { ...@@ -38,6 +38,8 @@ enum tpm_addr {
TPM_ADDR = 0x4E, TPM_ADDR = 0x4E,
}; };
#define TPM_WARN_DOING_SELFTEST 0x802
extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
char *); char *);
extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, 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 *); ...@@ -281,7 +283,7 @@ ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
extern int tpm_get_timeouts(struct tpm_chip *); extern int tpm_get_timeouts(struct tpm_chip *);
extern void tpm_gen_interrupt(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 unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
extern struct tpm_chip* tpm_register_hardware(struct device *, extern struct tpm_chip* tpm_register_hardware(struct device *,
const struct tpm_vendor_specific *); const struct tpm_vendor_specific *);
......
...@@ -616,6 +616,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, ...@@ -616,6 +616,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
/* get the timeouts before testing for irqs */ /* get the timeouts before testing for irqs */
tpm_get_timeouts(chip); tpm_get_timeouts(chip);
if (tpm_do_selftest(chip)) {
dev_err(dev, "TPM self test failed\n");
rc = -ENODEV;
goto out_err;
}
/* INTERRUPT Setup */ /* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue); init_waitqueue_head(&chip->vendor.int_queue);
...@@ -722,7 +728,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, ...@@ -722,7 +728,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
list_add(&chip->vendor.list, &tis_chips); list_add(&chip->vendor.list, &tis_chips);
spin_unlock(&tis_lock); spin_unlock(&tis_lock);
tpm_continue_selftest(chip);
return 0; return 0;
out_err: out_err:
...@@ -790,7 +795,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) ...@@ -790,7 +795,7 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev)
ret = tpm_pm_resume(&dev->dev); ret = tpm_pm_resume(&dev->dev);
if (!ret) if (!ret)
tpm_continue_selftest(chip); tpm_do_selftest(chip);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment