include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / drivers / char / tpm / tpm_tis.c
index abb0f2a..9434599 100644 (file)
@@ -5,6 +5,8 @@
  * Leendert van Doorn <leendert@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org
  *
@@ -20,6 +22,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/pnp.h>
+#include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/wait.h>
 #include "tpm.h"
@@ -255,6 +258,10 @@ out:
        return size;
 }
 
+static int itpm;
+module_param(itpm, bool, 0444);
+MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)");
+
 /*
  * If interrupts are used (signaled by an irq set in the vendor structure)
  * tpm.c can skip polling for the data to be available as the interrupt is
@@ -291,7 +298,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
                wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
                              &chip->vendor.int_queue);
                status = tpm_tis_status(chip);
-               if ((status & TPM_STS_DATA_EXPECT) == 0) {
+               if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
                        rc = -EIO;
                        goto out_err;
                }
@@ -330,7 +337,7 @@ out_err:
        return rc;
 }
 
-static struct file_operations tis_ops = {
+static const struct file_operations tis_ops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .open = tpm_open,
@@ -377,9 +384,9 @@ static struct tpm_vendor_specific tpm_tis = {
                    .fops = &tis_ops,},
 };
 
-static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tis_int_probe(int irq, void *dev_id)
 {
-       struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+       struct tpm_chip *chip = dev_id;
        u32 interrupt;
 
        interrupt = ioread32(chip->vendor.iobase +
@@ -397,9 +404,9 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tis_int_handler(int dummy, void *dev_id)
 {
-       struct tpm_chip *chip = (struct tpm_chip *) dev_id;
+       struct tpm_chip *chip = dev_id;
        u32 interrupt;
        int i;
 
@@ -424,6 +431,7 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
        iowrite32(interrupt,
                  chip->vendor.iobase +
                  TPM_INT_STATUS(chip->vendor.locality));
+       ioread32(chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
        return IRQ_HANDLED;
 }
 
@@ -431,23 +439,14 @@ static int interrupts = 1;
 module_param(interrupts, bool, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
-static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
-                                     const struct pnp_device_id *pnp_id)
+static int tpm_tis_init(struct device *dev, resource_size_t start,
+                       resource_size_t len, unsigned int irq)
 {
        u32 vendor, intfcaps, intmask;
        int rc, i;
-       unsigned long start, len;
        struct tpm_chip *chip;
 
-       start = pnp_mem_start(pnp_dev, 0);
-       len = pnp_mem_len(pnp_dev, 0);
-
-       if (!start)
-               start = TIS_MEM_BASE;
-       if (!len)
-               len = TIS_MEM_LEN;
-
-       if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
+       if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
                return -ENODEV;
 
        chip->vendor.iobase = ioremap(start, len);
@@ -456,47 +455,51 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                goto out_err;
        }
 
-       vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
-
        /* Default timeouts */
        chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
        chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
        chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
        chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
 
