/** * tpm_calc_ordinal_duration() - calculate the maximum command duration * @chip: TPM chip to use. * @ordinal: TPM command ordinal. * * The function returns the maximum amount of time the chip could take * to return the result for a particular ordinal in jiffies. * * Return: A maximal duration time for an ordinal in jiffies. */ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) { if (chip->flags & TPM_CHIP_FLAG_TPM2) return tpm2_calc_ordinal_duration(chip, ordinal); else return tpm1_calc_ordinal_duration(chip, ordinal); }
/* * Internal kernel interface to transmit TPM commands */ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags) { ssize_t rc; u32 count, ordinal; unsigned long stop; if (bufsiz < TPM_HEADER_SIZE) return -EINVAL; if (bufsiz > TPM_BUFSIZE) bufsiz = TPM_BUFSIZE; count = be32_to_cpu(*((__be32 *) (buf + 2))); ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); if (count == 0) return -ENODATA; if (count > bufsiz) { dev_err(&chip->dev, "invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(&chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); goto out; } if (chip->flags & TPM_CHIP_FLAG_IRQ) goto out_recv; if (chip->flags & TPM_CHIP_FLAG_TPM2) stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal); else stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); do { u8 status = chip->ops->status(chip); if ((status & chip->ops->req_complete_mask) == chip->ops->req_complete_val) goto out_recv; if (chip->ops->req_canceled(chip, status)) { dev_err(&chip->dev, "Operation Canceled\n"); rc = -ECANCELED; goto out; } msleep(TPM_TIMEOUT); /* CHECK */ rmb(); } while (time_before(jiffies, stop)); chip->ops->cancel(chip); dev_err(&chip->dev, "Operation Timed out\n"); rc = -ETIME; goto out; out_recv: rc = chip->ops->recv(chip, (u8 *) buf, bufsiz); if (rc < 0) dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc; }