Commit | Line | Data |
---|---|---|
b886d83c | 1 | // SPDX-License-Identifier: GPL-2.0-only |
afb5abc2 JS |
2 | /* |
3 | * Copyright (C) 2004 IBM Corporation | |
4 | * Copyright (C) 2014 Intel Corporation | |
5 | * | |
6 | * Authors: | |
7 | * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | |
8 | * Leendert van Doorn <leendert@watson.ibm.com> | |
9 | * Dave Safford <safford@watson.ibm.com> | |
10 | * Reiner Sailer <sailer@watson.ibm.com> | |
11 | * Kylene Hall <kjhall@us.ibm.com> | |
12 | * | |
13 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | |
14 | * | |
15 | * TPM chip management routines. | |
afb5abc2 JS |
16 | */ |
17 | ||
18 | #include <linux/poll.h> | |
19 | #include <linux/slab.h> | |
20 | #include <linux/mutex.h> | |
21 | #include <linux/spinlock.h> | |
22 | #include <linux/freezer.h> | |
313d21ee | 23 | #include <linux/major.h> |
fd3ec366 | 24 | #include <linux/tpm_eventlog.h> |
6e592a06 | 25 | #include <linux/hw_random.h> |
afb5abc2 | 26 | #include "tpm.h" |
afb5abc2 | 27 | |
15516788 SB |
28 | DEFINE_IDR(dev_nums_idr); |
29 | static DEFINE_MUTEX(idr_lock); | |
afb5abc2 | 30 | |
313d21ee | 31 | struct class *tpm_class; |
fdc915f7 | 32 | struct class *tpmrm_class; |
313d21ee JS |
33 | dev_t tpm_devt; |
34 | ||
47a6c28b | 35 | static int tpm_request_locality(struct tpm_chip *chip) |
719b7d81 JS |
36 | { |
37 | int rc; | |
38 | ||
719b7d81 JS |
39 | if (!chip->ops->request_locality) |
40 | return 0; | |
41 | ||
42 | rc = chip->ops->request_locality(chip, 0); | |
43 | if (rc < 0) | |
44 | return rc; | |
45 | ||
46 | chip->locality = rc; | |
47 | return 0; | |
48 | } | |
49 | ||
47a6c28b | 50 | static void tpm_relinquish_locality(struct tpm_chip *chip) |
719b7d81 JS |
51 | { |
52 | int rc; | |
53 | ||
719b7d81 JS |
54 | if (!chip->ops->relinquish_locality) |
55 | return; | |
56 | ||
57 | rc = chip->ops->relinquish_locality(chip, chip->locality); | |
58 | if (rc) | |
59 | dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); | |
60 | ||
61 | chip->locality = -1; | |
62 | } | |
63 | ||
47a6c28b | 64 | static int tpm_cmd_ready(struct tpm_chip *chip) |
719b7d81 | 65 | { |
719b7d81 JS |
66 | if (!chip->ops->cmd_ready) |
67 | return 0; | |
68 | ||
69 | return chip->ops->cmd_ready(chip); | |
70 | } | |
71 | ||
47a6c28b | 72 | static int tpm_go_idle(struct tpm_chip *chip) |
719b7d81 | 73 | { |
719b7d81 JS |
74 | if (!chip->ops->go_idle) |
75 | return 0; | |
76 | ||
77 | return chip->ops->go_idle(chip); | |
78 | } | |
79 | ||
1e5ac630 MB |
80 | static void tpm_clk_enable(struct tpm_chip *chip) |
81 | { | |
82 | if (chip->ops->clk_enable) | |
83 | chip->ops->clk_enable(chip, true); | |
84 | } | |
85 | ||
86 | static void tpm_clk_disable(struct tpm_chip *chip) | |
87 | { | |
88 | if (chip->ops->clk_enable) | |
89 | chip->ops->clk_enable(chip, false); | |
90 | } | |
91 | ||
719b7d81 JS |
92 | /** |
93 | * tpm_chip_start() - power on the TPM | |
94 | * @chip: a TPM chip to use | |
719b7d81 JS |
95 | * |
96 | * Return: | |
97 | * * The response length - OK | |
98 | * * -errno - A system error | |
99 | */ | |
47a6c28b | 100 | int tpm_chip_start(struct tpm_chip *chip) |
719b7d81 JS |
101 | { |
102 | int ret; | |
103 | ||
1e5ac630 | 104 | tpm_clk_enable(chip); |
719b7d81 JS |
105 | |
106 | if (chip->locality == -1) { | |
47a6c28b | 107 | ret = tpm_request_locality(chip); |
719b7d81 | 108 | if (ret) { |
1e5ac630 | 109 | tpm_clk_disable(chip); |
719b7d81 JS |
110 | return ret; |
111 | } | |
112 | } | |
113 | ||
47a6c28b | 114 | ret = tpm_cmd_ready(chip); |
719b7d81 | 115 | if (ret) { |
47a6c28b | 116 | tpm_relinquish_locality(chip); |
1e5ac630 | 117 | tpm_clk_disable(chip); |
719b7d81 JS |
118 | return ret; |
119 | } | |
120 | ||
121 | return 0; | |
122 | } | |
123 | EXPORT_SYMBOL_GPL(tpm_chip_start); | |
124 | ||
125 | /** | |
126 | * tpm_chip_stop() - power off the TPM | |
127 | * @chip: a TPM chip to use | |
719b7d81 JS |
128 | * |
129 | * Return: | |
130 | * * The response length - OK | |
131 | * * -errno - A system error | |
132 | */ | |
47a6c28b | 133 | void tpm_chip_stop(struct tpm_chip *chip) |
719b7d81 | 134 | { |
47a6c28b JS |
135 | tpm_go_idle(chip); |
136 | tpm_relinquish_locality(chip); | |
1e5ac630 | 137 | tpm_clk_disable(chip); |
719b7d81 JS |
138 | } |
139 | EXPORT_SYMBOL_GPL(tpm_chip_stop); | |
140 | ||
4e26195f JG |
141 | /** |
142 | * tpm_try_get_ops() - Get a ref to the tpm_chip | |
143 | * @chip: Chip to ref | |
144 | * | |
145 | * The caller must already have some kind of locking to ensure that chip is | |
146 | * valid. This function will lock the chip so that the ops member can be | |
147 | * accessed safely. The locking prevents tpm_chip_unregister from | |
148 | * completing, so it should not be held for long periods. | |
149 | * | |
150 | * Returns -ERRNO if the chip could not be got. | |
afb5abc2 | 151 | */ |
4e26195f JG |
152 | int tpm_try_get_ops(struct tpm_chip *chip) |
153 | { | |
154 | int rc = -EIO; | |
155 | ||
156 | get_device(&chip->dev); | |
157 | ||
158 | down_read(&chip->ops_sem); | |
159 | if (!chip->ops) | |
a3fbfae8 | 160 | goto out_ops; |
4e26195f | 161 | |
2f257402 | 162 | mutex_lock(&chip->tpm_mutex); |
47a6c28b | 163 | rc = tpm_chip_start(chip); |
a3fbfae8 JS |
164 | if (rc) |
165 | goto out_lock; | |
166 | ||
4e26195f JG |
167 | return 0; |
168 | out_lock: | |
a3fbfae8 JS |
169 | mutex_unlock(&chip->tpm_mutex); |
170 | out_ops: | |
4e26195f JG |
171 | up_read(&chip->ops_sem); |
172 | put_device(&chip->dev); | |
173 | return rc; | |
174 | } | |
175 | EXPORT_SYMBOL_GPL(tpm_try_get_ops); | |
176 | ||
177 | /** | |
178 | * tpm_put_ops() - Release a ref to the tpm_chip | |
179 | * @chip: Chip to put | |
180 | * | |
181 | * This is the opposite pair to tpm_try_get_ops(). After this returns chip may | |
182 | * be kfree'd. | |
183 | */ | |
184 | void tpm_put_ops(struct tpm_chip *chip) | |
185 | { | |
47a6c28b | 186 | tpm_chip_stop(chip); |
2f257402 | 187 | mutex_unlock(&chip->tpm_mutex); |
4e26195f JG |
188 | up_read(&chip->ops_sem); |
189 | put_device(&chip->dev); | |
190 | } | |
191 | EXPORT_SYMBOL_GPL(tpm_put_ops); | |
192 | ||
aaae8153 SB |
193 | /** |
194 | * tpm_default_chip() - find a TPM chip and get a reference to it | |
195 | */ | |
196 | struct tpm_chip *tpm_default_chip(void) | |
197 | { | |
198 | struct tpm_chip *chip, *res = NULL; | |
199 | int chip_num = 0; | |
200 | int chip_prev; | |
201 | ||
202 | mutex_lock(&idr_lock); | |
203 | ||
204 | do { | |
205 | chip_prev = chip_num; | |
206 | chip = idr_get_next(&dev_nums_idr, &chip_num); | |
207 | if (chip) { | |
208 | get_device(&chip->dev); | |
209 | res = chip; | |
210 | break; | |
211 | } | |
212 | } while (chip_prev != chip_num); | |
213 | ||
214 | mutex_unlock(&idr_lock); | |
215 | ||
216 | return res; | |
217 | } | |
218 | EXPORT_SYMBOL_GPL(tpm_default_chip); | |
219 | ||
4e26195f | 220 | /** |
fc1d52b7 | 221 | * tpm_find_get_ops() - find and reserve a TPM chip |
aad887f6 | 222 | * @chip: a &struct tpm_chip instance, %NULL for the default chip |
4e26195f | 223 | * |
aad887f6 | 224 | * Finds a TPM chip and reserves its class device and operations. The chip must |
fc1d52b7 SB |
225 | * be released with tpm_put_ops() after use. |
226 | * This function is for internal use only. It supports existing TPM callers | |
227 | * by accepting NULL, but those callers should be converted to pass in a chip | |
228 | * directly. | |
aad887f6 JS |
229 | * |
230 | * Return: | |
231 | * A reserved &struct tpm_chip instance. | |
232 | * %NULL if a chip is not found. | |
233 | * %NULL if the chip is not available. | |
37f4915f | 234 | */ |
fc1d52b7 | 235 | struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) |
afb5abc2 | 236 | { |
eccc9bb8 | 237 | int rc; |
15516788 | 238 | |
eccc9bb8 | 239 | if (chip) { |
aad887f6 | 240 | if (!tpm_try_get_ops(chip)) |
eccc9bb8 SB |
241 | return chip; |
242 | return NULL; | |
15516788 | 243 | } |
afb5abc2 | 244 | |
eccc9bb8 SB |
245 | chip = tpm_default_chip(); |
246 | if (!chip) | |
247 | return NULL; | |
248 | rc = tpm_try_get_ops(chip); | |
249 | /* release additional reference we got from tpm_default_chip() */ | |
250 | put_device(&chip->dev); | |
251 | if (rc) | |
252 | return NULL; | |
253 | return chip; | |
afb5abc2 JS |
254 | } |
255 | ||
256 | /** | |
313d21ee JS |
257 | * tpm_dev_release() - free chip memory and the device number |
258 | * @dev: the character device for the TPM chip | |
afb5abc2 | 259 | * |
313d21ee | 260 | * This is used as the release function for the character device. |
afb5abc2 | 261 | */ |
313d21ee | 262 | static void tpm_dev_release(struct device *dev) |
afb5abc2 | 263 | { |
313d21ee | 264 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); |
afb5abc2 | 265 | |
15516788 SB |
266 | mutex_lock(&idr_lock); |
267 | idr_remove(&dev_nums_idr, chip->dev_num); | |
268 | mutex_unlock(&idr_lock); | |
269 | ||
748935ee | 270 | kfree(chip->log.bios_event_log); |
745b361e | 271 | kfree(chip->work_space.context_buf); |
4d57856a | 272 | kfree(chip->work_space.session_buf); |
bcfff838 | 273 | kfree(chip->allocated_banks); |
afb5abc2 JS |
274 | kfree(chip); |
275 | } | |
276 | ||
fdc915f7 JB |
277 | static void tpm_devs_release(struct device *dev) |
278 | { | |
279 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, devs); | |
280 | ||
281 | /* release the master device reference */ | |
282 | put_device(&chip->dev); | |
283 | } | |
284 | ||
d1bd4a79 JZ |
285 | /** |
286 | * tpm_class_shutdown() - prepare the TPM device for loss of power. | |
287 | * @dev: device to which the chip is associated. | |
288 | * | |
289 | * Issues a TPM2_Shutdown command prior to loss of power, as required by the | |
28eba2fd | 290 | * TPM 2.0 spec. Then, calls bus- and device- specific shutdown code. |
d1bd4a79 | 291 | * |
28eba2fd | 292 | * Return: always 0 (i.e. success) |
d1bd4a79 JZ |
293 | */ |
294 | static int tpm_class_shutdown(struct device *dev) | |
295 | { | |
296 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); | |
297 | ||
db4d8cb9 | 298 | down_write(&chip->ops_sem); |
d1bd4a79 | 299 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
47a6c28b | 300 | if (!tpm_chip_start(chip)) { |
a3fbfae8 | 301 | tpm2_shutdown(chip, TPM2_SU_CLEAR); |
47a6c28b | 302 | tpm_chip_stop(chip); |
a3fbfae8 | 303 | } |
d1bd4a79 | 304 | } |
db4d8cb9 VS |
305 | chip->ops = NULL; |
306 | up_write(&chip->ops_sem); | |
7521621e | 307 | |
d1bd4a79 JZ |
308 | return 0; |
309 | } | |
310 | ||
afb5abc2 | 311 | /** |
3897cd9c JG |
312 | * tpm_chip_alloc() - allocate a new struct tpm_chip instance |
313 | * @pdev: device to which the chip is associated | |
314 | * At this point pdev mst be initialized, but does not have to | |
315 | * be registered | |
afb5abc2 JS |
316 | * @ops: struct tpm_class_ops instance |
317 | * | |
318 | * Allocates a new struct tpm_chip instance and assigns a free | |
3897cd9c | 319 | * device number for it. Must be paired with put_device(&chip->dev). |
afb5abc2 | 320 | */ |
2998b02b | 321 | struct tpm_chip *tpm_chip_alloc(struct device *pdev, |
3897cd9c | 322 | const struct tpm_class_ops *ops) |
afb5abc2 JS |
323 | { |
324 | struct tpm_chip *chip; | |
4f3b193d | 325 | int rc; |
afb5abc2 JS |
326 | |
327 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
328 | if (chip == NULL) | |
329 | return ERR_PTR(-ENOMEM); | |
330 | ||
331 | mutex_init(&chip->tpm_mutex); | |
4e26195f | 332 | init_rwsem(&chip->ops_sem); |
afb5abc2 JS |
333 | |
334 | chip->ops = ops; | |
335 | ||
15516788 SB |
336 | mutex_lock(&idr_lock); |
337 | rc = idr_alloc(&dev_nums_idr, NULL, 0, TPM_NUM_DEVICES, GFP_KERNEL); | |
338 | mutex_unlock(&idr_lock); | |
339 | if (rc < 0) { | |
2998b02b | 340 | dev_err(pdev, "No available tpm device numbers\n"); |
afb5abc2 | 341 | kfree(chip); |
15516788 | 342 | return ERR_PTR(rc); |
afb5abc2 | 343 | } |
15516788 | 344 | chip->dev_num = rc; |
afb5abc2 | 345 | |
3635e2ec | 346 | device_initialize(&chip->dev); |
fdc915f7 | 347 | device_initialize(&chip->devs); |
afb5abc2 | 348 | |
313d21ee | 349 | chip->dev.class = tpm_class; |
7521621e | 350 | chip->dev.class->shutdown_pre = tpm_class_shutdown; |
313d21ee | 351 | chip->dev.release = tpm_dev_release; |
2998b02b | 352 | chip->dev.parent = pdev; |
9b774d5c | 353 | chip->dev.groups = chip->groups; |
313d21ee | 354 | |
fdc915f7 JB |
355 | chip->devs.parent = pdev; |
356 | chip->devs.class = tpmrm_class; | |
357 | chip->devs.release = tpm_devs_release; | |
358 | /* get extra reference on main device to hold on | |
359 | * behalf of devs. This holds the chip structure | |
360 | * while cdevs is in use. The corresponding put | |
8979b02a | 361 | * is in the tpm_devs_release (TPM2 only) |
fdc915f7 | 362 | */ |
8979b02a SB |
363 | if (chip->flags & TPM_CHIP_FLAG_TPM2) |
364 | get_device(&chip->dev); | |
fdc915f7 | 365 | |
313d21ee JS |
366 | if (chip->dev_num == 0) |
367 | chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); | |
368 | else | |
369 | chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); | |
370 | ||
fdc915f7 JB |
371 | chip->devs.devt = |
372 | MKDEV(MAJOR(tpm_devt), chip->dev_num + TPM_NUM_DEVICES); | |
373 | ||
3635e2ec | 374 | rc = dev_set_name(&chip->dev, "tpm%d", chip->dev_num); |
fdc915f7 JB |
375 | if (rc) |
376 | goto out; | |
377 | rc = dev_set_name(&chip->devs, "tpmrm%d", chip->dev_num); | |
3635e2ec JG |
378 | if (rc) |
379 | goto out; | |
313d21ee | 380 | |
2998b02b | 381 | if (!pdev) |
2f9f5377 SB |
382 | chip->flags |= TPM_CHIP_FLAG_VIRTUAL; |
383 | ||
313d21ee | 384 | cdev_init(&chip->cdev, &tpm_fops); |
fdc915f7 | 385 | cdev_init(&chip->cdevs, &tpmrm_fops); |
2072df40 | 386 | chip->cdev.owner = THIS_MODULE; |
fdc915f7 | 387 | chip->cdevs.owner = THIS_MODULE; |
313d21ee | 388 | |
745b361e JS |
389 | chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); |
390 | if (!chip->work_space.context_buf) { | |
391 | rc = -ENOMEM; | |
392 | goto out; | |
393 | } | |
4d57856a JB |
394 | chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); |
395 | if (!chip->work_space.session_buf) { | |
396 | rc = -ENOMEM; | |
397 | goto out; | |
398 | } | |
745b361e | 399 | |
877c57d0 | 400 | chip->locality = -1; |
3897cd9c JG |
401 | return chip; |
402 | ||
403 | out: | |
fdc915f7 | 404 | put_device(&chip->devs); |
3897cd9c JG |
405 | put_device(&chip->dev); |
406 | return ERR_PTR(rc); | |
407 | } | |
408 | EXPORT_SYMBOL_GPL(tpm_chip_alloc); | |
409 | ||
410 | /** | |
411 | * tpmm_chip_alloc() - allocate a new struct tpm_chip instance | |
412 | * @pdev: parent device to which the chip is associated | |
413 | * @ops: struct tpm_class_ops instance | |
414 | * | |
415 | * Same as tpm_chip_alloc except devm is used to do the put_device | |
416 | */ | |
417 | struct tpm_chip *tpmm_chip_alloc(struct device *pdev, | |
418 | const struct tpm_class_ops *ops) | |
419 | { | |
420 | struct tpm_chip *chip; | |
421 | int rc; | |
422 | ||
423 | chip = tpm_chip_alloc(pdev, ops); | |
424 | if (IS_ERR(chip)) | |
425 | return chip; | |
426 | ||
2b88cd96 SM |
427 | rc = devm_add_action_or_reset(pdev, |
428 | (void (*)(void *)) put_device, | |
429 | &chip->dev); | |
430 | if (rc) | |
4f3b193d | 431 | return ERR_PTR(rc); |
8e0ee3c9 | 432 | |
3897cd9c | 433 | dev_set_drvdata(pdev, chip); |
3635e2ec | 434 | |
3897cd9c | 435 | return chip; |
afb5abc2 JS |
436 | } |
437 | EXPORT_SYMBOL_GPL(tpmm_chip_alloc); | |
438 | ||
72c91ce8 | 439 | static int tpm_add_char_device(struct tpm_chip *chip) |
313d21ee JS |
440 | { |
441 | int rc; | |
442 | ||
8dbbf582 | 443 | rc = cdev_device_add(&chip->cdev, &chip->dev); |
313d21ee JS |
444 | if (rc) { |
445 | dev_err(&chip->dev, | |
8dbbf582 | 446 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", |
3635e2ec | 447 | dev_name(&chip->dev), MAJOR(chip->dev.devt), |
313d21ee | 448 | MINOR(chip->dev.devt), rc); |
313d21ee JS |
449 | return rc; |
450 | } | |
451 | ||
af82455f LT |
452 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
453 | rc = cdev_device_add(&chip->cdevs, &chip->devs); | |
454 | if (rc) { | |
455 | dev_err(&chip->devs, | |
456 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", | |
457 | dev_name(&chip->devs), MAJOR(chip->devs.devt), | |
458 | MINOR(chip->devs.devt), rc); | |
459 | return rc; | |
460 | } | |
fdc915f7 JB |
461 | } |
462 | ||
15516788 SB |
463 | /* Make the chip available. */ |
464 | mutex_lock(&idr_lock); | |
465 | idr_replace(&dev_nums_idr, chip, chip->dev_num); | |
466 | mutex_unlock(&idr_lock); | |
467 | ||
313d21ee JS |
468 | return rc; |
469 | } | |
470 | ||
72c91ce8 | 471 | static void tpm_del_char_device(struct tpm_chip *chip) |
313d21ee | 472 | { |
8dbbf582 | 473 | cdev_device_del(&chip->cdev, &chip->dev); |
15516788 SB |
474 | |
475 | /* Make the chip unavailable. */ | |
476 | mutex_lock(&idr_lock); | |
477 | idr_replace(&dev_nums_idr, NULL, chip->dev_num); | |
478 | mutex_unlock(&idr_lock); | |
4e26195f JG |
479 | |
480 | /* Make the driver uncallable. */ | |
481 | down_write(&chip->ops_sem); | |
a3fbfae8 | 482 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
47a6c28b | 483 | if (!tpm_chip_start(chip)) { |
a3fbfae8 | 484 | tpm2_shutdown(chip, TPM2_SU_CLEAR); |
47a6c28b | 485 | tpm_chip_stop(chip); |
a3fbfae8 JS |
486 | } |
487 | } | |
4e26195f JG |
488 | chip->ops = NULL; |
489 | up_write(&chip->ops_sem); | |
313d21ee JS |
490 | } |
491 | ||
062807f2 JG |
492 | static void tpm_del_legacy_sysfs(struct tpm_chip *chip) |
493 | { | |
494 | struct attribute **i; | |
495 | ||
2f9f5377 | 496 | if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL)) |
062807f2 | 497 | return; |
34d47b63 | 498 | |
062807f2 JG |
499 | sysfs_remove_link(&chip->dev.parent->kobj, "ppi"); |
500 | ||
501 | for (i = chip->groups[0]->attrs; *i != NULL; ++i) | |
502 | sysfs_remove_link(&chip->dev.parent->kobj, (*i)->name); | |
34d47b63 JS |
503 | } |
504 | ||
062807f2 JG |
505 | /* For compatibility with legacy sysfs paths we provide symlinks from the |
506 | * parent dev directory to selected names within the tpm chip directory. Old | |
507 | * kernel versions created these files directly under the parent. | |
508 | */ | |
509 | static int tpm_add_legacy_sysfs(struct tpm_chip *chip) | |
510 | { | |
511 | struct attribute **i; | |
512 | int rc; | |
513 | ||
2f9f5377 | 514 | if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL)) |
062807f2 JG |
515 | return 0; |
516 | ||
70fbdfef LT |
517 | rc = compat_only_sysfs_link_entry_to_kobj( |
518 | &chip->dev.parent->kobj, &chip->dev.kobj, "ppi", NULL); | |
062807f2 JG |
519 | if (rc && rc != -ENOENT) |
520 | return rc; | |
521 | ||
522 | /* All the names from tpm-sysfs */ | |
523 | for (i = chip->groups[0]->attrs; *i != NULL; ++i) { | |
70fbdfef LT |
524 | rc = compat_only_sysfs_link_entry_to_kobj( |
525 | &chip->dev.parent->kobj, &chip->dev.kobj, (*i)->name, NULL); | |
062807f2 JG |
526 | if (rc) { |
527 | tpm_del_legacy_sysfs(chip); | |
528 | return rc; | |
529 | } | |
530 | } | |
531 | ||
532 | return 0; | |
533 | } | |
6e592a06 JG |
534 | |
535 | static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) | |
536 | { | |
537 | struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); | |
538 | ||
539 | return tpm_get_random(chip, data, max); | |
540 | } | |
541 | ||
542 | static int tpm_add_hwrng(struct tpm_chip *chip) | |
543 | { | |
544 | if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) | |
545 | return 0; | |
546 | ||
547 | snprintf(chip->hwrng_name, sizeof(chip->hwrng_name), | |
548 | "tpm-rng-%d", chip->dev_num); | |
549 | chip->hwrng.name = chip->hwrng_name; | |
550 | chip->hwrng.read = tpm_hwrng_read; | |
551 | return hwrng_register(&chip->hwrng); | |
552 | } | |
553 | ||
fa4f99c0 NJ |
554 | static int tpm_get_pcr_allocation(struct tpm_chip *chip) |
555 | { | |
556 | int rc; | |
557 | ||
558 | rc = (chip->flags & TPM_CHIP_FLAG_TPM2) ? | |
559 | tpm2_get_pcr_allocation(chip) : | |
560 | tpm1_get_pcr_allocation(chip); | |
561 | ||
562 | if (rc > 0) | |
563 | return -ENODEV; | |
564 | ||
565 | return rc; | |
566 | } | |
567 | ||
afb5abc2 | 568 | /* |
313d21ee | 569 | * tpm_chip_register() - create a character device for the TPM chip |
afb5abc2 JS |
570 | * @chip: TPM chip to use. |
571 | * | |
d972b052 JS |
572 | * Creates a character device for the TPM chip and adds sysfs attributes for |
573 | * the device. As the last step this function adds the chip to the list of TPM | |
574 | * chips available for in-kernel use. | |
afb5abc2 | 575 | * |
d972b052 JS |
576 | * This function should be only called after the chip initialization is |
577 | * complete. | |
afb5abc2 JS |
578 | */ |
579 | int tpm_chip_register(struct tpm_chip *chip) | |
580 | { | |
581 | int rc; | |
582 | ||
47a6c28b | 583 | rc = tpm_chip_start(chip); |
a3fbfae8 JS |
584 | if (rc) |
585 | return rc; | |
b03c4370 | 586 | rc = tpm_auto_startup(chip); |
fa4f99c0 NJ |
587 | if (rc) { |
588 | tpm_chip_stop(chip); | |
589 | return rc; | |
590 | } | |
591 | ||
592 | rc = tpm_get_pcr_allocation(chip); | |
47a6c28b | 593 | tpm_chip_stop(chip); |
b03c4370 TW |
594 | if (rc) |
595 | return rc; | |
cae8b441 | 596 | |
7518a21a JS |
597 | tpm_sysfs_add_device(chip); |
598 | ||
805fa88e | 599 | tpm_bios_log_setup(chip); |
afb5abc2 | 600 | |
9b774d5c JS |
601 | tpm_add_ppi(chip); |
602 | ||
6e592a06 JG |
603 | rc = tpm_add_hwrng(chip); |
604 | if (rc) | |
605 | goto out_ppi; | |
606 | ||
72c91ce8 | 607 | rc = tpm_add_char_device(chip); |
6e592a06 JG |
608 | if (rc) |
609 | goto out_hwrng; | |
d972b052 | 610 | |
062807f2 JG |
611 | rc = tpm_add_legacy_sysfs(chip); |
612 | if (rc) { | |
613 | tpm_chip_unregister(chip); | |
614 | return rc; | |
d56e4f75 JS |
615 | } |
616 | ||
afb5abc2 | 617 | return 0; |
6e592a06 JG |
618 | |
619 | out_hwrng: | |
620 | if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) | |
621 | hwrng_unregister(&chip->hwrng); | |
622 | out_ppi: | |
623 | tpm_bios_log_teardown(chip); | |
624 | ||
625 | return rc; | |
afb5abc2 JS |
626 | } |
627 | EXPORT_SYMBOL_GPL(tpm_chip_register); | |
628 | ||
629 | /* | |
630 | * tpm_chip_unregister() - release the TPM driver | |
631 | * @chip: TPM chip to use. | |
632 | * | |
633 | * Takes the chip first away from the list of available TPM chips and then | |
634 | * cleans up all the resources reserved by tpm_chip_register(). | |
635 | * | |
4e26195f JG |
636 | * Once this function returns the driver call backs in 'op's will not be |
637 | * running and will no longer start. | |
638 | * | |
afb5abc2 JS |
639 | * NOTE: This function should be only called before deinitializing chip |
640 | * resources. | |
641 | */ | |
642 | void tpm_chip_unregister(struct tpm_chip *chip) | |
643 | { | |
062807f2 | 644 | tpm_del_legacy_sysfs(chip); |
6e592a06 JG |
645 | if (IS_ENABLED(CONFIG_HW_RANDOM_TPM)) |
646 | hwrng_unregister(&chip->hwrng); | |
7518a21a | 647 | tpm_bios_log_teardown(chip); |
af82455f LT |
648 | if (chip->flags & TPM_CHIP_FLAG_TPM2) |
649 | cdev_device_del(&chip->cdevs, &chip->devs); | |
72c91ce8 | 650 | tpm_del_char_device(chip); |
afb5abc2 JS |
651 | } |
652 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); |