aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r--drivers/char/tpm/tpm.c96
-rw-r--r--drivers/char/tpm/tpm.h3
-rw-r--r--drivers/char/tpm/tpm_tis.c14
3 files changed, 61 insertions, 52 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index ae766d868454..1fee7034a386 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -954,72 +954,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel);
954 954
955/* 955/*
956 * Device file system interface to the TPM 956 * Device file system interface to the TPM
957 *
958 * It's assured that the chip will be opened just once,
959 * by the check of is_open variable, which is protected
960 * by driver_lock.
957 */ 961 */
958int tpm_open(struct inode *inode, struct file *file) 962int tpm_open(struct inode *inode, struct file *file)
959{ 963{
960 int rc = 0, minor = iminor(inode); 964 int minor = iminor(inode);
961 struct tpm_chip *chip = NULL, *pos; 965 struct tpm_chip *chip = NULL, *pos;
962 966
963 lock_kernel(); 967 rcu_read_lock();
964 spin_lock(&driver_lock); 968 list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
965
966 list_for_each_entry(pos, &tpm_chip_list, list) {
967 if (pos->vendor.miscdev.minor == minor) { 969 if (pos->vendor.miscdev.minor == minor) {
968 chip = pos; 970 chip = pos;
971 get_device(chip->dev);
969 break; 972 break;
970 } 973 }
971 } 974 }
975 rcu_read_unlock();
972 976
973 if (chip == NULL) { 977 if (!chip)
974 rc = -ENODEV; 978 return -ENODEV;
975 goto err_out;
976 }
977 979
978 if (chip->num_opens) { 980 if (test_and_set_bit(0, &chip->is_open)) {
979 dev_dbg(chip->dev, "Another process owns this TPM\n"); 981 dev_dbg(chip->dev, "Another process owns this TPM\n");
980 rc = -EBUSY; 982 put_device(chip->dev);
981 goto err_out; 983 return -EBUSY;
982 } 984 }
983 985
984 chip->num_opens++;
985 get_device(chip->dev);
986
987 spin_unlock(&driver_lock);
988
989 chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); 986 chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
990 if (chip->data_buffer == NULL) { 987 if (chip->data_buffer == NULL) {
991 chip->num_opens--; 988 clear_bit(0, &chip->is_open);
992 put_device(chip->dev); 989 put_device(chip->dev);
993 unlock_kernel();
994 return -ENOMEM; 990 return -ENOMEM;
995 } 991 }
996 992
997 atomic_set(&chip->data_pending, 0); 993 atomic_set(&chip->data_pending, 0);
998 994
999 file->private_data = chip; 995 file->private_data = chip;
1000 unlock_kernel();
1001 return 0; 996 return 0;
1002
1003err_out:
1004 spin_unlock(&driver_lock);
1005 unlock_kernel();
1006 return rc;
1007} 997}
1008EXPORT_SYMBOL_GPL(tpm_open); 998EXPORT_SYMBOL_GPL(tpm_open);
1009 999
1000/*
1001 * Called on file close
1002 */
1010int tpm_release(struct inode *inode, struct file *file) 1003int tpm_release(struct inode *inode, struct file *file)
1011{ 1004{
1012 struct tpm_chip *chip = file->private_data; 1005 struct tpm_chip *chip = file->private_data;
1013 1006
1007 del_singleshot_timer_sync(&chip->user_read_timer);
1014 flush_scheduled_work(); 1008 flush_scheduled_work();
1015 spin_lock(&driver_lock);
1016 file->private_data = NULL; 1009 file->private_data = NULL;
1017 del_singleshot_timer_sync(&chip->user_read_timer);
1018 atomic_set(&chip->data_pending, 0); 1010 atomic_set(&chip->data_pending, 0);
1019 chip->num_opens--;
1020 put_device(chip->dev);
1021 kfree(chip->data_buffer); 1011 kfree(chip->data_buffer);
1022 spin_unlock(&driver_lock); 1012 clear_bit(0, &chip->is_open);
1013 put_device(chip->dev);
1023 return 0; 1014 return 0;
1024} 1015}
1025EXPORT_SYMBOL_GPL(tpm_release); 1016EXPORT_SYMBOL_GPL(tpm_release);
@@ -1093,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev)
1093 } 1084 }
1094 1085
1095 spin_lock(&driver_lock); 1086 spin_lock(&driver_lock);
1096 1087 list_del_rcu(&chip->list);
1097 list_del(&chip->list);
1098
1099 spin_unlock(&driver_lock); 1088 spin_unlock(&driver_lock);
1089 synchronize_rcu();
1100 1090
1101 misc_deregister(&chip->vendor.miscdev); 1091 misc_deregister(&chip->vendor.miscdev);
1102
1103 sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); 1092 sysfs_remove_group(&dev->kobj, chip->vendor.attr_group);
1104 tpm_bios_log_teardown(chip->bios_dir); 1093 tpm_bios_log_teardown(chip->bios_dir);
1105 1094
@@ -1144,25 +1133,33 @@ int tpm_pm_resume(struct device *dev)
1144} 1133}
1145EXPORT_SYMBOL_GPL(tpm_pm_resume); 1134EXPORT_SYMBOL_GPL(tpm_pm_resume);
1146 1135
1136/* In case vendor provided release function, call it too.*/
1137
1138void tpm_dev_vendor_release(struct tpm_chip *chip)
1139{
1140 if (chip->vendor.release)
1141 chip->vendor.release(chip->dev);
1142
1143 clear_bit(chip->dev_num, dev_mask);
1144 kfree(chip->vendor.miscdev.name);
1145}
1146EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
1147
1148
1147/* 1149/*
1148 * Once all references to platform device are down to 0, 1150 * Once all references to platform device are down to 0,
1149 * release all allocated structures. 1151 * release all allocated structures.
1150 * In case vendor provided release function,
1151 * call it too.
1152 */ 1152 */
1153static void tpm_dev_release(struct device *dev) 1153static void tpm_dev_release(struct device *dev)
1154{ 1154{
1155 struct tpm_chip *chip = dev_get_drvdata(dev); 1155 struct tpm_chip *chip = dev_get_drvdata(dev);
1156 1156
1157 if (chip->vendor.release) 1157 tpm_dev_vendor_release(chip);
1158 chip->vendor.release(dev);
1159 1158
1160 chip->release(dev); 1159 chip->release(dev);
1161
1162 clear_bit(chip->dev_num, dev_mask);
1163 kfree(chip->vendor.miscdev.name);
1164 kfree(chip); 1160 kfree(chip);
1165} 1161}
1162EXPORT_SYMBOL_GPL(tpm_dev_release);
1166 1163
1167/* 1164/*
1168 * Called from tpm_<specific>.c probe function only for devices 1165 * Called from tpm_<specific>.c probe function only for devices
@@ -1171,8 +1168,8 @@ static void tpm_dev_release(struct device *dev)
1171 * upon errant exit from this function specific probe function should call 1168 * upon errant exit from this function specific probe function should call
1172 * pci_disable_device 1169 * pci_disable_device
1173 */ 1170 */
1174struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific 1171struct tpm_chip *tpm_register_hardware(struct device *dev,
1175 *entry) 1172 const struct tpm_vendor_specific *entry)
1176{ 1173{
1177#define DEVNAME_SIZE 7 1174#define DEVNAME_SIZE 7
1178 1175
@@ -1231,21 +1228,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
1231 return NULL; 1228 return NULL;
1232 } 1229 }
1233 1230
1234 spin_lock(&driver_lock);
1235
1236 list_add(&chip->list, &tpm_chip_list);
1237
1238 spin_unlock(&driver_lock);
1239
1240 if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { 1231 if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
1241 list_del(&chip->list);
1242 misc_deregister(&chip->vendor.miscdev); 1232 misc_deregister(&chip->vendor.miscdev);
1243 put_device(chip->dev); 1233 put_device(chip->dev);
1234
1244 return NULL; 1235 return NULL;
1245 } 1236 }
1246 1237
1247 chip->bios_dir = tpm_bios_log_setup(devname); 1238 chip->bios_dir = tpm_bios_log_setup(devname);
1248 1239
1240 /* Make chip available */
1241 spin_lock(&driver_lock);
1242 list_add_rcu(&chip->list, &tpm_chip_list);
1243 spin_unlock(&driver_lock);
1244
1249 return chip; 1245 return chip;
1250} 1246}
1251EXPORT_SYMBOL_GPL(tpm_register_hardware); 1247EXPORT_SYMBOL_GPL(tpm_register_hardware);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e885148b4cfb..8e30df4a4388 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -90,7 +90,7 @@ struct tpm_chip {
90 struct device *dev; /* Device stuff */ 90 struct device *dev; /* Device stuff */
91 91
92 int dev_num; /* /dev/tpm# */ 92 int dev_num; /* /dev/tpm# */
93 int num_opens; /* only one allowed */ 93 unsigned long is_open; /* only one allowed */
94 int time_expired; 94 int time_expired;
95 95
96 /* Data passed to and from the tpm via the read/write calls */ 96 /* Data passed to and from the tpm via the read/write calls */
@@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *,
132 const struct tpm_vendor_specific *); 132 const struct tpm_vendor_specific *);
133extern int tpm_open(struct inode *, struct file *); 133extern int tpm_open(struct inode *, struct file *);
134extern int tpm_release(struct inode *, struct file *); 134extern int tpm_release(struct inode *, struct file *);
135extern void tpm_dev_vendor_release(struct tpm_chip *);
135extern ssize_t tpm_write(struct file *, const char __user *, size_t, 136extern ssize_t tpm_write(struct file *, const char __user *, size_t,
136 loff_t *); 137 loff_t *);
137extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); 138extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index ed1879c0dd8d..717af7ad1bdf 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = {
630 {"", 0} /* Terminator */ 630 {"", 0} /* Terminator */
631}; 631};
632 632
633static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
634{
635 struct tpm_chip *chip = pnp_get_drvdata(dev);
636
637 tpm_dev_vendor_release(chip);
638
639 kfree(chip);
640}
641
642
633static struct pnp_driver tis_pnp_driver = { 643static struct pnp_driver tis_pnp_driver = {
634 .name = "tpm_tis", 644 .name = "tpm_tis",
635 .id_table = tpm_pnp_tbl, 645 .id_table = tpm_pnp_tbl,
636 .probe = tpm_tis_pnp_init, 646 .probe = tpm_tis_pnp_init,
637 .suspend = tpm_tis_pnp_suspend, 647 .suspend = tpm_tis_pnp_suspend,
638 .resume = tpm_tis_pnp_resume, 648 .resume = tpm_tis_pnp_resume,
649 .remove = tpm_tis_pnp_remove,
639}; 650};
640 651
641#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 652#define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -683,6 +694,7 @@ static void __exit cleanup_tis(void)
683 spin_lock(&tis_lock); 694 spin_lock(&tis_lock);
684 list_for_each_entry_safe(i, j, &tis_chips, list) { 695 list_for_each_entry_safe(i, j, &tis_chips, list) {
685 chip = to_tpm_chip(i); 696 chip = to_tpm_chip(i);
697 tpm_remove_hardware(chip->dev);
686 iowrite32(~TPM_GLOBAL_INT_ENABLE & 698 iowrite32(~TPM_GLOBAL_INT_ENABLE &
687 ioread32(chip->vendor.iobase + 699 ioread32(chip->vendor.iobase +
688 TPM_INT_ENABLE(chip->vendor. 700 TPM_INT_ENABLE(chip->vendor.
@@ -694,9 +706,9 @@ static void __exit cleanup_tis(void)
694 free_irq(chip->vendor.irq, chip); 706 free_irq(chip->vendor.irq, chip);
695 iounmap(i->iobase); 707 iounmap(i->iobase);
696 list_del(&i->list); 708 list_del(&i->list);
697 tpm_remove_hardware(chip->dev);
698 } 709 }
699 spin_unlock(&tis_lock); 710 spin_unlock(&tis_lock);
711
700 if (force) { 712 if (force) {
701 platform_device_unregister(pdev); 713 platform_device_unregister(pdev);
702 driver_unregister(&tis_drv); 714 driver_unregister(&tis_drv);