tpm_tis: Refactor the interrupt setup
authorJason Gunthorpe <jgunthorpe@obsidianresearch.com>
Wed, 25 Nov 2015 21:05:35 +0000 (14:05 -0700)
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Sun, 20 Dec 2015 13:26:27 +0000 (15:26 +0200)
Now that the probe and run cases are merged together we can use a
much simpler setup flow where probe and normal setup are done with
exactly the same code.

Since the new flow always calls tpm_gen_interrupt to confirm the IRQ
there is also no longer any need to call tpm_get_timeouts twice.

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Martin Wilck <Martin.Wilck@ts.fujitsu.com>
Tested-by: Scot Doyle <lkml14@scotdoyle.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Acked-by: Peter Huewe <peterhuewe@gmx.de>
drivers/char/tpm/tpm_tis.c

index 2580893..c29ae69 100644 (file)
@@ -99,7 +99,6 @@ static struct tpm_info tis_default_info = {
 #define        TPM_RID(l)                      (0x0F04 | ((l) << 12))
 
 struct priv_data {
-       bool irq_probing;
        bool irq_tested;
 };
 
@@ -462,12 +461,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
        chip->vendor.irq = irq;
        if (!priv->irq_tested)
                msleep(1);
-       if (!priv->irq_tested) {
+       if (!priv->irq_tested)
                disable_interrupts(chip);
-               if (!priv->irq_probing)
-                       dev_err(chip->pdev, FW_BUG
-                               "TPM interrupt not working, polling instead\n");
-       }
        priv->irq_tested = true;
        return rc;
 }
@@ -604,6 +599,80 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
        return IRQ_HANDLED;
 }
 
+/* Register the IRQ and issue a command that will cause an interrupt. If an
+ * irq is seen then leave the chip setup for IRQ operation, otherwise reverse
+ * everything and leave in polling mode. Returns 0 on success.
+ */
+static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, int irq)
+{
+       struct priv_data *priv = chip->vendor.priv;
+       u8 original_int_vec;
+
+       if (devm_request_irq(chip->pdev, irq, tis_int_handler, IRQF_SHARED,
+                            chip->devname, chip) != 0) {
+               dev_info(chip->pdev, "Unable to request irq: %d for probe\n",
+                        irq);
+               return -1;
+       }
+       chip->vendor.irq = irq;
+
+       original_int_vec = ioread8(chip->vendor.iobase +
+                                  TPM_INT_VECTOR(chip->vendor.locality));
+       iowrite8(irq,
+                chip->vendor.iobase + TPM_INT_VECTOR(chip->vendor.locality));
+
+       /* Clear all existing */
+       iowrite32(ioread32(chip->vendor.iobase +
+                          TPM_INT_STATUS(chip->vendor.locality)),
+                 chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
+
+       /* Turn on */
+       iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
+                 chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality));
+
+       priv->irq_tested = false;
+
+       /* Generate an interrupt by having the core call through to
+        * tpm_tis_send
+        */
+       if (chip->flags & TPM_CHIP_FLAG_TPM2)
+               tpm2_gen_interrupt(chip);
+       else
+               tpm_gen_interrupt(chip);
+
+       /* tpm_tis_send will either confirm the interrupt is working or it
+        * will call disable_irq which undoes all of the above.
+        */
+       if (!chip->vendor.irq) {
+               iowrite8(original_int_vec,
+                        chip->vendor.iobase +
+                            TPM_INT_VECTOR(chip->vendor.locality));
+               return 1;
+       }
+
+       return 0;
+}
+
+/* Try to find the IRQ the TPM is using. This is for legacy x86 systems that
+ * do not have ACPI/etc. We typically expect the interrupt to be declared if
+ * present.
+ */
+static void tpm_tis_probe_irq(struct tpm_chip *chip, u32 intmask)
+{
+       u8 original_int_vec;
+       int i;
+
+       original_int_vec = ioread8(chip->vendor.iobase +
+                                  TPM_INT_VECTOR(chip->vendor.locality));
+
+       if (!original_int_vec) {
+               for (i = 3; i <= 15; i++)
+                       if (!tpm_tis_probe_irq_single(chip, intmask, i))
+                               return;
+       } else if (!tpm_tis_probe_irq_single(chip, intmask, original_int_vec))
+               return;
+}
+
 static bool interrupts = true;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
