diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-27 22:26:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-27 22:26:38 -0400 |
commit | 95b6886526bb510b8370b625a49bc0ab3b8ff10f (patch) | |
tree | 2862606224820d200be12d2092dcd26df1654b80 /drivers/char | |
parent | 22712200e175e0df5c7f9edfe6c6bf5c94c23b83 (diff) | |
parent | 29412f0f6a19e34336368f13eab848091c343952 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6: (54 commits)
tpm_nsc: Fix bug when loading multiple TPM drivers
tpm: Move tpm_tis_reenable_interrupts out of CONFIG_PNP block
tpm: Fix compilation warning when CONFIG_PNP is not defined
TOMOYO: Update kernel-doc.
tpm: Fix a typo
tpm_tis: Probing function for Intel iTPM bug
tpm_tis: Fix the probing for interrupts
tpm_tis: Delay ACPI S3 suspend while the TPM is busy
tpm_tis: Re-enable interrupts upon (S3) resume
tpm: Fix display of data in pubek sysfs entry
tpm_tis: Add timeouts sysfs entry
tpm: Adjust interface timeouts if they are too small
tpm: Use interface timeouts returned from the TPM
tpm_tis: Introduce durations sysfs entry
tpm: Adjust the durations if they are too small
tpm: Use durations returned from TPM
TOMOYO: Enable conditional ACL.
TOMOYO: Allow using argv[]/envp[] of execve() as conditions.
TOMOYO: Allow using executable's realpath and symlink's target as conditions.
TOMOYO: Allow using owner/group etc. of file objects as conditions.
...
Fix up trivial conflict in security/tomoyo/realpath.c
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/tpm/tpm.c | 102 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 7 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_nsc.c | 14 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 182 |
4 files changed, 250 insertions, 55 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 7beb0e25f1e1..caf8012ef47c 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -534,6 +534,7 @@ void tpm_get_timeouts(struct tpm_chip *chip) | |||
534 | struct duration_t *duration_cap; | 534 | struct duration_t *duration_cap; |
535 | ssize_t rc; | 535 | ssize_t rc; |
536 | u32 timeout; | 536 | u32 timeout; |
537 | unsigned int scale = 1; | ||
537 | 538 | ||
538 | tpm_cmd.header.in = tpm_getcap_header; | 539 | tpm_cmd.header.in = tpm_getcap_header; |
539 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; | 540 | tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; |
@@ -545,24 +546,30 @@ void tpm_get_timeouts(struct tpm_chip *chip) | |||
545 | if (rc) | 546 | if (rc) |
546 | goto duration; | 547 | goto duration; |
547 | 548 | ||
548 | if (be32_to_cpu(tpm_cmd.header.out.length) | 549 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
549 | != 4 * sizeof(u32)) | 550 | be32_to_cpu(tpm_cmd.header.out.length) |
550 | goto duration; | 551 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) |
552 | return; | ||
551 | 553 | ||
552 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; | 554 | timeout_cap = &tpm_cmd.params.getcap_out.cap.timeout; |
553 | /* Don't overwrite default if value is 0 */ | 555 | /* Don't overwrite default if value is 0 */ |
554 | timeout = be32_to_cpu(timeout_cap->a); | 556 | timeout = be32_to_cpu(timeout_cap->a); |
557 | if (timeout && timeout < 1000) { | ||
558 | /* timeouts in msec rather usec */ | ||
559 | scale = 1000; | ||
560 | chip->vendor.timeout_adjusted = true; | ||
561 | } | ||
555 | if (timeout) | 562 | if (timeout) |
556 | chip->vendor.timeout_a = usecs_to_jiffies(timeout); | 563 | chip->vendor.timeout_a = usecs_to_jiffies(timeout * scale); |
557 | timeout = be32_to_cpu(timeout_cap->b); | 564 | timeout = be32_to_cpu(timeout_cap->b); |
558 | if (timeout) | 565 | if (timeout) |
559 | chip->vendor.timeout_b = usecs_to_jiffies(timeout); | 566 | chip->vendor.timeout_b = usecs_to_jiffies(timeout * scale); |
560 | timeout = be32_to_cpu(timeout_cap->c); | 567 | timeout = be32_to_cpu(timeout_cap->c); |
561 | if (timeout) | 568 | if (timeout) |
562 | chip->vendor.timeout_c = usecs_to_jiffies(timeout); | 569 | chip->vendor.timeout_c = usecs_to_jiffies(timeout * scale); |
563 | timeout = be32_to_cpu(timeout_cap->d); | 570 | timeout = be32_to_cpu(timeout_cap->d); |
564 | if (timeout) | 571 | if (timeout) |
565 | chip->vendor.timeout_d = usecs_to_jiffies(timeout); | 572 | chip->vendor.timeout_d = usecs_to_jiffies(timeout * scale); |
566 | 573 | ||
567 | duration: | 574 | duration: |
568 | tpm_cmd.header.in = tpm_getcap_header; | 575 | tpm_cmd.header.in = tpm_getcap_header; |
@@ -575,23 +582,31 @@ duration: | |||
575 | if (rc) | 582 | if (rc) |
576 | return; | 583 | return; |
577 | 584 | ||
578 | if (be32_to_cpu(tpm_cmd.header.out.return_code) | 585 | if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || |
579 | != 3 * sizeof(u32)) | 586 | be32_to_cpu(tpm_cmd.header.out.length) |
587 | != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) | ||
580 | return; | 588 | return; |
589 | |||
581 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; | 590 | duration_cap = &tpm_cmd.params.getcap_out.cap.duration; |
582 | chip->vendor.duration[TPM_SHORT] = | 591 | chip->vendor.duration[TPM_SHORT] = |
583 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); | 592 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); |
593 | chip->vendor.duration[TPM_MEDIUM] = | ||
594 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); | ||
595 | chip->vendor.duration[TPM_LONG] = | ||
596 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); | ||
597 | |||
584 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above | 598 | /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above |
585 | * value wrong and apparently reports msecs rather than usecs. So we | 599 | * value wrong and apparently reports msecs rather than usecs. So we |
586 | * fix up the resulting too-small TPM_SHORT value to make things work. | 600 | * fix up the resulting too-small TPM_SHORT value to make things work. |
601 | * We also scale the TPM_MEDIUM and -_LONG values by 1000. | ||
587 | */ | 602 | */ |
588 | if (chip->vendor.duration[TPM_SHORT] < (HZ/100)) | 603 | if (chip->vendor.duration[TPM_SHORT] < (HZ / 100)) { |
589 | chip->vendor.duration[TPM_SHORT] = HZ; | 604 | chip->vendor.duration[TPM_SHORT] = HZ; |
590 | 605 | chip->vendor.duration[TPM_MEDIUM] *= 1000; | |
591 | chip->vendor.duration[TPM_MEDIUM] = | 606 | chip->vendor.duration[TPM_LONG] *= 1000; |
592 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); | 607 | chip->vendor.duration_adjusted = true; |
593 | chip->vendor.duration[TPM_LONG] = | 608 | dev_info(chip->dev, "Adjusting TPM timeout parameters."); |
594 | usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); | 609 | } |
595 | } | 610 | } |
596 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); | 611 | EXPORT_SYMBOL_GPL(tpm_get_timeouts); |
597 | 612 | ||
@@ -600,7 +615,7 @@ void tpm_continue_selftest(struct tpm_chip *chip) | |||
600 | u8 data[] = { | 615 | u8 data[] = { |
601 | 0, 193, /* TPM_TAG_RQU_COMMAND */ | 616 | 0, 193, /* TPM_TAG_RQU_COMMAND */ |
602 | 0, 0, 0, 10, /* length */ | 617 | 0, 0, 0, 10, /* length */ |
603 | 0, 0, 0, 83, /* TPM_ORD_GetCapability */ | 618 | 0, 0, 0, 83, /* TPM_ORD_ContinueSelfTest */ |
604 | }; | 619 | }; |
605 | 620 | ||
606 | tpm_transmit(chip, data, sizeof(data)); | 621 | tpm_transmit(chip, data, sizeof(data)); |
@@ -863,18 +878,24 @@ ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, | |||
863 | data = tpm_cmd.params.readpubek_out_buffer; | 878 | data = tpm_cmd.params.readpubek_out_buffer; |
864 | str += | 879 | str += |
865 | sprintf(str, | 880 | sprintf(str, |
866 | "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" | 881 | "Algorithm: %02X %02X %02X %02X\n" |
867 | "Sigscheme: %02X %02X\nParameters: %02X %02X %02X %02X" | 882 | "Encscheme: %02X %02X\n" |
868 | " %02X %02X %02X %02X %02X %02X %02X %02X\n" | 883 | "Sigscheme: %02X %02X\n" |
869 | "Modulus length: %d\nModulus: \n", | 884 | "Parameters: %02X %02X %02X %02X " |
870 | data[10], data[11], data[12], data[13], data[14], | 885 | "%02X %02X %02X %02X " |
871 | data[15], data[16], data[17], data[22], data[23], | 886 | "%02X %02X %02X %02X\n" |
872 | data[24], data[25], data[26], data[27], data[28], | 887 | "Modulus length: %d\n" |
873 | data[29], data[30], data[31], data[32], data[33], | 888 | "Modulus:\n", |
874 | be32_to_cpu(*((__be32 *) (data + 34)))); | 889 | data[0], data[1], data[2], data[3], |
890 | data[4], data[5], | ||
891 | data[6], data[7], | ||
892 | data[12], data[13], data[14], data[15], | ||
893 | data[16], data[17], data[18], data[19], | ||
894 | data[20], data[21], data[22], data[23], | ||
895 | be32_to_cpu(*((__be32 *) (data + 24)))); | ||
875 | 896 | ||
876 | for (i = 0; i < 256; i++) { | 897 | for (i = 0; i < 256; i++) { |
877 | str += sprintf(str, "%02X ", data[i + 38]); | 898 | str += sprintf(str, "%02X ", data[i + 28]); |
878 | if ((i + 1) % 16 == 0) | 899 | if ((i + 1) % 16 == 0) |
879 | str += sprintf(str, "\n"); | 900 | str += sprintf(str, "\n"); |
880 | } | 901 | } |
@@ -937,6 +958,35 @@ ssize_t tpm_show_caps_1_2(struct device * dev, | |||
937 | } | 958 | } |
938 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); | 959 | EXPORT_SYMBOL_GPL(tpm_show_caps_1_2); |
939 | 960 | ||
961 | ssize_t tpm_show_durations(struct device *dev, struct device_attribute *attr, | ||
962 | char *buf) | ||
963 | { | ||
964 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
965 | |||
966 | return sprintf(buf, "%d %d %d [%s]\n", | ||
967 | jiffies_to_usecs(chip->vendor.duration[TPM_SHORT]), | ||
968 | jiffies_to_usecs(chip->vendor.duration[TPM_MEDIUM]), | ||
969 | jiffies_to_usecs(chip->vendor.duration[TPM_LONG]), | ||
970 | chip->vendor.duration_adjusted | ||
971 | ? "adjusted" : "original"); | ||
972 | } | ||
973 | EXPORT_SYMBOL_GPL(tpm_show_durations); | ||
974 | |||
975 | ssize_t tpm_show_timeouts(struct device *dev, struct device_attribute *attr, | ||
976 | char *buf) | ||
977 | { | ||
978 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
979 | |||
980 | return sprintf(buf, "%d %d %d %d [%s]\n", | ||
981 | jiffies_to_usecs(chip->vendor.timeout_a), | ||
982 | jiffies_to_usecs(chip->vendor.timeout_b), | ||
983 | jiffies_to_usecs(chip->vendor.timeout_c), | ||
984 | jiffies_to_usecs(chip->vendor.timeout_d), | ||
985 | chip->vendor.timeout_adjusted | ||
986 | ? "adjusted" : "original"); | ||
987 | } | ||
988 | EXPORT_SYMBOL_GPL(tpm_show_timeouts); | ||
989 | |||
940 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, | 990 | ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, |
941 | const char *buf, size_t count) | 991 | const char *buf, size_t count) |
942 | { | 992 | { |
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 72ddb031b69a..9c4163cfa3ce 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h | |||
@@ -56,6 +56,10 @@ extern ssize_t tpm_show_owned(struct device *, struct device_attribute *attr, | |||
56 | char *); | 56 | char *); |
57 | extern ssize_t tpm_show_temp_deactivated(struct device *, | 57 | extern ssize_t tpm_show_temp_deactivated(struct device *, |
58 | struct device_attribute *attr, char *); | 58 | struct device_attribute *attr, char *); |
59 | extern ssize_t tpm_show_durations(struct device *, | ||
60 | struct device_attribute *attr, char *); | ||
61 | extern ssize_t tpm_show_timeouts(struct device *, | ||
62 | struct device_attribute *attr, char *); | ||
59 | 63 | ||
60 | struct tpm_chip; | 64 | struct tpm_chip; |
61 | 65 | ||
@@ -67,6 +71,7 @@ struct tpm_vendor_specific { | |||
67 | unsigned long base; /* TPM base address */ | 71 | unsigned long base; /* TPM base address */ |
68 | 72 | ||
69 | int irq; | 73 | int irq; |
74 | int probed_irq; | ||
70 | 75 | ||
71 | int region_size; | 76 | int region_size; |
72 | int have_region; | 77 | int have_region; |
@@ -81,7 +86,9 @@ struct tpm_vendor_specific { | |||
81 | struct list_head list; | 86 | struct list_head list; |
82 | int locality; | 87 | int locality; |
83 | unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ | 88 | unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */ |
89 | bool timeout_adjusted; | ||
84 | unsigned long duration[3]; /* jiffies */ | 90 | unsigned long duration[3]; /* jiffies */ |
91 | bool duration_adjusted; | ||
85 | 92 | ||
86 | wait_queue_head_t read_queue; | 93 | wait_queue_head_t read_queue; |
87 | wait_queue_head_t int_queue; | 94 | wait_queue_head_t int_queue; |
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index a605cb7dd898..82facc9104c7 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c | |||
@@ -330,12 +330,12 @@ static int __init init_nsc(void) | |||
330 | pdev->dev.driver = &nsc_drv.driver; | 330 | pdev->dev.driver = &nsc_drv.driver; |
331 | pdev->dev.release = tpm_nsc_remove; | 331 | pdev->dev.release = tpm_nsc_remove; |
332 | 332 | ||
333 | if ((rc = platform_device_register(pdev)) < 0) | 333 | if ((rc = platform_device_add(pdev)) < 0) |
334 | goto err_free_dev; | 334 | goto err_put_dev; |
335 | 335 | ||
336 | if (request_region(base, 2, "tpm_nsc0") == NULL ) { | 336 | if (request_region(base, 2, "tpm_nsc0") == NULL ) { |
337 | rc = -EBUSY; | 337 | rc = -EBUSY; |
338 | goto err_unreg_dev; | 338 | goto err_del_dev; |
339 | } | 339 | } |
340 | 340 | ||
341 | if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { | 341 | if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) { |
@@ -382,10 +382,10 @@ static int __init init_nsc(void) | |||
382 | 382 | ||
383 | err_rel_reg: | 383 | err_rel_reg: |
384 | release_region(base, 2); | 384 | release_region(base, 2); |
385 | err_unreg_dev: | 385 | err_del_dev: |
386 | platform_device_unregister(pdev); | 386 | platform_device_del(pdev); |
387 | err_free_dev: | 387 | err_put_dev: |
388 | kfree(pdev); | 388 | platform_device_put(pdev); |
389 | err_unreg_drv: | 389 | err_unreg_drv: |
390 | platform_driver_unregister(&nsc_drv); | 390 | platform_driver_unregister(&nsc_drv); |
391 | return rc; | 391 | return rc; |
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index dd21df55689d..7fc2f108f490 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/wait.h> | 27 | #include <linux/wait.h> |
28 | #include <linux/acpi.h> | 28 | #include <linux/acpi.h> |
29 | #include <linux/freezer.h> | ||
29 | #include "tpm.h" | 30 | #include "tpm.h" |
30 | 31 | ||
31 | #define TPM_HEADER_SIZE 10 | 32 | #define TPM_HEADER_SIZE 10 |
@@ -79,7 +80,7 @@ enum tis_defaults { | |||
79 | static LIST_HEAD(tis_chips); | 80 | static LIST_HEAD(tis_chips); |
80 | static DEFINE_SPINLOCK(tis_lock); | 81 | static DEFINE_SPINLOCK(tis_lock); |
81 | 82 | ||
82 | #ifdef CONFIG_ACPI | 83 | #ifdef CONFIG_PNP |
83 | static int is_itpm(struct pnp_dev *dev) | 84 | static int is_itpm(struct pnp_dev *dev) |
84 | { | 85 | { |
85 | struct acpi_device *acpi = pnp_acpi_device(dev); | 86 | struct acpi_device *acpi = pnp_acpi_device(dev); |
@@ -92,11 +93,6 @@ static int is_itpm(struct pnp_dev *dev) | |||
92 | 93 | ||
93 | return 0; | 94 | return 0; |
94 | } | 95 | } |
95 | #else | ||
96 | static int is_itpm(struct pnp_dev *dev) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | #endif | 96 | #endif |
101 | 97 | ||
102 | static int check_locality(struct tpm_chip *chip, int l) | 98 | static int check_locality(struct tpm_chip *chip, int l) |
@@ -120,7 +116,7 @@ static void release_locality(struct tpm_chip *chip, int l, int force) | |||
120 | 116 | ||
121 | static int request_locality(struct tpm_chip *chip, int l) | 117 | static int request_locality(struct tpm_chip *chip, int l) |
122 | { | 118 | { |
123 | unsigned long stop; | 119 | unsigned long stop, timeout; |
124 | long rc; | 120 | long rc; |
125 | 121 | ||
126 | if (check_locality(chip, l) >= 0) | 122 | if (check_locality(chip, l) >= 0) |
@@ -129,17 +125,25 @@ static int request_locality(struct tpm_chip *chip, int l) | |||
129 | iowrite8(TPM_ACCESS_REQUEST_USE, | 125 | iowrite8(TPM_ACCESS_REQUEST_USE, |
130 | chip->vendor.iobase + TPM_ACCESS(l)); | 126 | chip->vendor.iobase + TPM_ACCESS(l)); |
131 | 127 | ||
128 | stop = jiffies + chip->vendor.timeout_a; | ||
129 | |||
132 | if (chip->vendor.irq) { | 130 | if (chip->vendor.irq) { |
131 | again: | ||
132 | timeout = stop - jiffies; | ||
133 | if ((long)timeout <= 0) | ||
134 | return -1; | ||
133 | rc = wait_event_interruptible_timeout(chip->vendor.int_queue, | 135 | rc = wait_event_interruptible_timeout(chip->vendor.int_queue, |
134 | (check_locality | 136 | (check_locality |
135 | (chip, l) >= 0), | 137 | (chip, l) >= 0), |
136 | chip->vendor.timeout_a); | 138 | timeout); |
137 | if (rc > 0) | 139 | if (rc > 0) |
138 | return l; | 140 | return l; |
139 | 141 | if (rc == -ERESTARTSYS && freezing(current)) { | |
142 | clear_thread_flag(TIF_SIGPENDING); | ||
143 | goto again; | ||
144 | } | ||
140 | } else { | 145 | } else { |
141 | /* wait for burstcount */ | 146 | /* wait for burstcount */ |
142 | stop = jiffies + chip->vendor.timeout_a; | ||
143 | do { | 147 | do { |
144 | if (check_locality(chip, l) >= 0) | 148 | if (check_locality(chip, l) >= 0) |
145 | return l; | 149 | return l; |
@@ -196,15 +200,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | |||
196 | if ((status & mask) == mask) | 200 | if ((status & mask) == mask) |
197 | return 0; | 201 | return 0; |
198 | 202 | ||
203 | stop = jiffies + timeout; | ||
204 | |||
199 | if (chip->vendor.irq) { | 205 | if (chip->vendor.irq) { |
206 | again: | ||
207 | timeout = stop - jiffies; | ||
208 | if ((long)timeout <= 0) | ||
209 | return -ETIME; | ||
200 | rc = wait_event_interruptible_timeout(*queue, | 210 | rc = wait_event_interruptible_timeout(*queue, |
201 | ((tpm_tis_status | 211 | ((tpm_tis_status |
202 | (chip) & mask) == | 212 | (chip) & mask) == |
203 | mask), timeout); | 213 | mask), timeout); |
204 | if (rc > 0) | 214 | if (rc > 0) |
205 | return 0; | 215 | return 0; |
216 | if (rc == -ERESTARTSYS && freezing(current)) { | ||
217 | clear_thread_flag(TIF_SIGPENDING); | ||
218 | goto again; | ||
219 | } | ||
206 | } else { | 220 | } else { |
207 | stop = jiffies + timeout; | ||
208 | do { | 221 | do { |
209 | msleep(TPM_TIMEOUT); | 222 | msleep(TPM_TIMEOUT); |
210 | status = tpm_tis_status(chip); | 223 | status = tpm_tis_status(chip); |
@@ -288,11 +301,10 @@ MODULE_PARM_DESC(itpm, "Force iTPM workarounds (found on some Lenovo laptops)"); | |||
288 | * tpm.c can skip polling for the data to be available as the interrupt is | 301 | * tpm.c can skip polling for the data to be available as the interrupt is |
289 | * waited for here | 302 | * waited for here |
290 | */ | 303 | */ |
291 | static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | 304 | static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) |
292 | { | 305 | { |
293 | int rc, status, burstcnt; | 306 | int rc, status, burstcnt; |
294 | size_t count = 0; | 307 | size_t count = 0; |
295 | u32 ordinal; | ||
296 | 308 | ||
297 | if (request_locality(chip, 0) < 0) | 309 | if (request_locality(chip, 0) < 0) |
298 | return -EBUSY; | 310 | return -EBUSY; |
@@ -327,8 +339,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | |||
327 | 339 | ||
328 | /* write last byte */ | 340 | /* write last byte */ |
329 | iowrite8(buf[count], | 341 | iowrite8(buf[count], |
330 | chip->vendor.iobase + | 342 | chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality)); |
331 | TPM_DATA_FIFO(chip->vendor.locality)); | ||
332 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, | 343 | wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, |
333 | &chip->vendor.int_queue); | 344 | &chip->vendor.int_queue); |
334 | status = tpm_tis_status(chip); | 345 | status = tpm_tis_status(chip); |
@@ -337,6 +348,28 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | |||
337 | goto out_err; | 348 | goto out_err; |
338 | } | 349 | } |
339 | 350 | ||
351 | return 0; | ||
352 | |||
353 | out_err: | ||
354 | tpm_tis_ready(chip); | ||
355 | release_locality(chip, chip->vendor.locality, 0); | ||
356 | return rc; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * If interrupts are used (signaled by an irq set in the vendor structure) | ||
361 | * tpm.c can skip polling for the data to be available as the interrupt is | ||
362 | * waited for here | ||
363 | */ | ||
364 | static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) | ||
365 | { | ||
366 | int rc; | ||
367 | u32 ordinal; | ||
368 | |||
369 | rc = tpm_tis_send_data(chip, buf, len); | ||
370 | if (rc < 0) | ||
371 | return rc; | ||
372 | |||
340 | /* go and do it */ | 373 | /* go and do it */ |
341 | iowrite8(TPM_STS_GO, | 374 | iowrite8(TPM_STS_GO, |
342 | chip->vendor.iobase + TPM_STS(chip->vendor.locality)); | 375 | chip->vendor.iobase + TPM_STS(chip->vendor.locality)); |
@@ -358,6 +391,47 @@ out_err: | |||
358 | return rc; | 391 | return rc; |
359 | } | 392 | } |
360 | 393 | ||
394 | /* | ||
395 | * Early probing for iTPM with STS_DATA_EXPECT flaw. | ||
396 | * Try sending command without itpm flag set and if that | ||
397 | * fails, repeat with itpm flag set. | ||
398 | */ | ||
399 | static int probe_itpm(struct tpm_chip *chip) | ||
400 | { | ||
401 | int rc = 0; | ||
402 | u8 cmd_getticks[] = { | ||
403 | 0x00, 0xc1, 0x00, 0x00, 0x00, 0x0a, | ||
404 | 0x00, 0x00, 0x00, 0xf1 | ||
405 | }; | ||
406 | size_t len = sizeof(cmd_getticks); | ||
407 | int rem_itpm = itpm; | ||
408 | |||
409 | itpm = 0; | ||
410 | |||
411 | rc = tpm_tis_send_data(chip, cmd_getticks, len); | ||
412 | if (rc == 0) | ||
413 | goto out; | ||
414 | |||
415 | tpm_tis_ready(chip); | ||
416 | release_locality(chip, chip->vendor.locality, 0); | ||
417 | |||
418 | itpm = 1; | ||
419 | |||
420 | rc = tpm_tis_send_data(chip, cmd_getticks, len); | ||
421 | if (rc == 0) { | ||
422 | dev_info(chip->dev, "Detected an iTPM.\n"); | ||
423 | rc = 1; | ||
424 | } else | ||
425 | rc = -EFAULT; | ||
426 | |||
427 | out: | ||
428 | itpm = rem_itpm; | ||
429 | tpm_tis_ready(chip); | ||
430 | release_locality(chip, chip->vendor.locality, 0); | ||
431 | |||
432 | return rc; | ||
433 | } | ||
434 | |||
361 | static const struct file_operations tis_ops = { | 435 | static const struct file_operations tis_ops = { |
362 | .owner = THIS_MODULE, | 436 | .owner = THIS_MODULE, |
363 | .llseek = no_llseek, | 437 | .llseek = no_llseek, |
@@ -376,6 +450,8 @@ static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, | |||
376 | NULL); | 450 | NULL); |
377 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); | 451 | static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps_1_2, NULL); |
378 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); | 452 | static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); |
453 | static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); | ||
454 | static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); | ||
379 | 455 | ||
380 | static struct attribute *tis_attrs[] = { | 456 | static struct attribute *tis_attrs[] = { |
381 | &dev_attr_pubek.attr, | 457 | &dev_attr_pubek.attr, |
@@ -385,7 +461,9 @@ static struct attribute *tis_attrs[] = { | |||
385 | &dev_attr_owned.attr, | 461 | &dev_attr_owned.attr, |
386 | &dev_attr_temp_deactivated.attr, | 462 | &dev_attr_temp_deactivated.attr, |
387 | &dev_attr_caps.attr, | 463 | &dev_attr_caps.attr, |
388 | &dev_attr_cancel.attr, NULL, | 464 | &dev_attr_cancel.attr, |
465 | &dev_attr_durations.attr, | ||
466 | &dev_attr_timeouts.attr, NULL, | ||
389 | }; | 467 | }; |
390 | 468 | ||
391 | static struct attribute_group tis_attr_grp = { | 469 | static struct attribute_group tis_attr_grp = { |
@@ -416,7 +494,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id) | |||
416 | if (interrupt == 0) | 494 | if (interrupt == 0) |
417 | return IRQ_NONE; | 495 | return IRQ_NONE; |
418 | 496 | ||
419 | chip->vendor.irq = irq; | 497 | chip->vendor.probed_irq = irq; |
420 | 498 | ||
421 | /* Clear interrupts handled with TPM_EOI */ | 499 | /* Clear interrupts handled with TPM_EOI */ |
422 | iowrite32(interrupt, | 500 | iowrite32(interrupt, |
@@ -464,7 +542,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
464 | resource_size_t len, unsigned int irq) | 542 | resource_size_t len, unsigned int irq) |
465 | { | 543 | { |
466 | u32 vendor, intfcaps, intmask; | 544 | u32 vendor, intfcaps, intmask; |
467 | int rc, i; | 545 | int rc, i, irq_s, irq_e; |
468 | struct tpm_chip *chip; | 546 | struct tpm_chip *chip; |
469 | 547 | ||
470 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) | 548 | if (!(chip = tpm_register_hardware(dev, &tpm_tis))) |
@@ -493,6 +571,14 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
493 | "1.2 TPM (device-id 0x%X, rev-id %d)\n", | 571 | "1.2 TPM (device-id 0x%X, rev-id %d)\n", |
494 | vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); | 572 | vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); |
495 | 573 | ||
574 | if (!itpm) { | ||
575 | itpm = probe_itpm(chip); | ||
576 | if (itpm < 0) { | ||
577 | rc = -ENODEV; | ||
578 | goto out_err; | ||
579 | } | ||
580 | } | ||
581 | |||
496 | if (itpm) | 582 | if (itpm) |
497 | dev_info(dev, "Intel iTPM workaround enabled\n"); | 583 | dev_info(dev, "Intel iTPM workaround enabled\n"); |
498 | 584 | ||
@@ -522,6 +608,9 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
522 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) | 608 | if (intfcaps & TPM_INTF_DATA_AVAIL_INT) |
523 | dev_dbg(dev, "\tData Avail Int Support\n"); | 609 | dev_dbg(dev, "\tData Avail Int Support\n"); |
524 | 610 | ||
611 | /* get the timeouts before testing for irqs */ | ||
612 | tpm_get_timeouts(chip); | ||
613 | |||
525 | /* INTERRUPT Setup */ | 614 | /* INTERRUPT Setup */ |
526 | init_waitqueue_head(&chip->vendor.read_queue); | 615 | init_waitqueue_head(&chip->vendor.read_queue); |
527 | init_waitqueue_head(&chip->vendor.int_queue); | 616 | init_waitqueue_head(&chip->vendor.int_queue); |
@@ -540,13 +629,19 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
540 | if (interrupts) | 629 | if (interrupts) |
541 | chip->vendor.irq = irq; | 630 | chip->vendor.irq = irq; |
542 | if (interrupts && !chip->vendor.irq) { | 631 | if (interrupts && !chip->vendor.irq) { |
543 | chip->vendor.irq = | 632 | irq_s = |
544 | ioread8(chip->vendor.iobase + | 633 | ioread8(chip->vendor.iobase + |
545 | TPM_INT_VECTOR(chip->vendor.locality)); | 634 | TPM_INT_VECTOR(chip->vendor.locality)); |
635 | if (irq_s) { | ||
636 | irq_e = irq_s; | ||
637 | } else { | ||
638 | irq_s = 3; | ||
639 | irq_e = 15; | ||
640 | } | ||
546 | 641 | ||
547 | for (i = 3; i < 16 && chip->vendor.irq == 0; i++) { | 642 | for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) { |
548 | iowrite8(i, chip->vendor.iobase + | 643 | iowrite8(i, chip->vendor.iobase + |
549 | TPM_INT_VECTOR(chip->vendor.locality)); | 644 | TPM_INT_VECTOR(chip->vendor.locality)); |
550 | if (request_irq | 645 | if (request_irq |
551 | (i, tis_int_probe, IRQF_SHARED, | 646 | (i, tis_int_probe, IRQF_SHARED, |
552 | chip->vendor.miscdev.name, chip) != 0) { | 647 | chip->vendor.miscdev.name, chip) != 0) { |
@@ -568,9 +663,22 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
568 | chip->vendor.iobase + | 663 | chip->vendor.iobase + |
569 | TPM_INT_ENABLE(chip->vendor.locality)); | 664 | TPM_INT_ENABLE(chip->vendor.locality)); |
570 | 665 | ||
666 | chip->vendor.probed_irq = 0; | ||
667 | |||
571 | /* Generate Interrupts */ | 668 | /* Generate Interrupts */ |
572 | tpm_gen_interrupt(chip); | 669 | tpm_gen_interrupt(chip); |
573 | 670 | ||
671 | chip->vendor.irq = chip->vendor.probed_irq; | ||
672 | |||
673 | /* free_irq will call into tis_int_probe; | ||
674 | clear all irqs we haven't seen while doing | ||
675 | tpm_gen_interrupt */ | ||
676 | iowrite32(ioread32 | ||
677 | (chip->vendor.iobase + | ||
678 | TPM_INT_STATUS(chip->vendor.locality)), | ||
679 | chip->vendor.iobase + | ||
680 | TPM_INT_STATUS(chip->vendor.locality)); | ||
681 | |||
574 | /* Turn off */ | 682 | /* Turn off */ |
575 | iowrite32(intmask, | 683 | iowrite32(intmask, |
576 | chip->vendor.iobase + | 684 | chip->vendor.iobase + |
@@ -609,7 +717,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, | |||
609 | list_add(&chip->vendor.list, &tis_chips); | 717 | list_add(&chip->vendor.list, &tis_chips); |
610 | spin_unlock(&tis_lock); | 718 | spin_unlock(&tis_lock); |
611 | 719 | ||
612 | tpm_get_timeouts(chip); | ||
613 | tpm_continue_selftest(chip); | 720 | tpm_continue_selftest(chip); |
614 | 721 | ||
615 | return 0; | 722 | return 0; |
@@ -619,6 +726,29 @@ out_err: | |||
619 | tpm_remove_hardware(chip->dev); | 726 | tpm_remove_hardware(chip->dev); |
620 | return rc; | 727 | return rc; |
621 | } | 728 | } |
729 | |||
730 | static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) | ||
731 | { | ||
732 | u32 intmask; | ||
733 | |||
734 | /* reenable interrupts that device may have lost or | ||
735 | BIOS/firmware may have disabled */ | ||
736 | iowrite8(chip->vendor.irq, chip->vendor.iobase + | ||
737 | TPM_INT_VECTOR(chip->vendor.locality)); | ||
738 | |||
739 | intmask = | ||
740 | ioread32(chip->vendor.iobase + | ||
741 | TPM_INT_ENABLE(chip->vendor.locality)); | ||
742 | |||
743 | intmask |= TPM_INTF_CMD_READY_INT | ||
744 | | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT | ||
745 | | TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE; | ||
746 | |||
747 | iowrite32(intmask, | ||
748 | chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor.locality)); | ||
749 | } | ||
750 | |||
751 | |||
622 | #ifdef CONFIG_PNP | 752 | #ifdef CONFIG_PNP |
623 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, | 753 | static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev, |
624 | const struct pnp_device_id *pnp_id) | 754 | const struct pnp_device_id *pnp_id) |
@@ -650,6 +780,9 @@ static int tpm_tis_pnp_resume(struct pnp_dev *dev) | |||
650 | struct tpm_chip *chip = pnp_get_drvdata(dev); | 780 | struct tpm_chip *chip = pnp_get_drvdata(dev); |
651 | int ret; | 781 | int ret; |
652 | 782 | ||
783 | if (chip->vendor.irq) | ||
784 | tpm_tis_reenable_interrupts(chip); | ||
785 | |||
653 | ret = tpm_pm_resume(&dev->dev); | 786 | ret = tpm_pm_resume(&dev->dev); |
654 | if (!ret) | 787 | if (!ret) |
655 | tpm_continue_selftest(chip); | 788 | tpm_continue_selftest(chip); |
@@ -702,6 +835,11 @@ static int tpm_tis_suspend(struct platform_device *dev, pm_message_t msg) | |||
702 | 835 | ||
703 | static int tpm_tis_resume(struct platform_device *dev) | 836 | static int tpm_tis_resume(struct platform_device *dev) |
704 | { | 837 | { |
838 | struct tpm_chip *chip = dev_get_drvdata(&dev->dev); | ||
839 | |||
840 | if (chip->vendor.irq) | ||
841 | tpm_tis_reenable_interrupts(chip); | ||
842 | |||
705 | return tpm_pm_resume(&dev->dev); | 843 | return tpm_pm_resume(&dev->dev); |
706 | } | 844 | } |
707 | static struct platform_driver tis_drv = { | 845 | static struct platform_driver tis_drv = { |