tpm: Fix cancellation of TPM commands (polling mode)
authorStefan Berger <stefanb@linux.vnet.ibm.com>
Tue, 22 Jan 2013 19:52:35 +0000 (13:52 -0600)
committerKent Yoder <key@linux.vnet.ibm.com>
Tue, 5 Feb 2013 15:38:24 +0000 (09:38 -0600)
On one of my machines the cancellation of TPM commands does not work.
The reason is that by writing into sysfs 'cancel' the tpm_tis_ready
call causes the status flag TPM_STS_VALID to be set in the statusregister.
However, the TIS driver seems to wait for TPM_STS_COMMAND_READY.
Once a 2nd time sysfs 'cancel' is written to, the TPM_STS_COMMAND_READY flag
also gets set, resulting in TPM_STS_VALID|TPM_STS_COMMAND_READY to be
read from the status register.

This patch now converts req_canceled into a function to enable more complex
comparisons against possible cancellation status codes.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
drivers/char/tpm/tpm.c
drivers/char/tpm/tpm.h
drivers/char/tpm/tpm_atmel.c
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_i2c_stm_st33.c
drivers/char/tpm/tpm_ibmvtpm.c
drivers/char/tpm/tpm_nsc.c
drivers/char/tpm/tpm_tis.c

index e38054b..a244cd3 100644 (file)
@@ -393,7 +393,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
                    chip->vendor.req_complete_val)
                        goto out_recv;
 
-               if ((status == chip->vendor.req_canceled)) {
+               if (chip->vendor.req_canceled(chip, status)) {
                        dev_err(chip->dev, "Operation Canceled\n");
                        rc = -ECANCELED;
                        goto out;
index ef4ba5f..725cb9b 100644 (file)
@@ -78,7 +78,7 @@ struct tpm_chip;
 struct tpm_vendor_specific {
        const u8 req_complete_mask;
        const u8 req_complete_val;
-       const u8 req_canceled;
+       bool (*req_canceled)(struct tpm_chip *chip, u8 status);
        void __iomem *iobase;           /* ioremapped address */
        unsigned long base;             /* TPM base address */
 
@@ -112,6 +112,8 @@ struct tpm_vendor_specific {
 #define TPM_VPRIV(c)   (c)->vendor.priv
 
 #define TPM_VID_INTEL    0x8086
+#define TPM_VID_WINBOND  0x1050
+#define TPM_VID_STM      0x104A
 
 struct tpm_chip {
        struct device *dev;     /* Device stuff */
index 678d570..99d6820 100644 (file)
@@ -116,6 +116,11 @@ static u8 tpm_atml_status(struct tpm_chip *chip)
        return ioread8(chip->vendor.iobase + 1);
 }
 
+static bool tpm_atml_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return (status == ATML_STATUS_READY);
+}
+
 static const struct file_operations atmel_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -147,7 +152,7 @@ static const struct tpm_vendor_specific tpm_atmel = {
        .status = tpm_atml_status,
        .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
        .req_complete_val = ATML_STATUS_DATA_AVAIL,
-       .req_canceled = ATML_STATUS_READY,
+       .req_canceled = tpm_atml_req_canceled,
        .attr_group = &atmel_attr_grp,
        .miscdev = { .fops = &atmel_ops, },
 };
index fb447bd..8fe7ac3 100644 (file)
@@ -505,6 +505,11 @@ out_err:
        return rc;
 }
 
+static bool tpm_tis_i2c_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return (status == TPM_STS_COMMAND_READY);
+}
+
 static const struct file_operations tis_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -550,7 +555,7 @@ static struct tpm_vendor_specific tpm_tis_i2c = {
        .cancel = tpm_tis_i2c_ready,
        .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
        .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-       .req_canceled = TPM_STS_COMMAND_READY,
+       .req_canceled = tpm_tis_i2c_req_canceled,
        .attr_group = &tis_attr_grp,
        .miscdev.fops = &tis_ops,
 };
index 36524ed..e4154bf 100644 (file)
@@ -587,6 +587,11 @@ out:
        return size;
 }
 
+static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return (status == TPM_STS_COMMAND_READY);
+}
+
 static const struct file_operations tpm_st33_i2c_fops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -627,7 +632,7 @@ static struct tpm_vendor_specific st_i2c_tpm = {
        .status = tpm_stm_i2c_status,
        .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
        .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-       .req_canceled = TPM_STS_COMMAND_READY,
+       .req_canceled = tpm_st33_i2c_req_canceled,
        .attr_group = &stm_tpm_attr_grp,
        .miscdev = {.fops = &tpm_st33_i2c_fops,},
 };
index 6cd99bc..56b07c3 100644 (file)
@@ -398,6 +398,11 @@ static int tpm_ibmvtpm_resume(struct device *dev)
        return rc;
 }
 
+static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return (status == 0);
+}
+
 static const struct file_operations ibmvtpm_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -441,7 +446,7 @@ static const struct tpm_vendor_specific tpm_ibmvtpm = {
        .status = tpm_ibmvtpm_status,
        .req_complete_mask = 0,
        .req_complete_val = 0,
-       .req_canceled = 0,
+       .req_canceled = tpm_ibmvtpm_req_canceled,
        .attr_group = &ibmvtpm_attr_grp,
        .miscdev = { .fops = &ibmvtpm_ops, },
 };
index 640c9a4..770c46f 100644 (file)
@@ -227,6 +227,11 @@ static u8 tpm_nsc_status(struct tpm_chip *chip)
        return inb(chip->vendor.base + NSC_STATUS);
 }
 
+static bool tpm_nsc_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       return (status == NSC_STATUS_RDY);
+}
+
 static const struct file_operations nsc_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -258,7 +263,7 @@ static const struct tpm_vendor_specific tpm_nsc = {
        .status = tpm_nsc_status,
        .req_complete_mask = NSC_STATUS_OBF,
        .req_complete_val = NSC_STATUS_OBF,
-       .req_canceled = NSC_STATUS_RDY,
+       .req_canceled = tpm_nsc_req_canceled,
        .attr_group = &nsc_attr_grp,
        .miscdev = { .fops = &nsc_ops, },
 };
index 3615d21..e4e0c65 100644 (file)
@@ -400,6 +400,19 @@ out:
        return rc;
 }
 
+static bool tpm_tis_req_canceled(struct tpm_chip *chip, u8 status)
+{
+       switch (chip->vendor.manufacturer_id) {
+       case TPM_VID_WINBOND:
+               return ((status == TPM_STS_VALID) ||
+                       (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY)));
+       case TPM_VID_STM:
+               return (status == (TPM_STS_VALID | TPM_STS_COMMAND_READY));
+       default:
+               return (status == TPM_STS_COMMAND_READY);
+       }
+}
+
 static const struct file_operations tis_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
@@ -445,7 +458,7 @@ static struct tpm_vendor_specific tpm_tis = {
        .cancel = tpm_tis_ready,
        .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
        .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
-       .req_canceled = TPM_STS_COMMAND_READY,
+       .req_canceled = tpm_tis_req_canceled,
        .attr_group = &tis_attr_grp,
        .miscdev = {
                    .fops = &tis_ops,},