tpm: rework tpm_get_timeouts()
[cascardo/linux.git] / drivers / char / tpm / tpm_tis.c
index 696ef1d..56a295d 100644 (file)
@@ -401,7 +401,7 @@ static void disable_interrupts(struct tpm_chip *chip)
        iowrite32(intmask,
                  chip->vendor.iobase +
                  TPM_INT_ENABLE(chip->vendor.locality));
-       free_irq(chip->vendor.irq, chip);
+       devm_free_irq(chip->pdev, chip->vendor.irq, chip);
        chip->vendor.irq = 0;
 }
 
@@ -645,6 +645,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
 {
        u32 vendor, intfcaps, intmask;
        int rc, i, irq_s, irq_e, probe;
+       int irq_r = -1;
        struct tpm_chip *chip;
        struct priv_data *priv;
 
@@ -676,6 +677,15 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                goto out_err;
        }
 
+       /* Take control of the TPM's interrupt hardware and shut it off */
+       intmask = ioread32(chip->vendor.iobase +
+                          TPM_INT_ENABLE(chip->vendor.locality));
+       intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
+                  TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
+       intmask &= ~TPM_GLOBAL_INT_ENABLE;
+       iowrite32(intmask,
+                 chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+
        if (request_locality(chip, 0) != 0) {
                rc = -ENODEV;
                goto out_err;
@@ -730,27 +740,27 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
        if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
                dev_dbg(dev, "\tData Avail Int Support\n");
 
+       /* Very early on issue a command to the TPM in polling mode to make
+        * sure it works. May as well use that command to set the proper
+        *  timeouts for the driver.
+        */
+       if (tpm_get_timeouts(chip)) {
+               dev_err(dev, "Could not get TPM timeouts and durations\n");
+               rc = -ENODEV;
+               goto out_err;
+       }
+
        /* INTERRUPT Setup */
        init_waitqueue_head(&chip->vendor.read_queue);
        init_waitqueue_head(&chip->vendor.int_queue);
 
-       intmask =
-           ioread32(chip->vendor.iobase +
-                    TPM_INT_ENABLE(chip->vendor.locality));
-
-       intmask |= TPM_INTF_CMD_READY_INT
-           | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
-           | TPM_INTF_STS_VALID_INT;
-
-       iowrite32(intmask,
-                 chip->vendor.iobase +
-                 TPM_INT_ENABLE(chip->vendor.locality));
        if (interrupts)
                chip->vendor.irq = tpm_info->irq;
        if (interrupts && !chip->vendor.irq) {
                irq_s =
                    ioread8(chip->vendor.iobase +
                            TPM_INT_VECTOR(chip->vendor.locality));
+               irq_r = irq_s;
                if (irq_s) {
                        irq_e = irq_s;
                } else {
@@ -805,6 +815,8 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                        iowrite32(intmask,
                                  chip->vendor.iobase +
                                  TPM_INT_ENABLE(chip->vendor.locality));
+
+                       devm_free_irq(dev, i, chip);
                }
        }
        if (chip->vendor.irq) {
@@ -831,20 +843,17 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                                  chip->vendor.iobase +
                                  TPM_INT_ENABLE(chip->vendor.locality));
                }
+       } else if (irq_r != -1)
+               iowrite8(irq_r, chip->vendor.iobase +
+                        TPM_INT_VECTOR(chip->vendor.locality));
+
+       if (tpm_get_timeouts(chip)) {
+               dev_err(dev, "Could not get TPM timeouts and durations\n");
+               rc = -ENODEV;
+               goto out_err;
        }
 
        if (chip->flags & TPM_CHIP_FLAG_TPM2) {
-               chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
-               chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
-               chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
-               chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
-               chip->vendor.duration[TPM_SHORT] =
-                       msecs_to_jiffies(TPM2_DURATION_SHORT);
-               chip->vendor.duration[TPM_MEDIUM] =
-                       msecs_to_jiffies(TPM2_DURATION_MEDIUM);
-               chip->vendor.duration[TPM_LONG] =
-                       msecs_to_jiffies(TPM2_DURATION_LONG);
-
                rc = tpm2_do_selftest(chip);
                if (rc == TPM2_RC_INITIALIZE) {
                        dev_warn(dev, "Firmware has not started TPM\n");
@@ -860,12 +869,6 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                        goto out_err;
                }
        } else {
-               if (tpm_get_timeouts(chip)) {
-                       dev_err(dev, "Could not get TPM timeouts and durations\n");
-                       rc = -ENODEV;
-                       goto out_err;
-               }
-
                if (tpm_do_selftest(chip)) {
                        dev_err(dev, "TPM self test failed\n");
                        rc = -ENODEV;