-       dev_info(&pnp_dev->dev,
+       if (request_locality(chip, 0) != 0) {
+               rc = -ENODEV;
+               goto out_err;
+       }
+
+       vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
+
+       dev_info(dev,
                 "1.2 TPM (device-id 0x%X, rev-id %d)\n",
                 vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
 
+       if (itpm)
+               dev_info(dev, "Intel iTPM workaround enabled\n");
+
+
        /* Figure out the capabilities */
        intfcaps =
            ioread32(chip->vendor.iobase +
                     TPM_INTF_CAPS(chip->vendor.locality));
-       dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
+       dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
                intfcaps);
        if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
-               dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
+               dev_dbg(dev, "\tBurst Count Static\n");
        if (intfcaps & TPM_INTF_CMD_READY_INT)
-               dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
+               dev_dbg(dev, "\tCommand Ready Int Support\n");
        if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
+               dev_dbg(dev, "\tInterrupt Edge Falling\n");
        if (intfcaps & TPM_INTF_INT_EDGE_RISING)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
+               dev_dbg(dev, "\tInterrupt Edge Rising\n");
        if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
+               dev_dbg(dev, "\tInterrupt Level Low\n");
        if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
-               dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
+               dev_dbg(dev, "\tInterrupt Level High\n");
        if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
-               dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
+               dev_dbg(dev, "\tLocality Change Int Support\n");
        if (intfcaps & TPM_INTF_STS_VALID_INT)
-               dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
+               dev_dbg(dev, "\tSts Valid Int Support\n");
        if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
-               dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
-
-       if (request_locality(chip, 0) != 0) {
-               rc = -ENODEV;
-               goto out_err;
-       }
+               dev_dbg(dev, "\tData Avail Int Support\n");
 
        /* INTERRUPT Setup */
        init_waitqueue_head(&chip->vendor.read_queue);
@@ -513,7 +516,9 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
        iowrite32(intmask,
                  chip->vendor.iobase +
                  TPM_INT_ENABLE(chip->vendor.locality));
-       if (interrupts) {
+       if (interrupts)
+               chip->vendor.irq = irq;
+       if (interrupts && !chip->vendor.irq) {
                chip->vendor.irq =
                    ioread8(chip->vendor.iobase +
                            TPM_INT_VECTOR(chip->vendor.locality));
@@ -594,6 +599,23 @@ out_err:
        return rc;
 }
 
+static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+                                     const struct pnp_device_id *pnp_id)
+{
+       resource_size_t start, len;
+       unsigned int irq = 0;
+
+       start = pnp_mem_start(pnp_dev, 0);
+       len = pnp_mem_len(pnp_dev, 0);
+
+       if (pnp_irq_valid(pnp_dev, 0))
+               irq = pnp_irq(pnp_dev, 0);
+       else
+               interrupts = 0;
+
+       return tpm_tis_init(&pnp_dev->dev, start, len, irq);
+}
+
 static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
 {
        return tpm_pm_suspend(&dev->dev, msg);
@@ -609,11 +631,24 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
        {"ATM1200", 0},         /* Atmel */
        {"IFX0102", 0},         /* Infineon */
        {"BCM0101", 0},         /* Broadcom */
+       {"BCM0102", 0},         /* Broadcom */
        {"NSC1200", 0},         /* National */
+       {"ICO0102", 0},         /* Intel */
        /* Add new here */
        {"", 0},                /* User Specified */
        {"", 0}                 /* Terminator */
 };
+MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
+
+static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
+{
+       struct tpm_chip *chip = pnp_get_drvdata(dev);
+
+       tpm_dev_vendor_release(chip);
+
+       kfree(chip);
+}
+
 
 static struct pnp_driver tis_pnp_driver = {
        .name = "tpm_tis",
@@ -621,6 +656,7 @@ static struct pnp_driver tis_pnp_driver = {
        .probe = tpm_tis_pnp_init,
        .suspend = tpm_tis_pnp_suspend,
        .resume = tpm_tis_pnp_resume,
+       .remove = tpm_tis_pnp_remove,
 };
 
 #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -628,8 +664,46 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
                    sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 
+static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg)
+{
+       return tpm_pm_suspend(&dev->dev, msg);
+}
+
+static int tpm_tis_resume(struct platform_device *dev)
+{
+       return tpm_pm_resume(&dev->dev);
+}
+static struct platform_driver tis_drv = {
+       .driver = {
+               .name = "tpm_tis",
+               .owner          = THIS_MODULE,
+       },
+       .suspend = tpm_tis_suspend,
+       .resume = tpm_tis_resume,
+};
+
+static struct platform_device *pdev;
+
+static int force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
 static int __init init_tis(void)
 {
+       int rc;
+
+       if (force) {
+               rc = platform_driver_register(&tis_drv);
+               if (rc < 0)
+                       return rc;
+               if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
+                       return PTR_ERR(pdev);
+               if((rc=tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0)) != 0) {
+                       platform_device_unregister(pdev);
+                       platform_driver_unregister(&tis_drv);
+               }
+               return rc;
+       }
+
        return pnp_register_driver(&tis_pnp_driver);
 }
 
@@ -640,6 +714,7 @@ static void __exit cleanup_tis(void)
        spin_lock(&tis_lock);
        list_for_each_entry_safe(i, j, &tis_chips, list) {
                chip = to_tpm_chip(i);
+               tpm_remove_hardware(chip->dev);
                iowrite32(~TPM_GLOBAL_INT_ENABLE &
                          ioread32(chip->vendor.iobase +
                                   TPM_INT_ENABLE(chip->vendor.
@@ -651,10 +726,14 @@ static void __exit cleanup_tis(void)
                        free_irq(chip->vendor.irq, chip);
                iounmap(i->iobase);
                list_del(&i->list);
-               tpm_remove_hardware(chip->dev);
        }
        spin_unlock(&tis_lock);
-       pnp_unregister_driver(&tis_pnp_driver);
+
+       if (force) {
+               platform_device_unregister(pdev);
+               platform_driver_unregister(&tis_drv);
+       } else
+               pnp_unregister_driver(&tis_pnp_driver);
 }
 
 module_init(init_tis);