mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
Signed-off-by: Christian Limpach <Christian.Limpach@xensource.com> --HG-- rename : patches/linux-2.6.16.13/blktap-aio-16_03_06.patch => patches/linux-2.6.16.29/blktap-aio-16_03_06.patch rename : patches/linux-2.6.16.13/device_bind.patch => patches/linux-2.6.16.29/device_bind.patch rename : patches/linux-2.6.16.13/fix-hz-suspend.patch => patches/linux-2.6.16.29/fix-hz-suspend.patch rename : patches/linux-2.6.16.13/fix-ide-cd-pio-mode.patch => patches/linux-2.6.16.29/fix-ide-cd-pio-mode.patch rename : patches/linux-2.6.16.13/i386-mach-io-check-nmi.patch => patches/linux-2.6.16.29/i386-mach-io-check-nmi.patch rename : patches/linux-2.6.16.13/ipv6-no-autoconf.patch => patches/linux-2.6.16.29/ipv6-no-autoconf.patch rename : patches/linux-2.6.16.13/net-csum.patch => patches/linux-2.6.16.29/net-csum.patch rename : patches/linux-2.6.16.13/net-gso-0-base.patch => patches/linux-2.6.16.29/net-gso-0-base.patch rename : patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch => patches/linux-2.6.16.29/net-gso-1-check-dodgy.patch rename : patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch => patches/linux-2.6.16.29/net-gso-2-checksum-fix.patch rename : patches/linux-2.6.16.13/net-gso-3-fix-errorcheck.patch => patches/linux-2.6.16.29/net-gso-3-fix-errorcheck.patch rename : patches/linux-2.6.16.13/net-gso-4-kill-warnon.patch => patches/linux-2.6.16.29/net-gso-4-kill-warnon.patch rename : patches/linux-2.6.16.13/pmd-shared.patch => patches/linux-2.6.16.29/pmd-shared.patch rename : patches/linux-2.6.16.13/rcu_needs_cpu.patch => patches/linux-2.6.16.29/rcu_needs_cpu.patch rename : patches/linux-2.6.16.13/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch => patches/linux-2.6.16.29/rename-TSS_sysenter_esp0-SYSENTER_stack_esp0.patch rename : patches/linux-2.6.16.13/series => patches/linux-2.6.16.29/series rename : patches/linux-2.6.16.13/smp-alts.patch => patches/linux-2.6.16.29/smp-alts.patch rename : patches/linux-2.6.16.13/tpm_plugin_2.6.17.patch => patches/linux-2.6.16.29/tpm_plugin_2.6.17.patch rename : patches/linux-2.6.16.13/x86-elfnote-as-preprocessor-macro.patch => patches/linux-2.6.16.29/x86-elfnote-as-preprocessor-macro.patch rename : patches/linux-2.6.16.13/x86-increase-interrupt-vector-range.patch => patches/linux-2.6.16.29/x86-increase-interrupt-vector-range.patch rename : patches/linux-2.6.16.13/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch => patches/linux-2.6.16.29/x86-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch rename : patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch => patches/linux-2.6.16.29/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch rename : patches/linux-2.6.16.13/xen-hotplug.patch => patches/linux-2.6.16.29/xen-hotplug.patch rename : patches/linux-2.6.16.13/xenoprof-generic.patch => patches/linux-2.6.16.29/xenoprof-generic.patch
1546 lines
43 KiB
Diff
1546 lines
43 KiB
Diff
diff -pruN ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.c ./drivers/char/tpm/tpm_atmel.c
|
|
--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.c 2006-09-12 19:02:10.000000000 +0100
|
|
+++ ./drivers/char/tpm/tpm_atmel.c 2006-09-19 14:05:52.000000000 +0100
|
|
@@ -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 ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.h ./drivers/char/tpm/tpm_atmel.h
|
|
--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_atmel.h 2006-09-12 19:02:10.000000000 +0100
|
|
+++ ./drivers/char/tpm/tpm_atmel.h 2006-09-19 14:05:52.000000000 +0100
|
|
@@ -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 ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_bios.c ./drivers/char/tpm/tpm_bios.c
|
|
--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_bios.c 2006-09-12 19:02:10.000000000 +0100
|
|
+++ ./drivers/char/tpm/tpm_bios.c 2006-09-19 14:05:52.000000000 +0100
|
|
@@ -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 ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_infineon.c ./drivers/char/tpm/tpm_infineon.c
|
|
--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_infineon.c 2006-09-12 19:02:10.000000000 +0100
|
|
+++ ./drivers/char/tpm/tpm_infineon.c 2006-09-19 14:05:52.000000000 +0100
|
|
@@ -15,6 +15,7 @@
|
|
* License.
|
|
*/
|
|
|
|
+#include <linux/init.h>
|
|
#include <linux/pnp.h>
|
|
#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 <selhorst@crypto.rub.de>");
|
|
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 ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_nsc.c ./drivers/char/tpm/tpm_nsc.c
|
|
--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_nsc.c 2006-09-12 19:02:10.000000000 +0100
|
|
+++ ./drivers/char/tpm/tpm_nsc.c 2006-09-19 14:05:52.000000000 +0100
|
|
@@ -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 ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_tis.c ./drivers/char/tpm/tpm_tis.c
|
|
--- ../orig-linux-2.6.16.29/drivers/char/tpm/tpm_tis.c 1970-01-01 01:00:00.000000000 +0100
|
|
+++ ./drivers/char/tpm/tpm_tis.c 2006-09-19 14:05:52.000000000 +0100
|
|
@@ -0,0 +1,665 @@
|
|
+/*
|
|
+ * Copyright (C) 2005, 2006 IBM Corporation
|
|
+ *
|
|
+ * Authors:
|
|
+ * Leendert van Doorn <leendert@watson.ibm.com>
|
|
+ * Kylene Hall <kjhall@us.ibm.com>
|
|
+ *
|
|
+ * 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 <linux/init.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/moduleparam.h>
|
|
+#include <linux/pnp.h>
|
|
+#include <linux/interrupt.h>
|
|
+#include <linux/wait.h>
|
|
+#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");
|