1 | // SPDX-License-Identifier: GPL-2.0-only |
---|---|
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. |
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> |
23 | #include <linux/major.h> |
24 | #include <linux/tpm_eventlog.h> |
25 | #include <linux/hw_random.h> |
26 | #include "tpm.h" |
27 | |
28 | DEFINE_IDR(dev_nums_idr); |
29 | static DEFINE_MUTEX(idr_lock); |
30 | |
31 | const struct class tpm_class = { |
32 | .name = "tpm", |
33 | .shutdown_pre = tpm_class_shutdown, |
34 | }; |
35 | const struct class tpmrm_class = { |
36 | .name = "tpmrm", |
37 | }; |
38 | dev_t tpm_devt; |
39 | |
40 | static int tpm_request_locality(struct tpm_chip *chip) |
41 | { |
42 | int rc; |
43 | |
44 | if (!chip->ops->request_locality) |
45 | return 0; |
46 | |
47 | rc = chip->ops->request_locality(chip, 0); |
48 | if (rc < 0) |
49 | return rc; |
50 | |
51 | chip->locality = rc; |
52 | return 0; |
53 | } |
54 | |
55 | static void tpm_relinquish_locality(struct tpm_chip *chip) |
56 | { |
57 | int rc; |
58 | |
59 | if (!chip->ops->relinquish_locality) |
60 | return; |
61 | |
62 | rc = chip->ops->relinquish_locality(chip, chip->locality); |
63 | if (rc) |
64 | dev_err(&chip->dev, "%s: : error %d\n", __func__, rc); |
65 | |
66 | chip->locality = -1; |
67 | } |
68 | |
69 | static int tpm_cmd_ready(struct tpm_chip *chip) |
70 | { |
71 | if (!chip->ops->cmd_ready) |
72 | return 0; |
73 | |
74 | return chip->ops->cmd_ready(chip); |
75 | } |
76 | |
77 | static int tpm_go_idle(struct tpm_chip *chip) |
78 | { |
79 | if (!chip->ops->go_idle) |
80 | return 0; |
81 | |
82 | return chip->ops->go_idle(chip); |
83 | } |
84 | |
85 | static void tpm_clk_enable(struct tpm_chip *chip) |
86 | { |
87 | if (chip->ops->clk_enable) |
88 | chip->ops->clk_enable(chip, true); |
89 | } |
90 | |
91 | static void tpm_clk_disable(struct tpm_chip *chip) |
92 | { |
93 | if (chip->ops->clk_enable) |
94 | chip->ops->clk_enable(chip, false); |
95 | } |
96 | |
97 | /** |
98 | * tpm_chip_start() - power on the TPM |
99 | * @chip: a TPM chip to use |
100 | * |
101 | * Return: |
102 | * * The response length - OK |
103 | * * -errno - A system error |
104 | */ |
105 | int tpm_chip_start(struct tpm_chip *chip) |
106 | { |
107 | int ret; |
108 | |
109 | tpm_clk_enable(chip); |
110 | |
111 | if (chip->locality == -1) { |
112 | ret = tpm_request_locality(chip); |
113 | if (ret) { |
114 | tpm_clk_disable(chip); |
115 | return ret; |
116 | } |
117 | } |
118 | |
119 | ret = tpm_cmd_ready(chip); |
120 | if (ret) { |
121 | tpm_relinquish_locality(chip); |
122 | tpm_clk_disable(chip); |
123 | return ret; |
124 | } |
125 | |
126 | return 0; |
127 | } |
128 | EXPORT_SYMBOL_GPL(tpm_chip_start); |
129 | |
130 | /** |
131 | * tpm_chip_stop() - power off the TPM |
132 | * @chip: a TPM chip to use |
133 | * |
134 | * Return: |
135 | * * The response length - OK |
136 | * * -errno - A system error |
137 | */ |
138 | void tpm_chip_stop(struct tpm_chip *chip) |
139 | { |
140 | tpm_go_idle(chip); |
141 | tpm_relinquish_locality(chip); |
142 | tpm_clk_disable(chip); |
143 | } |
144 | EXPORT_SYMBOL_GPL(tpm_chip_stop); |
145 | |
146 | /** |
147 | * tpm_try_get_ops() - Get a ref to the tpm_chip |
148 | * @chip: Chip to ref |
149 | * |
150 | * The caller must already have some kind of locking to ensure that chip is |
151 | * valid. This function will lock the chip so that the ops member can be |
152 | * accessed safely. The locking prevents tpm_chip_unregister from |
153 | * completing, so it should not be held for long periods. |
154 | * |
155 | * Returns -ERRNO if the chip could not be got. |
156 | */ |
157 | int tpm_try_get_ops(struct tpm_chip *chip) |
158 | { |
159 | int rc = -EIO; |
160 | |
161 | if (chip->flags & TPM_CHIP_FLAG_DISABLE) |
162 | return rc; |
163 | |
164 | get_device(dev: &chip->dev); |
165 | |
166 | down_read(sem: &chip->ops_sem); |
167 | if (!chip->ops) |
168 | goto out_ops; |
169 | |
170 | mutex_lock(&chip->tpm_mutex); |
171 | |
172 | /* tmp_chip_start may issue IO that is denied while suspended */ |
173 | if (chip->flags & TPM_CHIP_FLAG_SUSPENDED) |
174 | goto out_lock; |
175 | |
176 | rc = tpm_chip_start(chip); |
177 | if (rc) |
178 | goto out_lock; |
179 | |
180 | return 0; |
181 | out_lock: |
182 | mutex_unlock(lock: &chip->tpm_mutex); |
183 | out_ops: |
184 | up_read(sem: &chip->ops_sem); |
185 | put_device(dev: &chip->dev); |
186 | return rc; |
187 | } |
188 | EXPORT_SYMBOL_GPL(tpm_try_get_ops); |
189 | |
190 | /** |
191 | * tpm_put_ops() - Release a ref to the tpm_chip |
192 | * @chip: Chip to put |
193 | * |
194 | * This is the opposite pair to tpm_try_get_ops(). After this returns chip may |
195 | * be kfree'd. |
196 | */ |
197 | void tpm_put_ops(struct tpm_chip *chip) |
198 | { |
199 | tpm_chip_stop(chip); |
200 | mutex_unlock(lock: &chip->tpm_mutex); |
201 | up_read(sem: &chip->ops_sem); |
202 | put_device(dev: &chip->dev); |
203 | } |
204 | EXPORT_SYMBOL_GPL(tpm_put_ops); |
205 | |
206 | /** |
207 | * tpm_default_chip() - find a TPM chip and get a reference to it |
208 | */ |
209 | struct tpm_chip *tpm_default_chip(void) |
210 | { |
211 | struct tpm_chip *chip, *res = NULL; |
212 | int chip_num = 0; |
213 | int chip_prev; |
214 | |
215 | mutex_lock(&idr_lock); |
216 | |
217 | do { |
218 | chip_prev = chip_num; |
219 | chip = idr_get_next(&dev_nums_idr, nextid: &chip_num); |
220 | if (chip) { |
221 | get_device(dev: &chip->dev); |
222 | res = chip; |
223 | break; |
224 | } |
225 | } while (chip_prev != chip_num); |
226 | |
227 | mutex_unlock(lock: &idr_lock); |
228 | |
229 | return res; |
230 | } |
231 | EXPORT_SYMBOL_GPL(tpm_default_chip); |
232 | |
233 | /** |
234 | * tpm_find_get_ops() - find and reserve a TPM chip |
235 | * @chip: a &struct tpm_chip instance, %NULL for the default chip |
236 | * |
237 | * Finds a TPM chip and reserves its class device and operations. The chip must |
238 | * be released with tpm_put_ops() after use. |
239 | * This function is for internal use only. It supports existing TPM callers |
240 | * by accepting NULL, but those callers should be converted to pass in a chip |
241 | * directly. |
242 | * |
243 | * Return: |
244 | * A reserved &struct tpm_chip instance. |
245 | * %NULL if a chip is not found. |
246 | * %NULL if the chip is not available. |
247 | */ |
248 | struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip) |
249 | { |
250 | int rc; |
251 | |
252 | if (chip) { |
253 | if (!tpm_try_get_ops(chip)) |
254 | return chip; |
255 | return NULL; |
256 | } |
257 | |
258 | chip = tpm_default_chip(); |
259 | if (!chip) |
260 | return NULL; |
261 | rc = tpm_try_get_ops(chip); |
262 | /* release additional reference we got from tpm_default_chip() */ |
263 | put_device(dev: &chip->dev); |
264 | if (rc) |
265 | return NULL; |
266 | return chip; |
267 | } |
268 | |
269 | /** |
270 | * tpm_dev_release() - free chip memory and the device number |
271 | * @dev: the character device for the TPM chip |
272 | * |
273 | * This is used as the release function for the character device. |
274 | */ |
275 | static void tpm_dev_release(struct device *dev) |
276 | { |
277 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); |
278 | |
279 | mutex_lock(&idr_lock); |
280 | idr_remove(&dev_nums_idr, id: chip->dev_num); |
281 | mutex_unlock(lock: &idr_lock); |
282 | |
283 | kfree(objp: chip->work_space.context_buf); |
284 | kfree(objp: chip->work_space.session_buf); |
285 | kfree(objp: chip->allocated_banks); |
286 | #ifdef CONFIG_TCG_TPM2_HMAC |
287 | kfree(objp: chip->auth); |
288 | #endif |
289 | kfree(objp: chip); |
290 | } |
291 | |
292 | /** |
293 | * tpm_class_shutdown() - prepare the TPM device for loss of power. |
294 | * @dev: device to which the chip is associated. |
295 | * |
296 | * Issues a TPM2_Shutdown command prior to loss of power, as required by the |
297 | * TPM 2.0 spec. Then, calls bus- and device- specific shutdown code. |
298 | * |
299 | * Return: always 0 (i.e. success) |
300 | */ |
301 | int tpm_class_shutdown(struct device *dev) |
302 | { |
303 | struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev); |
304 | |
305 | down_write(sem: &chip->ops_sem); |
306 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
307 | if (!tpm_chip_start(chip)) { |
308 | tpm2_end_auth_session(chip); |
309 | tpm2_shutdown(chip, shutdown_type: TPM2_SU_CLEAR); |
310 | tpm_chip_stop(chip); |
311 | } |
312 | } |
313 | chip->ops = NULL; |
314 | up_write(sem: &chip->ops_sem); |
315 | |
316 | return 0; |
317 | } |
318 | |
319 | /** |
320 | * tpm_chip_alloc() - allocate a new struct tpm_chip instance |
321 | * @pdev: device to which the chip is associated |
322 | * At this point pdev mst be initialized, but does not have to |
323 | * be registered |
324 | * @ops: struct tpm_class_ops instance |
325 | * |
326 | * Allocates a new struct tpm_chip instance and assigns a free |
327 | * device number for it. Must be paired with put_device(&chip->dev). |
328 | */ |
329 | struct tpm_chip *tpm_chip_alloc(struct device *pdev, |
330 | const struct tpm_class_ops *ops) |
331 | { |
332 | struct tpm_chip *chip; |
333 | int rc; |
334 | |
335 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
336 | if (chip == NULL) |
337 | return ERR_PTR(error: -ENOMEM); |
338 | |
339 | mutex_init(&chip->tpm_mutex); |
340 | init_rwsem(&chip->ops_sem); |
341 | |
342 | chip->ops = ops; |
343 | |
344 | mutex_lock(&idr_lock); |
345 | rc = idr_alloc(&dev_nums_idr, NULL, start: 0, TPM_NUM_DEVICES, GFP_KERNEL); |
346 | mutex_unlock(lock: &idr_lock); |
347 | if (rc < 0) { |
348 | dev_err(pdev, "No available tpm device numbers\n"); |
349 | kfree(objp: chip); |
350 | return ERR_PTR(error: rc); |
351 | } |
352 | chip->dev_num = rc; |
353 | |
354 | device_initialize(dev: &chip->dev); |
355 | |
356 | chip->dev.class = &tpm_class; |
357 | chip->dev.release = tpm_dev_release; |
358 | chip->dev.parent = pdev; |
359 | chip->dev.groups = chip->groups; |
360 | |
361 | if (chip->dev_num == 0) |
362 | chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR); |
363 | else |
364 | chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num); |
365 | |
366 | rc = dev_set_name(dev: &chip->dev, name: "tpm%d", chip->dev_num); |
367 | if (rc) |
368 | goto out; |
369 | |
370 | if (!pdev) |
371 | chip->flags |= TPM_CHIP_FLAG_VIRTUAL; |
372 | |
373 | cdev_init(&chip->cdev, &tpm_fops); |
374 | chip->cdev.owner = THIS_MODULE; |
375 | |
376 | rc = tpm2_init_space(space: &chip->work_space, TPM2_SPACE_BUFFER_SIZE); |
377 | if (rc) { |
378 | rc = -ENOMEM; |
379 | goto out; |
380 | } |
381 | |
382 | chip->locality = -1; |
383 | return chip; |
384 | |
385 | out: |
386 | put_device(dev: &chip->dev); |
387 | return ERR_PTR(error: rc); |
388 | } |
389 | EXPORT_SYMBOL_GPL(tpm_chip_alloc); |
390 | |
391 | static void tpm_put_device(void *dev) |
392 | { |
393 | put_device(dev); |
394 | } |
395 | |
396 | /** |
397 | * tpmm_chip_alloc() - allocate a new struct tpm_chip instance |
398 | * @pdev: parent device to which the chip is associated |
399 | * @ops: struct tpm_class_ops instance |
400 | * |
401 | * Same as tpm_chip_alloc except devm is used to do the put_device |
402 | */ |
403 | struct tpm_chip *tpmm_chip_alloc(struct device *pdev, |
404 | const struct tpm_class_ops *ops) |
405 | { |
406 | struct tpm_chip *chip; |
407 | int rc; |
408 | |
409 | chip = tpm_chip_alloc(pdev, ops); |
410 | if (IS_ERR(ptr: chip)) |
411 | return chip; |
412 | |
413 | rc = devm_add_action_or_reset(pdev, |
414 | tpm_put_device, |
415 | &chip->dev); |
416 | if (rc) |
417 | return ERR_PTR(error: rc); |
418 | |
419 | dev_set_drvdata(dev: pdev, data: chip); |
420 | |
421 | return chip; |
422 | } |
423 | EXPORT_SYMBOL_GPL(tpmm_chip_alloc); |
424 | |
425 | static int tpm_add_char_device(struct tpm_chip *chip) |
426 | { |
427 | int rc; |
428 | |
429 | rc = cdev_device_add(cdev: &chip->cdev, dev: &chip->dev); |
430 | if (rc) { |
431 | dev_err(&chip->dev, |
432 | "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", |
433 | dev_name(&chip->dev), MAJOR(chip->dev.devt), |
434 | MINOR(chip->dev.devt), rc); |
435 | return rc; |
436 | } |
437 | |
438 | if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) { |
439 | rc = tpm_devs_add(chip); |
440 | if (rc) |
441 | goto err_del_cdev; |
442 | } |
443 | |
444 | /* Make the chip available. */ |
445 | mutex_lock(&idr_lock); |
446 | idr_replace(&dev_nums_idr, chip, id: chip->dev_num); |
447 | mutex_unlock(lock: &idr_lock); |
448 | |
449 | return 0; |
450 | |
451 | err_del_cdev: |
452 | cdev_device_del(cdev: &chip->cdev, dev: &chip->dev); |
453 | return rc; |
454 | } |
455 | |
456 | static void tpm_del_char_device(struct tpm_chip *chip) |
457 | { |
458 | cdev_device_del(cdev: &chip->cdev, dev: &chip->dev); |
459 | |
460 | /* Make the chip unavailable. */ |
461 | mutex_lock(&idr_lock); |
462 | idr_replace(&dev_nums_idr, NULL, id: chip->dev_num); |
463 | mutex_unlock(lock: &idr_lock); |
464 | |
465 | /* Make the driver uncallable. */ |
466 | down_write(sem: &chip->ops_sem); |
467 | |
468 | /* |
469 | * Check if chip->ops is still valid: In case that the controller |
470 | * drivers shutdown handler unregisters the controller in its |
471 | * shutdown handler we are called twice and chip->ops to NULL. |
472 | */ |
473 | if (chip->ops) { |
474 | if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
475 | if (!tpm_chip_start(chip)) { |
476 | tpm2_shutdown(chip, shutdown_type: TPM2_SU_CLEAR); |
477 | tpm_chip_stop(chip); |
478 | } |
479 | } |
480 | chip->ops = NULL; |
481 | } |
482 | up_write(sem: &chip->ops_sem); |
483 | } |
484 | |
485 | static void tpm_del_legacy_sysfs(struct tpm_chip *chip) |
486 | { |
487 | struct attribute **i; |
488 | |
489 | if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) || |
490 | tpm_is_firmware_upgrade(chip)) |
491 | return; |
492 | |
493 | sysfs_remove_link(kobj: &chip->dev.parent->kobj, name: "ppi"); |
494 | |
495 | for (i = chip->groups[0]->attrs; *i != NULL; ++i) |
496 | sysfs_remove_link(kobj: &chip->dev.parent->kobj, name: (*i)->name); |
497 | } |
498 | |
499 | /* For compatibility with legacy sysfs paths we provide symlinks from the |
500 | * parent dev directory to selected names within the tpm chip directory. Old |
501 | * kernel versions created these files directly under the parent. |
502 | */ |
503 | static int tpm_add_legacy_sysfs(struct tpm_chip *chip) |
504 | { |
505 | struct attribute **i; |
506 | int rc; |
507 | |
508 | if (chip->flags & (TPM_CHIP_FLAG_TPM2 | TPM_CHIP_FLAG_VIRTUAL) || |
509 | tpm_is_firmware_upgrade(chip)) |
510 | return 0; |
511 | |
512 | rc = compat_only_sysfs_link_entry_to_kobj( |
513 | kobj: &chip->dev.parent->kobj, target_kobj: &chip->dev.kobj, target_name: "ppi", NULL); |
514 | if (rc && rc != -ENOENT) |
515 | return rc; |
516 | |
517 | /* All the names from tpm-sysfs */ |
518 | for (i = chip->groups[0]->attrs; *i != NULL; ++i) { |
519 | rc = compat_only_sysfs_link_entry_to_kobj( |
520 | kobj: &chip->dev.parent->kobj, target_kobj: &chip->dev.kobj, target_name: (*i)->name, NULL); |
521 | if (rc) { |
522 | tpm_del_legacy_sysfs(chip); |
523 | return rc; |
524 | } |
525 | } |
526 | |
527 | return 0; |
528 | } |
529 | |
530 | static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait) |
531 | { |
532 | struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng); |
533 | |
534 | return tpm_get_random(chip, data, max); |
535 | } |
536 | |
537 | static bool tpm_is_hwrng_enabled(struct tpm_chip *chip) |
538 | { |
539 | if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM)) |
540 | return false; |
541 | if (tpm_is_firmware_upgrade(chip)) |
542 | return false; |
543 | if (chip->flags & TPM_CHIP_FLAG_HWRNG_DISABLED) |
544 | return false; |
545 | return true; |
546 | } |
547 | |
548 | static int tpm_add_hwrng(struct tpm_chip *chip) |
549 | { |
550 | if (!tpm_is_hwrng_enabled(chip)) |
551 | return 0; |
552 | |
553 | snprintf(buf: chip->hwrng_name, size: sizeof(chip->hwrng_name), |
554 | fmt: "tpm-rng-%d", chip->dev_num); |
555 | chip->hwrng.name = chip->hwrng_name; |
556 | chip->hwrng.read = tpm_hwrng_read; |
557 | return hwrng_register(rng: &chip->hwrng); |
558 | } |
559 | |
560 | static int tpm_get_pcr_allocation(struct tpm_chip *chip) |
561 | { |
562 | int rc; |
563 | |
564 | if (tpm_is_firmware_upgrade(chip)) |
565 | return 0; |
566 | |
567 | rc = (chip->flags & TPM_CHIP_FLAG_TPM2) ? |
568 | tpm2_get_pcr_allocation(chip) : |
569 | tpm1_get_pcr_allocation(chip); |
570 | |
571 | if (rc > 0) |
572 | return -ENODEV; |
573 | |
574 | return rc; |
575 | } |
576 | |
577 | /* |
578 | * tpm_chip_bootstrap() - Boostrap TPM chip after power on |
579 | * @chip: TPM chip to use. |
580 | * |
581 | * Initialize TPM chip after power on. This a one-shot function: subsequent |
582 | * calls will have no effect. |
583 | */ |
584 | int tpm_chip_bootstrap(struct tpm_chip *chip) |
585 | { |
586 | int rc; |
587 | |
588 | if (chip->flags & TPM_CHIP_FLAG_BOOTSTRAPPED) |
589 | return 0; |
590 | |
591 | rc = tpm_chip_start(chip); |
592 | if (rc) |
593 | return rc; |
594 | |
595 | rc = tpm_auto_startup(chip); |
596 | if (rc) |
597 | goto stop; |
598 | |
599 | rc = tpm_get_pcr_allocation(chip); |
600 | stop: |
601 | tpm_chip_stop(chip); |
602 | |
603 | /* |
604 | * Unconditionally set, as driver initialization should cease, when the |
605 | * boostrapping process fails. |
606 | */ |
607 | chip->flags |= TPM_CHIP_FLAG_BOOTSTRAPPED; |
608 | |
609 | return rc; |
610 | } |
611 | EXPORT_SYMBOL_GPL(tpm_chip_bootstrap); |
612 | |
613 | /* |
614 | * tpm_chip_register() - create a character device for the TPM chip |
615 | * @chip: TPM chip to use. |
616 | * |
617 | * Creates a character device for the TPM chip and adds sysfs attributes for |
618 | * the device. As the last step this function adds the chip to the list of TPM |
619 | * chips available for in-kernel use. |
620 | * |
621 | * This function should be only called after the chip initialization is |
622 | * complete. |
623 | */ |
624 | int tpm_chip_register(struct tpm_chip *chip) |
625 | { |
626 | int rc; |
627 | |
628 | rc = tpm_chip_bootstrap(chip); |
629 | if (rc) |
630 | return rc; |
631 | |
632 | tpm_sysfs_add_device(chip); |
633 | |
634 | tpm_bios_log_setup(chip); |
635 | |
636 | tpm_add_ppi(chip); |
637 | |
638 | rc = tpm_add_hwrng(chip); |
639 | if (rc) |
640 | goto out_ppi; |
641 | |
642 | rc = tpm_add_char_device(chip); |
643 | if (rc) |
644 | goto out_hwrng; |
645 | |
646 | rc = tpm_add_legacy_sysfs(chip); |
647 | if (rc) { |
648 | tpm_chip_unregister(chip); |
649 | return rc; |
650 | } |
651 | |
652 | return 0; |
653 | |
654 | out_hwrng: |
655 | if (tpm_is_hwrng_enabled(chip)) |
656 | hwrng_unregister(rng: &chip->hwrng); |
657 | out_ppi: |
658 | tpm_bios_log_teardown(chip); |
659 | |
660 | return rc; |
661 | } |
662 | EXPORT_SYMBOL_GPL(tpm_chip_register); |
663 | |
664 | /* |
665 | * tpm_chip_unregister() - release the TPM driver |
666 | * @chip: TPM chip to use. |
667 | * |
668 | * Takes the chip first away from the list of available TPM chips and then |
669 | * cleans up all the resources reserved by tpm_chip_register(). |
670 | * |
671 | * Once this function returns the driver call backs in 'op's will not be |
672 | * running and will no longer start. |
673 | * |
674 | * NOTE: This function should be only called before deinitializing chip |
675 | * resources. |
676 | */ |
677 | void tpm_chip_unregister(struct tpm_chip *chip) |
678 | { |
679 | #ifdef CONFIG_TCG_TPM2_HMAC |
680 | int rc; |
681 | |
682 | rc = tpm_try_get_ops(chip); |
683 | if (!rc) { |
684 | tpm2_end_auth_session(chip); |
685 | tpm_put_ops(chip); |
686 | } |
687 | #endif |
688 | |
689 | tpm_del_legacy_sysfs(chip); |
690 | if (tpm_is_hwrng_enabled(chip)) |
691 | hwrng_unregister(rng: &chip->hwrng); |
692 | tpm_bios_log_teardown(chip); |
693 | if (chip->flags & TPM_CHIP_FLAG_TPM2 && !tpm_is_firmware_upgrade(chip)) |
694 | tpm_devs_remove(chip); |
695 | tpm_del_char_device(chip); |
696 | } |
697 | EXPORT_SYMBOL_GPL(tpm_chip_unregister); |
698 |
Definitions
- dev_nums_idr
- idr_lock
- tpm_class
- tpmrm_class
- tpm_devt
- tpm_request_locality
- tpm_relinquish_locality
- tpm_cmd_ready
- tpm_go_idle
- tpm_clk_enable
- tpm_clk_disable
- tpm_chip_start
- tpm_chip_stop
- tpm_try_get_ops
- tpm_put_ops
- tpm_default_chip
- tpm_find_get_ops
- tpm_dev_release
- tpm_class_shutdown
- tpm_chip_alloc
- tpm_put_device
- tpmm_chip_alloc
- tpm_add_char_device
- tpm_del_char_device
- tpm_del_legacy_sysfs
- tpm_add_legacy_sysfs
- tpm_hwrng_read
- tpm_is_hwrng_enabled
- tpm_add_hwrng
- tpm_get_pcr_allocation
- tpm_chip_bootstrap
- tpm_chip_register
Improve your Profiling and Debugging skills
Find out more