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

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
...@@ -143,13 +143,58 @@ static bool check_locality(struct tpm_chip *chip, int l) ...@@ -143,13 +143,58 @@ static bool check_locality(struct tpm_chip *chip, int l)
return false; 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) static int release_locality(struct tpm_chip *chip, int l)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); 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); 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; return 0;
tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop));
}
return -1;
} }
static int request_locality(struct tpm_chip *chip, int l) static int request_locality(struct tpm_chip *chip, int l)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment