diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/char/tpm | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r-- | drivers/char/tpm/Kconfig | 22 | ||||
-rw-r--r-- | drivers/char/tpm/Makefile | 8 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.c | 275 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 50 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_acpi.c | 109 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_atmel.c | 12 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog.c | 419 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_eventlog.h | 86 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 695 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.c | 724 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.h | 76 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_infineon.c | 12 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_nsc.c | 13 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_of.c | 73 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ppi.c | 463 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 140 |
16 files changed, 164 insertions, 3013 deletions
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 915875e431d..fa567f1158c 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | menuconfig TCG_TPM | 5 | menuconfig TCG_TPM |
6 | tristate "TPM Hardware Support" | 6 | tristate "TPM Hardware Support" |
7 | depends on HAS_IOMEM | 7 | depends on HAS_IOMEM |
8 | depends on EXPERIMENTAL | ||
8 | select SECURITYFS | 9 | select SECURITYFS |
9 | ---help--- | 10 | ---help--- |
10 | If you have a TPM security chip in your system, which | 11 | If you have a TPM security chip in your system, which |
@@ -26,27 +27,14 @@ if TCG_TPM | |||
26 | 27 | ||
27 | config TCG_TIS | 28 | config TCG_TIS |
28 | tristate "TPM Interface Specification 1.2 Interface" | 29 | tristate "TPM Interface Specification 1.2 Interface" |
29 | depends on X86 | ||
30 | ---help--- | 30 | ---help--- |
31 | If you have a TPM security chip that is compliant with the | 31 | If you have a TPM security chip that is compliant with the |
32 | TCG TIS 1.2 TPM specification say Yes and it will be accessible | 32 | TCG TIS 1.2 TPM specification say Yes and it will be accessible |
33 | from within Linux. To compile this driver as a module, choose | 33 | from within Linux. To compile this driver as a module, choose |
34 | M here; the module will be called tpm_tis. | 34 | M here; the module will be called tpm_tis. |
35 | 35 | ||
36 | config TCG_TIS_I2C_INFINEON | ||
37 | tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)" | ||
38 | depends on I2C | ||
39 | ---help--- | ||
40 | If you have a TPM security chip that is compliant with the | ||
41 | TCG TIS 1.2 TPM specification and Infineon's I2C Protocol Stack | ||
42 | Specification 0.20 say Yes and it will be accessible from within | ||
43 | Linux. | ||
44 | To compile this driver as a module, choose M here; the module | ||
45 | will be called tpm_tis_i2c_infineon. | ||
46 | |||
47 | config TCG_NSC | 36 | config TCG_NSC |
48 | tristate "National Semiconductor TPM Interface" | 37 | tristate "National Semiconductor TPM Interface" |
49 | depends on X86 | ||
50 | ---help--- | 38 | ---help--- |
51 | If you have a TPM security chip from National Semiconductor | 39 | If you have a TPM security chip from National Semiconductor |
52 | say Yes and it will be accessible from within Linux. To | 40 | say Yes and it will be accessible from within Linux. To |
@@ -73,12 +61,4 @@ config TCG_INFINEON | |||
73 | Further information on this driver and the supported hardware | 61 | Further information on this driver and the supported hardware |
74 | can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ | 62 | can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ |
75 | 63 | ||
76 | config TCG_IBMVTPM | ||
77 | tristate "IBM VTPM Interface" | ||
78 | depends on PPC64 | ||
79 | ---help--- | ||
80 | If you have IBM virtual TPM (VTPM) support say Yes and it | ||
81 | will be accessible from within Linux. To compile this driver | ||
82 | as a module, choose M here; the module will be called tpm_ibmvtpm. | ||
83 | |||
84 | endif # TCG_TPM | 64 | endif # TCG_TPM |
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index 5b3fc8bc6c1..ea3a1e02a82 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile | |||
@@ -4,16 +4,8 @@ | |||
4 | obj-$(CONFIG_TCG_TPM) += tpm.o | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
5 | ifdef CONFIG_ACPI | 5 | ifdef CONFIG_ACPI |
6 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o | 6 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o |
7 | tpm_bios-objs += tpm_eventlog.o tpm_acpi.o tpm_ppi.o | ||
8 | else | ||
9 | ifdef CONFIG_TCG_IBMVTPM | ||
10 | obj-$(CONFIG_TCG_TPM) += tpm_bios.o | ||
11 | tpm_bios-objs += tpm_eventlog.o tpm_of.o | ||
12 | endif | ||
13 | endif | 7 | endif |
14 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o | 8 | obj-$(CONFIG_TCG_TIS) += tpm_tis.o |
15 | obj-$(CONFIG_TCG_TIS_I2C_INFINEON) += tpm_i2c_infineon.o | ||
16 | obj-$(CONFIG_TCG_NSC) += tpm_nsc.o | 9 | obj-$(CONFIG_TCG_NSC) += tpm_nsc.o |
17 | obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o | 10 | obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o |
18 | obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o | 11 | obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o |
19 | obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o | ||
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 93211df52aa..9ca5c021d0b 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -27,10 +27,14 @@ | |||
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/freezer.h> | ||
31 | 30 | ||
32 | #include "tpm.h" | 31 | #include "tpm.h" |
33 | #include "tpm_eventlog.h" | 32 | |
33 | enum tpm_const { | ||
34 | TPM_MINOR = 224, /* officially assigned */ | ||
35 | TPM_BUFSIZE = 4096, | ||
36 | TPM_NUM_DEVICES = 256, | ||
37 | }; | ||
34 | 38 | ||
35 | enum tpm_duration { | 39 | enum tpm_duration { |
36 | TPM_SHORT = 0, | 40 | TPM_SHORT = 0, |
@@ -436,6 +440,7 @@ out: | |||
436 | } | 440 | } |
437 | 441 | ||
438 | #define TPM_DIGEST_SIZE 20 | 442 | #define TPM_DIGEST_SIZE 20 |
443 | #define TPM_ERROR_SIZE 10 | ||
439 | #define TPM_RET_CODE_IDX 6 | 444 | #define TPM_RET_CODE_IDX 6 |
440 | 445 | ||
441 | enum tpm_capabilities { | 446 | enum tpm_capabilities { |
@@ -464,20 +469,17 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, | |||
464 | len = tpm_transmit(chip,(u8 *) cmd, len); | 469 | len = tpm_transmit(chip,(u8 *) cmd, len); |
465 | if (len < 0) | 470 | if (len < 0) |
466 | return len; | 471 | return len; |
467 | else if (len < TPM_HEADER_SIZE) | 472 | if (len == TPM_ERROR_SIZE) { |
468 | return -EFAULT; | 473 | err = be32_to_cpu(cmd->header.out.return_code); |
469 | 474 | dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | |
470 | err = be32_to_cpu(cmd->header.out.return_code); | 475 | return err; |
471 | if (err != 0) | 476 | } |
472 | dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); | 477 | return 0; |
473 | |||
474 | return err; | ||
475 | } | 478 | } |
476 | 479 | ||
477 | #define TPM_INTERNAL_RESULT_SIZE 200 | 480 | #define TPM_INTERNAL_RESULT_SIZE 200 |
478 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) | 481 | #define TPM_TAG_RQU_COMMAND cpu_to_be16(193) |
479 | #define TPM_ORD_GET_CAP cpu_to_be32(101) | 482 | #define TPM_ORD_GET_CAP cpu_to_be32(101) |
480 | #define TPM_ORD_GET_RANDOM cpu_to_be32(70) | ||
481 | 483 | ||
482 | static const struct tpm_input_header tpm_getcap_header = { | 484 | static const struct tpm_input_header tpm_getcap_header = { |
483 | .tag = TPM_TAG_RQU_COMMAND, | 485 | .tag = TPM_TAG_RQU_COMMAND, |
@@ -528,7 +530,7 @@ void tpm_gen_interrupt(struct tpm_chip *chip) | |||
528 | } | 530 | } |
529 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); | 531 | EXPORT_SYMBOL_GPL(tpm_gen_interrupt); |
530 | 532 | ||
531 | int tpm_get_timeouts(struct tpm_chip *chip) | 533 | void tpm_get_timeouts(struct tpm_chip *chip) |
532 | { | 534 | { |
533 | struct tpm_cmd_t tpm_cmd; | 535 | struct tpm_cmd_t tpm_cmd; |
534 | struct timeout_t *timeout_cap; | 536 | struct timeout_t *timeout_cap; |
@@ -550,7 +552,7 @@ int tpm_get_timeouts(struct tpm_chip *chip) | |||
550 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || | 552 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
551 | be32_to_cpu(tpm_cmd.header.out.length) | 553 | be32_to_cpu(tpm_cmd.header.out.length) |
552 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) | 554 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) |
553 | return -EINVAL; | 555 | return; |
554 | 556 | ||
555 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; | 557 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; |
556 | /* Don't overwrite default if value is 0 */ | 558 | /* Don't overwrite default if value is 0 */ |
@@ -581,12 +583,12 @@ duration: | |||
581 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, | 583 | rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, |
582 | "attempting to determine the durations"); | 584 | "attempting to determine the durations"); |
583 | if (rc) | 585 | if (rc) |
584 | return rc; | 586 | return; |
585 | 587 | ||
586 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || | 588 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
587 | be32_to_cpu(tpm_cmd.header.out.length) | 589 | be32_to_cpu(tpm_cmd.header.out.length) |
588 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) | 590 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) |
589 | return -EINVAL; | 591 | return; |
590 | 592 | ||
591 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; | 593 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; |
592 | chip->vendor.duration[TPM_SHORT] = | 594 | chip->vendor.duration[TPM_SHORT] = |
@@ -608,36 +610,20 @@ duration: | |||
608 | chip->vendor.duration_adjusted = true; | 610 | chip->vendor.duration_adjusted = true; |
609 | dev_info(chip->dev, "Adjusting TPM timeout parameters."); | 611 | dev_info(chip->dev, "Adjusting TPM timeout parameters."); |
610 | } | 612 | } |
611 | return 0; | ||
612 | } | 613 | } |
613 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 614 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
614 | 615 | ||
615 | #define TPM_ORD_CONTINUE_SELFTEST 83 | 616 | void tpm_continue_selftest(struct tpm_chip *chip) |
616 | #define CONTINUE_SELFTEST_RESULT_SIZE 10 | ||
617 | |||
618 | static struct tpm_input_header continue_selftest_header = { | ||
619 | .tag = TPM_TAG_RQU_COMMAND, | ||
620 | .length = cpu_to_be32(10), | ||
621 | .ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST), | ||
622 | }; | ||
623 | |||
624 | /** | ||
625 | * tpm_continue_selftest -- run TPM's selftest | ||
626 | * @chip: TPM chip to use | ||
627 | * | ||
628 | * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing | ||
629 | * a TPM error code. | ||
630 | */ | ||
631 | static int tpm_continue_selftest(struct tpm_chip *chip) | ||
632 | { | 617 | { |
633 | int rc; | 618 | u8 data[] = { |
634 | struct tpm_cmd_t cmd; | 619 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
620 | 0, 0, 0, 10, /* length */ | ||
621 | 0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */ | ||
622 | }; | ||
635 | 623 | ||
636 | cmd.header.in = continue_selftest_header; | 624 | tpm_transmit(chip, data, sizeof(data)); |
637 | rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE, | ||
638 | "continue selftest"); | ||
639 | return rc; | ||
640 | } | 625 | } |
626 | EXPORT_SYMBOL_GPL(tpm_continue_selftest); | ||
641 | 627 | ||
642 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, | 628 | ssize_t tpm_show_enabled(struct device * dev, struct device_attribute * attr, |
643 | char *buf) | 629 | char *buf) |
@@ -732,7 +718,7 @@ static struct tpm_input_header pcrread_header = { | |||
732 | .ordinal = TPM_ORDINAL_PCRREAD | 718 | .ordinal = TPM_ORDINAL_PCRREAD |
733 | }; | 719 | }; |
734 | 720 | ||
735 | static int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) | 721 | int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf) |
736 | { | 722 | { |
737 | int rc; | 723 | int rc; |
738 | struct tpm_cmd_t cmd; | 724 | struct tpm_cmd_t cmd; |
@@ -812,62 +798,6 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) | |||
812 | } | 798 | } |
813 | EXPORT_SYMBOL_GPL(tpm_pcr_extend); | 799 | EXPORT_SYMBOL_GPL(tpm_pcr_extend); |
814 | 800 | ||
815 | /** | ||
816 | * tpm_do_selftest - have the TPM continue its selftest and wait until it | ||
817 | * can receive further commands | ||
818 | * @chip: TPM chip to use | ||
819 | * | ||
820 | * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing | ||
821 | * a TPM error code. | ||
822 | */ | ||
823 | int tpm_do_selftest(struct tpm_chip *chip) | ||
824 | { | ||
825 | int rc; | ||
826 | unsigned int loops; | ||
827 | unsigned int delay_msec = 1000; | ||
828 | unsigned long duration; | ||
829 | struct tpm_cmd_t cmd; | ||
830 | |||
831 | duration = tpm_calc_ordinal_duration(chip, | ||
832 | TPM_ORD_CONTINUE_SELFTEST); | ||
833 | |||
834 | loops = jiffies_to_msecs(duration) / delay_msec; | ||
835 | |||
836 | rc = tpm_continue_selftest(chip); | ||
837 | /* This may fail if there was no TPM driver during a suspend/resume | ||
838 | * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) | ||
839 | */ | ||
840 | if (rc) | ||
841 | return rc; | ||
842 | |||
843 | do { | ||
844 | /* Attempt to read a PCR value */ | ||
845 | cmd.header.in = pcrread_header; | ||
846 | cmd.params.pcrread_in.pcr_idx = cpu_to_be32(0); | ||
847 | rc = tpm_transmit(chip, (u8 *) &cmd, READ_PCR_RESULT_SIZE); | ||
848 | |||
849 | if (rc < TPM_HEADER_SIZE) | ||
850 | return -EFAULT; | ||
851 | |||
852 | rc = be32_to_cpu(cmd.header.out.return_code); | ||
853 | if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) { | ||
854 | dev_info(chip->dev, | ||
855 | "TPM is disabled/deactivated (0x%X)\n", rc); | ||
856 | /* TPM is disabled and/or deactivated; driver can | ||
857 | * proceed and TPM does handle commands for | ||
858 | * suspend/resume correctly | ||
859 | */ | ||
860 | return 0; | ||
861 | } | ||
862 | if (rc != TPM_WARN_DOING_SELFTEST) | ||
863 | return rc; | ||
864 | msleep(delay_msec); | ||
865 | } while (--loops > 0); | ||
866 | |||
867 | return rc; | ||
868 | } | ||
869 | EXPORT_SYMBOL_GPL(tpm_do_selftest); | ||
870 | |||
871 | int tpm_send(u32 chip_num, void *cmd, size_t buflen) | 801 | int tpm_send(u32 chip_num, void *cmd, size_t buflen) |
872 | { | 802 | { |
873 | struct tpm_chip *chip; | 803 | struct tpm_chip *chip; |
@@ -915,7 +845,7 @@ EXPORT_SYMBOL_GPL(tpm_show_pcrs); | |||
915 | 845 | ||
916 | #define READ_PUBEK_RESULT_SIZE 314 | 846 | #define READ_PUBEK_RESULT_SIZE 314 |
917 | #define TPM_ORD_READPUBEK cpu_to_be32(124) | 847 | #define TPM_ORD_READPUBEK cpu_to_be32(124) |
918 | static struct tpm_input_header tpm_readpubek_header = { | 848 | struct tpm_input_header tpm_readpubek_header = { |
919 | .tag = TPM_TAG_RQU_COMMAND, | 849 | .tag = TPM_TAG_RQU_COMMAND, |
920 | .length = cpu_to_be32(30), | 850 | .length = cpu_to_be32(30), |
921 | .ordinal = TPM_ORD_READPUBEK | 851 | .ordinal = TPM_ORD_READPUBEK |
@@ -1036,9 +966,6 @@ ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, | |||
1036 | { | 966 | { |
1037 | struct tpm_chip *chip = dev_get_drvdata(dev); | 967 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1038 | 968 | ||
1039 | if (chip->vendor.duration[TPM_LONG] == 0) | ||
1040 | return 0; | ||
1041 | |||
1042 | return sprintf(buf, "%d %d %d [%s]\n", | 969 | return sprintf(buf, "%d %d %d [%s]\n", |
1043 | jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), | 970 | jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), |
1044 | jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), | 971 | jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), |
@@ -1075,46 +1002,6 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | |||
1075 | } | 1002 | } |
1076 | EXPORT_SYMBOL_GPL(tpm_store_cancel); | 1003 | EXPORT_SYMBOL_GPL(tpm_store_cancel); |
1077 | 1004 | ||
1078 | int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | ||
1079 | wait_queue_head_t *queue) | ||
1080 | { | ||
1081 | unsigned long stop; | ||
1082 | long rc; | ||
1083 | u8 status; | ||
1084 | |||
1085 | /* check current status */ | ||
1086 | status = chip->vendor.status(chip); | ||
1087 | if ((status & mask) == mask) | ||
1088 | return 0; | ||
1089 | |||
1090 | stop = jiffies + timeout; | ||
1091 | |||
1092 | if (chip->vendor.irq) { | ||
1093 | again: | ||
1094 | timeout = stop - jiffies; | ||
1095 | if ((long)timeout <= 0) | ||
1096 | return -ETIME; | ||
1097 | rc = wait_event_interruptible_timeout(*queue, | ||
1098 | ((chip->vendor.status(chip) | ||
1099 | & mask) == mask), | ||
1100 | timeout); | ||
1101 | if (rc > 0) | ||
1102 | return 0; | ||
1103 | if (rc == -ERESTARTSYS && freezing(current)) { | ||
1104 | clear_thread_flag(TIF_SIGPENDING); | ||
1105 | goto again; | ||
1106 | } | ||
1107 | } else { | ||
1108 | do { | ||
1109 | msleep(TPM_TIMEOUT); | ||
1110 | status = chip->vendor.status(chip); | ||
1111 | if ((status & mask) == mask) | ||
1112 | return 0; | ||
1113 | } while (time_before(jiffies, stop)); | ||
1114 | } | ||
1115 | return -ETIME; | ||
1116 | } | ||
1117 | EXPORT_SYMBOL_GPL(wait_for_tpm_stat); | ||
1118 | /* | 1005 | /* |
1119 | * Device file system interface to the TPM | 1006 | * Device file system interface to the TPM |
1120 | * | 1007 | * |
@@ -1168,10 +1055,10 @@ int tpm_release(struct inode *inode, struct file *file) | |||
1168 | struct tpm_chip *chip = file->private_data; | 1055 | struct tpm_chip *chip = file->private_data; |
1169 | 1056 | ||
1170 | del_singleshot_timer_sync(&chip->user_read_timer); | 1057 | del_singleshot_timer_sync(&chip->user_read_timer); |
1171 | flush_work(&chip->work); | 1058 | flush_work_sync(&chip->work); |
1172 | file->private_data = NULL; | 1059 | file->private_data = NULL; |
1173 | atomic_set(&chip->data_pending, 0); | 1060 | atomic_set(&chip->data_pending, 0); |
1174 | kzfree(chip->data_buffer); | 1061 | kfree(chip->data_buffer); |
1175 | clear_bit(0, &chip->is_open); | 1062 | clear_bit(0, &chip->is_open); |
1176 | put_device(chip->dev); | 1063 | put_device(chip->dev); |
1177 | return 0; | 1064 | return 0; |
@@ -1182,21 +1069,18 @@ ssize_t tpm_write(struct file *file, const char __user *buf, | |||
1182 | size_t size, loff_t *off) | 1069 | size_t size, loff_t *off) |
1183 | { | 1070 | { |
1184 | struct tpm_chip *chip = file->private_data; | 1071 | struct tpm_chip *chip = file->private_data; |
1185 | size_t in_size = size; | 1072 | size_t in_size = size, out_size; |
1186 | ssize_t out_size; | ||
1187 | 1073 | ||
1188 | /* cannot perform a write until the read has cleared | 1074 | /* cannot perform a write until the read has cleared |
1189 | either via tpm_read or a user_read_timer timeout. | 1075 | either via tpm_read or a user_read_timer timeout */ |
1190 | This also prevents splitted buffered writes from blocking here. | 1076 | while (atomic_read(&chip->data_pending) != 0) |
1191 | */ | 1077 | msleep(TPM_TIMEOUT); |
1192 | if (atomic_read(&chip->data_pending) != 0) | ||
1193 | return -EBUSY; | ||
1194 | |||
1195 | if (in_size > TPM_BUFSIZE) | ||
1196 | return -E2BIG; | ||
1197 | 1078 | ||
1198 | mutex_lock(&chip->buffer_mutex); | 1079 | mutex_lock(&chip->buffer_mutex); |
1199 | 1080 | ||
1081 | if (in_size > TPM_BUFSIZE) | ||
1082 | in_size = TPM_BUFSIZE; | ||
1083 | |||
1200 | if (copy_from_user | 1084 | if (copy_from_user |
1201 | (chip->data_buffer, (void __user *) buf, in_size)) { | 1085 | (chip->data_buffer, (void __user *) buf, in_size)) { |
1202 | mutex_unlock(&chip->buffer_mutex); | 1086 | mutex_unlock(&chip->buffer_mutex); |
@@ -1205,10 +1089,6 @@ ssize_t tpm_write(struct file *file, const char __user *buf, | |||
1205 | 1089 | ||
1206 | /* atomic tpm command send and result receive */ | 1090 | /* atomic tpm command send and result receive */ |
1207 | out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); | 1091 | out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE); |
1208 | if (out_size < 0) { | ||
1209 | mutex_unlock(&chip->buffer_mutex); | ||
1210 | return out_size; | ||
1211 | } | ||
1212 | 1092 | ||
1213 | atomic_set(&chip->data_pending, out_size); | 1093 | atomic_set(&chip->data_pending, out_size); |
1214 | mutex_unlock(&chip->buffer_mutex); | 1094 | mutex_unlock(&chip->buffer_mutex); |
@@ -1228,24 +1108,22 @@ ssize_t tpm_read(struct file *file, char __user *buf, | |||
1228 | int rc; | 1108 | int rc; |
1229 | 1109 | ||
1230 | del_singleshot_timer_sync(&chip->user_read_timer); | 1110 | del_singleshot_timer_sync(&chip->user_read_timer); |
1231 | flush_work(&chip->work); | 1111 | flush_work_sync(&chip->work); |
1232 | ret_size = atomic_read(&chip->data_pending); | 1112 | ret_size = atomic_read(&chip->data_pending); |
1113 | atomic_set(&chip->data_pending, 0); | ||
1233 | if (ret_size > 0) { /* relay data */ | 1114 | if (ret_size > 0) { /* relay data */ |
1234 | ssize_t orig_ret_size = ret_size; | ||
1235 | if (size < ret_size) | 1115 | if (size < ret_size) |
1236 | ret_size = size; | 1116 | ret_size = size; |
1237 | 1117 | ||
1238 | mutex_lock(&chip->buffer_mutex); | 1118 | mutex_lock(&chip->buffer_mutex); |
1239 | rc = copy_to_user(buf, chip->data_buffer, ret_size); | 1119 | rc = copy_to_user(buf, chip->data_buffer, ret_size); |
1240 | memset(chip->data_buffer, 0, orig_ret_size); | 1120 | memset(chip->data_buffer, 0, ret_size); |
1241 | if (rc) | 1121 | if (rc) |
1242 | ret_size = -EFAULT; | 1122 | ret_size = -EFAULT; |
1243 | 1123 | ||
1244 | mutex_unlock(&chip->buffer_mutex); | 1124 | mutex_unlock(&chip->buffer_mutex); |
1245 | } | 1125 | } |
1246 | 1126 | ||
1247 | atomic_set(&chip->data_pending, 0); | ||
1248 | |||
1249 | return ret_size; | 1127 | return ret_size; |
1250 | } | 1128 | } |
1251 | EXPORT_SYMBOL_GPL(tpm_read); | 1129 | EXPORT_SYMBOL_GPL(tpm_read); |
@@ -1266,7 +1144,6 @@ void tpm_remove_hardware(struct device *dev) | |||
1266 | 1144 | ||
1267 | misc_deregister(&chip->vendor.miscdev); | 1145 | misc_deregister(&chip->vendor.miscdev); |
1268 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); | 1146 | sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); |
1269 | tpm_remove_ppi(&dev->kobj); | ||
1270 | tpm_bios_log_teardown(chip->bios_dir); | 1147 | tpm_bios_log_teardown(chip->bios_dir); |
1271 | 1148 | ||
1272 | /* write it this way to be explicit (chip->dev == dev) */ | 1149 | /* write it this way to be explicit (chip->dev == dev) */ |
@@ -1287,7 +1164,7 @@ static struct tpm_input_header savestate_header = { | |||
1287 | * We are about to suspend. Save the TPM state | 1164 | * We are about to suspend. Save the TPM state |
1288 | * so that it can be restored. | 1165 | * so that it can be restored. |
1289 | */ | 1166 | */ |
1290 | int tpm_pm_suspend(struct device *dev) | 1167 | int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) |
1291 | { | 1168 | { |
1292 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1169 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1293 | struct tpm_cmd_t cmd; | 1170 | struct tpm_cmd_t cmd; |
@@ -1331,65 +1208,10 @@ int tpm_pm_resume(struct device *dev) | |||
1331 | } | 1208 | } |
1332 | EXPORT_SYMBOL_GPL(tpm_pm_resume); | 1209 | EXPORT_SYMBOL_GPL(tpm_pm_resume); |
1333 | 1210 | ||
1334 | #define TPM_GETRANDOM_RESULT_SIZE 18 | ||
1335 | static struct tpm_input_header tpm_getrandom_header = { | ||
1336 | .tag = TPM_TAG_RQU_COMMAND, | ||
1337 | .length = cpu_to_be32(14), | ||
1338 | .ordinal = TPM_ORD_GET_RANDOM | ||
1339 | }; | ||
1340 | |||
1341 | /** | ||
1342 | * tpm_get_random() - Get random bytes from the tpm's RNG | ||
1343 | * @chip_num: A specific chip number for the request or TPM_ANY_NUM | ||
1344 | * @out: destination buffer for the random bytes | ||
1345 | * @max: the max number of bytes to write to @out | ||
1346 | * | ||
1347 | * Returns < 0 on error and the number of bytes read on success | ||
1348 | */ | ||
1349 | int tpm_get_random(u32 chip_num, u8 *out, size_t max) | ||
1350 | { | ||
1351 | struct tpm_chip *chip; | ||
1352 | struct tpm_cmd_t tpm_cmd; | ||
1353 | u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA); | ||
1354 | int err, total = 0, retries = 5; | ||
1355 | u8 *dest = out; | ||
1356 | |||
1357 | chip = tpm_chip_find_get(chip_num); | ||
1358 | if (chip == NULL) | ||
1359 | return -ENODEV; | ||
1360 | |||
1361 | if (!out || !num_bytes || max > TPM_MAX_RNG_DATA) | ||
1362 | return -EINVAL; | ||
1363 | |||
1364 | do { | ||
1365 | tpm_cmd.header.in = tpm_getrandom_header; | ||
1366 | tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); | ||
1367 | |||
1368 | err = transmit_cmd(chip, &tpm_cmd, | ||
1369 | TPM_GETRANDOM_RESULT_SIZE + num_bytes, | ||
1370 | "attempting get random"); | ||
1371 | if (err) | ||
1372 | break; | ||
1373 | |||
1374 | recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); | ||
1375 | memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); | ||
1376 | |||
1377 | dest += recd; | ||
1378 | total += recd; | ||
1379 | num_bytes -= recd; | ||
1380 | } while (retries-- && total < max); | ||
1381 | |||
1382 | return total ? total : -EIO; | ||
1383 | } | ||
1384 | EXPORT_SYMBOL_GPL(tpm_get_random); | ||
1385 | |||
1386 | /* In case vendor provided release function, call it too.*/ | 1211 | /* In case vendor provided release function, call it too.*/ |
1387 | 1212 | ||
1388 | void tpm_dev_vendor_release(struct tpm_chip *chip) | 1213 | void tpm_dev_vendor_release(struct tpm_chip *chip) |
1389 | { | 1214 | { |
1390 | if (!chip) | ||
1391 | return; | ||
1392 | |||
1393 | if (chip->vendor.release) | 1215 | if (chip->vendor.release) |
1394 | chip->vendor.release(chip->dev); | 1216 | chip->vendor.release(chip->dev); |
1395 | 1217 | ||
@@ -1403,13 +1225,10 @@ EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); | |||
1403 | * Once all references to platform device are down to 0, | 1225 | * Once all references to platform device are down to 0, |
1404 | * release all allocated structures. | 1226 | * release all allocated structures. |
1405 | */ | 1227 | */ |
1406 | static void tpm_dev_release(struct device *dev) | 1228 | void tpm_dev_release(struct device *dev) |
1407 | { | 1229 | { |
1408 | struct tpm_chip *chip = dev_get_drvdata(dev); | 1230 | struct tpm_chip *chip = dev_get_drvdata(dev); |
1409 | 1231 | ||
1410 | if (!chip) | ||
1411 | return; | ||
1412 | |||
1413 | tpm_dev_vendor_release(chip); | 1232 | tpm_dev_vendor_release(chip); |
1414 | 1233 | ||
1415 | chip->release(dev); | 1234 | chip->release(dev); |
@@ -1476,17 +1295,15 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1476 | "unable to misc_register %s, minor %d\n", | 1295 | "unable to misc_register %s, minor %d\n", |
1477 | chip->vendor.miscdev.name, | 1296 | chip->vendor.miscdev.name, |
1478 | chip->vendor.miscdev.minor); | 1297 | chip->vendor.miscdev.minor); |
1479 | goto put_device; | 1298 | put_device(chip->dev); |
1299 | return NULL; | ||
1480 | } | 1300 | } |
1481 | 1301 | ||
1482 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { | 1302 | if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { |
1483 | misc_deregister(&chip->vendor.miscdev); | 1303 | misc_deregister(&chip->vendor.miscdev); |
1484 | goto put_device; | 1304 | put_device(chip->dev); |
1485 | } | ||
1486 | 1305 | ||
1487 | if (tpm_add_ppi(&dev->kobj)) { | 1306 | return NULL; |
1488 | misc_deregister(&chip->vendor.miscdev); | ||
1489 | goto put_device; | ||
1490 | } | 1307 | } |
1491 | 1308 | ||
1492 | chip->bios_dir = tpm_bios_log_setup(devname); | 1309 | chip->bios_dir = tpm_bios_log_setup(devname); |
@@ -1498,8 +1315,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, | |||
1498 | 1315 | ||
1499 | return chip; | 1316 | return chip; |
1500 | 1317 | ||
1501 | put_device: | ||
1502 | put_device(chip->dev); | ||
1503 | out_free: | 1318 | out_free: |
1504 | kfree(chip); | 1319 | kfree(chip); |
1505 | kfree(devname); | 1320 | kfree(devname); |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 8ef7649a50a..9c4163cfa3c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -28,12 +28,6 @@ | |||
28 | #include <linux/io.h> | 28 | #include <linux/io.h> |
29 | #include <linux/tpm.h> | 29 | #include <linux/tpm.h> |
30 | 30 | ||
31 | enum tpm_const { | ||
32 | TPM_MINOR = 224, /* officially assigned */ | ||
33 | TPM_BUFSIZE = 4096, | ||
34 | TPM_NUM_DEVICES = 256, | ||
35 | }; | ||
36 | |||
37 | enum tpm_timeout { | 31 | enum tpm_timeout { |
38 | TPM_TIMEOUT = 5, /* msecs */ | 32 | TPM_TIMEOUT = 5, /* msecs */ |
39 | }; | 33 | }; |
@@ -44,11 +38,6 @@ enum tpm_addr { | |||
44 | TPM_ADDR = 0x4E, | 38 | TPM_ADDR = 0x4E, |
45 | }; | 39 | }; |
46 | 40 | ||
47 | #define TPM_WARN_DOING_SELFTEST 0x802 | ||
48 | #define TPM_ERR_DEACTIVATED 0x6 | ||
49 | #define TPM_ERR_DISABLED 0x7 | ||
50 | |||
51 | #define TPM_HEADER_SIZE 10 | ||
52 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, | 41 | extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, |
53 | char *); | 42 | char *); |
54 | extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, | 43 | extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, |
@@ -100,14 +89,11 @@ struct tpm_vendor_specific { | |||
100 | bool timeout_adjusted; | 89 | bool timeout_adjusted; |
101 | unsigned long duration[3]; /* jiffies */ | 90 | unsigned long duration[3]; /* jiffies */ |
102 | bool duration_adjusted; | 91 | bool duration_adjusted; |
103 | void *data; | ||
104 | 92 | ||
105 | wait_queue_head_t read_queue; | 93 | wait_queue_head_t read_queue; |
106 | wait_queue_head_t int_queue; | 94 | wait_queue_head_t int_queue; |
107 | }; | 95 | }; |
108 | 96 | ||
109 | #define TPM_VID_INTEL 0x8086 | ||
110 | |||
111 | struct tpm_chip { | 97 | struct tpm_chip { |
112 | struct device *dev; /* Device stuff */ | 98 | struct device *dev; /* Device stuff */ |
113 | 99 | ||
@@ -276,21 +262,6 @@ struct tpm_pcrextend_in { | |||
276 | u8 hash[TPM_DIGEST_SIZE]; | 262 | u8 hash[TPM_DIGEST_SIZE]; |
277 | }__attribute__((packed)); | 263 | }__attribute__((packed)); |
278 | 264 | ||
279 | /* 128 bytes is an arbitrary cap. This could be as large as TPM_BUFSIZE - 18 | ||
280 | * bytes, but 128 is still a relatively large number of random bytes and | ||
281 | * anything much bigger causes users of struct tpm_cmd_t to start getting | ||
282 | * compiler warnings about stack frame size. */ | ||
283 | #define TPM_MAX_RNG_DATA 128 | ||
284 | |||
285 | struct tpm_getrandom_out { | ||
286 | __be32 rng_data_len; | ||
287 | u8 rng_data[TPM_MAX_RNG_DATA]; | ||
288 | }__attribute__((packed)); | ||
289 | |||
290 | struct tpm_getrandom_in { | ||
291 | __be32 num_bytes; | ||
292 | }__attribute__((packed)); | ||
293 | |||
294 | typedef union { | 265 | typedef union { |
295 | struct tpm_getcap_params_out getcap_out; | 266 | struct tpm_getcap_params_out getcap_out; |
296 | struct tpm_readpubek_params_out readpubek_out; | 267 | struct tpm_readpubek_params_out readpubek_out; |
@@ -299,8 +270,6 @@ typedef union { | |||
299 | struct tpm_pcrread_in pcrread_in; | 270 | struct tpm_pcrread_in pcrread_in; |
300 | struct tpm_pcrread_out pcrread_out; | 271 | struct tpm_pcrread_out pcrread_out; |
301 | struct tpm_pcrextend_in pcrextend_in; | 272 | struct tpm_pcrextend_in pcrextend_in; |
302 | struct tpm_getrandom_in getrandom_in; | ||
303 | struct tpm_getrandom_out getrandom_out; | ||
304 | } tpm_cmd_params; | 273 | } tpm_cmd_params; |
305 | 274 | ||
306 | struct tpm_cmd_t { | 275 | struct tpm_cmd_t { |
@@ -310,9 +279,9 @@ struct tpm_cmd_t { | |||
310 | 279 | ||
311 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); | 280 | ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *); |
312 | 281 | ||
313 | extern int tpm_get_timeouts(struct tpm_chip *); | 282 | extern void tpm_get_timeouts(struct tpm_chip *); |
314 | extern void tpm_gen_interrupt(struct tpm_chip *); | 283 | extern void tpm_gen_interrupt(struct tpm_chip *); |
315 | extern int tpm_do_selftest(struct tpm_chip *); | 284 | extern void tpm_continue_selftest(struct tpm_chip *); |
316 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); | 285 | extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32); |
317 | extern struct tpm_chip* tpm_register_hardware(struct device *, | 286 | extern struct tpm_chip* tpm_register_hardware(struct device *, |
318 | const struct tpm_vendor_specific *); | 287 | const struct tpm_vendor_specific *); |
@@ -323,21 +292,18 @@ extern ssize_t tpm_write(struct file *, const char __user *, size_t, | |||
323 | loff_t *); | 292 | loff_t *); |
324 | extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); | 293 | extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); |
325 | extern void tpm_remove_hardware(struct device *); | 294 | extern void tpm_remove_hardware(struct device *); |
326 | extern int tpm_pm_suspend(struct device *); | 295 | extern int tpm_pm_suspend(struct device *, pm_message_t); |
327 | extern int tpm_pm_resume(struct device *); | 296 | extern int tpm_pm_resume(struct device *); |
328 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, | ||
329 | wait_queue_head_t *); | ||
330 | 297 | ||
331 | #ifdef CONFIG_ACPI | 298 | #ifdef CONFIG_ACPI |
332 | extern int tpm_add_ppi(struct kobject *); | 299 | extern struct dentry ** tpm_bios_log_setup(char *); |
333 | extern void tpm_remove_ppi(struct kobject *); | 300 | extern void tpm_bios_log_teardown(struct dentry **); |
334 | #else | 301 | #else |
335 | static inline int tpm_add_ppi(struct kobject *parent) | 302 | static inline struct dentry ** tpm_bios_log_setup(char *name) |
336 | { | 303 | { |
337 | return 0; | 304 | return NULL; |
338 | } | 305 | } |
339 | 306 | static inline void tpm_bios_log_teardown(struct dentry **dir) | |
340 | static inline void tpm_remove_ppi(struct kobject *parent) | ||
341 | { | 307 | { |
342 | } | 308 | } |
343 | #endif | 309 | #endif |
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c deleted file mode 100644 index 56051d0c97a..00000000000 --- a/drivers/char/tpm/tpm_acpi.c +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Seiji Munetoh <munetoh@jp.ibm.com> | ||
6 | * Stefan Berger <stefanb@us.ibm.com> | ||
7 | * Reiner Sailer <sailer@watson.ibm.com> | ||
8 | * Kylene Hall <kjhall@us.ibm.com> | ||
9 | * | ||
10 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
11 | * | ||
12 | * Access to the eventlog extended by the TCG BIOS of PC platform | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version | ||
17 | * 2 of the License, or (at your option) any later version. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/security.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <acpi/acpi.h> | ||
27 | |||
28 | #include "tpm.h" | ||
29 | #include "tpm_eventlog.h" | ||
30 | |||
31 | struct acpi_tcpa { | ||
32 | struct acpi_table_header hdr; | ||
33 | u16 platform_class; | ||
34 | union { | ||
35 | struct client_hdr { | ||
36 | u32 log_max_len __attribute__ ((packed)); | ||
37 | u64 log_start_addr __attribute__ ((packed)); | ||
38 | } client; | ||
39 | struct server_hdr { | ||
40 | u16 reserved; | ||
41 | u64 log_max_len __attribute__ ((packed)); | ||
42 | u64 log_start_addr __attribute__ ((packed)); | ||
43 | } server; | ||
44 | }; | ||
45 | }; | ||
46 | |||
47 | /* read binary bios log */ | ||
48 | int read_log(struct tpm_bios_log *log) | ||
49 | { | ||
50 | struct acpi_tcpa *buff; | ||
51 | acpi_status status; | ||
52 | void __iomem *virt; | ||
53 | u64 len, start; | ||
54 | |||
55 | if (log->bios_event_log != NULL) { | ||
56 | printk(KERN_ERR | ||
57 | "%s: ERROR - Eventlog already initialized\n", | ||
58 | __func__); | ||
59 | return -EFAULT; | ||
60 | } | ||
61 | |||
62 | /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ | ||
63 | status = acpi_get_table(ACPI_SIG_TCPA, 1, | ||
64 | (struct acpi_table_header **)&buff); | ||
65 | |||
66 | if (ACPI_FAILURE(status)) { | ||
67 | printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", | ||
68 | __func__); | ||
69 | return -EIO; | ||
70 | } | ||
71 | |||
72 | switch(buff->platform_class) { | ||
73 | case BIOS_SERVER: | ||
74 | len = buff->server.log_max_len; | ||
75 | start = buff->server.log_start_addr; | ||
76 | break; | ||
77 | case BIOS_CLIENT: | ||
78 | default: | ||
79 | len = buff->client.log_max_len; | ||
80 | start = buff->client.log_start_addr; | ||
81 | break; | ||
82 | } | ||
83 | if (!len) { | ||
84 | printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); | ||
85 | return -EIO; | ||
86 | } | ||
87 | |||
88 | /* malloc EventLog space */ | ||
89 | log->bios_event_log = kmalloc(len, GFP_KERNEL); | ||
90 | if (!log->bios_event_log) { | ||
91 | printk("%s: ERROR - Not enough Memory for BIOS measurements\n", | ||
92 | __func__); | ||
93 | return -ENOMEM; | ||
94 | } | ||
95 | |||
96 | log->bios_event_log_end = log->bios_event_log + len; | ||
97 | |||
98 | virt = acpi_os_map_memory(start, len); | ||
99 | if (!virt) { | ||
100 | kfree(log->bios_event_log); | ||
101 | printk("%s: ERROR - Unable to map memory\n", __func__); | ||
102 | return -EIO; | ||
103 | } | ||
104 | |||
105 | memcpy_fromio(log->bios_event_log, virt, len); | ||
106 | |||
107 | acpi_os_unmap_memory(virt, len); | ||
108 | return 0; | ||
109 | } | ||
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index 678d57019dc..c64a1bc6534 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c | |||
@@ -168,14 +168,22 @@ static void atml_plat_remove(void) | |||
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | static SIMPLE_DEV_PM_OPS(tpm_atml_pm, tpm_pm_suspend, tpm_pm_resume); | 171 | static int tpm_atml_suspend(struct platform_device *dev, pm_message_t msg) |
172 | { | ||
173 | return tpm_pm_suspend(&dev->dev, msg); | ||
174 | } | ||
172 | 175 | ||
176 | static int tpm_atml_resume(struct platform_device *dev) | ||
177 | { | ||
178 | return tpm_pm_resume(&dev->dev); | ||
179 | } | ||
173 | static struct platform_driver atml_drv = { | 180 | static struct platform_driver atml_drv = { |
174 | .driver = { | 181 | .driver = { |
175 | .name = "tpm_atmel", | 182 | .name = "tpm_atmel", |
176 | .owner = THIS_MODULE, | 183 | .owner = THIS_MODULE, |
177 | .pm = &tpm_atml_pm, | ||
178 | }, | 184 | }, |
185 | .suspend = tpm_atml_suspend, | ||
186 | .resume = tpm_atml_resume, | ||
179 | }; | 187 | }; |
180 | 188 | ||
181 | static int __init init_atmel(void) | 189 | static int __init init_atmel(void) |
diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c deleted file mode 100644 index 84ddc557b8f..00000000000 --- a/drivers/char/tpm/tpm_eventlog.c +++ /dev/null | |||
@@ -1,419 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005, 2012 IBM Corporation | ||
3 | * | ||
4 | * Authors: | ||
5 | * Kent Yoder <key@linux.vnet.ibm.com> | ||
6 | * Seiji Munetoh <munetoh@jp.ibm.com> | ||
7 | * Stefan Berger <stefanb@us.ibm.com> | ||
8 | * Reiner Sailer <sailer@watson.ibm.com> | ||
9 | * Kylene Hall <kjhall@us.ibm.com> | ||
10 | * | ||
11 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
12 | * | ||
13 | * Access to the eventlog created by a system's firmware / BIOS | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version | ||
18 | * 2 of the License, or (at your option) any later version. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/seq_file.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/security.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include "tpm.h" | ||
29 | #include "tpm_eventlog.h" | ||
30 | |||
31 | |||
32 | static const char* tcpa_event_type_strings[] = { | ||
33 | "PREBOOT", | ||
34 | "POST CODE", | ||
35 | "", | ||
36 | "NO ACTION", | ||
37 | "SEPARATOR", | ||
38 | "ACTION", | ||
39 | "EVENT TAG", | ||
40 | "S-CRTM Contents", | ||
41 | "S-CRTM Version", | ||
42 | "CPU Microcode", | ||
43 | "Platform Config Flags", | ||
44 | "Table of Devices", | ||
45 | "Compact Hash", | ||
46 | "IPL", | ||
47 | "IPL Partition Data", | ||
48 | "Non-Host Code", | ||
49 | "Non-Host Config", | ||
50 | "Non-Host Info" | ||
51 | }; | ||
52 | |||
53 | static const char* tcpa_pc_event_id_strings[] = { | ||
54 | "", | ||
55 | "SMBIOS", | ||
56 | "BIS Certificate", | ||
57 | "POST BIOS ", | ||
58 | "ESCD ", | ||
59 | "CMOS", | ||
60 | "NVRAM", | ||
61 | "Option ROM", | ||
62 | "Option ROM config", | ||
63 | "", | ||
64 | "Option ROM microcode ", | ||
65 | "S-CRTM Version", | ||
66 | "S-CRTM Contents ", | ||
67 | "POST Contents ", | ||
68 | "Table of Devices", | ||
69 | }; | ||
70 | |||
71 | /* returns pointer to start of pos. entry of tcg log */ | ||
72 | static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) | ||
73 | { | ||
74 | loff_t i; | ||
75 | struct tpm_bios_log *log = m->private; | ||
76 | void *addr = log->bios_event_log; | ||
77 | void *limit = log->bios_event_log_end; | ||
78 | struct tcpa_event *event; | ||
79 | |||
80 | /* read over *pos measurements */ | ||
81 | for (i = 0; i < *pos; i++) { | ||
82 | event = addr; | ||
83 | |||
84 | if ((addr + sizeof(struct tcpa_event)) < limit) { | ||
85 | if (event->event_type == 0 && event->event_size == 0) | ||
86 | return NULL; | ||
87 | addr += sizeof(struct tcpa_event) + event->event_size; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /* now check if current entry is valid */ | ||
92 | if ((addr + sizeof(struct tcpa_event)) >= limit) | ||
93 | return NULL; | ||
94 | |||
95 | event = addr; | ||
96 | |||
97 | if ((event->event_type == 0 && event->event_size == 0) || | ||
98 | ((addr + sizeof(struct tcpa_event) + event->event_size) >= limit)) | ||
99 | return NULL; | ||
100 | |||
101 | return addr; | ||
102 | } | ||
103 | |||
104 | static void *tpm_bios_measurements_next(struct seq_file *m, void *v, | ||
105 | loff_t *pos) | ||
106 | { | ||
107 | struct tcpa_event *event = v; | ||
108 | struct tpm_bios_log *log = m->private; | ||
109 | void *limit = log->bios_event_log_end; | ||
110 | |||
111 | v += sizeof(struct tcpa_event) + event->event_size; | ||
112 | |||
113 | /* now check if current entry is valid */ | ||
114 | if ((v + sizeof(struct tcpa_event)) >= limit) | ||
115 | return NULL; | ||
116 | |||
117 | event = v; | ||
118 | |||
119 | if (event->event_type == 0 && event->event_size == 0) | ||
120 | return NULL; | ||
121 | |||
122 | if ((event->event_type == 0 && event->event_size == 0) || | ||
123 | ((v + sizeof(struct tcpa_event) + event->event_size) >= limit)) | ||
124 | return NULL; | ||
125 | |||
126 | (*pos)++; | ||
127 | return v; | ||
128 | } | ||
129 | |||
130 | static void tpm_bios_measurements_stop(struct seq_file *m, void *v) | ||
131 | { | ||
132 | } | ||
133 | |||
134 | static int get_event_name(char *dest, struct tcpa_event *event, | ||
135 | unsigned char * event_entry) | ||
136 | { | ||
137 | const char *name = ""; | ||
138 | /* 41 so there is room for 40 data and 1 nul */ | ||
139 | char data[41] = ""; | ||
140 | int i, n_len = 0, d_len = 0; | ||
141 | struct tcpa_pc_event *pc_event; | ||
142 | |||
143 | switch(event->event_type) { | ||
144 | case PREBOOT: | ||
145 | case POST_CODE: | ||
146 | case UNUSED: | ||
147 | case NO_ACTION: | ||
148 | case SCRTM_CONTENTS: | ||
149 | case SCRTM_VERSION: | ||
150 | case CPU_MICROCODE: | ||
151 | case PLATFORM_CONFIG_FLAGS: | ||
152 | case TABLE_OF_DEVICES: | ||
153 | case COMPACT_HASH: | ||
154 | case IPL: | ||
155 | case IPL_PARTITION_DATA: | ||
156 | case NONHOST_CODE: | ||
157 | case NONHOST_CONFIG: | ||
158 | case NONHOST_INFO: | ||
159 | name = tcpa_event_type_strings[event->event_type]; | ||
160 | n_len = strlen(name); | ||
161 | break; | ||
162 | case SEPARATOR: | ||
163 | case ACTION: | ||
164 | if (MAX_TEXT_EVENT > event->event_size) { | ||
165 | name = event_entry; | ||
166 | n_len = event->event_size; | ||
167 | } | ||
168 | break; | ||
169 | case EVENT_TAG: | ||
170 | pc_event = (struct tcpa_pc_event *)event_entry; | ||
171 | |||
172 | /* ToDo Row data -> Base64 */ | ||
173 | |||
174 | switch (pc_event->event_id) { | ||
175 | case SMBIOS: | ||
176 | case BIS_CERT: | ||
177 | case CMOS: | ||
178 | case NVRAM: | ||
179 | case OPTION_ROM_EXEC: | ||
180 | case OPTION_ROM_CONFIG: | ||
181 | case S_CRTM_VERSION: | ||
182 | name = tcpa_pc_event_id_strings[pc_event->event_id]; | ||
183 | n_len = strlen(name); | ||
184 | break; | ||
185 | /* hash data */ | ||
186 | case POST_BIOS_ROM: | ||
187 | case ESCD: | ||
188 | case OPTION_ROM_MICROCODE: | ||
189 | case S_CRTM_CONTENTS: | ||
190 | case POST_CONTENTS: | ||
191 | name = tcpa_pc_event_id_strings[pc_event->event_id]; | ||
192 | n_len = strlen(name); | ||
193 | for (i = 0; i < 20; i++) | ||
194 | d_len += sprintf(&data[2*i], "%02x", | ||
195 | pc_event->event_data[i]); | ||
196 | break; | ||
197 | default: | ||
198 | break; | ||
199 | } | ||
200 | default: | ||
201 | break; | ||
202 | } | ||
203 | |||
204 | return snprintf(dest, MAX_TEXT_EVENT, "[%.*s%.*s]", | ||
205 | n_len, name, d_len, data); | ||
206 | |||
207 | } | ||
208 | |||
209 | static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) | ||
210 | { | ||
211 | struct tcpa_event *event = v; | ||
212 | char *data = v; | ||
213 | int i; | ||
214 | |||
215 | for (i = 0; i < sizeof(struct tcpa_event) + event->event_size; i++) | ||
216 | seq_putc(m, data[i]); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int tpm_bios_measurements_release(struct inode *inode, | ||
222 | struct file *file) | ||
223 | { | ||
224 | struct seq_file *seq = file->private_data; | ||
225 | struct tpm_bios_log *log = seq->private; | ||
226 | |||
227 | if (log) { | ||
228 | kfree(log->bios_event_log); | ||
229 | kfree(log); | ||
230 | } | ||
231 | |||
232 | return seq_release(inode, file); | ||
233 | } | ||
234 | |||
235 | static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) | ||
236 | { | ||
237 | int len = 0; | ||
238 | int i; | ||
239 | char *eventname; | ||
240 | struct tcpa_event *event = v; | ||
241 | unsigned char *event_entry = | ||
242 | (unsigned char *) (v + sizeof(struct tcpa_event)); | ||
243 | |||
244 | eventname = kmalloc(MAX_TEXT_EVENT, GFP_KERNEL); | ||
245 | if (!eventname) { | ||
246 | printk(KERN_ERR "%s: ERROR - No Memory for event name\n ", | ||
247 | __func__); | ||
248 | return -EFAULT; | ||
249 | } | ||
250 | |||
251 | seq_printf(m, "%2d ", event->pcr_index); | ||
252 | |||
253 | /* 2nd: SHA1 */ | ||
254 | for (i = 0; i < 20; i++) | ||
255 | seq_printf(m, "%02x", event->pcr_value[i]); | ||
256 | |||
257 | /* 3rd: event type identifier */ | ||
258 | seq_printf(m, " %02x", event->event_type); | ||
259 | |||
260 | len += get_event_name(eventname, event, event_entry); | ||
261 | |||
262 | /* 4th: eventname <= max + \'0' delimiter */ | ||
263 | seq_printf(m, " %s\n", eventname); | ||
264 | |||
265 | kfree(eventname); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static const struct seq_operations tpm_ascii_b_measurments_seqops = { | ||
270 | .start = tpm_bios_measurements_start, | ||
271 | .next = tpm_bios_measurements_next, | ||
272 | .stop = tpm_bios_measurements_stop, | ||
273 | .show = tpm_ascii_bios_measurements_show, | ||
274 | }; | ||
275 | |||
276 | static const struct seq_operations tpm_binary_b_measurments_seqops = { | ||
277 | .start = tpm_bios_measurements_start, | ||
278 | .next = tpm_bios_measurements_next, | ||
279 | .stop = tpm_bios_measurements_stop, | ||
280 | .show = tpm_binary_bios_measurements_show, | ||
281 | }; | ||
282 | |||
283 | static int tpm_ascii_bios_measurements_open(struct inode *inode, | ||
284 | struct file *file) | ||
285 | { | ||
286 | int err; | ||
287 | struct tpm_bios_log *log; | ||
288 | struct seq_file *seq; | ||
289 | |||
290 | log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); | ||
291 | if (!log) | ||
292 | return -ENOMEM; | ||
293 | |||
294 | if ((err = read_log(log))) | ||
295 | goto out_free; | ||
296 | |||
297 | /* now register seq file */ | ||
298 | err = seq_open(file, &tpm_ascii_b_measurments_seqops); | ||
299 | if (!err) { | ||
300 | seq = file->private_data; | ||
301 | seq->private = log; | ||
302 | } else { | ||
303 | goto out_free; | ||
304 | } | ||
305 | |||
306 | out: | ||
307 | return err; | ||
308 | out_free: | ||
309 | kfree(log->bios_event_log); | ||
310 | kfree(log); | ||
311 | goto out; | ||
312 | } | ||
313 | |||
314 | static const struct file_operations tpm_ascii_bios_measurements_ops = { | ||
315 | .open = tpm_ascii_bios_measurements_open, | ||
316 | .read = seq_read, | ||
317 | .llseek = seq_lseek, | ||
318 | .release = tpm_bios_measurements_release, | ||
319 | }; | ||
320 | |||
321 | static int tpm_binary_bios_measurements_open(struct inode *inode, | ||
322 | struct file *file) | ||
323 | { | ||
324 | int err; | ||
325 | struct tpm_bios_log *log; | ||
326 | struct seq_file *seq; | ||
327 | |||
328 | log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); | ||
329 | if (!log) | ||
330 | return -ENOMEM; | ||
331 | |||
332 | if ((err = read_log(log))) | ||
333 | goto out_free; | ||
334 | |||
335 | /* now register seq file */ | ||
336 | err = seq_open(file, &tpm_binary_b_measurments_seqops); | ||
337 | if (!err) { | ||
338 | seq = file->private_data; | ||
339 | seq->private = log; | ||
340 | } else { | ||
341 | goto out_free; | ||
342 | } | ||
343 | |||
344 | out: | ||
345 | return err; | ||
346 | out_free: | ||
347 | kfree(log->bios_event_log); | ||
348 | kfree(log); | ||
349 | goto out; | ||
350 | } | ||
351 | |||
352 | static const struct file_operations tpm_binary_bios_measurements_ops = { | ||
353 | .open = tpm_binary_bios_measurements_open, | ||
354 | .read = seq_read, | ||
355 | .llseek = seq_lseek, | ||
356 | .release = tpm_bios_measurements_release, | ||
357 | }; | ||
358 | |||
359 | static int is_bad(void *p) | ||
360 | { | ||
361 | if (!p) | ||
362 | return 1; | ||
363 | if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV)) | ||
364 | return 1; | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | struct dentry **tpm_bios_log_setup(char *name) | ||
369 | { | ||
370 | struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; | ||
371 | |||
372 | tpm_dir = securityfs_create_dir(name, NULL); | ||
373 | if (is_bad(tpm_dir)) | ||
374 | goto out; | ||
375 | |||
376 | bin_file = | ||
377 | securityfs_create_file("binary_bios_measurements", | ||
378 | S_IRUSR | S_IRGRP, tpm_dir, NULL, | ||
379 | &tpm_binary_bios_measurements_ops); | ||
380 | if (is_bad(bin_file)) | ||
381 | goto out_tpm; | ||
382 | |||
383 | ascii_file = | ||
384 | securityfs_create_file("ascii_bios_measurements", | ||
385 | S_IRUSR | S_IRGRP, tpm_dir, NULL, | ||
386 | &tpm_ascii_bios_measurements_ops); | ||
387 | if (is_bad(ascii_file)) | ||
388 | goto out_bin; | ||
389 | |||
390 | ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); | ||
391 | if (!ret) | ||
392 | goto out_ascii; | ||
393 | |||
394 | ret[0] = ascii_file; | ||
395 | ret[1] = bin_file; | ||
396 | ret[2] = tpm_dir; | ||
397 | |||
398 | return ret; | ||
399 | |||
400 | out_ascii: | ||
401 | securityfs_remove(ascii_file); | ||
402 | out_bin: | ||
403 | securityfs_remove(bin_file); | ||
404 | out_tpm: | ||
405 | securityfs_remove(tpm_dir); | ||
406 | out: | ||
407 | return NULL; | ||
408 | } | ||
409 | EXPORT_SYMBOL_GPL(tpm_bios_log_setup); | ||
410 | |||
411 | void tpm_bios_log_teardown(struct dentry **lst) | ||
412 | { | ||
413 | int i; | ||
414 | |||
415 | for (i = 0; i < 3; i++) | ||
416 | securityfs_remove(lst[i]); | ||
417 | } | ||
418 | EXPORT_SYMBOL_GPL(tpm_bios_log_teardown); | ||
419 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h deleted file mode 100644 index e7da086d692..00000000000 --- a/drivers/char/tpm/tpm_eventlog.h +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | |||
2 | #ifndef __TPM_EVENTLOG_H__ | ||
3 | #define __TPM_EVENTLOG_H__ | ||
4 | |||
5 | #define TCG_EVENT_NAME_LEN_MAX 255 | ||
6 | #define MAX_TEXT_EVENT 1000 /* Max event string length */ | ||
7 | #define ACPI_TCPA_SIG "TCPA" /* 0x41504354 /'TCPA' */ | ||
8 | |||
9 | enum bios_platform_class { | ||
10 | BIOS_CLIENT = 0x00, | ||
11 | BIOS_SERVER = 0x01, | ||
12 | }; | ||
13 | |||
14 | struct tpm_bios_log { | ||
15 | void *bios_event_log; | ||
16 | void *bios_event_log_end; | ||
17 | }; | ||
18 | |||
19 | struct tcpa_event { | ||
20 | u32 pcr_index; | ||
21 | u32 event_type; | ||
22 | u8 pcr_value[20]; /* SHA1 */ | ||
23 | u32 event_size; | ||
24 | u8 event_data[0]; | ||
25 | }; | ||
26 | |||
27 | enum tcpa_event_types { | ||
28 | PREBOOT = 0, | ||
29 | POST_CODE, | ||
30 | UNUSED, | ||
31 | NO_ACTION, | ||
32 | SEPARATOR, | ||
33 | ACTION, | ||
34 | EVENT_TAG, | ||
35 | SCRTM_CONTENTS, | ||
36 | SCRTM_VERSION, | ||
37 | CPU_MICROCODE, | ||
38 | PLATFORM_CONFIG_FLAGS, | ||
39 | TABLE_OF_DEVICES, | ||
40 | COMPACT_HASH, | ||
41 | IPL, | ||
42 | IPL_PARTITION_DATA, | ||
43 | NONHOST_CODE, | ||
44 | NONHOST_CONFIG, | ||
45 | NONHOST_INFO, | ||
46 | }; | ||
47 | |||
48 | struct tcpa_pc_event { | ||
49 | u32 event_id; | ||
50 | u32 event_size; | ||
51 | u8 event_data[0]; | ||
52 | }; | ||
53 | |||
54 | enum tcpa_pc_event_ids { | ||
55 | SMBIOS = 1, | ||
56 | BIS_CERT, | ||
57 | POST_BIOS_ROM, | ||
58 | ESCD, | ||
59 | CMOS, | ||
60 | NVRAM, | ||
61 | OPTION_ROM_EXEC, | ||
62 | OPTION_ROM_CONFIG, | ||
63 | OPTION_ROM_MICROCODE = 10, | ||
64 | S_CRTM_VERSION, | ||
65 | S_CRTM_CONTENTS, | ||
66 | POST_CONTENTS, | ||
67 | HOST_TABLE_OF_DEVICES, | ||
68 | }; | ||
69 | |||
70 | int read_log(struct tpm_bios_log *log); | ||
71 | |||
72 | #if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ | ||
73 | defined(CONFIG_ACPI) | ||
74 | extern struct dentry **tpm_bios_log_setup(char *); | ||
75 | extern void tpm_bios_log_teardown(struct dentry **); | ||
76 | #else | ||
77 | static inline struct dentry **tpm_bios_log_setup(char *name) | ||
78 | { | ||
79 | return NULL; | ||
80 | } | ||
81 | static inline void tpm_bios_log_teardown(struct dentry **dir) | ||
82 | { | ||
83 | } | ||
84 | #endif | ||
85 | |||
86 | #endif | ||
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c deleted file mode 100644 index fb447bd0cb6..00000000000 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ /dev/null | |||
@@ -1,695 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Infineon Technologies | ||
3 | * | ||
4 | * Authors: | ||
5 | * Peter Huewe <peter.huewe@infineon.com> | ||
6 | * | ||
7 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
8 | * Specifications at www.trustedcomputinggroup.org | ||
9 | * | ||
10 | * This device driver implements the TPM interface as defined in | ||
11 | * the TCG TPM Interface Spec version 1.2, revision 1.0 and the | ||
12 | * Infineon I2C Protocol Stack Specification v0.20. | ||
13 | * | ||
14 | * It is based on the original tpm_tis device driver from Leendert van | ||
15 | * Dorn and Kyleen Hall. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or | ||
18 | * modify it under the terms of the GNU General Public License as | ||
19 | * published by the Free Software Foundation, version 2 of the | ||
20 | * License. | ||
21 | * | ||
22 | * | ||
23 | */ | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/wait.h> | ||
29 | #include "tpm.h" | ||
30 | |||
31 | /* max. buffer size supported by our TPM */ | ||
32 | #define TPM_BUFSIZE 1260 | ||
33 | |||
34 | /* max. number of iterations after I2C NAK */ | ||
35 | #define MAX_COUNT 3 | ||
36 | |||
37 | #define SLEEP_DURATION_LOW 55 | ||
38 | #define SLEEP_DURATION_HI 65 | ||
39 | |||
40 | /* max. number of iterations after I2C NAK for 'long' commands | ||
41 | * we need this especially for sending TPM_READY, since the cleanup after the | ||
42 | * transtion to the ready state may take some time, but it is unpredictable | ||
43 | * how long it will take. | ||
44 | */ | ||
45 | #define MAX_COUNT_LONG 50 | ||
46 | |||
47 | #define SLEEP_DURATION_LONG_LOW 200 | ||
48 | #define SLEEP_DURATION_LONG_HI 220 | ||
49 | |||
50 | /* After sending TPM_READY to 'reset' the TPM we have to sleep even longer */ | ||
51 | #define SLEEP_DURATION_RESET_LOW 2400 | ||
52 | #define SLEEP_DURATION_RESET_HI 2600 | ||
53 | |||
54 | /* we want to use usleep_range instead of msleep for the 5ms TPM_TIMEOUT */ | ||
55 | #define TPM_TIMEOUT_US_LOW (TPM_TIMEOUT * 1000) | ||
56 | #define TPM_TIMEOUT_US_HI (TPM_TIMEOUT_US_LOW + 2000) | ||
57 | |||
58 | /* expected value for DIDVID register */ | ||
59 | #define TPM_TIS_I2C_DID_VID 0x000b15d1L | ||
60 | |||
61 | /* Structure to store I2C TPM specific stuff */ | ||
62 | struct tpm_inf_dev { | ||
63 | struct i2c_client *client; | ||
64 | u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ | ||
65 | struct tpm_chip *chip; | ||
66 | }; | ||
67 | |||
68 | static struct tpm_inf_dev tpm_dev; | ||
69 | static struct i2c_driver tpm_tis_i2c_driver; | ||
70 | |||
71 | /* | ||
72 | * iic_tpm_read() - read from TPM register | ||
73 | * @addr: register address to read from | ||
74 | * @buffer: provided by caller | ||
75 | * @len: number of bytes to read | ||
76 | * | ||
77 | * Read len bytes from TPM register and put them into | ||
78 | * buffer (little-endian format, i.e. first byte is put into buffer[0]). | ||
79 | * | ||
80 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | ||
81 | * values have to be swapped. | ||
82 | * | ||
83 | * NOTE: We can't unfortunately use the combined read/write functions | ||
84 | * provided by the i2c core as the TPM currently does not support the | ||
85 | * repeated start condition and due to it's special requirements. | ||
86 | * The i2c_smbus* functions do not work for this chip. | ||
87 | * | ||
88 | * Return -EIO on error, 0 on success. | ||
89 | */ | ||
90 | static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) | ||
91 | { | ||
92 | |||
93 | struct i2c_msg msg1 = { tpm_dev.client->addr, 0, 1, &addr }; | ||
94 | struct i2c_msg msg2 = { tpm_dev.client->addr, I2C_M_RD, len, buffer }; | ||
95 | |||
96 | int rc; | ||
97 | int count; | ||
98 | |||
99 | /* Lock the adapter for the duration of the whole sequence. */ | ||
100 | if (!tpm_dev.client->adapter->algo->master_xfer) | ||
101 | return -EOPNOTSUPP; | ||
102 | i2c_lock_adapter(tpm_dev.client->adapter); | ||
103 | |||
104 | for (count = 0; count < MAX_COUNT; count++) { | ||
105 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | ||
106 | if (rc > 0) | ||
107 | break; /* break here to skip sleep */ | ||
108 | |||
109 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
110 | } | ||
111 | |||
112 | if (rc <= 0) | ||
113 | goto out; | ||
114 | |||
115 | /* After the TPM has successfully received the register address it needs | ||
116 | * some time, thus we're sleeping here again, before retrieving the data | ||
117 | */ | ||
118 | for (count = 0; count < MAX_COUNT; count++) { | ||
119 | usleep_range(SLEEP_DURATION_LOW, SLEEP_DURATION_HI); | ||
120 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg2, 1); | ||
121 | if (rc > 0) | ||
122 | break; | ||
123 | |||
124 | } | ||
125 | |||
126 | out: | ||
127 | i2c_unlock_adapter(tpm_dev.client->adapter); | ||
128 | if (rc <= 0) | ||
129 | return -EIO; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, | ||
135 | unsigned int sleep_low, | ||
136 | unsigned int sleep_hi, u8 max_count) | ||
137 | { | ||
138 | int rc = -EIO; | ||
139 | int count; | ||
140 | |||
141 | struct i2c_msg msg1 = { tpm_dev.client->addr, 0, len + 1, tpm_dev.buf }; | ||
142 | |||
143 | if (len > TPM_BUFSIZE) | ||
144 | return -EINVAL; | ||
145 | |||
146 | if (!tpm_dev.client->adapter->algo->master_xfer) | ||
147 | return -EOPNOTSUPP; | ||
148 | i2c_lock_adapter(tpm_dev.client->adapter); | ||
149 | |||
150 | /* prepend the 'register address' to the buffer */ | ||
151 | tpm_dev.buf[0] = addr; | ||
152 | memcpy(&(tpm_dev.buf[1]), buffer, len); | ||
153 | |||
154 | /* | ||
155 | * NOTE: We have to use these special mechanisms here and unfortunately | ||
156 | * cannot rely on the standard behavior of i2c_transfer. | ||
157 | */ | ||
158 | for (count = 0; count < max_count; count++) { | ||
159 | rc = __i2c_transfer(tpm_dev.client->adapter, &msg1, 1); | ||
160 | if (rc > 0) | ||
161 | break; | ||
162 | |||
163 | usleep_range(sleep_low, sleep_hi); | ||
164 | } | ||
165 | |||
166 | i2c_unlock_adapter(tpm_dev.client->adapter); | ||
167 | if (rc <= 0) | ||
168 | return -EIO; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * iic_tpm_write() - write to TPM register | ||
175 | * @addr: register address to write to | ||
176 | * @buffer: containing data to be written | ||
177 | * @len: number of bytes to write | ||
178 | * | ||
179 | * Write len bytes from provided buffer to TPM register (little | ||
180 | * endian format, i.e. buffer[0] is written as first byte). | ||
181 | * | ||
182 | * NOTE: TPM is big-endian for multi-byte values. Multi-byte | ||
183 | * values have to be swapped. | ||
184 | * | ||
185 | * NOTE: use this function instead of the iic_tpm_write_generic function. | ||
186 | * | ||
187 | * Return -EIO on error, 0 on success | ||
188 | */ | ||
189 | static int iic_tpm_write(u8 addr, u8 *buffer, size_t len) | ||
190 | { | ||
191 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LOW, | ||
192 | SLEEP_DURATION_HI, MAX_COUNT); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * This function is needed especially for the cleanup situation after | ||
197 | * sending TPM_READY | ||
198 | * */ | ||
199 | static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len) | ||
200 | { | ||
201 | return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG_LOW, | ||
202 | SLEEP_DURATION_LONG_HI, MAX_COUNT_LONG); | ||
203 | } | ||
204 | |||
205 | enum tis_access { | ||
206 | TPM_ACCESS_VALID = 0x80, | ||
207 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | ||
208 | TPM_ACCESS_REQUEST_PENDING = 0x04, | ||
209 | TPM_ACCESS_REQUEST_USE = 0x02, | ||
210 | }; | ||
211 | |||
212 | enum tis_status { | ||
213 | TPM_STS_VALID = 0x80, | ||
214 | TPM_STS_COMMAND_READY = 0x40, | ||
215 | TPM_STS_GO = 0x20, | ||
216 | TPM_STS_DATA_AVAIL = 0x10, | ||
217 | TPM_STS_DATA_EXPECT = 0x08, | ||
218 | }; | ||
219 | |||
220 | enum tis_defaults { | ||
221 | TIS_SHORT_TIMEOUT = 750, /* ms */ | ||
222 | TIS_LONG_TIMEOUT = 2000, /* 2 sec */ | ||
223 | }; | ||
224 | |||
225 | #define TPM_ACCESS(l) (0x0000 | ((l) << 4)) | ||
226 | #define TPM_STS(l) (0x0001 | ((l) << 4)) | ||
227 | #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) | ||
228 | #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) | ||
229 | |||
230 | static int check_locality(struct tpm_chip *chip, int loc) | ||
231 | { | ||
232 | u8 buf; | ||
233 | int rc; | ||
234 | |||
235 | rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1); | ||
236 | if (rc < 0) | ||
237 | return rc; | ||
238 | |||
239 | if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == | ||
240 | (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { | ||
241 | chip->vendor.locality = loc; | ||
242 | return loc; | ||
243 | } | ||
244 | |||
245 | return -EIO; | ||
246 | } | ||
247 | |||
248 | /* implementation similar to tpm_tis */ | ||
249 | static void release_locality(struct tpm_chip *chip, int loc, int force) | ||
250 | { | ||
251 | u8 buf; | ||
252 | if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) | ||
253 | return; | ||
254 | |||
255 | if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == | ||
256 | (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { | ||
257 | buf = TPM_ACCESS_ACTIVE_LOCALITY; | ||
258 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | static int request_locality(struct tpm_chip *chip, int loc) | ||
263 | { | ||
264 | unsigned long stop; | ||
265 | u8 buf = TPM_ACCESS_REQUEST_USE; | ||
266 | |||
267 | if (check_locality(chip, loc) >= 0) | ||
268 | return loc; | ||
269 | |||
270 | iic_tpm_write(TPM_ACCESS(loc), &buf, 1); | ||
271 | |||
272 | /* wait for burstcount */ | ||
273 | stop = jiffies + chip->vendor.timeout_a; | ||
274 | do { | ||
275 | if (check_locality(chip, loc) >= 0) | ||
276 | return loc; | ||
277 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
278 | } while (time_before(jiffies, stop)); | ||
279 | |||
280 | return -ETIME; | ||
281 | } | ||
282 | |||
283 | static u8 tpm_tis_i2c_status(struct tpm_chip *chip) | ||
284 | { | ||
285 | /* NOTE: since I2C read may fail, return 0 in this case --> time-out */ | ||
286 | u8 buf; | ||
287 | if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) | ||
288 | return 0; | ||
289 | else | ||
290 | return buf; | ||
291 | } | ||
292 | |||
293 | static void tpm_tis_i2c_ready(struct tpm_chip *chip) | ||
294 | { | ||
295 | /* this causes the current command to be aborted */ | ||
296 | u8 buf = TPM_STS_COMMAND_READY; | ||
297 | iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); | ||
298 | } | ||
299 | |||
300 | static ssize_t get_burstcount(struct tpm_chip *chip) | ||
301 | { | ||
302 | unsigned long stop; | ||
303 | ssize_t burstcnt; | ||
304 | u8 buf[3]; | ||
305 | |||
306 | /* wait for burstcount */ | ||
307 | /* which timeout value, spec has 2 answers (c & d) */ | ||
308 | stop = jiffies + chip->vendor.timeout_d; | ||
309 | do { | ||
310 | /* Note: STS is little endian */ | ||
311 | if (iic_tpm_read(TPM_STS(chip->vendor.locality)+1, buf, 3) < 0) | ||
312 | burstcnt = 0; | ||
313 | else | ||
314 | burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; | ||
315 | |||
316 | if (burstcnt) | ||
317 | return burstcnt; | ||
318 | |||
319 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
320 | } while (time_before(jiffies, stop)); | ||
321 | return -EBUSY; | ||
322 | } | ||
323 | |||
324 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | ||
325 | int *status) | ||
326 | { | ||
327 | unsigned long stop; | ||
328 | |||
329 | /* check current status */ | ||
330 | *status = tpm_tis_i2c_status(chip); | ||
331 | if ((*status & mask) == mask) | ||
332 | return 0; | ||
333 | |||
334 | stop = jiffies + timeout; | ||
335 | do { | ||
336 | /* since we just checked the status, give the TPM some time */ | ||
337 | usleep_range(TPM_TIMEOUT_US_LOW, TPM_TIMEOUT_US_HI); | ||
338 | *status = tpm_tis_i2c_status(chip); | ||
339 | if ((*status & mask) == mask) | ||
340 | return 0; | ||
341 | |||
342 | } while (time_before(jiffies, stop)); | ||
343 | |||
344 | return -ETIME; | ||
345 | } | ||
346 | |||
347 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | ||
348 | { | ||
349 | size_t size = 0; | ||
350 | ssize_t burstcnt; | ||
351 | u8 retries = 0; | ||
352 | int rc; | ||
353 | |||
354 | while (size < count) { | ||
355 | burstcnt = get_burstcount(chip); | ||
356 | |||
357 | /* burstcnt < 0 = TPM is busy */ | ||
358 | if (burstcnt < 0) | ||
359 | return burstcnt; | ||
360 | |||
361 | /* limit received data to max. left */ | ||
362 | if (burstcnt > (count - size)) | ||
363 | burstcnt = count - size; | ||
364 | |||
365 | rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), | ||
366 | &(buf[size]), burstcnt); | ||
367 | if (rc == 0) | ||
368 | size += burstcnt; | ||
369 | else if (rc < 0) | ||
370 | retries++; | ||
371 | |||
372 | /* avoid endless loop in case of broken HW */ | ||
373 | if (retries > MAX_COUNT_LONG) | ||
374 | return -EIO; | ||
375 | |||
376 | } | ||
377 | return size; | ||
378 | } | ||
379 | |||
380 | static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) | ||
381 | { | ||
382 | int size = 0; | ||
383 | int expected, status; | ||
384 | |||
385 | if (count < TPM_HEADER_SIZE) { | ||
386 | size = -EIO; | ||
387 | goto out; | ||
388 | } | ||
389 | |||
390 | /* read first 10 bytes, including tag, paramsize, and result */ | ||
391 | size = recv_data(chip, buf, TPM_HEADER_SIZE); | ||
392 | if (size < TPM_HEADER_SIZE) { | ||
393 | dev_err(chip->dev, "Unable to read header\n"); | ||
394 | goto out; | ||
395 | } | ||
396 | |||
397 | expected = be32_to_cpu(*(__be32 *)(buf + 2)); | ||
398 | if ((size_t) expected > count) { | ||
399 | size = -EIO; | ||
400 | goto out; | ||
401 | } | ||
402 | |||
403 | size += recv_data(chip, &buf[TPM_HEADER_SIZE], | ||
404 | expected - TPM_HEADER_SIZE); | ||
405 | if (size < expected) { | ||
406 | dev_err(chip->dev, "Unable to read remainder of result\n"); | ||
407 | size = -ETIME; | ||
408 | goto out; | ||
409 | } | ||
410 | |||
411 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | ||
412 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ | ||
413 | dev_err(chip->dev, "Error left over data\n"); | ||
414 | size = -EIO; | ||
415 | goto out; | ||
416 | } | ||
417 | |||
418 | out: | ||
419 | tpm_tis_i2c_ready(chip); | ||
420 | /* The TPM needs some time to clean up here, | ||
421 | * so we sleep rather than keeping the bus busy | ||
422 | */ | ||
423 | usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); | ||
424 | release_locality(chip, chip->vendor.locality, 0); | ||
425 | return size; | ||
426 | } | ||
427 | |||
428 | static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) | ||
429 | { | ||
430 | int rc, status; | ||
431 | ssize_t burstcnt; | ||
432 | size_t count = 0; | ||
433 | u8 retries = 0; | ||
434 | u8 sts = TPM_STS_GO; | ||
435 | |||
436 | if (len > TPM_BUFSIZE) | ||
437 | return -E2BIG; /* command is too long for our tpm, sorry */ | ||
438 | |||
439 | if (request_locality(chip, 0) < 0) | ||
440 | return -EBUSY; | ||
441 | |||
442 | status = tpm_tis_i2c_status(chip); | ||
443 | if ((status & TPM_STS_COMMAND_READY) == 0) { | ||
444 | tpm_tis_i2c_ready(chip); | ||
445 | if (wait_for_stat | ||
446 | (chip, TPM_STS_COMMAND_READY, | ||
447 | chip->vendor.timeout_b, &status) < 0) { | ||
448 | rc = -ETIME; | ||
449 | goto out_err; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | while (count < len - 1) { | ||
454 | burstcnt = get_burstcount(chip); | ||
455 | |||
456 | /* burstcnt < 0 = TPM is busy */ | ||
457 | if (burstcnt < 0) | ||
458 | return burstcnt; | ||
459 | |||
460 | if (burstcnt > (len - 1 - count)) | ||
461 | burstcnt = len - 1 - count; | ||
462 | |||
463 | rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), | ||
464 | &(buf[count]), burstcnt); | ||
465 | if (rc == 0) | ||
466 | count += burstcnt; | ||
467 | else if (rc < 0) | ||
468 | retries++; | ||
469 | |||
470 | /* avoid endless loop in case of broken HW */ | ||
471 | if (retries > MAX_COUNT_LONG) { | ||
472 | rc = -EIO; | ||
473 | goto out_err; | ||
474 | } | ||
475 | |||
476 | wait_for_stat(chip, TPM_STS_VALID, | ||
477 | chip->vendor.timeout_c, &status); | ||
478 | |||
479 | if ((status & TPM_STS_DATA_EXPECT) == 0) { | ||
480 | rc = -EIO; | ||
481 | goto out_err; | ||
482 | } | ||
483 | |||
484 | } | ||
485 | |||
486 | /* write last byte */ | ||
487 | iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); | ||
488 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); | ||
489 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | ||
490 | rc = -EIO; | ||
491 | goto out_err; | ||
492 | } | ||
493 | |||
494 | /* go and do it */ | ||
495 | iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); | ||
496 | |||
497 | return len; | ||
498 | out_err: | ||
499 | tpm_tis_i2c_ready(chip); | ||
500 | /* The TPM needs some time to clean up here, | ||
501 | * so we sleep rather than keeping the bus busy | ||
502 | */ | ||
503 | usleep_range(SLEEP_DURATION_RESET_LOW, SLEEP_DURATION_RESET_HI); | ||
504 | release_locality(chip, chip->vendor.locality, 0); | ||
505 | return rc; | ||
506 | } | ||
507 | |||
508 | static const struct file_operations tis_ops = { | ||
509 | .owner = THIS_MODULE, | ||
510 | .llseek = no_llseek, | ||
511 | .open = tpm_open, | ||
512 | .read = tpm_read, | ||
513 | .write = tpm_write, | ||
514 | .release = tpm_release, | ||
515 | }; | ||
516 | |||
517 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
518 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
519 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
520 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
521 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
522 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, NULL); | ||
523 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
524 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
525 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
526 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
527 | |||
528 | static struct attribute *tis_attrs[] = { | ||
529 | &dev_attr_pubek.attr, | ||
530 | &dev_attr_pcrs.attr, | ||
531 | &dev_attr_enabled.attr, | ||
532 | &dev_attr_active.attr, | ||
533 | &dev_attr_owned.attr, | ||
534 | &dev_attr_temp_deactivated.attr, | ||
535 | &dev_attr_caps.attr, | ||
536 | &dev_attr_cancel.attr, | ||
537 | &dev_attr_durations.attr, | ||
538 | &dev_attr_timeouts.attr, | ||
539 | NULL, | ||
540 | }; | ||
541 | |||
542 | static struct attribute_group tis_attr_grp = { | ||
543 | .attrs = tis_attrs | ||
544 | }; | ||
545 | |||
546 | static struct tpm_vendor_specific tpm_tis_i2c = { | ||
547 | .status = tpm_tis_i2c_status, | ||
548 | .recv = tpm_tis_i2c_recv, | ||
549 | .send = tpm_tis_i2c_send, | ||
550 | .cancel = tpm_tis_i2c_ready, | ||
551 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
552 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, | ||
553 | .req_canceled = TPM_STS_COMMAND_READY, | ||
554 | .attr_group = &tis_attr_grp, | ||
555 | .miscdev.fops = &tis_ops, | ||
556 | }; | ||
557 | |||
558 | static int tpm_tis_i2c_init(struct device *dev) | ||
559 | { | ||
560 | u32 vendor; | ||
561 | int rc = 0; | ||
562 | struct tpm_chip *chip; | ||
563 | |||
564 | chip = tpm_register_hardware(dev, &tpm_tis_i2c); | ||
565 | if (!chip) { | ||
566 | rc = -ENODEV; | ||
567 | goto out_err; | ||
568 | } | ||
569 | |||
570 | /* Disable interrupts */ | ||
571 | chip->vendor.irq = 0; | ||
572 | |||
573 | /* Default timeouts */ | ||
574 | chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
575 | chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT); | ||
576 | chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
577 | chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT); | ||
578 | |||
579 | if (request_locality(chip, 0) != 0) { | ||
580 | rc = -ENODEV; | ||
581 | goto out_vendor; | ||
582 | } | ||
583 | |||
584 | /* read four bytes from DID_VID register */ | ||
585 | if (iic_tpm_read(TPM_DID_VID(0), (u8 *)&vendor, 4) < 0) { | ||
586 | rc = -EIO; | ||
587 | goto out_release; | ||
588 | } | ||
589 | |||
590 | /* create DID_VID register value, after swapping to little-endian */ | ||
591 | vendor = be32_to_cpu((__be32) vendor); | ||
592 | |||
593 | if (vendor != TPM_TIS_I2C_DID_VID) { | ||
594 | rc = -ENODEV; | ||
595 | goto out_release; | ||
596 | } | ||
597 | |||
598 | dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16); | ||
599 | |||
600 | INIT_LIST_HEAD(&chip->vendor.list); | ||
601 | tpm_dev.chip = chip; | ||
602 | |||
603 | tpm_get_timeouts(chip); | ||
604 | tpm_do_selftest(chip); | ||
605 | |||
606 | return 0; | ||
607 | |||
608 | out_release: | ||
609 | release_locality(chip, chip->vendor.locality, 1); | ||
610 | |||
611 | out_vendor: | ||
612 | /* close file handles */ | ||
613 | tpm_dev_vendor_release(chip); | ||
614 | |||
615 | /* remove hardware */ | ||
616 | tpm_remove_hardware(chip->dev); | ||
617 | |||
618 | /* reset these pointers, otherwise we oops */ | ||
619 | chip->dev->release = NULL; | ||
620 | chip->release = NULL; | ||
621 | tpm_dev.client = NULL; | ||
622 | dev_set_drvdata(chip->dev, chip); | ||
623 | out_err: | ||
624 | return rc; | ||
625 | } | ||
626 | |||
627 | static const struct i2c_device_id tpm_tis_i2c_table[] = { | ||
628 | {"tpm_i2c_infineon", 0}, | ||
629 | {}, | ||
630 | }; | ||
631 | |||
632 | MODULE_DEVICE_TABLE(i2c, tpm_tis_i2c_table); | ||
633 | static SIMPLE_DEV_PM_OPS(tpm_tis_i2c_ops, tpm_pm_suspend, tpm_pm_resume); | ||
634 | |||
635 | static int tpm_tis_i2c_probe(struct i2c_client *client, | ||
636 | const struct i2c_device_id *id) | ||
637 | { | ||
638 | int rc; | ||
639 | if (tpm_dev.client != NULL) | ||
640 | return -EBUSY; /* We only support one client */ | ||
641 | |||
642 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { | ||
643 | dev_err(&client->dev, | ||
644 | "no algorithms associated to the i2c bus\n"); | ||
645 | return -ENODEV; | ||
646 | } | ||
647 | |||
648 | client->driver = &tpm_tis_i2c_driver; | ||
649 | tpm_dev.client = client; | ||
650 | rc = tpm_tis_i2c_init(&client->dev); | ||
651 | if (rc != 0) { | ||
652 | client->driver = NULL; | ||
653 | tpm_dev.client = NULL; | ||
654 | rc = -ENODEV; | ||
655 | } | ||
656 | return rc; | ||
657 | } | ||
658 | |||
659 | static int tpm_tis_i2c_remove(struct i2c_client *client) | ||
660 | { | ||
661 | struct tpm_chip *chip = tpm_dev.chip; | ||
662 | release_locality(chip, chip->vendor.locality, 1); | ||
663 | |||
664 | /* close file handles */ | ||
665 | tpm_dev_vendor_release(chip); | ||
666 | |||
667 | /* remove hardware */ | ||
668 | tpm_remove_hardware(chip->dev); | ||
669 | |||
670 | /* reset these pointers, otherwise we oops */ | ||
671 | chip->dev->release = NULL; | ||
672 | chip->release = NULL; | ||
673 | tpm_dev.client = NULL; | ||
674 | dev_set_drvdata(chip->dev, chip); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static struct i2c_driver tpm_tis_i2c_driver = { | ||
680 | |||
681 | .id_table = tpm_tis_i2c_table, | ||
682 | .probe = tpm_tis_i2c_probe, | ||
683 | .remove = tpm_tis_i2c_remove, | ||
684 | .driver = { | ||
685 | .name = "tpm_i2c_infineon", | ||
686 | .owner = THIS_MODULE, | ||
687 | .pm = &tpm_tis_i2c_ops, | ||
688 | }, | ||
689 | }; | ||
690 | |||
691 | module_i2c_driver(tpm_tis_i2c_driver); | ||
692 | MODULE_AUTHOR("Peter Huewe <peter.huewe@infineon.com>"); | ||
693 | MODULE_DESCRIPTION("TPM TIS I2C Infineon Driver"); | ||
694 | MODULE_VERSION("2.1.5"); | ||
695 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c deleted file mode 100644 index 9978609d93b..00000000000 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ /dev/null | |||
@@ -1,724 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 IBM Corporation | ||
3 | * | ||
4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
5 | * | ||
6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
7 | * | ||
8 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
9 | * Specifications at www.trustedcomputinggroup.org | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/dmapool.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <asm/vio.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/list.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <asm/prom.h> | ||
29 | |||
30 | #include "tpm.h" | ||
31 | #include "tpm_ibmvtpm.h" | ||
32 | |||
33 | static const char tpm_ibmvtpm_driver_name[] = "tpm_ibmvtpm"; | ||
34 | |||
35 | static struct vio_device_id tpm_ibmvtpm_device_table[] = { | ||
36 | { "IBM,vtpm", "IBM,vtpm"}, | ||
37 | { "", "" } | ||
38 | }; | ||
39 | MODULE_DEVICE_TABLE(vio, tpm_ibmvtpm_device_table); | ||
40 | |||
41 | /** | ||
42 | * ibmvtpm_send_crq - Send a CRQ request | ||
43 | * @vdev: vio device struct | ||
44 | * @w1: first word | ||
45 | * @w2: second word | ||
46 | * | ||
47 | * Return value: | ||
48 | * 0 -Sucess | ||
49 | * Non-zero - Failure | ||
50 | */ | ||
51 | static int ibmvtpm_send_crq(struct vio_dev *vdev, u64 w1, u64 w2) | ||
52 | { | ||
53 | return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, w1, w2); | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * ibmvtpm_get_data - Retrieve ibm vtpm data | ||
58 | * @dev: device struct | ||
59 | * | ||
60 | * Return value: | ||
61 | * vtpm device struct | ||
62 | */ | ||
63 | static struct ibmvtpm_dev *ibmvtpm_get_data(const struct device *dev) | ||
64 | { | ||
65 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
66 | if (chip) | ||
67 | return (struct ibmvtpm_dev *)chip->vendor.data; | ||
68 | return NULL; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * tpm_ibmvtpm_recv - Receive data after send | ||
73 | * @chip: tpm chip struct | ||
74 | * @buf: buffer to read | ||
75 | * count: size of buffer | ||
76 | * | ||
77 | * Return value: | ||
78 | * Number of bytes read | ||
79 | */ | ||
80 | static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | ||
81 | { | ||
82 | struct ibmvtpm_dev *ibmvtpm; | ||
83 | u16 len; | ||
84 | int sig; | ||
85 | |||
86 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | ||
87 | |||
88 | if (!ibmvtpm->rtce_buf) { | ||
89 | dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0); | ||
94 | if (sig) | ||
95 | return -EINTR; | ||
96 | |||
97 | len = ibmvtpm->res_len; | ||
98 | |||
99 | if (count < len) { | ||
100 | dev_err(ibmvtpm->dev, | ||
101 | "Invalid size in recv: count=%ld, crq_size=%d\n", | ||
102 | count, len); | ||
103 | return -EIO; | ||
104 | } | ||
105 | |||
106 | spin_lock(&ibmvtpm->rtce_lock); | ||
107 | memcpy((void *)buf, (void *)ibmvtpm->rtce_buf, len); | ||
108 | memset(ibmvtpm->rtce_buf, 0, len); | ||
109 | ibmvtpm->res_len = 0; | ||
110 | spin_unlock(&ibmvtpm->rtce_lock); | ||
111 | return len; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * tpm_ibmvtpm_send - Send tpm request | ||
116 | * @chip: tpm chip struct | ||
117 | * @buf: buffer contains data to send | ||
118 | * count: size of buffer | ||
119 | * | ||
120 | * Return value: | ||
121 | * Number of bytes sent | ||
122 | */ | ||
123 | static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) | ||
124 | { | ||
125 | struct ibmvtpm_dev *ibmvtpm; | ||
126 | struct ibmvtpm_crq crq; | ||
127 | u64 *word = (u64 *) &crq; | ||
128 | int rc; | ||
129 | |||
130 | ibmvtpm = (struct ibmvtpm_dev *)chip->vendor.data; | ||
131 | |||
132 | if (!ibmvtpm->rtce_buf) { | ||
133 | dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | if (count > ibmvtpm->rtce_size) { | ||
138 | dev_err(ibmvtpm->dev, | ||
139 | "Invalid size in send: count=%ld, rtce_size=%d\n", | ||
140 | count, ibmvtpm->rtce_size); | ||
141 | return -EIO; | ||
142 | } | ||
143 | |||
144 | spin_lock(&ibmvtpm->rtce_lock); | ||
145 | memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); | ||
146 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
147 | crq.msg = (u8)VTPM_TPM_COMMAND; | ||
148 | crq.len = (u16)count; | ||
149 | crq.data = ibmvtpm->rtce_dma_handle; | ||
150 | |||
151 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]); | ||
152 | if (rc != H_SUCCESS) { | ||
153 | dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); | ||
154 | rc = 0; | ||
155 | } else | ||
156 | rc = count; | ||
157 | |||
158 | spin_unlock(&ibmvtpm->rtce_lock); | ||
159 | return rc; | ||
160 | } | ||
161 | |||
162 | static void tpm_ibmvtpm_cancel(struct tpm_chip *chip) | ||
163 | { | ||
164 | return; | ||
165 | } | ||
166 | |||
167 | static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) | ||
168 | { | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * ibmvtpm_crq_get_rtce_size - Send a CRQ request to get rtce size | ||
174 | * @ibmvtpm: vtpm device struct | ||
175 | * | ||
176 | * Return value: | ||
177 | * 0 - Success | ||
178 | * Non-zero - Failure | ||
179 | */ | ||
180 | static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) | ||
181 | { | ||
182 | struct ibmvtpm_crq crq; | ||
183 | u64 *buf = (u64 *) &crq; | ||
184 | int rc; | ||
185 | |||
186 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
187 | crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; | ||
188 | |||
189 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
190 | if (rc != H_SUCCESS) | ||
191 | dev_err(ibmvtpm->dev, | ||
192 | "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); | ||
193 | |||
194 | return rc; | ||
195 | } | ||
196 | |||
197 | /** | ||
198 | * ibmvtpm_crq_get_version - Send a CRQ request to get vtpm version | ||
199 | * - Note that this is vtpm version and not tpm version | ||
200 | * @ibmvtpm: vtpm device struct | ||
201 | * | ||
202 | * Return value: | ||
203 | * 0 - Success | ||
204 | * Non-zero - Failure | ||
205 | */ | ||
206 | static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) | ||
207 | { | ||
208 | struct ibmvtpm_crq crq; | ||
209 | u64 *buf = (u64 *) &crq; | ||
210 | int rc; | ||
211 | |||
212 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
213 | crq.msg = (u8)VTPM_GET_VERSION; | ||
214 | |||
215 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
216 | if (rc != H_SUCCESS) | ||
217 | dev_err(ibmvtpm->dev, | ||
218 | "ibmvtpm_crq_get_version failed rc=%d\n", rc); | ||
219 | |||
220 | return rc; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * ibmvtpm_crq_send_init_complete - Send a CRQ initialize complete message | ||
225 | * @ibmvtpm: vtpm device struct | ||
226 | * | ||
227 | * Return value: | ||
228 | * 0 - Success | ||
229 | * Non-zero - Failure | ||
230 | */ | ||
231 | static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm) | ||
232 | { | ||
233 | int rc; | ||
234 | |||
235 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_COMP_CMD, 0); | ||
236 | if (rc != H_SUCCESS) | ||
237 | dev_err(ibmvtpm->dev, | ||
238 | "ibmvtpm_crq_send_init_complete failed rc=%d\n", rc); | ||
239 | |||
240 | return rc; | ||
241 | } | ||
242 | |||
243 | /** | ||
244 | * ibmvtpm_crq_send_init - Send a CRQ initialize message | ||
245 | * @ibmvtpm: vtpm device struct | ||
246 | * | ||
247 | * Return value: | ||
248 | * 0 - Success | ||
249 | * Non-zero - Failure | ||
250 | */ | ||
251 | static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm) | ||
252 | { | ||
253 | int rc; | ||
254 | |||
255 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, INIT_CRQ_CMD, 0); | ||
256 | if (rc != H_SUCCESS) | ||
257 | dev_err(ibmvtpm->dev, | ||
258 | "ibmvtpm_crq_send_init failed rc=%d\n", rc); | ||
259 | |||
260 | return rc; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * tpm_ibmvtpm_remove - ibm vtpm remove entry point | ||
265 | * @vdev: vio device struct | ||
266 | * | ||
267 | * Return value: | ||
268 | * 0 | ||
269 | */ | ||
270 | static int tpm_ibmvtpm_remove(struct vio_dev *vdev) | ||
271 | { | ||
272 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | ||
273 | int rc = 0; | ||
274 | |||
275 | free_irq(vdev->irq, ibmvtpm); | ||
276 | |||
277 | do { | ||
278 | if (rc) | ||
279 | msleep(100); | ||
280 | rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); | ||
281 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
282 | |||
283 | dma_unmap_single(ibmvtpm->dev, ibmvtpm->crq_dma_handle, | ||
284 | CRQ_RES_BUF_SIZE, DMA_BIDIRECTIONAL); | ||
285 | free_page((unsigned long)ibmvtpm->crq_queue.crq_addr); | ||
286 | |||
287 | if (ibmvtpm->rtce_buf) { | ||
288 | dma_unmap_single(ibmvtpm->dev, ibmvtpm->rtce_dma_handle, | ||
289 | ibmvtpm->rtce_size, DMA_BIDIRECTIONAL); | ||
290 | kfree(ibmvtpm->rtce_buf); | ||
291 | } | ||
292 | |||
293 | tpm_remove_hardware(ibmvtpm->dev); | ||
294 | |||
295 | kfree(ibmvtpm); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * tpm_ibmvtpm_get_desired_dma - Get DMA size needed by this driver | ||
302 | * @vdev: vio device struct | ||
303 | * | ||
304 | * Return value: | ||
305 | * Number of bytes the driver needs to DMA map | ||
306 | */ | ||
307 | static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev) | ||
308 | { | ||
309 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev); | ||
310 | return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size; | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * tpm_ibmvtpm_suspend - Suspend | ||
315 | * @dev: device struct | ||
316 | * | ||
317 | * Return value: | ||
318 | * 0 | ||
319 | */ | ||
320 | static int tpm_ibmvtpm_suspend(struct device *dev) | ||
321 | { | ||
322 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | ||
323 | struct ibmvtpm_crq crq; | ||
324 | u64 *buf = (u64 *) &crq; | ||
325 | int rc = 0; | ||
326 | |||
327 | crq.valid = (u8)IBMVTPM_VALID_CMD; | ||
328 | crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; | ||
329 | |||
330 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); | ||
331 | if (rc != H_SUCCESS) | ||
332 | dev_err(ibmvtpm->dev, | ||
333 | "tpm_ibmvtpm_suspend failed rc=%d\n", rc); | ||
334 | |||
335 | return rc; | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * ibmvtpm_reset_crq - Reset CRQ | ||
340 | * @ibmvtpm: ibm vtpm struct | ||
341 | * | ||
342 | * Return value: | ||
343 | * 0 - Success | ||
344 | * Non-zero - Failure | ||
345 | */ | ||
346 | static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm) | ||
347 | { | ||
348 | int rc = 0; | ||
349 | |||
350 | do { | ||
351 | if (rc) | ||
352 | msleep(100); | ||
353 | rc = plpar_hcall_norets(H_FREE_CRQ, | ||
354 | ibmvtpm->vdev->unit_address); | ||
355 | } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
356 | |||
357 | memset(ibmvtpm->crq_queue.crq_addr, 0, CRQ_RES_BUF_SIZE); | ||
358 | ibmvtpm->crq_queue.index = 0; | ||
359 | |||
360 | return plpar_hcall_norets(H_REG_CRQ, ibmvtpm->vdev->unit_address, | ||
361 | ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); | ||
362 | } | ||
363 | |||
364 | /** | ||
365 | * tpm_ibmvtpm_resume - Resume from suspend | ||
366 | * @dev: device struct | ||
367 | * | ||
368 | * Return value: | ||
369 | * 0 | ||
370 | */ | ||
371 | static int tpm_ibmvtpm_resume(struct device *dev) | ||
372 | { | ||
373 | struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(dev); | ||
374 | int rc = 0; | ||
375 | |||
376 | do { | ||
377 | if (rc) | ||
378 | msleep(100); | ||
379 | rc = plpar_hcall_norets(H_ENABLE_CRQ, | ||
380 | ibmvtpm->vdev->unit_address); | ||
381 | } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); | ||
382 | |||
383 | if (rc) { | ||
384 | dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc); | ||
385 | return rc; | ||
386 | } | ||
387 | |||
388 | rc = vio_enable_interrupts(ibmvtpm->vdev); | ||
389 | if (rc) { | ||
390 | dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc); | ||
391 | return rc; | ||
392 | } | ||
393 | |||
394 | rc = ibmvtpm_crq_send_init(ibmvtpm); | ||
395 | if (rc) | ||
396 | dev_err(dev, "Error send_init rc=%d\n", rc); | ||
397 | |||
398 | return rc; | ||
399 | } | ||
400 | |||
401 | static const struct file_operations ibmvtpm_ops = { | ||
402 | .owner = THIS_MODULE, | ||
403 | .llseek = no_llseek, | ||
404 | .open = tpm_open, | ||
405 | .read = tpm_read, | ||
406 | .write = tpm_write, | ||
407 | .release = tpm_release, | ||
408 | }; | ||
409 | |||
410 | static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); | ||
411 | static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); | ||
412 | static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); | ||
413 | static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); | ||
414 | static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); | ||
415 | static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | ||
416 | NULL); | ||
417 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | ||
418 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | ||
419 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
420 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
421 | |||
422 | static struct attribute *ibmvtpm_attrs[] = { | ||
423 | &dev_attr_pubek.attr, | ||
424 | &dev_attr_pcrs.attr, | ||
425 | &dev_attr_enabled.attr, | ||
426 | &dev_attr_active.attr, | ||
427 | &dev_attr_owned.attr, | ||
428 | &dev_attr_temp_deactivated.attr, | ||
429 | &dev_attr_caps.attr, | ||
430 | &dev_attr_cancel.attr, | ||
431 | &dev_attr_durations.attr, | ||
432 | &dev_attr_timeouts.attr, NULL, | ||
433 | }; | ||
434 | |||
435 | static struct attribute_group ibmvtpm_attr_grp = { .attrs = ibmvtpm_attrs }; | ||
436 | |||
437 | static const struct tpm_vendor_specific tpm_ibmvtpm = { | ||
438 | .recv = tpm_ibmvtpm_recv, | ||
439 | .send = tpm_ibmvtpm_send, | ||
440 | .cancel = tpm_ibmvtpm_cancel, | ||
441 | .status = tpm_ibmvtpm_status, | ||
442 | .req_complete_mask = 0, | ||
443 | .req_complete_val = 0, | ||
444 | .req_canceled = 0, | ||
445 | .attr_group = &ibmvtpm_attr_grp, | ||
446 | .miscdev = { .fops = &ibmvtpm_ops, }, | ||
447 | }; | ||
448 | |||
449 | static const struct dev_pm_ops tpm_ibmvtpm_pm_ops = { | ||
450 | .suspend = tpm_ibmvtpm_suspend, | ||
451 | .resume = tpm_ibmvtpm_resume, | ||
452 | }; | ||
453 | |||
454 | /** | ||
455 | * ibmvtpm_crq_get_next - Get next responded crq | ||
456 | * @ibmvtpm vtpm device struct | ||
457 | * | ||
458 | * Return value: | ||
459 | * vtpm crq pointer | ||
460 | */ | ||
461 | static struct ibmvtpm_crq *ibmvtpm_crq_get_next(struct ibmvtpm_dev *ibmvtpm) | ||
462 | { | ||
463 | struct ibmvtpm_crq_queue *crq_q = &ibmvtpm->crq_queue; | ||
464 | struct ibmvtpm_crq *crq = &crq_q->crq_addr[crq_q->index]; | ||
465 | |||
466 | if (crq->valid & VTPM_MSG_RES) { | ||
467 | if (++crq_q->index == crq_q->num_entry) | ||
468 | crq_q->index = 0; | ||
469 | smp_rmb(); | ||
470 | } else | ||
471 | crq = NULL; | ||
472 | return crq; | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * ibmvtpm_crq_process - Process responded crq | ||
477 | * @crq crq to be processed | ||
478 | * @ibmvtpm vtpm device struct | ||
479 | * | ||
480 | * Return value: | ||
481 | * Nothing | ||
482 | */ | ||
483 | static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | ||
484 | struct ibmvtpm_dev *ibmvtpm) | ||
485 | { | ||
486 | int rc = 0; | ||
487 | |||
488 | switch (crq->valid) { | ||
489 | case VALID_INIT_CRQ: | ||
490 | switch (crq->msg) { | ||
491 | case INIT_CRQ_RES: | ||
492 | dev_info(ibmvtpm->dev, "CRQ initialized\n"); | ||
493 | rc = ibmvtpm_crq_send_init_complete(ibmvtpm); | ||
494 | if (rc) | ||
495 | dev_err(ibmvtpm->dev, "Unable to send CRQ init complete rc=%d\n", rc); | ||
496 | return; | ||
497 | case INIT_CRQ_COMP_RES: | ||
498 | dev_info(ibmvtpm->dev, | ||
499 | "CRQ initialization completed\n"); | ||
500 | return; | ||
501 | default: | ||
502 | dev_err(ibmvtpm->dev, "Unknown crq message type: %d\n", crq->msg); | ||
503 | return; | ||
504 | } | ||
505 | return; | ||
506 | case IBMVTPM_VALID_CMD: | ||
507 | switch (crq->msg) { | ||
508 | case VTPM_GET_RTCE_BUFFER_SIZE_RES: | ||
509 | if (crq->len <= 0) { | ||
510 | dev_err(ibmvtpm->dev, "Invalid rtce size\n"); | ||
511 | return; | ||
512 | } | ||
513 | ibmvtpm->rtce_size = crq->len; | ||
514 | ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, | ||
515 | GFP_KERNEL); | ||
516 | if (!ibmvtpm->rtce_buf) { | ||
517 | dev_err(ibmvtpm->dev, "Failed to allocate memory for rtce buffer\n"); | ||
518 | return; | ||
519 | } | ||
520 | |||
521 | ibmvtpm->rtce_dma_handle = dma_map_single(ibmvtpm->dev, | ||
522 | ibmvtpm->rtce_buf, ibmvtpm->rtce_size, | ||
523 | DMA_BIDIRECTIONAL); | ||
524 | |||
525 | if (dma_mapping_error(ibmvtpm->dev, | ||
526 | ibmvtpm->rtce_dma_handle)) { | ||
527 | kfree(ibmvtpm->rtce_buf); | ||
528 | ibmvtpm->rtce_buf = NULL; | ||
529 | dev_err(ibmvtpm->dev, "Failed to dma map rtce buffer\n"); | ||
530 | } | ||
531 | |||
532 | return; | ||
533 | case VTPM_GET_VERSION_RES: | ||
534 | ibmvtpm->vtpm_version = crq->data; | ||
535 | return; | ||
536 | case VTPM_TPM_COMMAND_RES: | ||
537 | /* len of the data in rtce buffer */ | ||
538 | ibmvtpm->res_len = crq->len; | ||
539 | wake_up_interruptible(&ibmvtpm->wq); | ||
540 | return; | ||
541 | default: | ||
542 | return; | ||
543 | } | ||
544 | } | ||
545 | return; | ||
546 | } | ||
547 | |||
548 | /** | ||
549 | * ibmvtpm_interrupt - Interrupt handler | ||
550 | * @irq: irq number to handle | ||
551 | * @vtpm_instance: vtpm that received interrupt | ||
552 | * | ||
553 | * Returns: | ||
554 | * IRQ_HANDLED | ||
555 | **/ | ||
556 | static irqreturn_t ibmvtpm_interrupt(int irq, void *vtpm_instance) | ||
557 | { | ||
558 | struct ibmvtpm_dev *ibmvtpm = (struct ibmvtpm_dev *) vtpm_instance; | ||
559 | struct ibmvtpm_crq *crq; | ||
560 | |||
561 | /* while loop is needed for initial setup (get version and | ||
562 | * get rtce_size). There should be only one tpm request at any | ||
563 | * given time. | ||
564 | */ | ||
565 | while ((crq = ibmvtpm_crq_get_next(ibmvtpm)) != NULL) { | ||
566 | ibmvtpm_crq_process(crq, ibmvtpm); | ||
567 | crq->valid = 0; | ||
568 | smp_wmb(); | ||
569 | } | ||
570 | |||
571 | return IRQ_HANDLED; | ||
572 | } | ||
573 | |||
574 | /** | ||
575 | * tpm_ibmvtpm_probe - ibm vtpm initialize entry point | ||
576 | * @vio_dev: vio device struct | ||
577 | * @id: vio device id struct | ||
578 | * | ||
579 | * Return value: | ||
580 | * 0 - Success | ||
581 | * Non-zero - Failure | ||
582 | */ | ||
583 | static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, | ||
584 | const struct vio_device_id *id) | ||
585 | { | ||
586 | struct ibmvtpm_dev *ibmvtpm; | ||
587 | struct device *dev = &vio_dev->dev; | ||
588 | struct ibmvtpm_crq_queue *crq_q; | ||
589 | struct tpm_chip *chip; | ||
590 | int rc = -ENOMEM, rc1; | ||
591 | |||
592 | chip = tpm_register_hardware(dev, &tpm_ibmvtpm); | ||
593 | if (!chip) { | ||
594 | dev_err(dev, "tpm_register_hardware failed\n"); | ||
595 | return -ENODEV; | ||
596 | } | ||
597 | |||
598 | ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL); | ||
599 | if (!ibmvtpm) { | ||
600 | dev_err(dev, "kzalloc for ibmvtpm failed\n"); | ||
601 | goto cleanup; | ||
602 | } | ||
603 | |||
604 | crq_q = &ibmvtpm->crq_queue; | ||
605 | crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL); | ||
606 | if (!crq_q->crq_addr) { | ||
607 | dev_err(dev, "Unable to allocate memory for crq_addr\n"); | ||
608 | goto cleanup; | ||
609 | } | ||
610 | |||
611 | crq_q->num_entry = CRQ_RES_BUF_SIZE / sizeof(*crq_q->crq_addr); | ||
612 | ibmvtpm->crq_dma_handle = dma_map_single(dev, crq_q->crq_addr, | ||
613 | CRQ_RES_BUF_SIZE, | ||
614 | DMA_BIDIRECTIONAL); | ||
615 | |||
616 | if (dma_mapping_error(dev, ibmvtpm->crq_dma_handle)) { | ||
617 | dev_err(dev, "dma mapping failed\n"); | ||
618 | goto cleanup; | ||
619 | } | ||
620 | |||
621 | rc = plpar_hcall_norets(H_REG_CRQ, vio_dev->unit_address, | ||
622 | ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE); | ||
623 | if (rc == H_RESOURCE) | ||
624 | rc = ibmvtpm_reset_crq(ibmvtpm); | ||
625 | |||
626 | if (rc) { | ||
627 | dev_err(dev, "Unable to register CRQ rc=%d\n", rc); | ||
628 | goto reg_crq_cleanup; | ||
629 | } | ||
630 | |||
631 | rc = request_irq(vio_dev->irq, ibmvtpm_interrupt, 0, | ||
632 | tpm_ibmvtpm_driver_name, ibmvtpm); | ||
633 | if (rc) { | ||
634 | dev_err(dev, "Error %d register irq 0x%x\n", rc, vio_dev->irq); | ||
635 | goto init_irq_cleanup; | ||
636 | } | ||
637 | |||
638 | rc = vio_enable_interrupts(vio_dev); | ||
639 | if (rc) { | ||
640 | dev_err(dev, "Error %d enabling interrupts\n", rc); | ||
641 | goto init_irq_cleanup; | ||
642 | } | ||
643 | |||
644 | init_waitqueue_head(&ibmvtpm->wq); | ||
645 | |||
646 | crq_q->index = 0; | ||
647 | |||
648 | ibmvtpm->dev = dev; | ||
649 | ibmvtpm->vdev = vio_dev; | ||
650 | chip->vendor.data = (void *)ibmvtpm; | ||
651 | |||
652 | spin_lock_init(&ibmvtpm->rtce_lock); | ||
653 | |||
654 | rc = ibmvtpm_crq_send_init(ibmvtpm); | ||
655 | if (rc) | ||
656 | goto init_irq_cleanup; | ||
657 | |||
658 | rc = ibmvtpm_crq_get_version(ibmvtpm); | ||
659 | if (rc) | ||
660 | goto init_irq_cleanup; | ||
661 | |||
662 | rc = ibmvtpm_crq_get_rtce_size(ibmvtpm); | ||
663 | if (rc) | ||
664 | goto init_irq_cleanup; | ||
665 | |||
666 | return rc; | ||
667 | init_irq_cleanup: | ||
668 | do { | ||
669 | rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address); | ||
670 | } while (rc1 == H_BUSY || H_IS_LONG_BUSY(rc1)); | ||
671 | reg_crq_cleanup: | ||
672 | dma_unmap_single(dev, ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE, | ||
673 | DMA_BIDIRECTIONAL); | ||
674 | cleanup: | ||
675 | if (ibmvtpm) { | ||
676 | if (crq_q->crq_addr) | ||
677 | free_page((unsigned long)crq_q->crq_addr); | ||
678 | kfree(ibmvtpm); | ||
679 | } | ||
680 | |||
681 | tpm_remove_hardware(dev); | ||
682 | |||
683 | return rc; | ||
684 | } | ||
685 | |||
686 | static struct vio_driver ibmvtpm_driver = { | ||
687 | .id_table = tpm_ibmvtpm_device_table, | ||
688 | .probe = tpm_ibmvtpm_probe, | ||
689 | .remove = tpm_ibmvtpm_remove, | ||
690 | .get_desired_dma = tpm_ibmvtpm_get_desired_dma, | ||
691 | .name = tpm_ibmvtpm_driver_name, | ||
692 | .pm = &tpm_ibmvtpm_pm_ops, | ||
693 | }; | ||
694 | |||
695 | /** | ||
696 | * ibmvtpm_module_init - Initialize ibm vtpm module | ||
697 | * | ||
698 | * Return value: | ||
699 | * 0 -Success | ||
700 | * Non-zero - Failure | ||
701 | */ | ||
702 | static int __init ibmvtpm_module_init(void) | ||
703 | { | ||
704 | return vio_register_driver(&ibmvtpm_driver); | ||
705 | } | ||
706 | |||
707 | /** | ||
708 | * ibmvtpm_module_exit - Teardown ibm vtpm module | ||
709 | * | ||
710 | * Return value: | ||
711 | * Nothing | ||
712 | */ | ||
713 | static void __exit ibmvtpm_module_exit(void) | ||
714 | { | ||
715 | vio_unregister_driver(&ibmvtpm_driver); | ||
716 | } | ||
717 | |||
718 | module_init(ibmvtpm_module_init); | ||
719 | module_exit(ibmvtpm_module_exit); | ||
720 | |||
721 | MODULE_AUTHOR("adlai@us.ibm.com"); | ||
722 | MODULE_DESCRIPTION("IBM vTPM Driver"); | ||
723 | MODULE_VERSION("1.0"); | ||
724 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h deleted file mode 100644 index bd82a791f99..00000000000 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 IBM Corporation | ||
3 | * | ||
4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
5 | * | ||
6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
7 | * | ||
8 | * Device driver for TCG/TCPA TPM (trusted platform module). | ||
9 | * Specifications at www.trustedcomputinggroup.org | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation, version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef __TPM_IBMVTPM_H__ | ||
19 | #define __TPM_IBMVTPM_H__ | ||
20 | |||
21 | /* vTPM Message Format 1 */ | ||
22 | struct ibmvtpm_crq { | ||
23 | u8 valid; | ||
24 | u8 msg; | ||
25 | u16 len; | ||
26 | u32 data; | ||
27 | u64 reserved; | ||
28 | } __attribute__((packed, aligned(8))); | ||
29 | |||
30 | struct ibmvtpm_crq_queue { | ||
31 | struct ibmvtpm_crq *crq_addr; | ||
32 | u32 index; | ||
33 | u32 num_entry; | ||
34 | }; | ||
35 | |||
36 | struct ibmvtpm_dev { | ||
37 | struct device *dev; | ||
38 | struct vio_dev *vdev; | ||
39 | struct ibmvtpm_crq_queue crq_queue; | ||
40 | dma_addr_t crq_dma_handle; | ||
41 | u32 rtce_size; | ||
42 | void __iomem *rtce_buf; | ||
43 | dma_addr_t rtce_dma_handle; | ||
44 | spinlock_t rtce_lock; | ||
45 | wait_queue_head_t wq; | ||
46 | u16 res_len; | ||
47 | u32 vtpm_version; | ||
48 | }; | ||
49 | |||
50 | #define CRQ_RES_BUF_SIZE PAGE_SIZE | ||
51 | |||
52 | /* Initialize CRQ */ | ||
53 | #define INIT_CRQ_CMD 0xC001000000000000LL /* Init cmd */ | ||
54 | #define INIT_CRQ_COMP_CMD 0xC002000000000000LL /* Init complete cmd */ | ||
55 | #define INIT_CRQ_RES 0x01 /* Init respond */ | ||
56 | #define INIT_CRQ_COMP_RES 0x02 /* Init complete respond */ | ||
57 | #define VALID_INIT_CRQ 0xC0 /* Valid command for init crq */ | ||
58 | |||
59 | /* vTPM CRQ response is the message type | 0x80 */ | ||
60 | #define VTPM_MSG_RES 0x80 | ||
61 | #define IBMVTPM_VALID_CMD 0x80 | ||
62 | |||
63 | /* vTPM CRQ message types */ | ||
64 | #define VTPM_GET_VERSION 0x01 | ||
65 | #define VTPM_GET_VERSION_RES (0x01 | VTPM_MSG_RES) | ||
66 | |||
67 | #define VTPM_TPM_COMMAND 0x02 | ||
68 | #define VTPM_TPM_COMMAND_RES (0x02 | VTPM_MSG_RES) | ||
69 | |||
70 | #define VTPM_GET_RTCE_BUFFER_SIZE 0x03 | ||
71 | #define VTPM_GET_RTCE_BUFFER_SIZE_RES (0x03 | VTPM_MSG_RES) | ||
72 | |||
73 | #define VTPM_PREPARE_TO_SUSPEND 0x04 | ||
74 | #define VTPM_PREPARE_TO_SUSPEND_RES (0x04 | VTPM_MSG_RES) | ||
75 | |||
76 | #endif | ||
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 2b480c2960b..76da32e11f1 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module | 4 | * SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module |
5 | * Specifications at www.trustedcomputinggroup.org | 5 | * Specifications at www.trustedcomputinggroup.org |
6 | * | 6 | * |
7 | * Copyright (C) 2005, Marcel Selhorst <tpmdd@selhorst.net> | 7 | * Copyright (C) 2005, Marcel Selhorst <m.selhorst@sirrix.com> |
8 | * Sirrix AG - security technologies <tpmdd@sirrix.com> and | 8 | * Sirrix AG - security technologies, http://www.sirrix.com and |
9 | * Applied Data Security Group, Ruhr-University Bochum, Germany | 9 | * Applied Data Security Group, Ruhr-University Bochum, Germany |
10 | * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ | 10 | * Project-Homepage: http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ |
11 | * | 11 | * |
@@ -415,7 +415,7 @@ static const struct pnp_device_id tpm_inf_pnp_tbl[] = { | |||
415 | 415 | ||
416 | MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl); | 416 | MODULE_DEVICE_TABLE(pnp, tpm_inf_pnp_tbl); |
417 | 417 | ||
418 | static int tpm_inf_pnp_probe(struct pnp_dev *dev, | 418 | static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev, |
419 | const struct pnp_device_id *dev_id) | 419 | const struct pnp_device_id *dev_id) |
420 | { | 420 | { |
421 | int rc = 0; | 421 | int rc = 0; |
@@ -594,7 +594,7 @@ err_last: | |||
594 | return rc; | 594 | return rc; |
595 | } | 595 | } |
596 | 596 | ||
597 | static void tpm_inf_pnp_remove(struct pnp_dev *dev) | 597 | static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) |
598 | { | 598 | { |
599 | struct tpm_chip *chip = pnp_get_drvdata(dev); | 599 | struct tpm_chip *chip = pnp_get_drvdata(dev); |
600 | 600 | ||
@@ -655,7 +655,7 @@ static struct pnp_driver tpm_inf_pnp_driver = { | |||
655 | .probe = tpm_inf_pnp_probe, | 655 | .probe = tpm_inf_pnp_probe, |
656 | .suspend = tpm_inf_pnp_suspend, | 656 | .suspend = tpm_inf_pnp_suspend, |
657 | .resume = tpm_inf_pnp_resume, | 657 | .resume = tpm_inf_pnp_resume, |
658 | .remove = tpm_inf_pnp_remove | 658 | .remove = __devexit_p(tpm_inf_pnp_remove) |
659 | }; | 659 | }; |
660 | 660 | ||
661 | static int __init init_inf(void) | 661 | static int __init init_inf(void) |
@@ -671,7 +671,7 @@ static void __exit cleanup_inf(void) | |||
671 | module_init(init_inf); | 671 | module_init(init_inf); |
672 | module_exit(cleanup_inf); | 672 | module_exit(cleanup_inf); |
673 | 673 | ||
674 | MODULE_AUTHOR("Marcel Selhorst <tpmdd@sirrix.com>"); | 674 | MODULE_AUTHOR("Marcel Selhorst <m.selhorst@sirrix.com>"); |
675 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); | 675 | MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2"); |
676 | MODULE_VERSION("1.9.2"); | 676 | MODULE_VERSION("1.9.2"); |
677 | MODULE_LICENSE("GPL"); | 677 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 640c9a427b5..4d2464871ad 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c | |||
@@ -274,13 +274,22 @@ static void tpm_nsc_remove(struct device *dev) | |||
274 | } | 274 | } |
275 | } | 275 | } |
276 | 276 | ||
277 | static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume); | 277 | static int tpm_nsc_suspend(struct platform_device *dev, pm_message_t msg) |
278 | { | ||
279 | return tpm_pm_suspend(&dev->dev, msg); | ||
280 | } | ||
281 | |||
282 | static int tpm_nsc_resume(struct platform_device *dev) | ||
283 | { | ||
284 | return tpm_pm_resume(&dev->dev); | ||
285 | } | ||
278 | 286 | ||
279 | static struct platform_driver nsc_drv = { | 287 | static struct platform_driver nsc_drv = { |
288 | .suspend = tpm_nsc_suspend, | ||
289 | .resume = tpm_nsc_resume, | ||
280 | .driver = { | 290 | .driver = { |
281 | .name = "tpm_nsc", | 291 | .name = "tpm_nsc", |
282 | .owner = THIS_MODULE, | 292 | .owner = THIS_MODULE, |
283 | .pm = &tpm_nsc_pm, | ||
284 | }, | 293 | }, |
285 | }; | 294 | }; |
286 | 295 | ||
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c deleted file mode 100644 index 98ba2bd1a35..00000000000 --- a/drivers/char/tpm/tpm_of.c +++ /dev/null | |||
@@ -1,73 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2012 IBM Corporation | ||
3 | * | ||
4 | * Author: Ashley Lai <adlai@us.ibm.com> | ||
5 | * | ||
6 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> | ||
7 | * | ||
8 | * Read the event log created by the firmware on PPC64 | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/slab.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include "tpm.h" | ||
21 | #include "tpm_eventlog.h" | ||
22 | |||
23 | int read_log(struct tpm_bios_log *log) | ||
24 | { | ||
25 | struct device_node *np; | ||
26 | const u32 *sizep; | ||
27 | const __be64 *basep; | ||
28 | |||
29 | if (log->bios_event_log != NULL) { | ||
30 | pr_err("%s: ERROR - Eventlog already initialized\n", __func__); | ||
31 | return -EFAULT; | ||
32 | } | ||
33 | |||
34 | np = of_find_node_by_name(NULL, "ibm,vtpm"); | ||
35 | if (!np) { | ||
36 | pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); | ||
37 | return -ENODEV; | ||
38 | } | ||
39 | |||
40 | sizep = of_get_property(np, "linux,sml-size", NULL); | ||
41 | if (sizep == NULL) { | ||
42 | pr_err("%s: ERROR - SML size not found\n", __func__); | ||
43 | goto cleanup_eio; | ||
44 | } | ||
45 | if (*sizep == 0) { | ||
46 | pr_err("%s: ERROR - event log area empty\n", __func__); | ||
47 | goto cleanup_eio; | ||
48 | } | ||
49 | |||
50 | basep = of_get_property(np, "linux,sml-base", NULL); | ||
51 | if (basep == NULL) { | ||
52 | pr_err(KERN_ERR "%s: ERROR - SML not found\n", __func__); | ||
53 | goto cleanup_eio; | ||
54 | } | ||
55 | |||
56 | of_node_put(np); | ||
57 | log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); | ||
58 | if (!log->bios_event_log) { | ||
59 | pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", | ||
60 | __func__); | ||
61 | return -ENOMEM; | ||
62 | } | ||
63 | |||
64 | log->bios_event_log_end = log->bios_event_log + *sizep; | ||
65 | |||
66 | memcpy(log->bios_event_log, __va(be64_to_cpup(basep)), *sizep); | ||
67 | |||
68 | return 0; | ||
69 | |||
70 | cleanup_eio: | ||
71 | of_node_put(np); | ||
72 | return -EIO; | ||
73 | } | ||
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c deleted file mode 100644 index 720ebcf29fd..00000000000 --- a/drivers/char/tpm/tpm_ppi.c +++ /dev/null | |||
@@ -1,463 +0,0 @@ | |||
1 | #include <linux/acpi.h> | ||
2 | #include <acpi/acpi_drivers.h> | ||
3 | #include "tpm.h" | ||
4 | |||
5 | static const u8 tpm_ppi_uuid[] = { | ||
6 | 0xA6, 0xFA, 0xDD, 0x3D, | ||
7 | 0x1B, 0x36, | ||
8 | 0xB4, 0x4E, | ||
9 | 0xA4, 0x24, | ||
10 | 0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53 | ||
11 | }; | ||
12 | static char *tpm_device_name = "TPM"; | ||
13 | |||
14 | #define TPM_PPI_REVISION_ID 1 | ||
15 | #define TPM_PPI_FN_VERSION 1 | ||
16 | #define TPM_PPI_FN_SUBREQ 2 | ||
17 | #define TPM_PPI_FN_GETREQ 3 | ||
18 | #define TPM_PPI_FN_GETACT 4 | ||
19 | #define TPM_PPI_FN_GETRSP 5 | ||
20 | #define TPM_PPI_FN_SUBREQ2 7 | ||
21 | #define TPM_PPI_FN_GETOPR 8 | ||
22 | #define PPI_TPM_REQ_MAX 22 | ||
23 | #define PPI_VS_REQ_START 128 | ||
24 | #define PPI_VS_REQ_END 255 | ||
25 | #define PPI_VERSION_LEN 3 | ||
26 | |||
27 | static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, | ||
28 | void **return_value) | ||
29 | { | ||
30 | acpi_status status; | ||
31 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
32 | status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | ||
33 | if (strstr(buffer.pointer, context) != NULL) { | ||
34 | *return_value = handle; | ||
35 | kfree(buffer.pointer); | ||
36 | return AE_CTRL_TERMINATE; | ||
37 | } | ||
38 | return AE_OK; | ||
39 | } | ||
40 | |||
41 | static inline void ppi_assign_params(union acpi_object params[4], | ||
42 | u64 function_num) | ||
43 | { | ||
44 | params[0].type = ACPI_TYPE_BUFFER; | ||
45 | params[0].buffer.length = sizeof(tpm_ppi_uuid); | ||
46 | params[0].buffer.pointer = (char *)tpm_ppi_uuid; | ||
47 | params[1].type = ACPI_TYPE_INTEGER; | ||
48 | params[1].integer.value = TPM_PPI_REVISION_ID; | ||
49 | params[2].type = ACPI_TYPE_INTEGER; | ||
50 | params[2].integer.value = function_num; | ||
51 | params[3].type = ACPI_TYPE_PACKAGE; | ||
52 | params[3].package.count = 0; | ||
53 | params[3].package.elements = NULL; | ||
54 | } | ||
55 | |||
56 | static ssize_t tpm_show_ppi_version(struct device *dev, | ||
57 | struct device_attribute *attr, char *buf) | ||
58 | { | ||
59 | acpi_handle handle; | ||
60 | acpi_status status; | ||
61 | struct acpi_object_list input; | ||
62 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
63 | union acpi_object params[4]; | ||
64 | union acpi_object *obj; | ||
65 | |||
66 | input.count = 4; | ||
67 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
68 | input.pointer = params; | ||
69 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
70 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
71 | tpm_device_name, &handle); | ||
72 | if (ACPI_FAILURE(status)) | ||
73 | return -ENXIO; | ||
74 | |||
75 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
76 | ACPI_TYPE_STRING); | ||
77 | if (ACPI_FAILURE(status)) | ||
78 | return -ENOMEM; | ||
79 | obj = (union acpi_object *)output.pointer; | ||
80 | status = scnprintf(buf, PAGE_SIZE, "%s\n", obj->string.pointer); | ||
81 | kfree(output.pointer); | ||
82 | return status; | ||
83 | } | ||
84 | |||
85 | static ssize_t tpm_show_ppi_request(struct device *dev, | ||
86 | struct device_attribute *attr, char *buf) | ||
87 | { | ||
88 | acpi_handle handle; | ||
89 | acpi_status status; | ||
90 | struct acpi_object_list input; | ||
91 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
92 | union acpi_object params[4]; | ||
93 | union acpi_object *ret_obj; | ||
94 | |||
95 | input.count = 4; | ||
96 | ppi_assign_params(params, TPM_PPI_FN_GETREQ); | ||
97 | input.pointer = params; | ||
98 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
99 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
100 | tpm_device_name, &handle); | ||
101 | if (ACPI_FAILURE(status)) | ||
102 | return -ENXIO; | ||
103 | |||
104 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
105 | ACPI_TYPE_PACKAGE); | ||
106 | if (ACPI_FAILURE(status)) | ||
107 | return -ENOMEM; | ||
108 | /* | ||
109 | * output.pointer should be of package type, including two integers. | ||
110 | * The first is function return code, 0 means success and 1 means | ||
111 | * error. The second is pending TPM operation requested by the OS, 0 | ||
112 | * means none and >0 means operation value. | ||
113 | */ | ||
114 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | ||
115 | if (ret_obj->type == ACPI_TYPE_INTEGER) { | ||
116 | if (ret_obj->integer.value) { | ||
117 | status = -EFAULT; | ||
118 | goto cleanup; | ||
119 | } | ||
120 | ret_obj++; | ||
121 | if (ret_obj->type == ACPI_TYPE_INTEGER) | ||
122 | status = scnprintf(buf, PAGE_SIZE, "%llu\n", | ||
123 | ret_obj->integer.value); | ||
124 | else | ||
125 | status = -EINVAL; | ||
126 | } else { | ||
127 | status = -EINVAL; | ||
128 | } | ||
129 | cleanup: | ||
130 | kfree(output.pointer); | ||
131 | return status; | ||
132 | } | ||
133 | |||
134 | static ssize_t tpm_store_ppi_request(struct device *dev, | ||
135 | struct device_attribute *attr, | ||
136 | const char *buf, size_t count) | ||
137 | { | ||
138 | char version[PPI_VERSION_LEN + 1]; | ||
139 | acpi_handle handle; | ||
140 | acpi_status status; | ||
141 | struct acpi_object_list input; | ||
142 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
143 | union acpi_object params[4]; | ||
144 | union acpi_object obj; | ||
145 | u32 req; | ||
146 | u64 ret; | ||
147 | |||
148 | input.count = 4; | ||
149 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
150 | input.pointer = params; | ||
151 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
152 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
153 | tpm_device_name, &handle); | ||
154 | if (ACPI_FAILURE(status)) | ||
155 | return -ENXIO; | ||
156 | |||
157 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
158 | ACPI_TYPE_STRING); | ||
159 | if (ACPI_FAILURE(status)) | ||
160 | return -ENOMEM; | ||
161 | strncpy(version, | ||
162 | ((union acpi_object *)output.pointer)->string.pointer, | ||
163 | PPI_VERSION_LEN); | ||
164 | kfree(output.pointer); | ||
165 | output.length = ACPI_ALLOCATE_BUFFER; | ||
166 | output.pointer = NULL; | ||
167 | /* | ||
168 | * the function to submit TPM operation request to pre-os environment | ||
169 | * is updated with function index from SUBREQ to SUBREQ2 since PPI | ||
170 | * version 1.1 | ||
171 | */ | ||
172 | if (strcmp(version, "1.1") == -1) | ||
173 | params[2].integer.value = TPM_PPI_FN_SUBREQ; | ||
174 | else | ||
175 | params[2].integer.value = TPM_PPI_FN_SUBREQ2; | ||
176 | /* | ||
177 | * PPI spec defines params[3].type as ACPI_TYPE_PACKAGE. Some BIOS | ||
178 | * accept buffer/string/integer type, but some BIOS accept buffer/ | ||
179 | * string/package type. For PPI version 1.0 and 1.1, use buffer type | ||
180 | * for compatibility, and use package type since 1.2 according to spec. | ||
181 | */ | ||
182 | if (strcmp(version, "1.2") == -1) { | ||
183 | params[3].type = ACPI_TYPE_BUFFER; | ||
184 | params[3].buffer.length = sizeof(req); | ||
185 | sscanf(buf, "%d", &req); | ||
186 | params[3].buffer.pointer = (char *)&req; | ||
187 | } else { | ||
188 | params[3].package.count = 1; | ||
189 | obj.type = ACPI_TYPE_INTEGER; | ||
190 | sscanf(buf, "%llu", &obj.integer.value); | ||
191 | params[3].package.elements = &obj; | ||
192 | } | ||
193 | |||
194 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
195 | ACPI_TYPE_INTEGER); | ||
196 | if (ACPI_FAILURE(status)) | ||
197 | return -ENOMEM; | ||
198 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
199 | if (ret == 0) | ||
200 | status = (acpi_status)count; | ||
201 | else if (ret == 1) | ||
202 | status = -EPERM; | ||
203 | else | ||
204 | status = -EFAULT; | ||
205 | kfree(output.pointer); | ||
206 | return status; | ||
207 | } | ||
208 | |||
209 | static ssize_t tpm_show_ppi_transition_action(struct device *dev, | ||
210 | struct device_attribute *attr, | ||
211 | char *buf) | ||
212 | { | ||
213 | char version[PPI_VERSION_LEN + 1]; | ||
214 | acpi_handle handle; | ||
215 | acpi_status status; | ||
216 | struct acpi_object_list input; | ||
217 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
218 | union acpi_object params[4]; | ||
219 | u32 ret; | ||
220 | char *info[] = { | ||
221 | "None", | ||
222 | "Shutdown", | ||
223 | "Reboot", | ||
224 | "OS Vendor-specific", | ||
225 | "Error", | ||
226 | }; | ||
227 | input.count = 4; | ||
228 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
229 | input.pointer = params; | ||
230 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
231 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
232 | tpm_device_name, &handle); | ||
233 | if (ACPI_FAILURE(status)) | ||
234 | return -ENXIO; | ||
235 | |||
236 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
237 | ACPI_TYPE_STRING); | ||
238 | if (ACPI_FAILURE(status)) | ||
239 | return -ENOMEM; | ||
240 | strncpy(version, | ||
241 | ((union acpi_object *)output.pointer)->string.pointer, | ||
242 | PPI_VERSION_LEN); | ||
243 | /* | ||
244 | * PPI spec defines params[3].type as empty package, but some platforms | ||
245 | * (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for | ||
246 | * compatibility, define params[3].type as buffer, if PPI version < 1.2 | ||
247 | */ | ||
248 | if (strcmp(version, "1.2") == -1) { | ||
249 | params[3].type = ACPI_TYPE_BUFFER; | ||
250 | params[3].buffer.length = 0; | ||
251 | params[3].buffer.pointer = NULL; | ||
252 | } | ||
253 | params[2].integer.value = TPM_PPI_FN_GETACT; | ||
254 | kfree(output.pointer); | ||
255 | output.length = ACPI_ALLOCATE_BUFFER; | ||
256 | output.pointer = NULL; | ||
257 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
258 | ACPI_TYPE_INTEGER); | ||
259 | if (ACPI_FAILURE(status)) | ||
260 | return -ENOMEM; | ||
261 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
262 | if (ret < ARRAY_SIZE(info) - 1) | ||
263 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, info[ret]); | ||
264 | else | ||
265 | status = scnprintf(buf, PAGE_SIZE, "%d: %s\n", ret, | ||
266 | info[ARRAY_SIZE(info)-1]); | ||
267 | kfree(output.pointer); | ||
268 | return status; | ||
269 | } | ||
270 | |||
271 | static ssize_t tpm_show_ppi_response(struct device *dev, | ||
272 | struct device_attribute *attr, | ||
273 | char *buf) | ||
274 | { | ||
275 | acpi_handle handle; | ||
276 | acpi_status status; | ||
277 | struct acpi_object_list input; | ||
278 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
279 | union acpi_object params[4]; | ||
280 | union acpi_object *ret_obj; | ||
281 | u64 req; | ||
282 | |||
283 | input.count = 4; | ||
284 | ppi_assign_params(params, TPM_PPI_FN_GETRSP); | ||
285 | input.pointer = params; | ||
286 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
287 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
288 | tpm_device_name, &handle); | ||
289 | if (ACPI_FAILURE(status)) | ||
290 | return -ENXIO; | ||
291 | |||
292 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
293 | ACPI_TYPE_PACKAGE); | ||
294 | if (ACPI_FAILURE(status)) | ||
295 | return -ENOMEM; | ||
296 | /* | ||
297 | * parameter output.pointer should be of package type, including | ||
298 | * 3 integers. The first means function return code, the second means | ||
299 | * most recent TPM operation request, and the last means response to | ||
300 | * the most recent TPM operation request. Only if the first is 0, and | ||
301 | * the second integer is not 0, the response makes sense. | ||
302 | */ | ||
303 | ret_obj = ((union acpi_object *)output.pointer)->package.elements; | ||
304 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
305 | status = -EINVAL; | ||
306 | goto cleanup; | ||
307 | } | ||
308 | if (ret_obj->integer.value) { | ||
309 | status = -EFAULT; | ||
310 | goto cleanup; | ||
311 | } | ||
312 | ret_obj++; | ||
313 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
314 | status = -EINVAL; | ||
315 | goto cleanup; | ||
316 | } | ||
317 | if (ret_obj->integer.value) { | ||
318 | req = ret_obj->integer.value; | ||
319 | ret_obj++; | ||
320 | if (ret_obj->type != ACPI_TYPE_INTEGER) { | ||
321 | status = -EINVAL; | ||
322 | goto cleanup; | ||
323 | } | ||
324 | if (ret_obj->integer.value == 0) | ||
325 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
326 | "0: Success"); | ||
327 | else if (ret_obj->integer.value == 0xFFFFFFF0) | ||
328 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
329 | "0xFFFFFFF0: User Abort"); | ||
330 | else if (ret_obj->integer.value == 0xFFFFFFF1) | ||
331 | status = scnprintf(buf, PAGE_SIZE, "%llu %s\n", req, | ||
332 | "0xFFFFFFF1: BIOS Failure"); | ||
333 | else if (ret_obj->integer.value >= 1 && | ||
334 | ret_obj->integer.value <= 0x00000FFF) | ||
335 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | ||
336 | req, ret_obj->integer.value, | ||
337 | "Corresponding TPM error"); | ||
338 | else | ||
339 | status = scnprintf(buf, PAGE_SIZE, "%llu %llu: %s\n", | ||
340 | req, ret_obj->integer.value, | ||
341 | "Error"); | ||
342 | } else { | ||
343 | status = scnprintf(buf, PAGE_SIZE, "%llu: %s\n", | ||
344 | ret_obj->integer.value, "No Recent Request"); | ||
345 | } | ||
346 | cleanup: | ||
347 | kfree(output.pointer); | ||
348 | return status; | ||
349 | } | ||
350 | |||
351 | static ssize_t show_ppi_operations(char *buf, u32 start, u32 end) | ||
352 | { | ||
353 | char *str = buf; | ||
354 | char version[PPI_VERSION_LEN]; | ||
355 | acpi_handle handle; | ||
356 | acpi_status status; | ||
357 | struct acpi_object_list input; | ||
358 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
359 | union acpi_object params[4]; | ||
360 | union acpi_object obj; | ||
361 | int i; | ||
362 | u32 ret; | ||
363 | char *info[] = { | ||
364 | "Not implemented", | ||
365 | "BIOS only", | ||
366 | "Blocked for OS by BIOS", | ||
367 | "User required", | ||
368 | "User not required", | ||
369 | }; | ||
370 | input.count = 4; | ||
371 | ppi_assign_params(params, TPM_PPI_FN_VERSION); | ||
372 | input.pointer = params; | ||
373 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | ||
374 | ACPI_UINT32_MAX, ppi_callback, NULL, | ||
375 | tpm_device_name, &handle); | ||
376 | if (ACPI_FAILURE(status)) | ||
377 | return -ENXIO; | ||
378 | |||
379 | status = acpi_evaluate_object_typed(handle, "_DSM", &input, &output, | ||
380 | ACPI_TYPE_STRING); | ||
381 | if (ACPI_FAILURE(status)) | ||
382 | return -ENOMEM; | ||
383 | |||
384 | strncpy(version, | ||
385 | ((union acpi_object *)output.pointer)->string.pointer, | ||
386 | PPI_VERSION_LEN); | ||
387 | kfree(output.pointer); | ||
388 | output.length = ACPI_ALLOCATE_BUFFER; | ||
389 | output.pointer = NULL; | ||
390 | if (strcmp(version, "1.2") == -1) | ||
391 | return -EPERM; | ||
392 | |||
393 | params[2].integer.value = TPM_PPI_FN_GETOPR; | ||
394 | params[3].package.count = 1; | ||
395 | obj.type = ACPI_TYPE_INTEGER; | ||
396 | params[3].package.elements = &obj; | ||
397 | for (i = start; i <= end; i++) { | ||
398 | obj.integer.value = i; | ||
399 | status = acpi_evaluate_object_typed(handle, "_DSM", | ||
400 | &input, &output, ACPI_TYPE_INTEGER); | ||
401 | if (ACPI_FAILURE(status)) | ||
402 | return -ENOMEM; | ||
403 | |||
404 | ret = ((union acpi_object *)output.pointer)->integer.value; | ||
405 | if (ret > 0 && ret < ARRAY_SIZE(info)) | ||
406 | str += scnprintf(str, PAGE_SIZE, "%d %d: %s\n", | ||
407 | i, ret, info[ret]); | ||
408 | kfree(output.pointer); | ||
409 | output.length = ACPI_ALLOCATE_BUFFER; | ||
410 | output.pointer = NULL; | ||
411 | } | ||
412 | return str - buf; | ||
413 | } | ||
414 | |||
415 | static ssize_t tpm_show_ppi_tcg_operations(struct device *dev, | ||
416 | struct device_attribute *attr, | ||
417 | char *buf) | ||
418 | { | ||
419 | return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX); | ||
420 | } | ||
421 | |||
422 | static ssize_t tpm_show_ppi_vs_operations(struct device *dev, | ||
423 | struct device_attribute *attr, | ||
424 | char *buf) | ||
425 | { | ||
426 | return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END); | ||
427 | } | ||
428 | |||
429 | static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL); | ||
430 | static DEVICE_ATTR(request, S_IRUGO | S_IWUSR | S_IWGRP, | ||
431 | tpm_show_ppi_request, tpm_store_ppi_request); | ||
432 | static DEVICE_ATTR(transition_action, S_IRUGO, | ||
433 | tpm_show_ppi_transition_action, NULL); | ||
434 | static DEVICE_ATTR(response, S_IRUGO, tpm_show_ppi_response, NULL); | ||
435 | static DEVICE_ATTR(tcg_operations, S_IRUGO, tpm_show_ppi_tcg_operations, NULL); | ||
436 | static DEVICE_ATTR(vs_operations, S_IRUGO, tpm_show_ppi_vs_operations, NULL); | ||
437 | |||
438 | static struct attribute *ppi_attrs[] = { | ||
439 | &dev_attr_version.attr, | ||
440 | &dev_attr_request.attr, | ||
441 | &dev_attr_transition_action.attr, | ||
442 | &dev_attr_response.attr, | ||
443 | &dev_attr_tcg_operations.attr, | ||
444 | &dev_attr_vs_operations.attr, NULL, | ||
445 | }; | ||
446 | static struct attribute_group ppi_attr_grp = { | ||
447 | .name = "ppi", | ||
448 | .attrs = ppi_attrs | ||
449 | }; | ||
450 | |||
451 | int tpm_add_ppi(struct kobject *parent) | ||
452 | { | ||
453 | return sysfs_create_group(parent, &ppi_attr_grp); | ||
454 | } | ||
455 | EXPORT_SYMBOL_GPL(tpm_add_ppi); | ||
456 | |||
457 | void tpm_remove_ppi(struct kobject *parent) | ||
458 | { | ||
459 | sysfs_remove_group(parent, &ppi_attr_grp); | ||
460 | } | ||
461 | EXPORT_SYMBOL_GPL(tpm_remove_ppi); | ||
462 | |||
463 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ea31dafbcac..3f4051a7c5a 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/freezer.h> | 29 | #include <linux/freezer.h> |
30 | #include "tpm.h" | 30 | #include "tpm.h" |
31 | 31 | ||
32 | #define TPM_HEADER_SIZE 10 | ||
33 | |||
32 | enum tis_access { | 34 | enum tis_access { |
33 | TPM_ACCESS_VALID = 0x80, | 35 | TPM_ACCESS_VALID = 0x80, |
34 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, | 36 | TPM_ACCESS_ACTIVE_LOCALITY = 0x20, |
@@ -76,7 +78,7 @@ enum tis_defaults { | |||
76 | #define TPM_RID(l) (0x0F04 | ((l) << 12)) | 78 | #define TPM_RID(l) (0x0F04 | ((l) << 12)) |
77 | 79 | ||
78 | static LIST_HEAD(tis_chips); | 80 | static LIST_HEAD(tis_chips); |
79 | static DEFINE_MUTEX(tis_lock); | 81 | static DEFINE_SPINLOCK(tis_lock); |
80 | 82 | ||
81 | #if defined(CONFIG_PNP) && defined(CONFIG_ACPI) | 83 | #if defined(CONFIG_PNP) && defined(CONFIG_ACPI) |
82 | static int is_itpm(struct pnp_dev *dev) | 84 | static int is_itpm(struct pnp_dev *dev) |
@@ -191,14 +193,54 @@ static int get_burstcount(struct tpm_chip *chip) | |||
191 | return -EBUSY; | 193 | return -EBUSY; |
192 | } | 194 | } |
193 | 195 | ||
196 | static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | ||
197 | wait_queue_head_t *queue) | ||
198 | { | ||
199 | unsigned long stop; | ||
200 | long rc; | ||
201 | u8 status; | ||
202 | |||
203 | /* check current status */ | ||
204 | status = tpm_tis_status(chip); | ||
205 | if ((status & mask) == mask) | ||
206 | return 0; | ||
207 | |||
208 | stop = jiffies + timeout; | ||
209 | |||
210 | if (chip->vendor.irq) { | ||
211 | again: | ||
212 | timeout = stop - jiffies; | ||
213 | if ((long)timeout <= 0) | ||
214 | return -ETIME; | ||
215 | rc = wait_event_interruptible_timeout(*queue, | ||
216 | ((tpm_tis_status | ||
217 | (chip) & mask) == | ||
218 | mask), timeout); | ||
219 | if (rc > 0) | ||
220 | return 0; | ||
221 | if (rc == -ERESTARTSYS && freezing(current)) { | ||
222 | clear_thread_flag(TIF_SIGPENDING); | ||
223 | goto again; | ||
224 | } | ||
225 | } else { | ||
226 | do { | ||
227 | msleep(TPM_TIMEOUT); | ||
228 | status = tpm_tis_status(chip); | ||
229 | if ((status & mask) == mask) | ||
230 | return 0; | ||
231 | } while (time_before(jiffies, stop)); | ||
232 | } | ||
233 | return -ETIME; | ||
234 | } | ||
235 | |||
194 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) | 236 | static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) |
195 | { | 237 | { |
196 | int size = 0, burstcnt; | 238 | int size = 0, burstcnt; |
197 | while (size < count && | 239 | while (size < count && |
198 | wait_for_tpm_stat(chip, | 240 | wait_for_stat(chip, |
199 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 241 | TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
200 | chip->vendor.timeout_c, | 242 | chip->vendor.timeout_c, |
201 | &chip->vendor.read_queue) | 243 | &chip->vendor.read_queue) |
202 | == 0) { | 244 | == 0) { |
203 | burstcnt = get_burstcount(chip); | 245 | burstcnt = get_burstcount(chip); |
204 | for (; burstcnt > 0 && size < count; burstcnt--) | 246 | for (; burstcnt > 0 && size < count; burstcnt--) |
@@ -240,8 +282,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
240 | goto out; | 282 | goto out; |
241 | } | 283 | } |
242 | 284 | ||
243 | wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, | 285 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, |
244 | &chip->vendor.int_queue); | 286 | &chip->vendor.int_queue); |
245 | status = tpm_tis_status(chip); | 287 | status = tpm_tis_status(chip); |
246 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ | 288 | if (status & TPM_STS_DATA_AVAIL) { /* retry? */ |
247 | dev_err(chip->dev, "Error left over data\n"); | 289 | dev_err(chip->dev, "Error left over data\n"); |
@@ -255,7 +297,7 @@ out: | |||
255 | return size; | 297 | return size; |
256 | } | 298 | } |
257 | 299 | ||
258 | static bool itpm; | 300 | static int itpm; |
259 | module_param(itpm, bool, 0444); | 301 | module_param(itpm, bool, 0444); |
260 | MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)"); | 302 | MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)"); |
261 | 303 | ||
@@ -275,7 +317,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) | |||
275 | status = tpm_tis_status(chip); | 317 | status = tpm_tis_status(chip); |
276 | if ((status & TPM_STS_COMMAND_READY) == 0) { | 318 | if ((status & TPM_STS_COMMAND_READY) == 0) { |
277 | tpm_tis_ready(chip); | 319 | tpm_tis_ready(chip); |
278 | if (wait_for_tpm_stat | 320 | if (wait_for_stat |
279 | (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, | 321 | (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, |
280 | &chip->vendor.int_queue) < 0) { | 322 | &chip->vendor.int_queue) < 0) { |
281 | rc = -ETIME; | 323 | rc = -ETIME; |
@@ -291,8 +333,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) | |||
291 | count++; | 333 | count++; |
292 | } | 334 | } |
293 | 335 | ||
294 | wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, | 336 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, |
295 | &chip->vendor.int_queue); | 337 | &chip->vendor.int_queue); |
296 | status = tpm_tis_status(chip); | 338 | status = tpm_tis_status(chip); |
297 | if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { | 339 | if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { |
298 | rc = -EIO; | 340 | rc = -EIO; |
@@ -303,8 +345,8 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) | |||
303 | /* write last byte */ | 345 | /* write last byte */ |
304 | iowrite8(buf[count], | 346 | iowrite8(buf[count], |
305 | chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality)); | 347 | chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality)); |
306 | wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, | 348 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, |
307 | &chip->vendor.int_queue); | 349 | &chip->vendor.int_queue); |
308 | status = tpm_tis_status(chip); | 350 | status = tpm_tis_status(chip); |
309 | if ((status & TPM_STS_DATA_EXPECT) != 0) { | 351 | if ((status & TPM_STS_DATA_EXPECT) != 0) { |
310 | rc = -EIO; | 352 | rc = -EIO; |
@@ -339,7 +381,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | |||
339 | 381 | ||
340 | if (chip->vendor.irq) { | 382 | if (chip->vendor.irq) { |
341 | ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); | 383 | ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); |
342 | if (wait_for_tpm_stat | 384 | if (wait_for_stat |
343 | (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, | 385 | (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
344 | tpm_calc_ordinal_duration(chip, ordinal), | 386 | tpm_calc_ordinal_duration(chip, ordinal), |
345 | &chip->vendor.read_queue) < 0) { | 387 | &chip->vendor.read_queue) < 0) { |
@@ -367,12 +409,7 @@ static int probe_itpm(struct tpm_chip *chip) | |||
367 | 0x00, 0x00, 0x00, 0xf1 | 409 | 0x00, 0x00, 0x00, 0xf1 |
368 | }; | 410 | }; |
369 | size_t len = sizeof(cmd_getticks); | 411 | size_t len = sizeof(cmd_getticks); |
370 | bool rem_itpm = itpm; | 412 | int rem_itpm = itpm; |
371 | u16 vendor = ioread16(chip->vendor.iobase + TPM_DID_VID(0)); | ||
372 | |||
373 | /* probe only iTPMS */ | ||
374 | if (vendor != TPM_VID_INTEL) | ||
375 | return 0; | ||
376 | 413 | ||
377 | itpm = 0; | 414 | itpm = 0; |
378 | 415 | ||
@@ -502,7 +539,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) | |||
502 | return IRQ_HANDLED; | 539 | return IRQ_HANDLED; |
503 | } | 540 | } |
504 | 541 | ||
505 | static bool interrupts = 1; | 542 | static int interrupts = 1; |
506 | module_param(interrupts, bool, 0444); | 543 | module_param(interrupts, bool, 0444); |
507 | MODULE_PARM_DESC(interrupts, "Enable interrupts"); | 544 | MODULE_PARM_DESC(interrupts, "Enable interrupts"); |
508 | 545 | ||
@@ -510,7 +547,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
510 | resource_size_t len, unsigned int irq) | 547 | resource_size_t len, unsigned int irq) |
511 | { | 548 | { |
512 | u32 vendor, intfcaps, intmask; | 549 | u32 vendor, intfcaps, intmask; |
513 | int rc, i, irq_s, irq_e, probe; | 550 | int rc, i, irq_s, irq_e; |
514 | struct tpm_chip *chip; | 551 | struct tpm_chip *chip; |
515 | 552 | ||
516 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) | 553 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) |
@@ -540,12 +577,11 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
540 | vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); | 577 | vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); |
541 | 578 | ||
542 | if (!itpm) { | 579 | if (!itpm) { |
543 | probe = probe_itpm(chip); | 580 | itpm = probe_itpm(chip); |
544 | if (probe < 0) { | 581 | if (itpm < 0) { |
545 | rc = -ENODEV; | 582 | rc = -ENODEV; |
546 | goto out_err; | 583 | goto out_err; |
547 | } | 584 | } |
548 | itpm = (probe == 0) ? 0 : 1; | ||
549 | } | 585 | } |
550 | 586 | ||
551 | if (itpm) | 587 | if (itpm) |
@@ -578,17 +614,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
578 | dev_dbg(dev, "\tData Avail Int Support\n"); | 614 | dev_dbg(dev, "\tData Avail Int Support\n"); |
579 | 615 | ||
580 | /* get the timeouts before testing for irqs */ | 616 | /* get the timeouts before testing for irqs */ |
581 | if (tpm_get_timeouts(chip)) { | 617 | tpm_get_timeouts(chip); |
582 | dev_err(dev, "Could not get TPM timeouts and durations\n"); | ||
583 | rc = -ENODEV; | ||
584 | goto out_err; | ||
585 | } | ||
586 | |||
587 | if (tpm_do_selftest(chip)) { | ||
588 | dev_err(dev, "TPM self test failed\n"); | ||
589 | rc = -ENODEV; | ||
590 | goto out_err; | ||
591 | } | ||
592 | 618 | ||
593 | /* INTERRUPT Setup */ | 619 | /* INTERRUPT Setup */ |
594 | init_waitqueue_head(&chip->vendor.read_queue); | 620 | init_waitqueue_head(&chip->vendor.read_queue); |
@@ -692,10 +718,11 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
692 | } | 718 | } |
693 | 719 | ||
694 | INIT_LIST_HEAD(&chip->vendor.list); | 720 | INIT_LIST_HEAD(&chip->vendor.list); |
695 | mutex_lock(&tis_lock); | 721 | spin_lock(&tis_lock); |
696 | list_add(&chip->vendor.list, &tis_chips); | 722 | list_add(&chip->vendor.list, &tis_chips); |
697 | mutex_unlock(&tis_lock); | 723 | spin_unlock(&tis_lock); |
698 | 724 | ||
725 | tpm_continue_selftest(chip); | ||
699 | 726 | ||
700 | return 0; | 727 | return 0; |
701 | out_err: | 728 | out_err: |
@@ -705,7 +732,6 @@ out_err: | |||
705 | return rc; | 732 | return rc; |
706 | } | 733 | } |
707 | 734 | ||
708 | #if defined(CONFIG_PNP) || defined(CONFIG_PM_SLEEP) | ||
709 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | 735 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) |
710 | { | 736 | { |
711 | u32 intmask; | 737 | u32 intmask; |
@@ -726,10 +752,10 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | |||
726 | iowrite32(intmask, | 752 | iowrite32(intmask, |
727 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); | 753 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); |
728 | } | 754 | } |
729 | #endif | 755 | |
730 | 756 | ||
731 | #ifdef CONFIG_PNP | 757 | #ifdef CONFIG_PNP |
732 | static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, | 758 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, |
733 | const struct pnp_device_id *pnp_id) | 759 | const struct pnp_device_id *pnp_id) |
734 | { | 760 | { |
735 | resource_size_t start, len; | 761 | resource_size_t start, len; |
@@ -751,7 +777,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev, | |||
751 | 777 | ||
752 | static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) | 778 | static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg) |
753 | { | 779 | { |
754 | return tpm_pm_suspend(&dev->dev); | 780 | return tpm_pm_suspend(&dev->dev, msg); |
755 | } | 781 | } |
756 | 782 | ||
757 | static int tpm_tis_pnp_resume(struct pnp_dev *dev) | 783 | static int tpm_tis_pnp_resume(struct pnp_dev *dev) |
@@ -764,12 +790,12 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) | |||
764 | 790 | ||
765 | ret = tpm_pm_resume(&dev->dev); | 791 | ret = tpm_pm_resume(&dev->dev); |
766 | if (!ret) | 792 | if (!ret) |
767 | tpm_do_selftest(chip); | 793 | tpm_continue_selftest(chip); |
768 | 794 | ||
769 | return ret; | 795 | return ret; |
770 | } | 796 | } |
771 | 797 | ||
772 | static struct pnp_device_id tpm_pnp_tbl[] = { | 798 | static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { |
773 | {"PNP0C31", 0}, /* TPM */ | 799 | {"PNP0C31", 0}, /* TPM */ |
774 | {"ATM1200", 0}, /* Atmel */ | 800 | {"ATM1200", 0}, /* Atmel */ |
775 | {"IFX0102", 0}, /* Infineon */ | 801 | {"IFX0102", 0}, /* Infineon */ |
@@ -783,7 +809,7 @@ static struct pnp_device_id tpm_pnp_tbl[] = { | |||
783 | }; | 809 | }; |
784 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); | 810 | MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl); |
785 | 811 | ||
786 | static void tpm_tis_pnp_remove(struct pnp_dev *dev) | 812 | static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) |
787 | { | 813 | { |
788 | struct tpm_chip *chip = pnp_get_drvdata(dev); | 814 | struct tpm_chip *chip = pnp_get_drvdata(dev); |
789 | 815 | ||
@@ -807,32 +833,32 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id, | |||
807 | sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); | 833 | sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444); |
808 | MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); | 834 | MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe"); |
809 | #endif | 835 | #endif |
836 | static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg) | ||
837 | { | ||
838 | return tpm_pm_suspend(&dev->dev, msg); | ||
839 | } | ||
810 | 840 | ||
811 | #ifdef CONFIG_PM_SLEEP | 841 | static int tpm_tis_resume(struct platform_device *dev) |
812 | static int tpm_tis_resume(struct device *dev) | ||
813 | { | 842 | { |
814 | struct tpm_chip *chip = dev_get_drvdata(dev); | 843 | struct tpm_chip *chip = dev_get_drvdata(&dev->dev); |
815 | 844 | ||
816 | if (chip->vendor.irq) | 845 | if (chip->vendor.irq) |
817 | tpm_tis_reenable_interrupts(chip); | 846 | tpm_tis_reenable_interrupts(chip); |
818 | 847 | ||
819 | return tpm_pm_resume(dev); | 848 | return tpm_pm_resume(&dev->dev); |
820 | } | 849 | } |
821 | #endif | ||
822 | |||
823 | static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume); | ||
824 | |||
825 | static struct platform_driver tis_drv = { | 850 | static struct platform_driver tis_drv = { |
826 | .driver = { | 851 | .driver = { |
827 | .name = "tpm_tis", | 852 | .name = "tpm_tis", |
828 | .owner = THIS_MODULE, | 853 | .owner = THIS_MODULE, |
829 | .pm = &tpm_tis_pm, | ||
830 | }, | 854 | }, |
855 | .suspend = tpm_tis_suspend, | ||
856 | .resume = tpm_tis_resume, | ||
831 | }; | 857 | }; |
832 | 858 | ||
833 | static struct platform_device *pdev; | 859 | static struct platform_device *pdev; |
834 | 860 | ||
835 | static bool force; | 861 | static int force; |
836 | module_param(force, bool, 0444); | 862 | module_param(force, bool, 0444); |
837 | MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry"); | 863 | MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry"); |
838 | static int __init init_tis(void) | 864 | static int __init init_tis(void) |
@@ -859,7 +885,7 @@ static void __exit cleanup_tis(void) | |||
859 | { | 885 | { |
860 | struct tpm_vendor_specific *i, *j; | 886 | struct tpm_vendor_specific *i, *j; |
861 | struct tpm_chip *chip; | 887 | struct tpm_chip *chip; |
862 | mutex_lock(&tis_lock); | 888 | spin_lock(&tis_lock); |
863 | list_for_each_entry_safe(i, j, &tis_chips, list) { | 889 | list_for_each_entry_safe(i, j, &tis_chips, list) { |
864 | chip = to_tpm_chip(i); | 890 | chip = to_tpm_chip(i); |
865 | tpm_remove_hardware(chip->dev); | 891 | tpm_remove_hardware(chip->dev); |
@@ -875,7 +901,7 @@ static void __exit cleanup_tis(void) | |||
875 | iounmap(i->iobase); | 901 | iounmap(i->iobase); |
876 | list_del(&i->list); | 902 | list_del(&i->list); |
877 | } | 903 | } |
878 | mutex_unlock(&tis_lock); | 904 | spin_unlock(&tis_lock); |
879 | #ifdef CONFIG_PNP | 905 | #ifdef CONFIG_PNP |
880 | if (!force) { | 906 | if (!force) { |
881 | pnp_unregister_driver(&tis_pnp_driver); | 907 | pnp_unregister_driver(&tis_pnp_driver); |