|
@@ -399,21 +399,10 @@ static void tpm_relinquish_locality(struct tpm_chip *chip)
|
|
|
chip->locality = -1;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * tpm_transmit - Internal kernel interface to transmit TPM commands.
|
|
|
- *
|
|
|
- * @chip: TPM chip to use
|
|
|
- * @space: tpm space
|
|
|
- * @buf: TPM command buffer
|
|
|
- * @bufsiz: length of the TPM command buffer
|
|
|
- * @flags: tpm transmit flags - bitmap
|
|
|
- *
|
|
|
- * Return:
|
|
|
- * 0 when the operation is successful.
|
|
|
- * A negative number for system errors (errno).
|
|
|
- */
|
|
|
-ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
|
|
- u8 *buf, size_t bufsiz, unsigned int flags)
|
|
|
+static ssize_t tpm_try_transmit(struct tpm_chip *chip,
|
|
|
+ struct tpm_space *space,
|
|
|
+ u8 *buf, size_t bufsiz,
|
|
|
+ unsigned int flags)
|
|
|
{
|
|
|
struct tpm_output_header *header = (void *)buf;
|
|
|
int rc;
|
|
@@ -544,6 +533,62 @@ out_no_locality:
|
|
|
return rc ? rc : len;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * tpm_transmit - Internal kernel interface to transmit TPM commands.
|
|
|
+ *
|
|
|
+ * @chip: TPM chip to use
|
|
|
+ * @space: tpm space
|
|
|
+ * @buf: TPM command buffer
|
|
|
+ * @bufsiz: length of the TPM command buffer
|
|
|
+ * @flags: tpm transmit flags - bitmap
|
|
|
+ *
|
|
|
+ * A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY
|
|
|
+ * returns from the TPM and retransmits the command after a delay up
|
|
|
+ * to a maximum wait of TPM2_DURATION_LONG.
|
|
|
+ *
|
|
|
+ * Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2
|
|
|
+ * only
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ * the length of the return when the operation is successful.
|
|
|
+ * A negative number for system errors (errno).
|
|
|
+ */
|
|
|
+ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
|
|
|
+ u8 *buf, size_t bufsiz, unsigned int flags)
|
|
|
+{
|
|
|
+ struct tpm_output_header *header = (struct tpm_output_header *)buf;
|
|
|
+ /* space for header and handles */
|
|
|
+ u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)];
|
|
|
+ unsigned int delay_msec = TPM2_DURATION_SHORT;
|
|
|
+ u32 rc = 0;
|
|
|
+ ssize_t ret;
|
|
|
+ const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE,
|
|
|
+ bufsiz);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Subtlety here: if we have a space, the handles will be
|
|
|
+ * transformed, so when we restore the header we also have to
|
|
|
+ * restore the handles.
|
|
|
+ */
|
|
|
+ memcpy(save, buf, save_size);
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ ret = tpm_try_transmit(chip, space, buf, bufsiz, flags);
|
|
|
+ if (ret < 0)
|
|
|
+ break;
|
|
|
+ rc = be32_to_cpu(header->return_code);
|
|
|
+ if (rc != TPM2_RC_RETRY)
|
|
|
+ break;
|
|
|
+ delay_msec *= 2;
|
|
|
+ if (delay_msec > TPM2_DURATION_LONG) {
|
|
|
+ dev_err(&chip->dev, "TPM is in retry loop\n");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ tpm_msleep(delay_msec);
|
|
|
+ memcpy(buf, save, save_size);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
/**
|
|
|
* tpm_transmit_cmd - send a tpm command to the device
|
|
|
* The function extracts tpm out header return code
|