Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33bafe90 authored by Jerry Snitselaar's avatar Jerry Snitselaar Committed by Jarkko Sakkinen
Browse files

tpm_tis: verify locality released before returning from release_locality



For certain tpm chips releasing locality can take long enough that a
subsequent call to request_locality will see the locality as being active
when the access register is read in check_locality. So check that the
locality has been released before returning from release_locality.

Cc: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Cc: Peter Huewe <peterhuewe@gmx.de>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Reported-by: default avatarLaurent Bigonville <bigon@debian.org>
Signed-off-by: default avatarJerry Snitselaar <jsnitsel@redhat.com>
Tested-by: default avatarLaurent Bigonville <bigon@debian.org>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
parent 1fbad302
Loading
Loading
Loading
Loading
+46 −1
Original line number Diff line number Diff line
@@ -143,13 +143,58 @@ static bool check_locality(struct tpm_chip *chip, int l)
	return false;
}

static bool locality_inactive(struct tpm_chip *chip, int l)
{
	struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
	int rc;
	u8 access;

	rc = tpm_tis_read8(priv, TPM_ACCESS(l), &access);
	if (rc < 0)
		return false;

	if ((access & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
	    == TPM_ACCESS_VALID)
		return true;

	return false;
}

static int release_locality(struct tpm_chip *chip, int l)
{
	struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
	unsigned long stop, timeout;
	long rc;

	tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);

	stop = jiffies + chip->timeout_a;

	if (chip->flags & TPM_CHIP_FLAG_IRQ) {
again:
		timeout = stop - jiffies;
		if ((long)timeout <= 0)
			return -1;

		rc = wait_event_interruptible_timeout(priv->int_queue,
						      (locality_inactive(chip, l)),
						      timeout);

		if (rc > 0)
			return 0;

		if (rc == -ERESTARTSYS && freezing(current)) {
			clear_thread_flag(TIF_SIGPENDING);
			goto again;
		}
	} else {
		do {
			if (locality_inactive(chip, l))
				return 0;
			tpm_msleep(TPM_TIMEOUT);
		} while (time_before(jiffies, stop));
	}
	return -1;
}

static int request_locality(struct tpm_chip *chip, int l)