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: Stefan Berger <stefanb@linux.vnet.ibm.com>
This commit is contained in:
Stefan Berger 2011-11-11 12:57:04 -05:00 committed by Rajiv Andrade
parent d97c6ade59
commit 68d6e6713f
3 changed files with 51 additions and 6 deletions

View File

@ -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;

View File

@ -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 *);

View File

@ -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;
}