From ea8fcd4e40d396a302b4f2512005394e163f768e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 28 Jun 2006 16:21:30 +0100 Subject: [TPM] Add an upgrade patch to bring TPM subsystem to 2.6.17-rc4. This patch adds the updated and newer driver plugins appearing in 2.6.17-rc4 to the 2.6.16.13 kernel. The patch needs to be placed into the patches/linux-2.6.16.13 directory and should be removed once an upgrade is done to 2.6.17-rc4 or later version. Signed-off-by: Stefan Berger --- patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch | 1546 +++++++++++++++++++++++ 1 file changed, 1546 insertions(+) create mode 100644 patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch (limited to 'patches') diff --git a/patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch b/patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch new file mode 100644 index 0000000000..df0bc02e78 --- /dev/null +++ b/patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch @@ -0,0 +1,1546 @@ +diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.c ./drivers/char/tpm/tpm_atmel.c +--- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.c 2006-06-26 18:05:03.000000000 -0400 ++++ ./drivers/char/tpm/tpm_atmel.c 2006-06-26 18:16:33.000000000 -0400 +@@ -47,12 +47,12 @@ static int tpm_atml_recv(struct tpm_chip + return -EIO; + + for (i = 0; i < 6; i++) { +- status = ioread8(chip->vendor->iobase + 1); ++ status = ioread8(chip->vendor.iobase + 1); + if ((status & ATML_STATUS_DATA_AVAIL) == 0) { + dev_err(chip->dev, "error reading header\n"); + return -EIO; + } +- *buf++ = ioread8(chip->vendor->iobase); ++ *buf++ = ioread8(chip->vendor.iobase); + } + + /* size of the data received */ +@@ -63,7 +63,7 @@ static int tpm_atml_recv(struct tpm_chip + dev_err(chip->dev, + "Recv size(%d) less than available space\n", size); + for (; i < size; i++) { /* clear the waiting data anyway */ +- status = ioread8(chip->vendor->iobase + 1); ++ status = ioread8(chip->vendor.iobase + 1); + if ((status & ATML_STATUS_DATA_AVAIL) == 0) { + dev_err(chip->dev, "error reading data\n"); + return -EIO; +@@ -74,16 +74,16 @@ static int tpm_atml_recv(struct tpm_chip + + /* read all the data available */ + for (; i < size; i++) { +- status = ioread8(chip->vendor->iobase + 1); ++ status = ioread8(chip->vendor.iobase + 1); + if ((status & ATML_STATUS_DATA_AVAIL) == 0) { + dev_err(chip->dev, "error reading data\n"); + return -EIO; + } +- *buf++ = ioread8(chip->vendor->iobase); ++ *buf++ = ioread8(chip->vendor.iobase); + } + + /* make sure data available is gone */ +- status = ioread8(chip->vendor->iobase + 1); ++ status = ioread8(chip->vendor.iobase + 1); + + if (status & ATML_STATUS_DATA_AVAIL) { + dev_err(chip->dev, "data available is stuck\n"); +@@ -100,7 +100,7 @@ static int tpm_atml_send(struct tpm_chip + dev_dbg(chip->dev, "tpm_atml_send:\n"); + for (i = 0; i < count; i++) { + dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); +- iowrite8(buf[i], chip->vendor->iobase); ++ iowrite8(buf[i], chip->vendor.iobase); + } + + return count; +@@ -108,12 +108,12 @@ static int tpm_atml_send(struct tpm_chip + + static void tpm_atml_cancel(struct tpm_chip *chip) + { +- iowrite8(ATML_STATUS_ABORT, chip->vendor->iobase + 1); ++ iowrite8(ATML_STATUS_ABORT, chip->vendor.iobase + 1); + } + + static u8 tpm_atml_status(struct tpm_chip *chip) + { +- return ioread8(chip->vendor->iobase + 1); ++ return ioread8(chip->vendor.iobase + 1); + } + + static struct file_operations atmel_ops = { +@@ -140,7 +140,7 @@ static struct attribute* atmel_attrs[] = + + static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; + +-static struct tpm_vendor_specific tpm_atmel = { ++static const struct tpm_vendor_specific tpm_atmel = { + .recv = tpm_atml_recv, + .send = tpm_atml_send, + .cancel = tpm_atml_cancel, +@@ -159,10 +159,10 @@ static void atml_plat_remove(void) + struct tpm_chip *chip = dev_get_drvdata(&pdev->dev); + + if (chip) { +- if (chip->vendor->have_region) +- atmel_release_region(chip->vendor->base, +- chip->vendor->region_size); +- atmel_put_base_addr(chip->vendor); ++ if (chip->vendor.have_region) ++ atmel_release_region(chip->vendor.base, ++ chip->vendor.region_size); ++ atmel_put_base_addr(chip->vendor.iobase); + tpm_remove_hardware(chip->dev); + platform_device_unregister(pdev); + } +@@ -179,18 +179,22 @@ static struct device_driver atml_drv = { + static int __init init_atmel(void) + { + int rc = 0; ++ void __iomem *iobase = NULL; ++ int have_region, region_size; ++ unsigned long base; ++ struct tpm_chip *chip; + + driver_register(&atml_drv); + +- if ((tpm_atmel.iobase = atmel_get_base_addr(&tpm_atmel)) == NULL) { ++ if ((iobase = atmel_get_base_addr(&base, ®ion_size)) == NULL) { + rc = -ENODEV; + goto err_unreg_drv; + } + +- tpm_atmel.have_region = ++ have_region = + (atmel_request_region +- (tpm_atmel.base, tpm_atmel.region_size, +- "tpm_atmel0") == NULL) ? 0 : 1; ++ (tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1; ++ + + if (IS_ERR + (pdev = +@@ -199,17 +203,25 @@ static int __init init_atmel(void) + goto err_rel_reg; + } + +- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) ++ if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) { ++ rc = -ENODEV; + goto err_unreg_dev; ++ } ++ ++ chip->vendor.iobase = iobase; ++ chip->vendor.base = base; ++ chip->vendor.have_region = have_region; ++ chip->vendor.region_size = region_size; ++ + return 0; + + err_unreg_dev: + platform_device_unregister(pdev); + err_rel_reg: +- atmel_put_base_addr(&tpm_atmel); +- if (tpm_atmel.have_region) +- atmel_release_region(tpm_atmel.base, +- tpm_atmel.region_size); ++ atmel_put_base_addr(iobase); ++ if (have_region) ++ atmel_release_region(base, ++ region_size); + err_unreg_drv: + driver_unregister(&atml_drv); + return rc; +diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.h ./drivers/char/tpm/tpm_atmel.h +--- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_atmel.h 2006-06-26 18:05:03.000000000 -0400 ++++ ./drivers/char/tpm/tpm_atmel.h 2006-06-26 18:16:33.000000000 -0400 +@@ -28,13 +28,12 @@ + #define atmel_request_region request_mem_region + #define atmel_release_region release_mem_region + +-static inline void atmel_put_base_addr(struct tpm_vendor_specific +- *vendor) ++static inline void atmel_put_base_addr(void __iomem *iobase) + { +- iounmap(vendor->iobase); ++ iounmap(iobase); + } + +-static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific *vendor) ++static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) + { + struct device_node *dn; + unsigned long address, size; +@@ -71,9 +70,9 @@ static void __iomem * atmel_get_base_add + else + size = reg[naddrc]; + +- vendor->base = address; +- vendor->region_size = size; +- return ioremap(vendor->base, vendor->region_size); ++ *base = address; ++ *region_size = size; ++ return ioremap(*base, *region_size); + } + #else + #define atmel_getb(chip, offset) inb(chip->vendor->base + offset) +@@ -106,14 +105,12 @@ static int atmel_verify_tpm11(void) + return 0; + } + +-static inline void atmel_put_base_addr(struct tpm_vendor_specific +- *vendor) ++static inline void atmel_put_base_addr(void __iomem *iobase) + { + } + + /* Determine where to talk to device */ +-static void __iomem * atmel_get_base_addr(struct tpm_vendor_specific +- *vendor) ++static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size) + { + int lo, hi; + +@@ -123,9 +120,9 @@ static void __iomem * atmel_get_base_add + lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); + hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); + +- vendor->base = (hi << 8) | lo; +- vendor->region_size = 2; ++ *base = (hi << 8) | lo; ++ *region_size = 2; + +- return ioport_map(vendor->base, vendor->region_size); ++ return ioport_map(*base, *region_size); + } + #endif +diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_bios.c ./drivers/char/tpm/tpm_bios.c +--- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_bios.c 2006-06-26 18:05:03.000000000 -0400 ++++ ./drivers/char/tpm/tpm_bios.c 2006-06-26 18:16:33.000000000 -0400 +@@ -29,6 +29,11 @@ + #define MAX_TEXT_EVENT 1000 /* Max event string length */ + #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ + ++enum bios_platform_class { ++ BIOS_CLIENT = 0x00, ++ BIOS_SERVER = 0x01, ++}; ++ + struct tpm_bios_log { + void *bios_event_log; + void *bios_event_log_end; +@@ -36,9 +41,18 @@ struct tpm_bios_log { + + struct acpi_tcpa { + struct acpi_table_header hdr; +- u16 reserved; +- u32 log_max_len __attribute__ ((packed)); +- u32 log_start_addr __attribute__ ((packed)); ++ u16 platform_class; ++ union { ++ struct client_hdr { ++ u32 log_max_len __attribute__ ((packed)); ++ u64 log_start_addr __attribute__ ((packed)); ++ } client; ++ struct server_hdr { ++ u16 reserved; ++ u64 log_max_len __attribute__ ((packed)); ++ u64 log_start_addr __attribute__ ((packed)); ++ } server; ++ }; + }; + + struct tcpa_event { +@@ -91,6 +105,12 @@ static const char* tcpa_event_type_strin + "Non-Host Info" + }; + ++struct tcpa_pc_event { ++ u32 event_id; ++ u32 event_size; ++ u8 event_data[0]; ++}; ++ + enum tcpa_pc_event_ids { + SMBIOS = 1, + BIS_CERT, +@@ -100,14 +120,15 @@ enum tcpa_pc_event_ids { + NVRAM, + OPTION_ROM_EXEC, + OPTION_ROM_CONFIG, +- OPTION_ROM_MICROCODE, ++ OPTION_ROM_MICROCODE = 10, + S_CRTM_VERSION, + S_CRTM_CONTENTS, + POST_CONTENTS, ++ HOST_TABLE_OF_DEVICES, + }; + + static const char* tcpa_pc_event_id_strings[] = { +- "" ++ "", + "SMBIOS", + "BIS Certificate", + "POST BIOS ", +@@ -116,10 +137,12 @@ static const char* tcpa_pc_event_id_stri + "NVRAM", + "Option ROM", + "Option ROM config", +- "Option ROM microcode", ++ "", ++ "Option ROM microcode ", + "S-CRTM Version", +- "S-CRTM Contents", +- "S-CRTM POST Contents", ++ "S-CRTM Contents ", ++ "POST Contents ", ++ "Table of Devices", + }; + + /* returns pointer to start of pos. entry of tcg log */ +@@ -191,7 +214,7 @@ static int get_event_name(char *dest, st + const char *name = ""; + char data[40] = ""; + int i, n_len = 0, d_len = 0; +- u32 event_id; ++ struct tcpa_pc_event *pc_event; + + switch(event->event_type) { + case PREBOOT: +@@ -220,31 +243,32 @@ static int get_event_name(char *dest, st + } + break; + case EVENT_TAG: +- event_id = be32_to_cpu(*((u32 *)event_entry)); ++ pc_event = (struct tcpa_pc_event *)event_entry; + + /* ToDo Row data -> Base64 */ + +- switch (event_id) { ++ switch (pc_event->event_id) { + case SMBIOS: + case BIS_CERT: + case CMOS: + case NVRAM: + case OPTION_ROM_EXEC: + case OPTION_ROM_CONFIG: +- case OPTION_ROM_MICROCODE: + case S_CRTM_VERSION: +- case S_CRTM_CONTENTS: +- case POST_CONTENTS: +- name = tcpa_pc_event_id_strings[event_id]; ++ name = tcpa_pc_event_id_strings[pc_event->event_id]; + n_len = strlen(name); + break; ++ /* hash data */ + case POST_BIOS_ROM: + case ESCD: +- name = tcpa_pc_event_id_strings[event_id]; ++ case OPTION_ROM_MICROCODE: ++ case S_CRTM_CONTENTS: ++ case POST_CONTENTS: ++ name = tcpa_pc_event_id_strings[pc_event->event_id]; + n_len = strlen(name); + for (i = 0; i < 20; i++) +- d_len += sprintf(data, "%02x", +- event_entry[8 + i]); ++ d_len += sprintf(&data[2*i], "%02x", ++ pc_event->event_data[i]); + break; + default: + break; +@@ -260,52 +284,13 @@ static int get_event_name(char *dest, st + + static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) + { ++ struct tcpa_event *event = v; ++ char *data = v; ++ int i; + +- char *eventname; +- char data[4]; +- u32 help; +- int i, len; +- struct tcpa_event *event = (struct tcpa_event *) v; +- unsigned char *event_entry = +- (unsigned char *) (v + sizeof(struct tcpa_event)); +- +- eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); +- if (!eventname) { +- printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", +- __func__); +- return -ENOMEM; +- } +- +- /* 1st: PCR used is in little-endian format (4 bytes) */ +- help = le32_to_cpu(event->pcr_index); +- memcpy(data, &help, 4); +- for (i = 0; i < 4; i++) +- seq_putc(m, data[i]); +- +- /* 2nd: SHA1 (20 bytes) */ +- for (i = 0; i < 20; i++) +- seq_putc(m, event->pcr_value[i]); +- +- /* 3rd: event type identifier (4 bytes) */ +- help = le32_to_cpu(event->event_type); +- memcpy(data, &help, 4); +- for (i = 0; i < 4; i++) ++ for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++) + seq_putc(m, data[i]); + +- len = 0; +- +- len += get_event_name(eventname, event, event_entry); +- +- /* 4th: filename <= 255 + \'0' delimiter */ +- if (len > TCG_EVENT_NAME_LEN_MAX) +- len = TCG_EVENT_NAME_LEN_MAX; +- +- for (i = 0; i < len; i++) +- seq_putc(m, eventname[i]); +- +- /* 5th: delimiter */ +- seq_putc(m, '\0'); +- + return 0; + } + +@@ -353,6 +338,7 @@ static int tpm_ascii_bios_measurements_s + /* 4th: eventname <= max + \'0' delimiter */ + seq_printf(m, " %s\n", eventname); + ++ kfree(eventname); + return 0; + } + +@@ -376,6 +362,7 @@ static int read_log(struct tpm_bios_log + struct acpi_tcpa *buff; + acpi_status status; + struct acpi_table_header *virt; ++ u64 len, start; + + if (log->bios_event_log != NULL) { + printk(KERN_ERR +@@ -396,27 +383,37 @@ static int read_log(struct tpm_bios_log + return -EIO; + } + +- if (buff->log_max_len == 0) { ++ switch(buff->platform_class) { ++ case BIOS_SERVER: ++ len = buff->server.log_max_len; ++ start = buff->server.log_start_addr; ++ break; ++ case BIOS_CLIENT: ++ default: ++ len = buff->client.log_max_len; ++ start = buff->client.log_start_addr; ++ break; ++ } ++ if (!len) { + printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); + return -EIO; + } + + /* malloc EventLog space */ +- log->bios_event_log = kmalloc(buff->log_max_len, GFP_KERNEL); ++ log->bios_event_log = kmalloc(len, GFP_KERNEL); + if (!log->bios_event_log) { +- printk +- ("%s: ERROR - Not enough Memory for BIOS measurements\n", +- __func__); ++ printk("%s: ERROR - Not enough Memory for BIOS measurements\n", ++ __func__); + return -ENOMEM; + } + +- log->bios_event_log_end = log->bios_event_log + buff->log_max_len; ++ log->bios_event_log_end = log->bios_event_log + len; + +- acpi_os_map_memory(buff->log_start_addr, buff->log_max_len, (void *) &virt); ++ acpi_os_map_memory(start, len, (void *) &virt); + +- memcpy(log->bios_event_log, virt, buff->log_max_len); ++ memcpy(log->bios_event_log, virt, len); + +- acpi_os_unmap_memory(virt, buff->log_max_len); ++ acpi_os_unmap_memory(virt, len); + return 0; + } + +diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_infineon.c ./drivers/char/tpm/tpm_infineon.c +--- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_infineon.c 2006-06-26 18:05:03.000000000 -0400 ++++ ./drivers/char/tpm/tpm_infineon.c 2006-06-26 18:16:33.000000000 -0400 +@@ -15,6 +15,7 @@ + * License. + */ + ++#include + #include + #include "tpm.h" + +@@ -104,7 +105,7 @@ static int empty_fifo(struct tpm_chip *c + + if (clear_wrfifo) { + for (i = 0; i < 4096; i++) { +- status = inb(chip->vendor->base + WRFIFO); ++ status = inb(chip->vendor.base + WRFIFO); + if (status == 0xff) { + if (check == 5) + break; +@@ -124,8 +125,8 @@ static int empty_fifo(struct tpm_chip *c + */ + i = 0; + do { +- status = inb(chip->vendor->base + RDFIFO); +- status = inb(chip->vendor->base + STAT); ++ status = inb(chip->vendor.base + RDFIFO); ++ status = inb(chip->vendor.base + STAT); + i++; + if (i == TPM_MAX_TRIES) + return -EIO; +@@ -138,7 +139,7 @@ static int wait(struct tpm_chip *chip, i + int status; + int i; + for (i = 0; i < TPM_MAX_TRIES; i++) { +- status = inb(chip->vendor->base + STAT); ++ status = inb(chip->vendor.base + STAT); + /* check the status-register if wait_for_bit is set */ + if (status & 1 << wait_for_bit) + break; +@@ -157,7 +158,7 @@ static int wait(struct tpm_chip *chip, i + static void wait_and_send(struct tpm_chip *chip, u8 sendbyte) + { + wait(chip, STAT_XFE); +- outb(sendbyte, chip->vendor->base + WRFIFO); ++ outb(sendbyte, chip->vendor.base + WRFIFO); + } + + /* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more +@@ -204,7 +205,7 @@ recv_begin: + ret = wait(chip, STAT_RDA); + if (ret) + return -EIO; +- buf[i] = inb(chip->vendor->base + RDFIFO); ++ buf[i] = inb(chip->vendor.base + RDFIFO); + } + + if (buf[0] != TPM_VL_VER) { +@@ -219,7 +220,7 @@ recv_begin: + + for (i = 0; i < size; i++) { + wait(chip, STAT_RDA); +- buf[i] = inb(chip->vendor->base + RDFIFO); ++ buf[i] = inb(chip->vendor.base + RDFIFO); + } + + if ((size == 0x6D00) && (buf[1] == 0x80)) { +@@ -268,7 +269,7 @@ static int tpm_inf_send(struct tpm_chip + u8 count_high, count_low, count_4, count_3, count_2, count_1; + + /* Disabling Reset, LP and IRQC */ +- outb(RESET_LP_IRQC_DISABLE, chip->vendor->base + CMD); ++ outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD); + + ret = empty_fifo(chip, 1); + if (ret) { +@@ -319,7 +320,7 @@ static void tpm_inf_cancel(struct tpm_ch + + static u8 tpm_inf_status(struct tpm_chip *chip) + { +- return inb(chip->vendor->base + STAT); ++ return inb(chip->vendor.base + STAT); + } + + static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); +@@ -346,7 +347,7 @@ static struct file_operations inf_ops = + .release = tpm_release, + }; + +-static struct tpm_vendor_specific tpm_inf = { ++static const struct tpm_vendor_specific tpm_inf = { + .recv = tpm_inf_recv, + .send = tpm_inf_send, + .cancel = tpm_inf_cancel, +@@ -375,6 +376,7 @@ static int __devinit tpm_inf_pnp_probe(s + int version[2]; + int productid[2]; + char chipname[20]; ++ struct tpm_chip *chip; + + /* read IO-ports through PnP */ + if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) && +@@ -395,14 +397,13 @@ static int __devinit tpm_inf_pnp_probe(s + goto err_last; + } + /* publish my base address and request region */ +- tpm_inf.base = TPM_INF_BASE; + if (request_region +- (tpm_inf.base, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { ++ (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) { + rc = -EINVAL; + goto err_last; + } +- if (request_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN, +- "tpm_infineon0") == NULL) { ++ if (request_region ++ (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) { + rc = -EINVAL; + goto err_last; + } +@@ -442,9 +443,9 @@ static int __devinit tpm_inf_pnp_probe(s + + /* configure TPM with IO-ports */ + outb(IOLIMH, TPM_INF_ADDR); +- outb(((tpm_inf.base >> 8) & 0xff), TPM_INF_DATA); ++ outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA); + outb(IOLIML, TPM_INF_ADDR); +- outb((tpm_inf.base & 0xff), TPM_INF_DATA); ++ outb((TPM_INF_BASE & 0xff), TPM_INF_DATA); + + /* control if IO-ports are set correctly */ + outb(IOLIMH, TPM_INF_ADDR); +@@ -452,10 +453,10 @@ static int __devinit tpm_inf_pnp_probe(s + outb(IOLIML, TPM_INF_ADDR); + iol = inb(TPM_INF_DATA); + +- if ((ioh << 8 | iol) != tpm_inf.base) { ++ if ((ioh << 8 | iol) != TPM_INF_BASE) { + dev_err(&dev->dev, +- "Could not set IO-ports to 0x%lx\n", +- tpm_inf.base); ++ "Could not set IO-ports to 0x%x\n", ++ TPM_INF_BASE); + rc = -EIO; + goto err_release_region; + } +@@ -466,15 +467,15 @@ static int __devinit tpm_inf_pnp_probe(s + outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR); + + /* disable RESET, LP and IRQC */ +- outb(RESET_LP_IRQC_DISABLE, tpm_inf.base + CMD); ++ outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD); + + /* Finally, we're done, print some infos */ + dev_info(&dev->dev, "TPM found: " + "config base 0x%x, " + "io base 0x%x, " +- "chip version %02x%02x, " +- "vendor id %x%x (Infineon), " +- "product id %02x%02x" ++ "chip version 0x%02x%02x, " ++ "vendor id 0x%x%x (Infineon), " ++ "product id 0x%02x%02x" + "%s\n", + TPM_INF_ADDR, + TPM_INF_BASE, +@@ -482,11 +483,10 @@ static int __devinit tpm_inf_pnp_probe(s + vendorid[0], vendorid[1], + productid[0], productid[1], chipname); + +- rc = tpm_register_hardware(&dev->dev, &tpm_inf); +- if (rc < 0) { +- rc = -ENODEV; ++ if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) { + goto err_release_region; + } ++ chip->vendor.base = TPM_INF_BASE; + return 0; + } else { + rc = -ENODEV; +@@ -494,7 +494,7 @@ static int __devinit tpm_inf_pnp_probe(s + } + + err_release_region: +- release_region(tpm_inf.base, TPM_INF_PORT_LEN); ++ release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); + release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + + err_last: +@@ -506,7 +506,8 @@ static __devexit void tpm_inf_pnp_remove + struct tpm_chip *chip = pnp_get_drvdata(dev); + + if (chip) { +- release_region(chip->vendor->base, TPM_INF_PORT_LEN); ++ release_region(TPM_INF_BASE, TPM_INF_PORT_LEN); ++ release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN); + tpm_remove_hardware(chip->dev); + } + } +@@ -520,7 +521,7 @@ static struct pnp_driver tpm_inf_pnp = { + }, + .id_table = tpm_pnp_tbl, + .probe = tpm_inf_pnp_probe, +- .remove = tpm_inf_pnp_remove, ++ .remove = __devexit_p(tpm_inf_pnp_remove), + }; + + static int __init init_inf(void) +@@ -538,5 +539,5 @@ module_exit(cleanup_inf); + + MODULE_AUTHOR("Marcel Selhorst "); + MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); +-MODULE_VERSION("1.7"); ++MODULE_VERSION("1.8"); + MODULE_LICENSE("GPL"); +diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_nsc.c ./drivers/char/tpm/tpm_nsc.c +--- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_nsc.c 2006-06-26 18:05:03.000000000 -0400 ++++ ./drivers/char/tpm/tpm_nsc.c 2006-06-26 18:16:33.000000000 -0400 +@@ -71,7 +71,7 @@ static int wait_for_stat(struct tpm_chip + unsigned long stop; + + /* status immediately available check */ +- *data = inb(chip->vendor->base + NSC_STATUS); ++ *data = inb(chip->vendor.base + NSC_STATUS); + if ((*data & mask) == val) + return 0; + +@@ -79,7 +79,7 @@ static int wait_for_stat(struct tpm_chip + stop = jiffies + 10 * HZ; + do { + msleep(TPM_TIMEOUT); +- *data = inb(chip->vendor->base + 1); ++ *data = inb(chip->vendor.base + 1); + if ((*data & mask) == val) + return 0; + } +@@ -94,9 +94,9 @@ static int nsc_wait_for_ready(struct tpm + unsigned long stop; + + /* status immediately available check */ +- status = inb(chip->vendor->base + NSC_STATUS); ++ status = inb(chip->vendor.base + NSC_STATUS); + if (status & NSC_STATUS_OBF) +- status = inb(chip->vendor->base + NSC_DATA); ++ status = inb(chip->vendor.base + NSC_DATA); + if (status & NSC_STATUS_RDY) + return 0; + +@@ -104,9 +104,9 @@ static int nsc_wait_for_ready(struct tpm + stop = jiffies + 100; + do { + msleep(TPM_TIMEOUT); +- status = inb(chip->vendor->base + NSC_STATUS); ++ status = inb(chip->vendor.base + NSC_STATUS); + if (status & NSC_STATUS_OBF) +- status = inb(chip->vendor->base + NSC_DATA); ++ status = inb(chip->vendor.base + NSC_DATA); + if (status & NSC_STATUS_RDY) + return 0; + } +@@ -132,7 +132,7 @@ static int tpm_nsc_recv(struct tpm_chip + return -EIO; + } + if ((data = +- inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_NORMAL) { ++ inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) { + dev_err(chip->dev, "not in normal mode (0x%x)\n", + data); + return -EIO; +@@ -148,7 +148,7 @@ static int tpm_nsc_recv(struct tpm_chip + } + if (data & NSC_STATUS_F0) + break; +- *p = inb(chip->vendor->base + NSC_DATA); ++ *p = inb(chip->vendor.base + NSC_DATA); + } + + if ((data & NSC_STATUS_F0) == 0 && +@@ -156,7 +156,7 @@ static int tpm_nsc_recv(struct tpm_chip + dev_err(chip->dev, "F0 not set\n"); + return -EIO; + } +- if ((data = inb(chip->vendor->base + NSC_DATA)) != NSC_COMMAND_EOC) { ++ if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) { + dev_err(chip->dev, + "expected end of command(0x%x)\n", data); + return -EIO; +@@ -182,7 +182,7 @@ static int tpm_nsc_send(struct tpm_chip + * fix it. Not sure why this is needed, we followed the flow + * chart in the manual to the letter. + */ +- outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); ++ outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND); + + if (nsc_wait_for_ready(chip) != 0) + return -EIO; +@@ -192,7 +192,7 @@ static int tpm_nsc_send(struct tpm_chip + return -EIO; + } + +- outb(NSC_COMMAND_NORMAL, chip->vendor->base + NSC_COMMAND); ++ outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND); + if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) { + dev_err(chip->dev, "IBR timeout\n"); + return -EIO; +@@ -204,26 +204,26 @@ static int tpm_nsc_send(struct tpm_chip + "IBF timeout (while writing data)\n"); + return -EIO; + } +- outb(buf[i], chip->vendor->base + NSC_DATA); ++ outb(buf[i], chip->vendor.base + NSC_DATA); + } + + if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) { + dev_err(chip->dev, "IBF timeout\n"); + return -EIO; + } +- outb(NSC_COMMAND_EOC, chip->vendor->base + NSC_COMMAND); ++ outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND); + + return count; + } + + static void tpm_nsc_cancel(struct tpm_chip *chip) + { +- outb(NSC_COMMAND_CANCEL, chip->vendor->base + NSC_COMMAND); ++ outb(NSC_COMMAND_CANCEL, chip->vendor.base + NSC_COMMAND); + } + + static u8 tpm_nsc_status(struct tpm_chip *chip) + { +- return inb(chip->vendor->base + NSC_STATUS); ++ return inb(chip->vendor.base + NSC_STATUS); + } + + static struct file_operations nsc_ops = { +@@ -250,7 +250,7 @@ static struct attribute * nsc_attrs[] = + + static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; + +-static struct tpm_vendor_specific tpm_nsc = { ++static const struct tpm_vendor_specific tpm_nsc = { + .recv = tpm_nsc_recv, + .send = tpm_nsc_send, + .cancel = tpm_nsc_cancel, +@@ -268,7 +268,7 @@ static void __devexit tpm_nsc_remove(str + { + struct tpm_chip *chip = dev_get_drvdata(dev); + if ( chip ) { +- release_region(chip->vendor->base, 2); ++ release_region(chip->vendor.base, 2); + tpm_remove_hardware(chip->dev); + } + } +@@ -286,7 +286,8 @@ static int __init init_nsc(void) + int rc = 0; + int lo, hi; + int nscAddrBase = TPM_ADDR; +- ++ struct tpm_chip *chip; ++ unsigned long base; + + /* verify that it is a National part (SID) */ + if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { +@@ -300,7 +301,7 @@ static int __init init_nsc(void) + + hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); + lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); +- tpm_nsc.base = (hi<<8) | lo; ++ base = (hi<<8) | lo; + + /* enable the DPM module */ + tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); +@@ -320,13 +321,15 @@ static int __init init_nsc(void) + if ((rc = platform_device_register(pdev)) < 0) + goto err_free_dev; + +- if (request_region(tpm_nsc.base, 2, "tpm_nsc0") == NULL ) { ++ if (request_region(base, 2, "tpm_nsc0") == NULL ) { + rc = -EBUSY; + goto err_unreg_dev; + } + +- if ((rc = tpm_register_hardware(&pdev->dev, &tpm_nsc)) < 0) ++ if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { ++ rc = -ENODEV; + goto err_rel_reg; ++ } + + dev_dbg(&pdev->dev, "NSC TPM detected\n"); + dev_dbg(&pdev->dev, +@@ -361,10 +364,12 @@ static int __init init_nsc(void) + "NSC TPM revision %d\n", + tpm_read_index(nscAddrBase, 0x27) & 0x1F); + ++ chip->vendor.base = base; ++ + return 0; + + err_rel_reg: +- release_region(tpm_nsc.base, 2); ++ release_region(base, 2); + err_unreg_dev: + platform_device_unregister(pdev); + err_free_dev: +diff -pruN ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_tis.c ./drivers/char/tpm/tpm_tis.c +--- ../pristine-linux-2.6.16.13/drivers/char/tpm/tpm_tis.c 1969-12-31 19:00:00.000000000 -0500 ++++ ./drivers/char/tpm/tpm_tis.c 2006-06-26 18:16:33.000000000 -0400 +@@ -0,0 +1,665 @@ ++/* ++ * Copyright (C) 2005, 2006 IBM Corporation ++ * ++ * Authors: ++ * Leendert van Doorn ++ * Kylene Hall ++ * ++ * Device driver for TCG/TCPA TPM (trusted platform module). ++ * Specifications at www.trustedcomputinggroup.org ++ * ++ * This device driver implements the TPM interface as defined in ++ * the TCG TPM Interface Spec version 1.2, revision 1.0. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation, version 2 of the ++ * License. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "tpm.h" ++ ++#define TPM_HEADER_SIZE 10 ++ ++enum tis_access { ++ TPM_ACCESS_VALID = 0x80, ++ TPM_ACCESS_ACTIVE_LOCALITY = 0x20, ++ TPM_ACCESS_REQUEST_PENDING = 0x04, ++ TPM_ACCESS_REQUEST_USE = 0x02, ++}; ++ ++enum tis_status { ++ TPM_STS_VALID = 0x80, ++ TPM_STS_COMMAND_READY = 0x40, ++ TPM_STS_GO = 0x20, ++ TPM_STS_DATA_AVAIL = 0x10, ++ TPM_STS_DATA_EXPECT = 0x08, ++}; ++ ++enum tis_int_flags { ++ TPM_GLOBAL_INT_ENABLE = 0x80000000, ++ TPM_INTF_BURST_COUNT_STATIC = 0x100, ++ TPM_INTF_CMD_READY_INT = 0x080, ++ TPM_INTF_INT_EDGE_FALLING = 0x040, ++ TPM_INTF_INT_EDGE_RISING = 0x020, ++ TPM_INTF_INT_LEVEL_LOW = 0x010, ++ TPM_INTF_INT_LEVEL_HIGH = 0x008, ++ TPM_INTF_LOCALITY_CHANGE_INT = 0x004, ++ TPM_INTF_STS_VALID_INT = 0x002, ++ TPM_INTF_DATA_AVAIL_INT = 0x001, ++}; ++ ++enum tis_defaults { ++ TIS_MEM_BASE = 0xFED40000, ++ TIS_MEM_LEN = 0x5000, ++ TIS_SHORT_TIMEOUT = 750, /* ms */ ++ TIS_LONG_TIMEOUT = 2000, /* 2 sec */ ++}; ++ ++#define TPM_ACCESS(l) (0x0000 | ((l) << 12)) ++#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12)) ++#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12)) ++#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12)) ++#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12)) ++#define TPM_STS(l) (0x0018 | ((l) << 12)) ++#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12)) ++ ++#define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) ++#define TPM_RID(l) (0x0F04 | ((l) << 12)) ++ ++static LIST_HEAD(tis_chips); ++static DEFINE_SPINLOCK(tis_lock); ++ ++static int check_locality(struct tpm_chip *chip, int l) ++{ ++ if ((ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & ++ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == ++ (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ++ return chip->vendor.locality = l; ++ ++ return -1; ++} ++ ++static void release_locality(struct tpm_chip *chip, int l, int force) ++{ ++ if (force || (ioread8(chip->vendor.iobase + TPM_ACCESS(l)) & ++ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == ++ (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ++ iowrite8(TPM_ACCESS_ACTIVE_LOCALITY, ++ chip->vendor.iobase + TPM_ACCESS(l)); ++} ++ ++static int request_locality(struct tpm_chip *chip, int l) ++{ ++ unsigned long stop; ++ long rc; ++ ++ if (check_locality(chip, l) >= 0) ++ return l; ++ ++ iowrite8(TPM_ACCESS_REQUEST_USE, ++ chip->vendor.iobase + TPM_ACCESS(l)); ++ ++ if (chip->vendor.irq) { ++ rc = wait_event_interruptible_timeout(chip->vendor.int_queue, ++ (check_locality ++ (chip, l) >= 0), ++ chip->vendor.timeout_a); ++ if (rc > 0) ++ return l; ++ ++ } else { ++ /* wait for burstcount */ ++ stop = jiffies + chip->vendor.timeout_a; ++ do { ++ if (check_locality(chip, l) >= 0) ++ return l; ++ msleep(TPM_TIMEOUT); ++ } ++ while (time_before(jiffies, stop)); ++ } ++ return -1; ++} ++ ++static u8 tpm_tis_status(struct tpm_chip *chip) ++{ ++ return ioread8(chip->vendor.iobase + ++ TPM_STS(chip->vendor.locality)); ++} ++ ++static void tpm_tis_ready(struct tpm_chip *chip) ++{ ++ /* this causes the current command to be aborted */ ++ iowrite8(TPM_STS_COMMAND_READY, ++ chip->vendor.iobase + TPM_STS(chip->vendor.locality)); ++} ++ ++static int get_burstcount(struct tpm_chip *chip) ++{ ++ unsigned long stop; ++ int burstcnt; ++ ++ /* wait for burstcount */ ++ /* which timeout value, spec has 2 answers (c & d) */ ++ stop = jiffies + chip->vendor.timeout_d; ++ do { ++ burstcnt = ioread8(chip->vendor.iobase + ++ TPM_STS(chip->vendor.locality) + 1); ++ burstcnt += ioread8(chip->vendor.iobase + ++ TPM_STS(chip->vendor.locality) + ++ 2) << 8; ++ if (burstcnt) ++ return burstcnt; ++ msleep(TPM_TIMEOUT); ++ } while (time_before(jiffies, stop)); ++ return -EBUSY; ++} ++ ++static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, ++ wait_queue_head_t *queue) ++{ ++ unsigned long stop; ++ long rc; ++ u8 status; ++ ++ /* check current status */ ++ status = tpm_tis_status(chip); ++ if ((status & mask) == mask) ++ return 0; ++ ++ if (chip->vendor.irq) { ++ rc = wait_event_interruptible_timeout(*queue, ++ ((tpm_tis_status ++ (chip) & mask) == ++ mask), timeout); ++ if (rc > 0) ++ return 0; ++ } else { ++ stop = jiffies + timeout; ++ do { ++ msleep(TPM_TIMEOUT); ++ status = tpm_tis_status(chip); ++ if ((status & mask) == mask) ++ return 0; ++ } while (time_before(jiffies, stop)); ++ } ++ return -ETIME; ++} ++ ++static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) ++{ ++ int size = 0, burstcnt; ++ while (size < count && ++ wait_for_stat(chip, ++ TPM_STS_DATA_AVAIL | TPM_STS_VALID, ++ chip->vendor.timeout_c, ++ &chip->vendor.read_queue) ++ == 0) { ++ burstcnt = get_burstcount(chip); ++ for (; burstcnt > 0 && size < count; burstcnt--) ++ buf[size++] = ioread8(chip->vendor.iobase + ++ TPM_DATA_FIFO(chip->vendor. ++ locality)); ++ } ++ return size; ++} ++ ++static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) ++{ ++ int size = 0; ++ int expected, status; ++ ++ if (count < TPM_HEADER_SIZE) { ++ size = -EIO; ++ goto out; ++ } ++ ++ /* read first 10 bytes, including tag, paramsize, and result */ ++ if ((size = ++ recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) { ++ dev_err(chip->dev, "Unable to read header\n"); ++ goto out; ++ } ++ ++ expected = be32_to_cpu(*(__be32 *) (buf + 2)); ++ if (expected > count) { ++ size = -EIO; ++ goto out; ++ } ++ ++ if ((size += ++ recv_data(chip, &buf[TPM_HEADER_SIZE], ++ expected - TPM_HEADER_SIZE)) < expected) { ++ dev_err(chip->dev, "Unable to read remainder of result\n"); ++ size = -ETIME; ++ goto out; ++ } ++ ++ 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_AVAIL) { /* retry? */ ++ dev_err(chip->dev, "Error left over data\n"); ++ size = -EIO; ++ goto out; ++ } ++ ++out: ++ tpm_tis_ready(chip); ++ release_locality(chip, chip->vendor.locality, 0); ++ return size; ++} ++ ++/* ++ * 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 ++ * waited for here ++ */ ++static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) ++{ ++ int rc, status, burstcnt; ++ size_t count = 0; ++ u32 ordinal; ++ ++ if (request_locality(chip, 0) < 0) ++ return -EBUSY; ++ ++ status = tpm_tis_status(chip); ++ if ((status & TPM_STS_COMMAND_READY) == 0) { ++ tpm_tis_ready(chip); ++ if (wait_for_stat ++ (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, ++ &chip->vendor.int_queue) < 0) { ++ rc = -ETIME; ++ goto out_err; ++ } ++ } ++ ++ while (count < len - 1) { ++ burstcnt = get_burstcount(chip); ++ for (; burstcnt > 0 && count < len - 1; burstcnt--) { ++ iowrite8(buf[count], chip->vendor.iobase + ++ TPM_DATA_FIFO(chip->vendor.locality)); ++ count++; ++ } ++ ++ 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) { ++ rc = -EIO; ++ goto out_err; ++ } ++ } ++ ++ /* write last byte */ ++ iowrite8(buf[count], ++ chip->vendor.iobase + ++ TPM_DATA_FIFO(chip->vendor.locality)); ++ 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) { ++ rc = -EIO; ++ goto out_err; ++ } ++ ++ /* go and do it */ ++ iowrite8(TPM_STS_GO, ++ chip->vendor.iobase + TPM_STS(chip->vendor.locality)); ++ ++ if (chip->vendor.irq) { ++ ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); ++ if (wait_for_stat ++ (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, ++ tpm_calc_ordinal_duration(chip, ordinal), ++ &chip->vendor.read_queue) < 0) { ++ rc = -ETIME; ++ goto out_err; ++ } ++ } ++ return len; ++out_err: ++ tpm_tis_ready(chip); ++ release_locality(chip, chip->vendor.locality, 0); ++ return rc; ++} ++ ++static struct file_operations tis_ops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .open = tpm_open, ++ .read = tpm_read, ++ .write = tpm_write, ++ .release = tpm_release, ++}; ++ ++static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); ++static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); ++static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); ++static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); ++static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); ++static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, ++ NULL); ++static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); ++static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); ++ ++static struct attribute *tis_attrs[] = { ++ &dev_attr_pubek.attr, ++ &dev_attr_pcrs.attr, ++ &dev_attr_enabled.attr, ++ &dev_attr_active.attr, ++ &dev_attr_owned.attr, ++ &dev_attr_temp_deactivated.attr, ++ &dev_attr_caps.attr, ++ &dev_attr_cancel.attr, NULL, ++}; ++ ++static struct attribute_group tis_attr_grp = { ++ .attrs = tis_attrs ++}; ++ ++static struct tpm_vendor_specific tpm_tis = { ++ .status = tpm_tis_status, ++ .recv = tpm_tis_recv, ++ .send = tpm_tis_send, ++ .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, ++ .attr_group = &tis_attr_grp, ++ .miscdev = { ++ .fops = &tis_ops,}, ++}; ++ ++static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct tpm_chip *chip = (struct tpm_chip *) dev_id; ++ u32 interrupt; ++ ++ interrupt = ioread32(chip->vendor.iobase + ++ TPM_INT_STATUS(chip->vendor.locality)); ++ ++ if (interrupt == 0) ++ return IRQ_NONE; ++ ++ chip->vendor.irq = irq; ++ ++ /* Clear interrupts handled with TPM_EOI */ ++ iowrite32(interrupt, ++ chip->vendor.iobase + ++ TPM_INT_STATUS(chip->vendor.locality)); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct tpm_chip *chip = (struct tpm_chip *) dev_id; ++ u32 interrupt; ++ int i; ++ ++ interrupt = ioread32(chip->vendor.iobase + ++ TPM_INT_STATUS(chip->vendor.locality)); ++ ++ if (interrupt == 0) ++ return IRQ_NONE; ++ ++ if (interrupt & TPM_INTF_DATA_AVAIL_INT) ++ wake_up_interruptible(&chip->vendor.read_queue); ++ if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) ++ for (i = 0; i < 5; i++) ++ if (check_locality(chip, i) >= 0) ++ break; ++ if (interrupt & ++ (TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_STS_VALID_INT | ++ TPM_INTF_CMD_READY_INT)) ++ wake_up_interruptible(&chip->vendor.int_queue); ++ ++ /* Clear interrupts handled with TPM_EOI */ ++ iowrite32(interrupt, ++ chip->vendor.iobase + ++ TPM_INT_STATUS(chip->vendor.locality)); ++ return IRQ_HANDLED; ++} ++ ++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) ++{ ++ 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))) ++ return -ENODEV; ++ ++ chip->vendor.iobase = ioremap(start, len); ++ if (!chip->vendor.iobase) { ++ rc = -EIO; ++ 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, ++ "1.2 TPM (device-id 0x%X, rev-id %d)\n", ++ vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); ++ ++ /* 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", ++ intfcaps); ++ if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) ++ dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n"); ++ if (intfcaps & TPM_INTF_CMD_READY_INT) ++ dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n"); ++ if (intfcaps & TPM_INTF_INT_EDGE_FALLING) ++ dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n"); ++ if (intfcaps & TPM_INTF_INT_EDGE_RISING) ++ dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n"); ++ if (intfcaps & TPM_INTF_INT_LEVEL_LOW) ++ dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n"); ++ if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) ++ dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n"); ++ if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) ++ dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n"); ++ if (intfcaps & TPM_INTF_STS_VALID_INT) ++ dev_dbg(&pnp_dev->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; ++ } ++ ++ /* 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 = ++ ioread8(chip->vendor.iobase + ++ TPM_INT_VECTOR(chip->vendor.locality)); ++ ++ for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { ++ iowrite8(i, chip->vendor.iobase + ++ TPM_INT_VECTOR(chip->vendor.locality)); ++ if (request_irq ++ (i, tis_int_probe, SA_SHIRQ, ++ chip->vendor.miscdev.name, chip) != 0) { ++ dev_info(chip->dev, ++ "Unable to request irq: %d for probe\n", ++ i); ++ continue; ++ } ++ ++ /* 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)); ++ ++ /* Generate Interrupts */ ++ tpm_gen_interrupt(chip); ++ ++ /* Turn off */ ++ iowrite32(intmask, ++ chip->vendor.iobase + ++ TPM_INT_ENABLE(chip->vendor.locality)); ++ free_irq(i, chip); ++ } ++ } ++ if (chip->vendor.irq) { ++ iowrite8(chip->vendor.irq, ++ chip->vendor.iobase + ++ TPM_INT_VECTOR(chip->vendor.locality)); ++ if (request_irq ++ (chip->vendor.irq, tis_int_handler, SA_SHIRQ, ++ chip->vendor.miscdev.name, chip) != 0) { ++ dev_info(chip->dev, ++ "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)); ++ } ++ } ++ ++ INIT_LIST_HEAD(&chip->vendor.list); ++ spin_lock(&tis_lock); ++ list_add(&chip->vendor.list, &tis_chips); ++ spin_unlock(&tis_lock); ++ ++ tpm_get_timeouts(chip); ++ tpm_continue_selftest(chip); ++ ++ return 0; ++out_err: ++ if (chip->vendor.iobase) ++ iounmap(chip->vendor.iobase); ++ tpm_remove_hardware(chip->dev); ++ return rc; ++} ++ ++static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) ++{ ++ return tpm_pm_suspend(&dev->dev, msg); ++} ++ ++static int tpm_tis_pnp_resume(struct pnp_dev *dev) ++{ ++ return tpm_pm_resume(&dev->dev); ++} ++ ++static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { ++ {"PNP0C31", 0}, /* TPM */ ++ {"ATM1200", 0}, /* Atmel */ ++ {"IFX0102", 0}, /* Infineon */ ++ {"BCM0101", 0}, /* Broadcom */ ++ {"NSC1200", 0}, /* National */ ++ /* Add new here */ ++ {"", 0}, /* User Specified */ ++ {"", 0} /* Terminator */ ++}; ++ ++static struct pnp_driver tis_pnp_driver = { ++ .name = "tpm_tis", ++ .id_table = tpm_pnp_tbl, ++ .probe = tpm_tis_pnp_init, ++ .suspend = tpm_tis_pnp_suspend, ++ .resume = tpm_tis_pnp_resume, ++}; ++ ++#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 ++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 __init init_tis(void) ++{ ++ return pnp_register_driver(&tis_pnp_driver); ++} ++ ++static void __exit cleanup_tis(void) ++{ ++ struct tpm_vendor_specific *i, *j; ++ struct tpm_chip *chip; ++ spin_lock(&tis_lock); ++ list_for_each_entry_safe(i, j, &tis_chips, list) { ++ chip = to_tpm_chip(i); ++ iowrite32(~TPM_GLOBAL_INT_ENABLE & ++ ioread32(chip->vendor.iobase + ++ TPM_INT_ENABLE(chip->vendor. ++ locality)), ++ chip->vendor.iobase + ++ TPM_INT_ENABLE(chip->vendor.locality)); ++ release_locality(chip, chip->vendor.locality, 1); ++ if (chip->vendor.irq) ++ 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); ++} ++ ++module_init(init_tis); ++module_exit(cleanup_tis); ++MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); ++MODULE_DESCRIPTION("TPM Driver"); ++MODULE_VERSION("2.0"); ++MODULE_LICENSE("GPL"); + -- cgit v1.2.3