| .. | .. |
|---|
| 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 |
|---|