tpm: separate cmd_ready/go_idle from runtime_pm

Fix tpm ptt initialization error:
tpm tpm0: A TPM error (378) occurred get tpm pcr allocation.

We cannot use go_idle cmd_ready commands via runtime_pm handles
as with the introduction of localities this is no longer an optional
feature, while runtime pm can be not enabled.
Though cmd_ready/go_idle provides a power saving, it's also a part of
TPM2 protocol and should be called explicitly.
This patch exposes cmd_read/go_idle via tpm class ops and removes
runtime pm support as it is not used by any driver.

When calling from nested context always use both flags:
TPM_TRANSMIT_UNLOCKED and TPM_TRANSMIT_RAW. Both are needed to resolve
tpm spaces and locality request recursive calls to tpm_transmit().
TPM_TRANSMIT_RAW should never be used standalone as it will fail
on double locking. While TPM_TRANSMIT_UNLOCKED standalone should be
called from non-recursive locked contexts.

New wrappers are added tpm_cmd_ready() and tpm_go_idle() to
streamline tpm_try_transmit code.

tpm_crb no longer needs own power saving functions and can drop using
tpm_pm_suspend/resume.

This patch cannot be really separated from the locality fix.
Fixes: 888d867df4 (tpm: cmd_ready command can be issued only after granting locality)

Cc: stable@vger.kernel.org
Fixes: 888d867df4 (tpm: cmd_ready command can be issued only after granting locality)
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
This commit is contained in:
Tomas Winkler
2018-06-28 18:13:33 +03:00
committed by Jarkko Sakkinen
parent 79e2472f99
commit 627448e85c
5 changed files with 90 additions and 92 deletions

View File

@@ -29,7 +29,6 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include <linux/pm_runtime.h>
#include <linux/tpm_eventlog.h>
#include "tpm.h"
@@ -369,10 +368,13 @@ err_len:
return -EINVAL;
}
static int tpm_request_locality(struct tpm_chip *chip)
static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags)
{
int rc;
if (flags & TPM_TRANSMIT_RAW)
return 0;
if (!chip->ops->request_locality)
return 0;
@@ -385,10 +387,13 @@ static int tpm_request_locality(struct tpm_chip *chip)
return 0;
}
static void tpm_relinquish_locality(struct tpm_chip *chip)
static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags)
{
int rc;
if (flags & TPM_TRANSMIT_RAW)
return;
if (!chip->ops->relinquish_locality)
return;
@@ -399,6 +404,28 @@ static void tpm_relinquish_locality(struct tpm_chip *chip)
chip->locality = -1;
}
static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags)
{
if (flags & TPM_TRANSMIT_RAW)
return 0;
if (!chip->ops->cmd_ready)
return 0;
return chip->ops->cmd_ready(chip);
}
static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags)
{
if (flags & TPM_TRANSMIT_RAW)
return 0;
if (!chip->ops->go_idle)
return 0;
return chip->ops->go_idle(chip);
}
static ssize_t tpm_try_transmit(struct tpm_chip *chip,
struct tpm_space *space,
u8 *buf, size_t bufsiz,
@@ -449,14 +476,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
/* Store the decision as chip->locality will be changed. */
need_locality = chip->locality == -1;
if (!(flags & TPM_TRANSMIT_RAW) && need_locality) {
rc = tpm_request_locality(chip);
if (need_locality) {
rc = tpm_request_locality(chip, flags);
if (rc < 0)
goto out_no_locality;
}
if (chip->dev.parent)
pm_runtime_get_sync(chip->dev.parent);
rc = tpm_cmd_ready(chip, flags);
if (rc)
goto out;
rc = tpm2_prepare_space(chip, space, ordinal, buf);
if (rc)
@@ -516,13 +544,16 @@ out_recv:
}
rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
if (rc)
dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);
out:
if (chip->dev.parent)
pm_runtime_put_sync(chip->dev.parent);
rc = tpm_go_idle(chip, flags);
if (rc)
goto out;
if (need_locality)
tpm_relinquish_locality(chip);
tpm_relinquish_locality(chip, flags);
out_no_locality:
if (chip->ops->clk_enable != NULL)