Skip to content

Commit

Permalink
tpm_tis: Use tpm_chip_{start,stop} decoration inside tpm_tis_resume
Browse files Browse the repository at this point in the history
Before sending a TPM command, CLKRUN protocol must be disabled. This is not
done in the case of tpm1_do_selftest() call site inside tpm_tis_resume().

Address this by decorating the calls with tpm_chip_{start,stop}, which
should be always used to arm and disarm the TPM chip for transmission.

Finally, move the call to the main TPM driver callback as the last step
because it should arm the chip by itself, if it needs that type of
functionality.

Cc: stable@vger.kernel.org
Reported-by: Jason A. Donenfeld <Jason@zx2c4.com>
Closes: https://lore.kernel.org/linux-integrity/CS68AWILHXS4.3M36M1EKZLUMS@suppilovahvero/
Fixes: a3fbfae ("tpm: take TPM chip power gating out of tpm_transmit()")
Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
  • Loading branch information
jarkkojs committed May 15, 2023
1 parent f1fcbaa commit 1398aa8
Showing 1 changed file with 19 additions and 24 deletions.
43 changes: 19 additions & 24 deletions drivers/char/tpm/tpm_tis_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1209,53 +1209,48 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
u32 intmask;
int rc;

if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true);

/* reenable interrupts that device may have lost or
* BIOS/firmware may have disabled
/*
* Re-enable interrupts that device may have lost or BIOS/firmware may
* have disabled.
*/
rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq);
if (rc < 0)
goto out;
if (rc < 0) {
dev_err(&chip->dev, "Setting IRQ failed.\n");
return;
}

intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE;

tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);

out:
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, false);

return;
rc = tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
if (rc < 0)
dev_err(&chip->dev, "Enabling interrupts failed.\n");
}

int tpm_tis_resume(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
int ret;

ret = tpm_tis_request_locality(chip, 0);
if (ret < 0)
ret = tpm_chip_start(chip);
if (ret)
return ret;

if (chip->flags & TPM_CHIP_FLAG_IRQ)
tpm_tis_reenable_interrupts(chip);

ret = tpm_pm_resume(dev);
if (ret)
goto out;

/*
* TPM 1.2 requires self-test on resume. This function actually returns
* an error code but for unknown reason it isn't handled.
*/
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
tpm1_do_selftest(chip);
out:
tpm_tis_relinquish_locality(chip, 0);

return ret;
tpm_chip_stop(chip);

ret = tpm_pm_resume(dev);
if (ret)
return ret;

return 0;
}
EXPORT_SYMBOL_GPL(tpm_tis_resume);
#endif
Expand Down

0 comments on commit 1398aa8

Please sign in to comment.