@@ -626,8 +695,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
                        acpi_handle acpi_dev_handle)
 {
        u32 vendor, intfcaps, intmask;
-       int rc, i, irq_s, irq_e, probe;
-       int irq_r = -1;
+       int rc, probe;
        struct tpm_chip *chip;
        struct priv_data *priv;
 
@@ -735,98 +803,14 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
        /* INTERRUPT Setup */
        init_waitqueue_head(&chip->vendor.read_queue);
        init_waitqueue_head(&chip->vendor.int_queue);
-
-       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 {
-                       irq_s = 3;
-                       irq_e = 15;
-               }
-
-               for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
-                       iowrite8(i, chip->vendor.iobase +
-                                TPM_INT_VECTOR(chip->vendor.locality));
-                       if (devm_request_irq
-                           (dev, i, tis_int_handler, IRQF_SHARED,
-                            chip->devname, chip) != 0) {
-                               dev_info(chip->pdev,
-                                        "Unable to request irq: %d for probe\n",
-                                        i);
-                               continue;
-                       }
-                       chip->vendor.irq = i;
-
-                       /* Clear all existing */
-                       iowrite32(ioread32
-                                 (chip->vendor.iobase +
-                                  TPM_INT_STATUS(chip->vendor.locality)),
-                                 chip->vendor.iobase +
-                                 TPM_INT_STATUS(chip->vendor.locality));
-
-                       /* Turn on */
-                       iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
-                                 chip->vendor.iobase +
-                                 TPM_INT_ENABLE(chip->vendor.locality));
-
-                       priv->irq_tested = false;
-                       priv->irq_probing = true;
-
-                       /* Generate Interrupts */
-                       if (chip->flags & TPM_CHIP_FLAG_TPM2)
-                               tpm2_gen_interrupt(chip);
-                       else
-                               tpm_gen_interrupt(chip);
-
-                       priv->irq_probing = false;
-
-                       /* tpm_tis_send will either confirm the interrupt is
-                        * working or it will call disable_irq which undoes
-                        * all of the above.
-                        */
-                       if (chip->vendor.irq)
-                               break;
-               }
-               if (!chip->vendor.irq)
-                       iowrite8(irq_r, chip->vendor.iobase +
-                                TPM_INT_VECTOR(chip->vendor.locality));
-       }
-       if (chip->vendor.irq && !priv->irq_tested) {
-               iowrite8(chip->vendor.irq,
-                        chip->vendor.iobase +
-                        TPM_INT_VECTOR(chip->vendor.locality));
-               if (devm_request_irq
-                   (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
-                    chip->devname, chip) != 0) {
-                       dev_info(chip->pdev,
-                                "Unable to request irq: %d for use\n",
-                                chip->vendor.irq);
-                       chip->vendor.irq = 0;
-               } else {
-                       /* Clear all existing */
-                       iowrite32(ioread32
-                                 (chip->vendor.iobase +
-                                  TPM_INT_STATUS(chip->vendor.locality)),
-                                 chip->vendor.iobase +
-                                 TPM_INT_STATUS(chip->vendor.locality));
-
-                       /* Turn on */
-                       iowrite32(intmask | TPM_GLOBAL_INT_ENABLE,
-                                 chip->vendor.iobase +
-                                 TPM_INT_ENABLE(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 (interrupts) {
+               if (tpm_info->irq) {
+                       tpm_tis_probe_irq_single(chip, intmask, tpm_info->irq);
+                       if (!chip->vendor.irq)
+                               dev_err(chip->pdev, FW_BUG
+                                       "TPM interrupt not working, polling instead\n");
+               } else
+                       tpm_tis_probe_irq(chip, intmask);
        }
 
        if (chip->flags & TPM_CHIP_FLAG_TPM2) {