diff options
author | Stefan Berger <stefanb@linux.vnet.ibm.com> | 2016-02-29 08:53:02 -0500 |
---|---|---|
committer | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | 2016-06-25 10:26:35 -0400 |
commit | 15516788e581eb32ec1c50e5f00aba3faf95d817 (patch) | |
tree | fc21e9a76367a73ba36b1e9315ca8fd741c544d8 | |
parent | 3897cd9c8d1d1a9ff81fed893502911c2b9f4a79 (diff) |
tpm: Replace device number bitmap with IDR
Replace the device number bitmap with IDR. Extend the number of devices we
can create to 64k.
Since an IDR allows us to associate a pointer with an ID, we use this now
to rewrite tpm_chip_find_get() to simply look up the chip pointer by the
given device ID.
Protect the IDR calls with a mutex.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Reviewed-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 84 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 1 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 5 |
3 files changed, 48 insertions, 42 deletions
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 588037733107..f62c8518cd68 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c | |||
@@ -29,9 +29,8 @@ | |||
29 | #include "tpm.h" | 29 | #include "tpm.h" |
30 | #include "tpm_eventlog.h" | 30 | #include "tpm_eventlog.h" |
31 | 31 | ||
32 | static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES); | 32 | DEFINE_IDR(dev_nums_idr); |
33 | static LIST_HEAD(tpm_chip_list); | 33 | static DEFINE_MUTEX(idr_lock); |
34 | static DEFINE_SPINLOCK(driver_lock); | ||
35 | 34 | ||
36 | struct class *tpm_class; | 35 | struct class *tpm_class; |
37 | dev_t tpm_devt; | 36 | dev_t tpm_devt; |
@@ -88,20 +87,30 @@ EXPORT_SYMBOL_GPL(tpm_put_ops); | |||
88 | */ | 87 | */ |
89 | struct tpm_chip *tpm_chip_find_get(int chip_num) | 88 | struct tpm_chip *tpm_chip_find_get(int chip_num) |
90 | { | 89 | { |
91 | struct tpm_chip *pos, *chip = NULL; | 90 | struct tpm_chip *chip, *res = NULL; |
91 | int chip_prev; | ||
92 | |||
93 | mutex_lock(&idr_lock); | ||
94 | |||
95 | if (chip_num == TPM_ANY_NUM) { | ||
96 | chip_num = 0; | ||
97 | do { | ||
98 | chip_prev = chip_num; | ||
99 | chip = idr_get_next(&dev_nums_idr, &chip_num); | ||
100 | if (chip && !tpm_try_get_ops(chip)) { | ||
101 | res = chip; | ||
102 | break; | ||
103 | } | ||
104 | } while (chip_prev != chip_num); | ||
105 | } else { | ||
106 | chip = idr_find_slowpath(&dev_nums_idr, chip_num); | ||
107 | if (chip && !tpm_try_get_ops(chip)) | ||
108 | res = chip; | ||
109 | } | ||
92 | 110 | ||
93 | rcu_read_lock(); | 111 | mutex_unlock(&idr_lock); |
94 | list_for_each_entry_rcu(pos, &tpm_chip_list, list) { | ||
95 | if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num) | ||
96 | continue; | ||
97 | 112 | ||
98 | /* rcu prevents chip from being free'd */ | 113 | return res; |
99 | if (!tpm_try_get_ops(pos)) | ||
100 | chip = pos; | ||
101 | break; | ||
102 | } | ||
103 | rcu_read_unlock(); | ||
104 | return chip; | ||
105 | } | 114 | } |
106 | 115 | ||
107 | /** | 116 | /** |
@@ -114,9 +123,10 @@ static void tpm_dev_release(struct device *dev) | |||
114 | { | 123 | { |
115 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); | 124 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); |
116 | 125 | ||
117 | spin_lock(&driver_lock); | 126 | mutex_lock(&idr_lock); |
118 | clear_bit(chip->dev_num, dev_mask); | 127 | idr_remove(&dev_nums_idr, chip->dev_num); |
119 | spin_unlock(&driver_lock); | 128 | mutex_unlock(&idr_lock); |
129 | |||
120 | kfree(chip); | 130 | kfree(chip); |
121 | } | 131 | } |
122 | 132 | ||
@@ -142,21 +152,18 @@ struct tpm_chip *tpm_chip_alloc(struct device *dev, | |||
142 | 152 | ||
143 | mutex_init(&chip->tpm_mutex); | 153 | mutex_init(&chip->tpm_mutex); |
144 | init_rwsem(&chip->ops_sem); | 154 | init_rwsem(&chip->ops_sem); |
145 | INIT_LIST_HEAD(&chip->list); | ||
146 | 155 | ||
147 | chip->ops = ops; | 156 | chip->ops = ops; |
148 | 157 | ||
149 | spin_lock(&driver_lock); | 158 | mutex_lock(&idr_lock); |
150 | chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES); | 159 | rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL); |
151 | spin_unlock(&driver_lock); | 160 | mutex_unlock(&idr_lock); |
152 | 161 | if (rc < 0) { | |
153 | if (chip->dev_num >= TPM_NUM_DEVICES) { | ||
154 | dev_err(dev, "No available tpm device numbers\n"); | 162 | dev_err(dev, "No available tpm device numbers\n"); |
155 | kfree(chip); | 163 | kfree(chip); |
156 | return ERR_PTR(-ENOMEM); | 164 | return ERR_PTR(rc); |
157 | } | 165 | } |
158 | 166 | chip->dev_num = rc; | |
159 | set_bit(chip->dev_num, dev_mask); | ||
160 | 167 | ||
161 | device_initialize(&chip->dev); | 168 | device_initialize(&chip->dev); |
162 | 169 | ||
@@ -242,19 +249,28 @@ static int tpm_add_char_device(struct tpm_chip *chip) | |||
242 | return rc; | 249 | return rc; |
243 | } | 250 | } |
244 | 251 | ||
252 | /* Make the chip available. */ | ||
253 | mutex_lock(&idr_lock); | ||
254 | idr_replace(&dev_nums_idr, chip, chip->dev_num); | ||
255 | mutex_unlock(&idr_lock); | ||
256 | |||
245 | return rc; | 257 | return rc; |
246 | } | 258 | } |
247 | 259 | ||
248 | static void tpm_del_char_device(struct tpm_chip *chip) | 260 | static void tpm_del_char_device(struct tpm_chip *chip) |
249 | { | 261 | { |
250 | cdev_del(&chip->cdev); | 262 | cdev_del(&chip->cdev); |
263 | device_del(&chip->dev); | ||
264 | |||
265 | /* Make the chip unavailable. */ | ||
266 | mutex_lock(&idr_lock); | ||
267 | idr_replace(&dev_nums_idr, NULL, chip->dev_num); | ||
268 | mutex_unlock(&idr_lock); | ||
251 | 269 | ||
252 | /* Make the driver uncallable. */ | 270 | /* Make the driver uncallable. */ |
253 | down_write(&chip->ops_sem); | 271 | down_write(&chip->ops_sem); |
254 | chip->ops = NULL; | 272 | chip->ops = NULL; |
255 | up_write(&chip->ops_sem); | 273 | up_write(&chip->ops_sem); |
256 | |||
257 | device_del(&chip->dev); | ||
258 | } | 274 | } |
259 | 275 | ||
260 | static int tpm1_chip_register(struct tpm_chip *chip) | 276 | static int tpm1_chip_register(struct tpm_chip *chip) |
@@ -309,11 +325,6 @@ int tpm_chip_register(struct tpm_chip *chip) | |||
309 | if (rc) | 325 | if (rc) |
310 | goto out_err; | 326 | goto out_err; |
311 | 327 | ||
312 | /* Make the chip available. */ | ||
313 | spin_lock(&driver_lock); | ||
314 | list_add_tail_rcu(&chip->list, &tpm_chip_list); | ||
315 | spin_unlock(&driver_lock); | ||
316 | |||
317 | chip->flags |= TPM_CHIP_FLAG_REGISTERED; | 328 | chip->flags |= TPM_CHIP_FLAG_REGISTERED; |
318 | 329 | ||
319 | if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { | 330 | if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { |
@@ -350,11 +361,6 @@ void tpm_chip_unregister(struct tpm_chip *chip) | |||
350 | if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) | 361 | if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) |
351 | return; | 362 | return; |
352 | 363 | ||
353 | spin_lock(&driver_lock); | ||
354 | list_del_rcu(&chip->list); | ||
355 | spin_unlock(&driver_lock); | ||
356 | synchronize_rcu(); | ||
357 | |||
358 | if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) | 364 | if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) |
359 | sysfs_remove_link(&chip->dev.parent->kobj, "ppi"); | 365 | sysfs_remove_link(&chip->dev.parent->kobj, "ppi"); |
360 | 366 | ||
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 5caf15421ef7..5397b64b6c96 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c | |||
@@ -1139,6 +1139,7 @@ static int __init tpm_init(void) | |||
1139 | 1139 | ||
1140 | static void __exit tpm_exit(void) | 1140 | static void __exit tpm_exit(void) |
1141 | { | 1141 | { |
1142 | idr_destroy(&dev_nums_idr); | ||
1142 | class_destroy(tpm_class); | 1143 | class_destroy(tpm_class); |
1143 | unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); | 1144 | unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES); |
1144 | } | 1145 | } |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 5fcf7885a4b9..928b47f58771 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -34,7 +34,7 @@ | |||
34 | enum tpm_const { | 34 | enum tpm_const { |
35 | TPM_MINOR = 224, /* officially assigned */ | 35 | TPM_MINOR = 224, /* officially assigned */ |
36 | TPM_BUFSIZE = 4096, | 36 | TPM_BUFSIZE = 4096, |
37 | TPM_NUM_DEVICES = 256, | 37 | TPM_NUM_DEVICES = 65536, |
38 | TPM_RETRY = 50, /* 5 seconds */ | 38 | TPM_RETRY = 50, /* 5 seconds */ |
39 | }; | 39 | }; |
40 | 40 | ||
@@ -195,8 +195,6 @@ struct tpm_chip { | |||
195 | acpi_handle acpi_dev_handle; | 195 | acpi_handle acpi_dev_handle; |
196 | char ppi_version[TPM_PPI_VERSION_LEN + 1]; | 196 | char ppi_version[TPM_PPI_VERSION_LEN + 1]; |
197 | #endif /* CONFIG_ACPI */ | 197 | #endif /* CONFIG_ACPI */ |
198 | |||
199 | struct list_head list; | ||
200 | }; | 198 | }; |
201 | 199 | ||
202 | #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) | 200 | #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev) |
@@ -492,6 +490,7 @@ static inline void tpm_buf_append_u32(struct tpm_buf *buf, const u32 value) | |||
492 | extern struct class *tpm_class; | 490 | extern struct class *tpm_class; |
493 | extern dev_t tpm_devt; | 491 | extern dev_t tpm_devt; |
494 | extern const struct file_operations tpm_fops; | 492 | extern const struct file_operations tpm_fops; |
493 | extern struct idr dev_nums_idr; | ||
495 | 494 | ||
496 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); | 495 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); |
497 | ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | 496 | ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, |