Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tpm: device class for tpm

Added own device class for TPM. Uses MISC_MAJOR:TPM_MINOR for the
first character device in order to retain backwards compatibility.
Added tpm_dev_release() back attached to the character device.

I've been running this code now for a while on my laptop (Lenovo
T430S) TrouSerS works perfectly without modifications. I don't
believe it breaks anything significantly.

The sysfs attributes that have been placed under the wrong place
and are against sysfs-rules.txt should be probably left to
stagnate under platform device directory and start defining
new sysfs attributes to the char device directory.

Guidelines for future TPM sysfs attributes should be probably
along the lines of

- Single flat set of mandatory sysfs attributes. For example,
current PPI interface is way way too rich when you only want
to use it to clear and activate the TPM.

- Define sysfs attribute if and only if there's no way to get
the value from ring-3. No attributes for TPM properties. It's
just unnecessary maintenance hurdle that we don't want.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jasob Gunthorpe <jason.gunthorpe@obsidianresearch.com>
Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Tested-by: Scot Doyle <lkml14@scotdoyle.com>
Tested-by: Peter Huewe <peterhuewe@gmx.de>
Signed-off-by: Peter Huewe <peterhuewe@gmx.de>

authored by

Jarkko Sakkinen and committed by
Peter Huewe
313d21ee 71ed848f

