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: Laurent Bigonville <bigon@debian.org>
Signed-off-by: Jerry Snitselaar <jsnitsel@redhat.com>
Tested-by: Laurent Bigonville <bigon@debian.org>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
This commit is contained in:
Jerry Snitselaar 2018-05-05 12:54:53 -07:00 коммит произвёл Jarkko Sakkinen
Родитель 1fbad30286
Коммит 33bafe9082
1 изменённых файлов: 46 добавлений и 1 удалений

Просмотреть файл

@ -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);
return 0;
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)