| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2004 IBM Corporation | 
|  | 3 | * | 
|  | 4 | * Authors: | 
|  | 5 | * Leendert van Doorn <leendert@watson.ibm.com> | 
|  | 6 | * Dave Safford <safford@watson.ibm.com> | 
|  | 7 | * Reiner Sailer <sailer@watson.ibm.com> | 
|  | 8 | * Kylene Hall <kjhall@us.ibm.com> | 
|  | 9 | * | 
| Kent Yoder | 8e81cc1 | 2007-08-22 14:01:04 -0700 | [diff] [blame] | 10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 | * | 
|  | 12 | * Device driver for TCG/TCPA TPM (trusted platform module). | 
|  | 13 | * Specifications at www.trustedcomputinggroup.org | 
|  | 14 | * | 
|  | 15 | * This program is free software; you can redistribute it and/or | 
|  | 16 | * modify it under the terms of the GNU General Public License as | 
|  | 17 | * published by the Free Software Foundation, version 2 of the | 
|  | 18 | * License. | 
|  | 19 | * | 
|  | 20 | */ | 
|  | 21 | #include <linux/module.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 22 | #include <linux/delay.h> | 
|  | 23 | #include <linux/fs.h> | 
| Matthias Kaehlcke | d081d47 | 2007-05-08 00:32:02 -0700 | [diff] [blame] | 24 | #include <linux/mutex.h> | 
| Al Viro | 914e263 | 2006-10-18 13:55:46 -0400 | [diff] [blame] | 25 | #include <linux/sched.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 | #include <linux/miscdevice.h> | 
| Al Viro | bbc5b21 | 2005-11-01 15:14:05 +0000 | [diff] [blame] | 27 | #include <linux/platform_device.h> | 
| Andrew Morton | 276ad0c | 2006-03-25 03:07:35 -0800 | [diff] [blame] | 28 | #include <linux/io.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 |  | 
| Kylene Hall | 3122a88 | 2005-06-23 22:01:48 -0700 | [diff] [blame] | 30 | enum tpm_timeout { | 
|  | 31 | TPM_TIMEOUT = 5,	/* msecs */ | 
|  | 32 | }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 33 |  | 
|  | 34 | /* TPM addresses */ | 
| Kylene Hall | 3122a88 | 2005-06-23 22:01:48 -0700 | [diff] [blame] | 35 | enum tpm_addr { | 
| Kylene Jo Hall | daacdfa | 2005-06-25 14:55:39 -0700 | [diff] [blame] | 36 | TPM_SUPERIO_ADDR = 0x2E, | 
| Kylene Hall | 3122a88 | 2005-06-23 22:01:48 -0700 | [diff] [blame] | 37 | TPM_ADDR = 0x4E, | 
| Kylene Hall | 3122a88 | 2005-06-23 22:01:48 -0700 | [diff] [blame] | 38 | }; | 
|  | 39 |  | 
| Kylene Hall | 6659ca2 | 2005-06-23 22:02:00 -0700 | [diff] [blame] | 40 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, | 
|  | 41 | char *); | 
|  | 42 | extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, | 
|  | 43 | char *); | 
|  | 44 | extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, | 
|  | 45 | char *); | 
| Kylene Jo Hall | 08e96e4 | 2006-04-22 02:37:50 -0700 | [diff] [blame] | 46 | extern ssize_t tpm_show_caps_1_2(struct device *, struct device_attribute *attr, | 
|  | 47 | char *); | 
| Kylene Hall | 6659ca2 | 2005-06-23 22:02:00 -0700 | [diff] [blame] | 48 | extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, | 
|  | 49 | const char *, size_t); | 
| Kylene Jo Hall | 08e96e4 | 2006-04-22 02:37:50 -0700 | [diff] [blame] | 50 | extern ssize_t tpm_show_enabled(struct device *, struct device_attribute *attr, | 
|  | 51 | char *); | 
|  | 52 | extern ssize_t tpm_show_active(struct device *, struct device_attribute *attr, | 
|  | 53 | char *); | 
|  | 54 | extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, | 
|  | 55 | char *); | 
|  | 56 | extern ssize_t tpm_show_temp_deactivated(struct device *, | 
|  | 57 | struct device_attribute *attr, char *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 58 |  | 
|  | 59 | struct tpm_chip; | 
|  | 60 |  | 
|  | 61 | struct tpm_vendor_specific { | 
| Kylene Jo Hall | e0dd03c | 2006-04-22 02:37:26 -0700 | [diff] [blame] | 62 | const u8 req_complete_mask; | 
|  | 63 | const u8 req_complete_val; | 
|  | 64 | const u8 req_canceled; | 
| Kylene Jo Hall | ad5ea3c | 2005-11-13 16:07:41 -0800 | [diff] [blame] | 65 | void __iomem *iobase;		/* ioremapped address */ | 
|  | 66 | unsigned long base;		/* TPM base address */ | 
|  | 67 |  | 
| Leendert van Doorn | 27084ef | 2006-04-22 02:38:03 -0700 | [diff] [blame] | 68 | int irq; | 
|  | 69 |  | 
| Kylene Jo Hall | ad5ea3c | 2005-11-13 16:07:41 -0800 | [diff] [blame] | 70 | int region_size; | 
|  | 71 | int have_region; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 |  | 
|  | 73 | int (*recv) (struct tpm_chip *, u8 *, size_t); | 
|  | 74 | int (*send) (struct tpm_chip *, u8 *, size_t); | 
|  | 75 | void (*cancel) (struct tpm_chip *); | 
| Kylene Jo Hall | b4ed3e3 | 2005-10-30 15:03:23 -0800 | [diff] [blame] | 76 | u8 (*status) (struct tpm_chip *); | 
| Richard MUSIL | 5bd91f1 | 2008-02-06 01:37:02 -0800 | [diff] [blame] | 77 | void (*release) (struct device *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | struct miscdevice miscdev; | 
| Kylene Hall | 6659ca2 | 2005-06-23 22:02:00 -0700 | [diff] [blame] | 79 | struct attribute_group *attr_group; | 
| Leendert van Doorn | 27084ef | 2006-04-22 02:38:03 -0700 | [diff] [blame] | 80 | struct list_head list; | 
|  | 81 | int locality; | 
| Kylene Jo Hall | 36b2002 | 2006-04-22 02:38:19 -0700 | [diff] [blame] | 82 | unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ | 
|  | 83 | unsigned long duration[3]; /* jiffies */ | 
| Leendert van Doorn | 27084ef | 2006-04-22 02:38:03 -0700 | [diff] [blame] | 84 |  | 
|  | 85 | wait_queue_head_t read_queue; | 
|  | 86 | wait_queue_head_t int_queue; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 87 | }; | 
|  | 88 |  | 
|  | 89 | struct tpm_chip { | 
| Kylene Jo Hall | e659a3f | 2005-10-30 15:03:24 -0800 | [diff] [blame] | 90 | struct device *dev;	/* Device stuff */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 |  | 
|  | 92 | int dev_num;		/* /dev/tpm# */ | 
|  | 93 | int num_opens;		/* only one allowed */ | 
|  | 94 | int time_expired; | 
|  | 95 |  | 
|  | 96 | /* Data passed to and from the tpm via the read/write calls */ | 
|  | 97 | u8 *data_buffer; | 
|  | 98 | atomic_t data_pending; | 
| Matthias Kaehlcke | d081d47 | 2007-05-08 00:32:02 -0700 | [diff] [blame] | 99 | struct mutex buffer_mutex; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 100 |  | 
|  | 101 | struct timer_list user_read_timer;	/* user needs to claim result */ | 
| Kylene Jo Hall | 09e12f9 | 2005-11-13 16:07:43 -0800 | [diff] [blame] | 102 | struct work_struct work; | 
| Matthias Kaehlcke | d081d47 | 2007-05-08 00:32:02 -0700 | [diff] [blame] | 103 | struct mutex tpm_mutex;	/* tpm is processing */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 |  | 
| Kylene Jo Hall | 90dda52 | 2006-04-22 02:37:15 -0700 | [diff] [blame] | 105 | struct tpm_vendor_specific vendor; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 |  | 
| Kylene Jo Hall | 55a82ab | 2006-01-08 01:03:15 -0800 | [diff] [blame] | 107 | struct dentry **bios_dir; | 
|  | 108 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | struct list_head list; | 
| Richard MUSIL | 5bd91f1 | 2008-02-06 01:37:02 -0800 | [diff] [blame] | 110 | void (*release) (struct device *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | }; | 
|  | 112 |  | 
| Leendert van Doorn | 27084ef | 2006-04-22 02:38:03 -0700 | [diff] [blame] | 113 | #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) | 
|  | 114 |  | 
| Kylene Jo Hall | daacdfa | 2005-06-25 14:55:39 -0700 | [diff] [blame] | 115 | static inline int tpm_read_index(int base, int index) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 116 | { | 
| Kylene Jo Hall | daacdfa | 2005-06-25 14:55:39 -0700 | [diff] [blame] | 117 | outb(index, base); | 
|  | 118 | return inb(base+1) & 0xFF; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 | } | 
|  | 120 |  | 
| Kylene Jo Hall | daacdfa | 2005-06-25 14:55:39 -0700 | [diff] [blame] | 121 | static inline void tpm_write_index(int base, int index, int value) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | { | 
| Kylene Jo Hall | daacdfa | 2005-06-25 14:55:39 -0700 | [diff] [blame] | 123 | outb(index, base); | 
|  | 124 | outb(value & 0xFF, base+1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 125 | } | 
|  | 126 |  | 
| Kylene Jo Hall | 08e96e4 | 2006-04-22 02:37:50 -0700 | [diff] [blame] | 127 | extern void tpm_get_timeouts(struct tpm_chip *); | 
|  | 128 | extern void tpm_gen_interrupt(struct tpm_chip *); | 
|  | 129 | extern void tpm_continue_selftest(struct tpm_chip *); | 
| Kylene Jo Hall | 9e18ee1 | 2006-04-22 02:37:38 -0700 | [diff] [blame] | 130 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); | 
| Kylene Jo Hall | e0dd03c | 2006-04-22 02:37:26 -0700 | [diff] [blame] | 131 | extern struct tpm_chip* tpm_register_hardware(struct device *, | 
|  | 132 | const struct tpm_vendor_specific *); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | extern int tpm_open(struct inode *, struct file *); | 
|  | 134 | extern int tpm_release(struct inode *, struct file *); | 
|  | 135 | extern ssize_t tpm_write(struct file *, const char __user *, size_t, | 
|  | 136 | loff_t *); | 
|  | 137 | extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); | 
| Kylene Jo Hall | e659a3f | 2005-10-30 15:03:24 -0800 | [diff] [blame] | 138 | extern void tpm_remove_hardware(struct device *); | 
| Kylene Jo Hall | ce2c87d | 2005-10-30 15:03:25 -0800 | [diff] [blame] | 139 | extern int tpm_pm_suspend(struct device *, pm_message_t); | 
|  | 140 | extern int tpm_pm_resume(struct device *); | 
| Kylene Jo Hall | 55a82ab | 2006-01-08 01:03:15 -0800 | [diff] [blame] | 141 |  | 
|  | 142 | #ifdef CONFIG_ACPI | 
|  | 143 | extern struct dentry ** tpm_bios_log_setup(char *); | 
|  | 144 | extern void tpm_bios_log_teardown(struct dentry **); | 
|  | 145 | #else | 
| Daniel Walker | bb53a76 | 2006-05-15 09:44:27 -0700 | [diff] [blame] | 146 | static inline struct dentry ** tpm_bios_log_setup(char *name) | 
| Kylene Jo Hall | 55a82ab | 2006-01-08 01:03:15 -0800 | [diff] [blame] | 147 | { | 
|  | 148 | return NULL; | 
|  | 149 | } | 
|  | 150 | static inline void tpm_bios_log_teardown(struct dentry **dir) | 
|  | 151 | { | 
|  | 152 | } | 
|  | 153 | #endif |