Merge 6.3-rc5 into driver-core-next
[platform/kernel/linux-starfive.git] / drivers / char / tpm / tpm-chip.c
index 7c44420..29305a0 100644 (file)
@@ -510,6 +510,63 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip)
        return 0;
 }
 
+/*
+ * Some AMD fTPM versions may cause stutter
+ * https://www.amd.com/en/support/kb/faq/pa-410
+ *
+ * Fixes are available in two series of fTPM firmware:
+ * 6.x.y.z series: 6.0.18.6 +
+ * 3.x.y.z series: 3.57.y.5 +
+ */
+static bool tpm_amd_is_rng_defective(struct tpm_chip *chip)
+{
+       u32 val1, val2;
+       u64 version;
+       int ret;
+
+       if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
+               return false;
+
+       ret = tpm_request_locality(chip);
+       if (ret)
+               return false;
+
+       ret = tpm2_get_tpm_pt(chip, TPM2_PT_MANUFACTURER, &val1, NULL);
+       if (ret)
+               goto release;
+       if (val1 != 0x414D4400U /* AMD */) {
+               ret = -ENODEV;
+               goto release;
+       }
+       ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_1, &val1, NULL);
+       if (ret)
+               goto release;
+       ret = tpm2_get_tpm_pt(chip, TPM2_PT_FIRMWARE_VERSION_2, &val2, NULL);
+
+release:
+       tpm_relinquish_locality(chip);
+
+       if (ret)
+               return false;
+
+       version = ((u64)val1 << 32) | val2;
+       if ((version >> 48) == 6) {
+               if (version >= 0x0006000000180006ULL)
+                       return false;
+       } else if ((version >> 48) == 3) {
+               if (version >= 0x0003005700000005ULL)
+                       return false;
+       } else {
+               return false;
+       }
+
+       dev_warn(&chip->dev,
+                "AMD fTPM version 0x%llx causes system stutter; hwrng disabled\n",
+                version);
+
+       return true;
+}
+
 static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
 {
        struct tpm_chip *chip = container_of(rng, struct tpm_chip, hwrng);
@@ -519,7 +576,8 @@ static int tpm_hwrng_read(struct hwrng *rng, void *data, size_t max, bool wait)
 
 static int tpm_add_hwrng(struct tpm_chip *chip)
 {
-       if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip))
+       if (!IS_ENABLED(CONFIG_HW_RANDOM_TPM) || tpm_is_firmware_upgrade(chip) ||
+           tpm_amd_is_rng_defective(chip))
                return 0;
 
        snprintf(chip->hwrng_name, sizeof(chip->hwrng_name),