+116 -61
+11 -11
Documentation/ABI/stable/sysfs-class-tpm
··· 1 - What: /sys/class/misc/tpmX/device/ 1 + What: /sys/class/tpm/tpmX/device/ 2 2 Date: April 2005 3 3 KernelVersion: 2.6.12 4 4 Contact: tpmdd-devel@lists.sf.net ··· 6 6 the properties of that TPM chip 7 7 8 8 9 - What: /sys/class/misc/tpmX/device/active 9 + What: /sys/class/tpm/tpmX/device/active 10 10 Date: April 2006 11 11 KernelVersion: 2.6.17 12 12 Contact: tpmdd-devel@lists.sf.net ··· 18 18 section 17 for more information on which commands are 19 19 available. 20 20 21 - What: /sys/class/misc/tpmX/device/cancel 21 + What: /sys/class/tpm/tpmX/device/cancel 22 22 Date: June 2005 23 23 KernelVersion: 2.6.13 24 24 Contact: tpmdd-devel@lists.sf.net ··· 26 26 pending TPM command. Writing any value to cancel will call the 27 27 TPM vendor specific cancel operation. 28 28 29 - What: /sys/class/misc/tpmX/device/caps 29 + What: /sys/class/tpm/tpmX/device/caps 30 30 Date: April 2005 31 31 KernelVersion: 2.6.12 32 32 Contact: tpmdd-devel@lists.sf.net ··· 43 43 the chip supports. Firmware version is that of the chip and 44 44 is manufacturer specific. 45 45 46 - What: /sys/class/misc/tpmX/device/durations 46 + What: /sys/class/tpm/tpmX/device/durations 47 47 Date: March 2011 48 48 KernelVersion: 3.1 49 49 Contact: tpmdd-devel@lists.sf.net ··· 66 66 scaled to be displayed in usecs. In this case "[adjusted]" 67 67 will be displayed in place of "[original]". 68 68 69 - What: /sys/class/misc/tpmX/device/enabled 69 + What: /sys/class/tpm/tpmX/device/enabled 70 70 Date: April 2006 71 71 KernelVersion: 2.6.17 72 72 Contact: tpmdd-devel@lists.sf.net ··· 75 75 may be visible but produce a '0' after some operation that 76 76 disables the TPM. 77 77 78 - What: /sys/class/misc/tpmX/device/owned 78 + What: /sys/class/tpm/tpmX/device/owned 79 79 Date: April 2006 80 80 KernelVersion: 2.6.17 81 81 Contact: tpmdd-devel@lists.sf.net ··· 83 83 ordinal has been executed successfully in the chip. A '0' 84 84 indicates that ownership hasn't been taken. 85 85 86 - What: /sys/class/misc/tpmX/device/pcrs 86 + What: /sys/class/tpm/tpmX/device/pcrs 87 87 Date: April 2005 88 88 KernelVersion: 2.6.12 89 89 Contact: tpmdd-devel@lists.sf.net ··· 106 106 1.2 chips, PCRs represent SHA-1 hashes, which are 20 bytes 107 107 long. Use the "caps" property to determine TPM version. 108 108 109 - What: /sys/class/misc/tpmX/device/pubek 109 + What: /sys/class/tpm/tpmX/device/pubek 110 110 Date: April 2005 111 111 KernelVersion: 2.6.12 112 112 Contact: tpmdd-devel@lists.sf.net ··· 158 158 Modulus Length: 256 (bytes) 159 159 Modulus: The 256 byte Endorsement Key modulus 160 160 161 - What: /sys/class/misc/tpmX/device/temp_deactivated 161 + What: /sys/class/tpm/tpmX/device/temp_deactivated 162 162 Date: April 2006 163 163 KernelVersion: 2.6.17 164 164 Contact: tpmdd-devel@lists.sf.net ··· 167 167 cycle. Whether a warm boot (reboot) will clear a TPM chip 168 168 from a temp_deactivated state is platform specific. 169 169 170 - What: /sys/class/misc/tpmX/device/timeouts 170 + What: /sys/class/tpm/tpmX/device/timeouts 171 171 Date: March 2011 172 172 KernelVersion: 3.1 173 173 Contact: tpmdd-devel@lists.sf.net
+62 -10
drivers/char/tpm/tpm-chip.c
··· 25 25 #include <linux/mutex.h> 26 26 #include <linux/spinlock.h> 27 27 #include <linux/freezer.h> 28 + #include <linux/major.h> 28 29 #include "tpm.h" 29 30 #include "tpm_eventlog.h" 30 31 31 32 static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); 32 33 static LIST_HEAD(tpm_chip_list); 33 34 static DEFINE_SPINLOCK(driver_lock); 35 + 36 + struct class *tpm_class; 37 + dev_t tpm_devt; 34 38 35 39 /* 36 40 * tpm_chip_find_get - return tpm_chip for a given chip number ··· 59 55 } 60 56 61 57 /** 62 - * tpmm_chip_remove() - free chip memory and device number 63 - * @data: points to struct tpm_chip instance 58 + * tpm_dev_release() - free chip memory and the device number 59 + * @dev: the character device for the TPM chip 64 60 * 65 - * This is used internally by tpmm_chip_alloc() and called by devres 66 - * when the device is released. This function does the opposite of 67 - * tpmm_chip_alloc() freeing memory and the device number. 61 + * This is used as the release function for the character device. 68 62 */ 69 - static void tpmm_chip_remove(void *data) 63 + static void tpm_dev_release(struct device *dev) 70 64 { 71 - struct tpm_chip *chip = (struct tpm_chip *) data; 65 + struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); 72 66 73 67 spin_lock(&driver_lock); 74 68 clear_bit(chip->dev_num, dev_mask); ··· 113 111 scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num); 114 112 115 113 chip->pdev = dev; 116 - devm_add_action(dev, tpmm_chip_remove, chip); 114 + 117 115 dev_set_drvdata(dev, chip); 116 + 117 + chip->dev.class = tpm_class; 118 + chip->dev.release = tpm_dev_release; 119 + chip->dev.parent = chip->pdev; 120 + 121 + if (chip->dev_num == 0) 122 + chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); 123 + else 124 + chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); 125 + 126 + dev_set_name(&chip->dev, chip->devname); 127 + 128 + device_initialize(&chip->dev); 129 + 130 + chip->cdev.owner = chip->pdev->driver->owner; 131 + cdev_init(&chip->cdev, &tpm_fops); 118 132 119 133 return chip; 120 134 } 121 135 EXPORT_SYMBOL_GPL(tpmm_chip_alloc); 122 136 137 + static int tpm_dev_add_device(struct tpm_chip *chip) 138 + { 139 + int rc; 140 + 141 + rc = device_add(&chip->dev); 142 + if (rc) { 143 + dev_err(&chip->dev, 144 + "unable to device_register() %s, major %d, minor %d, err=%d\n", 145 + chip->devname, MAJOR(chip->dev.devt), 146 + MINOR(chip->dev.devt), rc); 147 + 148 + return rc; 149 + } 150 + 151 + rc = cdev_add(&chip->cdev, chip->dev.devt, 1); 152 + if (rc) { 153 + dev_err(&chip->dev, 154 + "unable to cdev_add() %s, major %d, minor %d, err=%d\n", 155 + chip->devname, MAJOR(chip->dev.devt), 156 + MINOR(chip->dev.devt), rc); 157 + 158 + device_unregister(&chip->dev); 159 + return rc; 160 + } 161 + 162 + return rc; 163 + } 164 + 165 + static void tpm_dev_del_device(struct tpm_chip *chip) 166 + { 167 + cdev_del(&chip->cdev); 168 + device_unregister(&chip->dev); 169 + } 170 + 123 171 /* 124 - * tpm_chip_register() - create a misc driver for the TPM chip 172 + * tpm_chip_register() - create a character device for the TPM chip 125 173 * @chip: TPM chip to use. 126 174 * 127 - * Creates a misc driver for the TPM chip and adds sysfs interfaces for 175 + * Creates a character device for the TPM chip and adds sysfs interfaces for 128 176 * the device, PPI and TCPA. As the last step this function adds the 129 177 * chip to the list of TPM chips available for use. 130 178 *
+3 -33
drivers/char/tpm/tpm-dev.c
··· 17 17 * License. 18 18 * 19 19 */ 20 - #include <linux/miscdevice.h> 21 20 #include <linux/slab.h> 22 21 #include <linux/uaccess.h> 23 22 #include "tpm.h" ··· 53 54 54 55 static int tpm_open(struct inode *inode, struct file *file) 55 56 { 56 - struct miscdevice *misc = file->private_data; 57 - struct tpm_chip *chip = container_of(misc, struct tpm_chip, 58 - vendor.miscdev); 57 + struct tpm_chip *chip = 58 + container_of(inode->i_cdev, struct tpm_chip, cdev); 59 59 struct file_priv *priv; 60 60 61 61 /* It's assured that the chip will be opened just once, ··· 171 173 return 0; 172 174 } 173 175 174 - static const struct file_operations tpm_fops = { 176 + const struct file_operations tpm_fops = { 175 177 .owner = THIS_MODULE, 176 178 .llseek = no_llseek, 177 179 .open = tpm_open, ··· 180 182 .release = tpm_release, 181 183 }; 182 184 183 - int tpm_dev_add_device(struct tpm_chip *chip) 184 - { 185 - int rc; 186 185 187 - chip->vendor.miscdev.fops = &tpm_fops; 188 - if (chip->dev_num == 0) 189 - chip->vendor.miscdev.minor = TPM_MINOR; 190 - else 191 - chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR; 192 - 193 - chip->vendor.miscdev.name = chip->devname; 194 - chip->vendor.miscdev.parent = chip->pdev; 195 - 196 - rc = misc_register(&chip->vendor.miscdev); 197 - if (rc) { 198 - chip->vendor.miscdev.name = NULL; 199 - dev_err(chip->pdev, 200 - "unable to misc_register %s, minor %d err=%d\n", 201 - chip->vendor.miscdev.name, 202 - chip->vendor.miscdev.minor, rc); 203 - } 204 - return rc; 205 - } 206 - 207 - void tpm_dev_del_device(struct tpm_chip *chip) 208 - { 209 - if (chip->vendor.miscdev.name) 210 - misc_deregister(&chip->vendor.miscdev); 211 - }
+29
drivers/char/tpm/tpm-interface.c
··· 997 997 } 998 998 EXPORT_SYMBOL_GPL(tpm_get_random); 999 999 1000 + static int __init tpm_init(void) 1001 + { 1002 + int rc; 1003 + 1004 + tpm_class = class_create(THIS_MODULE, "tpm"); 1005 + if (IS_ERR(tpm_class)) { 1006 + pr_err("couldn't create tpm class\n"); 1007 + return PTR_ERR(tpm_class); 1008 + } 1009 + 1010 + rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm"); 1011 + if (rc < 0) { 1012 + pr_err("tpm: failed to allocate char dev region\n"); 1013 + class_destroy(tpm_class); 1014 + return rc; 1015 + } 1016 + 1017 + return 0; 1018 + } 1019 + 1020 + static void __exit tpm_exit(void) 1021 + { 1022 + class_destroy(tpm_class); 1023 + unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); 1024 + } 1025 + 1026 + subsys_initcall(tpm_init); 1027 + module_exit(tpm_exit); 1028 + 1000 1029 MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); 1001 1030 MODULE_DESCRIPTION("TPM Driver"); 1002 1031 MODULE_VERSION("2.0");
+8 -4
drivers/char/tpm/tpm.h
··· 23 23 #include <linux/fs.h> 24 24 #include <linux/mutex.h> 25 25 #include <linux/sched.h> 26 - #include <linux/miscdevice.h> 27 26 #include <linux/platform_device.h> 28 27 #include <linux/io.h> 29 28 #include <linux/tpm.h> 30 29 #include <linux/acpi.h> 30 + #include <linux/cdev.h> 31 31 32 32 enum tpm_const { 33 33 TPM_MINOR = 224, /* officially assigned */ ··· 74 74 int region_size; 75 75 int have_region; 76 76 77 - struct miscdevice miscdev; 78 77 struct list_head list; 79 78 int locality; 80 79 unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ ··· 103 104 104 105 struct tpm_chip { 105 106 struct device *pdev; /* Device stuff */ 107 + struct device dev; 108 + struct cdev cdev; 109 + 106 110 const struct tpm_class_ops *ops; 107 111 unsigned int flags; 108 112 ··· 328 326 tpm_cmd_params params; 329 327 } __packed; 330 328 329 + extern struct class *tpm_class; 330 + extern dev_t tpm_devt; 331 + extern const struct file_operations tpm_fops; 332 + 331 333 ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); 332 334 ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, 333 335 size_t bufsiz); ··· 352 346 extern int tpm_chip_register(struct tpm_chip *chip); 353 347 extern void tpm_chip_unregister(struct tpm_chip *chip); 354 348 355 - int tpm_dev_add_device(struct tpm_chip *chip); 356 - void tpm_dev_del_device(struct tpm_chip *chip); 357 349 int tpm_sysfs_add_device(struct tpm_chip *chip); 358 350 void tpm_sysfs_del_device(struct tpm_chip *chip); 359 351
+1 -1
drivers/char/tpm/tpm_i2c_nuvoton.c
··· 560 560 rc = devm_request_irq(dev, chip->vendor.irq, 561 561 i2c_nuvoton_int_handler, 562 562 IRQF_TRIGGER_LOW, 563 - chip->vendor.miscdev.name, 563 + chip->devname, 564 564 chip); 565 565 if (rc) { 566 566 dev_err(dev, "%s() Unable to request irq: %d for use\n",
+2 -2
drivers/char/tpm/tpm_tis.c
··· 698 698 TPM_INT_VECTOR(chip->vendor.locality)); 699 699 if (devm_request_irq 700 700 (dev, i, tis_int_probe, IRQF_SHARED, 701 - chip->vendor.miscdev.name, chip) != 0) { 701 + chip->devname, chip) != 0) { 702 702 dev_info(chip->pdev, 703 703 "Unable to request irq: %d for probe\n", 704 704 i); ··· 745 745 TPM_INT_VECTOR(chip->vendor.locality)); 746 746 if (devm_request_irq 747 747 (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED, 748 - chip->vendor.miscdev.name, chip) != 0) { 748 + chip->devname, chip) != 0) { 749 749 dev_info(chip->pdev, 750 750 "Unable to request irq: %d for use\n", 751 751 chip->vendor.irq);