tpm: fix suspend/resume paths for TPM 2.0
[cascardo/linux.git] / drivers / char / tpm / tpm-interface.c
index e2af28f..e85d341 100644 (file)
@@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
        if (chip->vendor.irq)
                goto out_recv;
 
-       stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
+       else
+               stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
        do {
                u8 status = chip->ops->status(chip);
                if ((status & chip->ops->req_complete_mask) ==
@@ -484,6 +487,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
 {
        struct tpm_cmd_t start_cmd;
        start_cmd.header.in = tpm_startup_header;
+
        start_cmd.params.startup_in.startup_type = startup_type;
        return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
                                "attempting to start the TPM");
@@ -680,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
        chip = tpm_chip_find_get(chip_num);
        if (chip == NULL)
                return -ENODEV;
-       rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
+       else
+               rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
        tpm_chip_put(chip);
        return rc;
 }
@@ -714,6 +721,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
        if (chip == NULL)
                return -ENODEV;
 
+       if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+               rc = tpm2_pcr_extend(chip, pcr_idx, hash);
+               tpm_chip_put(chip);
+               return rc;
+       }
+
        cmd.header.in = pcrextend_header;
        cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
        memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
@@ -888,6 +901,11 @@ int tpm_pm_suspend(struct device *dev)
        if (chip == NULL)
                return -ENODEV;
 
+       if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+               tpm2_shutdown(chip, TPM2_SU_STATE);
+               return 0;
+       }
+
        /* for buggy tpm, flush pcrs with extend to selected dummy */
        if (tpm_suspend_pcr) {
                cmd.header.in = pcrextend_header;
@@ -974,6 +992,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
        if (chip == NULL)
                return -ENODEV;
 
+       if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+               err = tpm2_get_random(chip, out, max);
+               tpm_chip_put(chip);
+               return err;
+       }
+
        do {
                tpm_cmd.header.in = tpm_getrandom_header;
                tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
@@ -997,6 +1021,35 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
 }
 EXPORT_SYMBOL_GPL(tpm_get_random);
 
+static int __init tpm_init(void)
+{
+       int rc;
+
+       tpm_class = class_create(THIS_MODULE, "tpm");
+       if (IS_ERR(tpm_class)) {
+               pr_err("couldn't create tpm class\n");
+               return PTR_ERR(tpm_class);
+       }
+
+       rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
+       if (rc < 0) {
+               pr_err("tpm: failed to allocate char dev region\n");
+               class_destroy(tpm_class);
+               return rc;
+       }
+
+       return 0;
+}
+
+static void __exit tpm_exit(void)
+{
+       class_destroy(tpm_class);
+       unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
+}
+
+subsys_initcall(tpm_init);
+module_exit(tpm_exit);
+
 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
 MODULE_DESCRIPTION("TPM Driver");
 MODULE_VERSION("2.0");