.. | .. |
---|
136 | 136 | return false; |
---|
137 | 137 | } |
---|
138 | 138 | |
---|
139 | | -static int release_locality(struct tpm_chip *chip, int l) |
---|
| 139 | +static int __tpm_tis_relinquish_locality(struct tpm_tis_data *priv, int l) |
---|
140 | 140 | { |
---|
141 | | - struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
---|
142 | | - |
---|
143 | 141 | tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY); |
---|
144 | 142 | |
---|
145 | 143 | return 0; |
---|
146 | 144 | } |
---|
147 | 145 | |
---|
148 | | -static int request_locality(struct tpm_chip *chip, int l) |
---|
| 146 | +static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l) |
---|
| 147 | +{ |
---|
| 148 | + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
---|
| 149 | + |
---|
| 150 | + mutex_lock(&priv->locality_count_mutex); |
---|
| 151 | + priv->locality_count--; |
---|
| 152 | + if (priv->locality_count == 0) |
---|
| 153 | + __tpm_tis_relinquish_locality(priv, l); |
---|
| 154 | + mutex_unlock(&priv->locality_count_mutex); |
---|
| 155 | + |
---|
| 156 | + return 0; |
---|
| 157 | +} |
---|
| 158 | + |
---|
| 159 | +static int __tpm_tis_request_locality(struct tpm_chip *chip, int l) |
---|
149 | 160 | { |
---|
150 | 161 | struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
---|
151 | 162 | unsigned long stop, timeout; |
---|
.. | .. |
---|
184 | 195 | } while (time_before(jiffies, stop)); |
---|
185 | 196 | } |
---|
186 | 197 | return -1; |
---|
| 198 | +} |
---|
| 199 | + |
---|
| 200 | +static int tpm_tis_request_locality(struct tpm_chip *chip, int l) |
---|
| 201 | +{ |
---|
| 202 | + struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); |
---|
| 203 | + int ret = 0; |
---|
| 204 | + |
---|
| 205 | + mutex_lock(&priv->locality_count_mutex); |
---|
| 206 | + if (priv->locality_count == 0) |
---|
| 207 | + ret = __tpm_tis_request_locality(chip, l); |
---|
| 208 | + if (!ret) |
---|
| 209 | + priv->locality_count++; |
---|
| 210 | + mutex_unlock(&priv->locality_count_mutex); |
---|
| 211 | + return ret; |
---|
187 | 212 | } |
---|
188 | 213 | |
---|
189 | 214 | static u8 tpm_tis_status(struct tpm_chip *chip) |
---|
.. | .. |
---|
289 | 314 | int size = 0; |
---|
290 | 315 | int status; |
---|
291 | 316 | u32 expected; |
---|
| 317 | + int rc; |
---|
292 | 318 | |
---|
293 | 319 | if (count < TPM_HEADER_SIZE) { |
---|
294 | 320 | size = -EIO; |
---|
.. | .. |
---|
308 | 334 | goto out; |
---|
309 | 335 | } |
---|
310 | 336 | |
---|
311 | | - size += recv_data(chip, &buf[TPM_HEADER_SIZE], |
---|
312 | | - expected - TPM_HEADER_SIZE); |
---|
| 337 | + rc = recv_data(chip, &buf[TPM_HEADER_SIZE], |
---|
| 338 | + expected - TPM_HEADER_SIZE); |
---|
| 339 | + if (rc < 0) { |
---|
| 340 | + size = rc; |
---|
| 341 | + goto out; |
---|
| 342 | + } |
---|
| 343 | + size += rc; |
---|
313 | 344 | if (size < expected) { |
---|
314 | 345 | dev_err(&chip->dev, "Unable to read remainder of result\n"); |
---|
315 | 346 | size = -ETIME; |
---|
.. | .. |
---|
438 | 469 | int rc; |
---|
439 | 470 | u32 ordinal; |
---|
440 | 471 | unsigned long dur; |
---|
| 472 | + unsigned int try; |
---|
441 | 473 | |
---|
442 | | - rc = tpm_tis_send_data(chip, buf, len); |
---|
443 | | - if (rc < 0) |
---|
444 | | - return rc; |
---|
| 474 | + for (try = 0; try < TPM_RETRY; try++) { |
---|
| 475 | + rc = tpm_tis_send_data(chip, buf, len); |
---|
| 476 | + if (rc >= 0) |
---|
| 477 | + /* Data transfer done successfully */ |
---|
| 478 | + break; |
---|
| 479 | + else if (rc != -EIO) |
---|
| 480 | + /* Data transfer failed, not recoverable */ |
---|
| 481 | + return rc; |
---|
| 482 | + } |
---|
445 | 483 | |
---|
446 | 484 | /* go and do it */ |
---|
447 | 485 | rc = tpm_tis_write8(priv, TPM_STS(priv->locality), TPM_STS_GO); |
---|
.. | .. |
---|
638 | 676 | if (vendor != TPM_VID_INTEL) |
---|
639 | 677 | return 0; |
---|
640 | 678 | |
---|
641 | | - if (request_locality(chip, 0) != 0) |
---|
| 679 | + if (tpm_tis_request_locality(chip, 0) != 0) |
---|
642 | 680 | return -EBUSY; |
---|
643 | 681 | |
---|
644 | 682 | rc = tpm_tis_send_data(chip, cmd_getticks, len); |
---|
.. | .. |
---|
659 | 697 | |
---|
660 | 698 | out: |
---|
661 | 699 | tpm_tis_ready(chip); |
---|
662 | | - release_locality(chip, priv->locality); |
---|
| 700 | + tpm_tis_relinquish_locality(chip, priv->locality); |
---|
663 | 701 | |
---|
664 | 702 | return rc; |
---|
665 | 703 | } |
---|
.. | .. |
---|
706 | 744 | wake_up_interruptible(&priv->int_queue); |
---|
707 | 745 | |
---|
708 | 746 | /* Clear interrupts handled with TPM_EOI */ |
---|
| 747 | + tpm_tis_request_locality(chip, 0); |
---|
709 | 748 | rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), interrupt); |
---|
| 749 | + tpm_tis_relinquish_locality(chip, 0); |
---|
710 | 750 | if (rc < 0) |
---|
711 | 751 | return IRQ_NONE; |
---|
712 | 752 | |
---|
.. | .. |
---|
714 | 754 | return IRQ_HANDLED; |
---|
715 | 755 | } |
---|
716 | 756 | |
---|
717 | | -static int tpm_tis_gen_interrupt(struct tpm_chip *chip) |
---|
| 757 | +static void tpm_tis_gen_interrupt(struct tpm_chip *chip) |
---|
718 | 758 | { |
---|
719 | 759 | const char *desc = "attempting to generate an interrupt"; |
---|
720 | 760 | u32 cap2; |
---|
721 | 761 | cap_t cap; |
---|
722 | 762 | int ret; |
---|
723 | 763 | |
---|
724 | | - ret = request_locality(chip, 0); |
---|
725 | | - if (ret < 0) |
---|
726 | | - return ret; |
---|
727 | | - |
---|
728 | 764 | if (chip->flags & TPM_CHIP_FLAG_TPM2) |
---|
729 | 765 | ret = tpm2_get_tpm_pt(chip, 0x100, &cap2, desc); |
---|
730 | 766 | else |
---|
731 | 767 | ret = tpm1_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, desc, 0); |
---|
732 | | - |
---|
733 | | - release_locality(chip, 0); |
---|
734 | | - |
---|
735 | | - return ret; |
---|
736 | 768 | } |
---|
737 | 769 | |
---|
738 | 770 | /* Register the IRQ and issue a command that will cause an interrupt. If an |
---|
.. | .. |
---|
747 | 779 | int rc; |
---|
748 | 780 | u32 int_status; |
---|
749 | 781 | |
---|
750 | | - if (devm_request_irq(chip->dev.parent, irq, tis_int_handler, flags, |
---|
751 | | - dev_name(&chip->dev), chip) != 0) { |
---|
| 782 | + |
---|
| 783 | + rc = devm_request_threaded_irq(chip->dev.parent, irq, NULL, |
---|
| 784 | + tis_int_handler, IRQF_ONESHOT | flags, |
---|
| 785 | + dev_name(&chip->dev), chip); |
---|
| 786 | + if (rc) { |
---|
752 | 787 | dev_info(&chip->dev, "Unable to request irq: %d for probe\n", |
---|
753 | 788 | irq); |
---|
754 | 789 | return -1; |
---|
755 | 790 | } |
---|
756 | 791 | priv->irq = irq; |
---|
757 | 792 | |
---|
758 | | - rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality), |
---|
759 | | - &original_int_vec); |
---|
| 793 | + rc = tpm_tis_request_locality(chip, 0); |
---|
760 | 794 | if (rc < 0) |
---|
761 | 795 | return rc; |
---|
| 796 | + |
---|
| 797 | + rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality), |
---|
| 798 | + &original_int_vec); |
---|
| 799 | + if (rc < 0) { |
---|
| 800 | + tpm_tis_relinquish_locality(chip, priv->locality); |
---|
| 801 | + return rc; |
---|
| 802 | + } |
---|
762 | 803 | |
---|
763 | 804 | rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), irq); |
---|
764 | 805 | if (rc < 0) |
---|
765 | | - return rc; |
---|
| 806 | + goto restore_irqs; |
---|
766 | 807 | |
---|
767 | 808 | rc = tpm_tis_read32(priv, TPM_INT_STATUS(priv->locality), &int_status); |
---|
768 | 809 | if (rc < 0) |
---|
769 | | - return rc; |
---|
| 810 | + goto restore_irqs; |
---|
770 | 811 | |
---|
771 | 812 | /* Clear all existing */ |
---|
772 | 813 | rc = tpm_tis_write32(priv, TPM_INT_STATUS(priv->locality), int_status); |
---|
773 | 814 | if (rc < 0) |
---|
774 | | - return rc; |
---|
775 | | - |
---|
| 815 | + goto restore_irqs; |
---|
776 | 816 | /* Turn on */ |
---|
777 | 817 | rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), |
---|
778 | 818 | intmask | TPM_GLOBAL_INT_ENABLE); |
---|
779 | 819 | if (rc < 0) |
---|
780 | | - return rc; |
---|
| 820 | + goto restore_irqs; |
---|
781 | 821 | |
---|
782 | 822 | priv->irq_tested = false; |
---|
783 | 823 | |
---|
784 | 824 | /* Generate an interrupt by having the core call through to |
---|
785 | 825 | * tpm_tis_send |
---|
786 | 826 | */ |
---|
787 | | - rc = tpm_tis_gen_interrupt(chip); |
---|
788 | | - if (rc < 0) |
---|
789 | | - return rc; |
---|
| 827 | + tpm_tis_gen_interrupt(chip); |
---|
790 | 828 | |
---|
| 829 | +restore_irqs: |
---|
791 | 830 | /* tpm_tis_send will either confirm the interrupt is working or it |
---|
792 | 831 | * will call disable_irq which undoes all of the above. |
---|
793 | 832 | */ |
---|
794 | 833 | if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { |
---|
795 | | - rc = tpm_tis_write8(priv, original_int_vec, |
---|
796 | | - TPM_INT_VECTOR(priv->locality)); |
---|
797 | | - if (rc < 0) |
---|
798 | | - return rc; |
---|
799 | | - |
---|
800 | | - return 1; |
---|
| 834 | + tpm_tis_write8(priv, original_int_vec, |
---|
| 835 | + TPM_INT_VECTOR(priv->locality)); |
---|
| 836 | + rc = -1; |
---|
801 | 837 | } |
---|
802 | 838 | |
---|
803 | | - return 0; |
---|
| 839 | + tpm_tis_relinquish_locality(chip, priv->locality); |
---|
| 840 | + |
---|
| 841 | + return rc; |
---|
804 | 842 | } |
---|
805 | 843 | |
---|
806 | 844 | /* Try to find the IRQ the TPM is using. This is for legacy x86 systems that |
---|
.. | .. |
---|
914 | 952 | .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
---|
915 | 953 | .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, |
---|
916 | 954 | .req_canceled = tpm_tis_req_canceled, |
---|
917 | | - .request_locality = request_locality, |
---|
918 | | - .relinquish_locality = release_locality, |
---|
| 955 | + .request_locality = tpm_tis_request_locality, |
---|
| 956 | + .relinquish_locality = tpm_tis_relinquish_locality, |
---|
919 | 957 | .clk_enable = tpm_tis_clkrun_enable, |
---|
920 | 958 | }; |
---|
921 | 959 | |
---|
.. | .. |
---|
949 | 987 | priv->timeout_min = TPM_TIMEOUT_USECS_MIN; |
---|
950 | 988 | priv->timeout_max = TPM_TIMEOUT_USECS_MAX; |
---|
951 | 989 | priv->phy_ops = phy_ops; |
---|
| 990 | + priv->locality_count = 0; |
---|
| 991 | + mutex_init(&priv->locality_count_mutex); |
---|
952 | 992 | |
---|
953 | 993 | dev_set_drvdata(&chip->dev, priv); |
---|
954 | 994 | |
---|
.. | .. |
---|
995 | 1035 | TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT; |
---|
996 | 1036 | intmask &= ~TPM_GLOBAL_INT_ENABLE; |
---|
997 | 1037 | |
---|
998 | | - rc = request_locality(chip, 0); |
---|
| 1038 | + rc = tpm_tis_request_locality(chip, 0); |
---|
999 | 1039 | if (rc < 0) { |
---|
1000 | 1040 | rc = -ENODEV; |
---|
1001 | 1041 | goto out_err; |
---|
1002 | 1042 | } |
---|
1003 | 1043 | |
---|
1004 | 1044 | tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); |
---|
1005 | | - release_locality(chip, 0); |
---|
| 1045 | + tpm_tis_relinquish_locality(chip, 0); |
---|
1006 | 1046 | |
---|
1007 | 1047 | rc = tpm_chip_start(chip); |
---|
1008 | 1048 | if (rc) |
---|
.. | .. |
---|
1062 | 1102 | * proper timeouts for the driver. |
---|
1063 | 1103 | */ |
---|
1064 | 1104 | |
---|
1065 | | - rc = request_locality(chip, 0); |
---|
| 1105 | + rc = tpm_tis_request_locality(chip, 0); |
---|
1066 | 1106 | if (rc < 0) |
---|
1067 | 1107 | goto out_err; |
---|
1068 | 1108 | |
---|
1069 | 1109 | rc = tpm_get_timeouts(chip); |
---|
1070 | 1110 | |
---|
1071 | | - release_locality(chip, 0); |
---|
| 1111 | + tpm_tis_relinquish_locality(chip, 0); |
---|
1072 | 1112 | |
---|
1073 | 1113 | if (rc) { |
---|
1074 | 1114 | dev_err(dev, "Could not get TPM timeouts and durations\n"); |
---|
.. | .. |
---|
1076 | 1116 | goto out_err; |
---|
1077 | 1117 | } |
---|
1078 | 1118 | |
---|
1079 | | - if (irq) { |
---|
| 1119 | + if (irq) |
---|
1080 | 1120 | tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, |
---|
1081 | 1121 | irq); |
---|
1082 | | - if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { |
---|
1083 | | - dev_err(&chip->dev, FW_BUG |
---|
| 1122 | + else |
---|
| 1123 | + tpm_tis_probe_irq(chip, intmask); |
---|
| 1124 | + |
---|
| 1125 | + if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { |
---|
| 1126 | + dev_err(&chip->dev, FW_BUG |
---|
1084 | 1127 | "TPM interrupt not working, polling instead\n"); |
---|
1085 | 1128 | |
---|
1086 | | - disable_interrupts(chip); |
---|
1087 | | - } |
---|
1088 | | - } else { |
---|
1089 | | - tpm_tis_probe_irq(chip, intmask); |
---|
| 1129 | + rc = tpm_tis_request_locality(chip, 0); |
---|
| 1130 | + if (rc < 0) |
---|
| 1131 | + goto out_err; |
---|
| 1132 | + disable_interrupts(chip); |
---|
| 1133 | + tpm_tis_relinquish_locality(chip, 0); |
---|
1090 | 1134 | } |
---|
1091 | 1135 | } |
---|
1092 | 1136 | |
---|
.. | .. |
---|
1147 | 1191 | struct tpm_chip *chip = dev_get_drvdata(dev); |
---|
1148 | 1192 | int ret; |
---|
1149 | 1193 | |
---|
| 1194 | + ret = tpm_tis_request_locality(chip, 0); |
---|
| 1195 | + if (ret < 0) |
---|
| 1196 | + return ret; |
---|
| 1197 | + |
---|
1150 | 1198 | if (chip->flags & TPM_CHIP_FLAG_IRQ) |
---|
1151 | 1199 | tpm_tis_reenable_interrupts(chip); |
---|
1152 | 1200 | |
---|
1153 | 1201 | ret = tpm_pm_resume(dev); |
---|
1154 | 1202 | if (ret) |
---|
1155 | | - return ret; |
---|
| 1203 | + goto out; |
---|
1156 | 1204 | |
---|
1157 | 1205 | /* |
---|
1158 | 1206 | * TPM 1.2 requires self-test on resume. This function actually returns |
---|
1159 | 1207 | * an error code but for unknown reason it isn't handled. |
---|
1160 | 1208 | */ |
---|
1161 | | - if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { |
---|
1162 | | - ret = request_locality(chip, 0); |
---|
1163 | | - if (ret < 0) |
---|
1164 | | - return ret; |
---|
1165 | | - |
---|
| 1209 | + if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) |
---|
1166 | 1210 | tpm1_do_selftest(chip); |
---|
| 1211 | +out: |
---|
| 1212 | + tpm_tis_relinquish_locality(chip, 0); |
---|
1167 | 1213 | |
---|
1168 | | - release_locality(chip, 0); |
---|
1169 | | - } |
---|
1170 | | - |
---|
1171 | | - return 0; |
---|
| 1214 | + return ret; |
---|
1172 | 1215 | } |
---|
1173 | 1216 | EXPORT_SYMBOL_GPL(tpm_tis_resume); |
---|
1174 | 1217 | #endif |
---|