Commit 627448e8 authored by Tomas Winkler's avatar Tomas Winkler Committed by Jarkko Sakkinen

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: 888d867d (tpm: cmd_ready command can be issued only after granting locality)

Cc: stable@vger.kernel.org
Fixes: 888d867d (tpm: cmd_ready command can be issued only after granting locality)
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Tested-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
parent 79e2472f
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/pm_runtime.h>
#include <linux/tpm_eventlog.h> #include <linux/tpm_eventlog.h>
#include "tpm.h" #include "tpm.h"
...@@ -369,10 +368,13 @@ static int tpm_validate_command(struct tpm_chip *chip, ...@@ -369,10 +368,13 @@ static int tpm_validate_command(struct tpm_chip *chip,
return -EINVAL; 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; int rc;
if (flags & TPM_TRANSMIT_RAW)
return 0;
if (!chip->ops->request_locality) if (!chip->ops->request_locality)
return 0; return 0;
...@@ -385,10 +387,13 @@ static int tpm_request_locality(struct tpm_chip *chip) ...@@ -385,10 +387,13 @@ static int tpm_request_locality(struct tpm_chip *chip)
return 0; 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; int rc;
if (flags & TPM_TRANSMIT_RAW)
return;
if (!chip->ops->relinquish_locality) if (!chip->ops->relinquish_locality)
return; return;
...@@ -399,6 +404,28 @@ static void tpm_relinquish_locality(struct tpm_chip *chip) ...@@ -399,6 +404,28 @@ static void tpm_relinquish_locality(struct tpm_chip *chip)
chip->locality = -1; 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, static ssize_t tpm_try_transmit(struct tpm_chip *chip,
struct tpm_space *space, struct tpm_space *space,
u8 *buf, size_t bufsiz, u8 *buf, size_t bufsiz,
...@@ -449,14 +476,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, ...@@ -449,14 +476,15 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
/* Store the decision as chip->locality will be changed. */ /* Store the decision as chip->locality will be changed. */
need_locality = chip->locality == -1; need_locality = chip->locality == -1;
if (!(flags & TPM_TRANSMIT_RAW) && need_locality) { if (need_locality) {
rc = tpm_request_locality(chip); rc = tpm_request_locality(chip, flags);
if (rc < 0) if (rc < 0)
goto out_no_locality; goto out_no_locality;
} }
if (chip->dev.parent) rc = tpm_cmd_ready(chip, flags);
pm_runtime_get_sync(chip->dev.parent); if (rc)
goto out;
rc = tpm2_prepare_space(chip, space, ordinal, buf); rc = tpm2_prepare_space(chip, space, ordinal, buf);
if (rc) if (rc)
...@@ -516,13 +544,16 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip, ...@@ -516,13 +544,16 @@ static ssize_t tpm_try_transmit(struct tpm_chip *chip,
} }
rc = tpm2_commit_space(chip, space, ordinal, buf, &len); rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
if (rc)
dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);
out: out:
if (chip->dev.parent) rc = tpm_go_idle(chip, flags);
pm_runtime_put_sync(chip->dev.parent); if (rc)
goto out;
if (need_locality) if (need_locality)
tpm_relinquish_locality(chip); tpm_relinquish_locality(chip, flags);
out_no_locality: out_no_locality:
if (chip->ops->clk_enable != NULL) if (chip->ops->clk_enable != NULL)
......
...@@ -512,9 +512,17 @@ extern const struct file_operations tpm_fops; ...@@ -512,9 +512,17 @@ extern const struct file_operations tpm_fops;
extern const struct file_operations tpmrm_fops; extern const struct file_operations tpmrm_fops;
extern struct idr dev_nums_idr; extern struct idr dev_nums_idr;
/**
* enum tpm_transmit_flags
*
* @TPM_TRANSMIT_UNLOCKED: used to lock sequence of tpm_transmit calls.
* @TPM_TRANSMIT_RAW: prevent recursive calls into setup steps
* (go idle, locality,..). Always use with UNLOCKED
* as it will fail on double locking.
*/
enum tpm_transmit_flags { enum tpm_transmit_flags {
TPM_TRANSMIT_UNLOCKED = BIT(0), TPM_TRANSMIT_UNLOCKED = BIT(0),
TPM_TRANSMIT_RAW = BIT(1), TPM_TRANSMIT_RAW = BIT(1),
}; };
ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
......
...@@ -39,7 +39,8 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space) ...@@ -39,7 +39,8 @@ static void tpm2_flush_sessions(struct tpm_chip *chip, struct tpm_space *space)
for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) { for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
if (space->session_tbl[i]) if (space->session_tbl[i])
tpm2_flush_context_cmd(chip, space->session_tbl[i], tpm2_flush_context_cmd(chip, space->session_tbl[i],
TPM_TRANSMIT_UNLOCKED); TPM_TRANSMIT_UNLOCKED |
TPM_TRANSMIT_RAW);
} }
} }
...@@ -84,7 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf, ...@@ -84,7 +85,7 @@ static int tpm2_load_context(struct tpm_chip *chip, u8 *buf,
tpm_buf_append(&tbuf, &buf[*offset], body_size); tpm_buf_append(&tbuf, &buf[*offset], body_size);
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4, rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 4,
TPM_TRANSMIT_UNLOCKED, NULL); TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL);
if (rc < 0) { if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n", dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc); __func__, rc);
...@@ -133,7 +134,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf, ...@@ -133,7 +134,7 @@ static int tpm2_save_context(struct tpm_chip *chip, u32 handle, u8 *buf,
tpm_buf_append_u32(&tbuf, handle); tpm_buf_append_u32(&tbuf, handle);
rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0, rc = tpm_transmit_cmd(chip, NULL, tbuf.data, PAGE_SIZE, 0,
TPM_TRANSMIT_UNLOCKED, NULL); TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW, NULL);
if (rc < 0) { if (rc < 0) {
dev_warn(&chip->dev, "%s: failed with a system error %d\n", dev_warn(&chip->dev, "%s: failed with a system error %d\n",
__func__, rc); __func__, rc);
...@@ -170,7 +171,8 @@ static void tpm2_flush_space(struct tpm_chip *chip) ...@@ -170,7 +171,8 @@ static void tpm2_flush_space(struct tpm_chip *chip)
for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++) for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
if (space->context_tbl[i] && ~space->context_tbl[i]) if (space->context_tbl[i] && ~space->context_tbl[i])
tpm2_flush_context_cmd(chip, space->context_tbl[i], tpm2_flush_context_cmd(chip, space->context_tbl[i],
TPM_TRANSMIT_UNLOCKED); TPM_TRANSMIT_UNLOCKED |
TPM_TRANSMIT_RAW);
tpm2_flush_sessions(chip, space); tpm2_flush_sessions(chip, space);
} }
...@@ -377,7 +379,8 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp, ...@@ -377,7 +379,8 @@ static int tpm2_map_response_header(struct tpm_chip *chip, u32 cc, u8 *rsp,
return 0; return 0;
out_no_slots: out_no_slots:
tpm2_flush_context_cmd(chip, phandle, TPM_TRANSMIT_UNLOCKED); tpm2_flush_context_cmd(chip, phandle,
TPM_TRANSMIT_UNLOCKED | TPM_TRANSMIT_RAW);
dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__, dev_warn(&chip->dev, "%s: out of slots for 0x%08X\n", __func__,
phandle); phandle);
return -ENOMEM; return -ENOMEM;
...@@ -465,7 +468,8 @@ static int tpm2_save_space(struct tpm_chip *chip) ...@@ -465,7 +468,8 @@ static int tpm2_save_space(struct tpm_chip *chip)
return rc; return rc;
tpm2_flush_context_cmd(chip, space->context_tbl[i], tpm2_flush_context_cmd(chip, space->context_tbl[i],
TPM_TRANSMIT_UNLOCKED); TPM_TRANSMIT_UNLOCKED |
TPM_TRANSMIT_RAW);
space->context_tbl[i] = ~0; space->context_tbl[i] = ~0;
} }
......
...@@ -132,7 +132,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, ...@@ -132,7 +132,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
} }
/** /**
* crb_go_idle - request tpm crb device to go the idle state * __crb_go_idle - request tpm crb device to go the idle state
* *
* @dev: crb device * @dev: crb device
* @priv: crb private data * @priv: crb private data
...@@ -147,7 +147,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value, ...@@ -147,7 +147,7 @@ static bool crb_wait_for_reg_32(u32 __iomem *reg, u32 mask, u32 value,
* *
* Return: 0 always * Return: 0 always
*/ */
static int crb_go_idle(struct device *dev, struct crb_priv *priv) static int __crb_go_idle(struct device *dev, struct crb_priv *priv)
{ {
if ((priv->sm == ACPI_TPM2_START_METHOD) || if ((priv->sm == ACPI_TPM2_START_METHOD) ||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
...@@ -163,11 +163,20 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv) ...@@ -163,11 +163,20 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv)
dev_warn(dev, "goIdle timed out\n"); dev_warn(dev, "goIdle timed out\n");
return -ETIME; return -ETIME;
} }
return 0; return 0;
} }
static int crb_go_idle(struct tpm_chip *chip)
{
struct device *dev = &chip->dev;
struct crb_priv *priv = dev_get_drvdata(dev);
return __crb_go_idle(dev, priv);
}
/** /**
* crb_cmd_ready - request tpm crb device to enter ready state * __crb_cmd_ready - request tpm crb device to enter ready state
* *
* @dev: crb device * @dev: crb device
* @priv: crb private data * @priv: crb private data
...@@ -181,7 +190,7 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv) ...@@ -181,7 +190,7 @@ static int crb_go_idle(struct device *dev, struct crb_priv *priv)
* *
* Return: 0 on success -ETIME on timeout; * Return: 0 on success -ETIME on timeout;
*/ */
static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv)
{ {
if ((priv->sm == ACPI_TPM2_START_METHOD) || if ((priv->sm == ACPI_TPM2_START_METHOD) ||
(priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) || (priv->sm == ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD) ||
...@@ -200,6 +209,14 @@ static int crb_cmd_ready(struct device *dev, struct crb_priv *priv) ...@@ -200,6 +209,14 @@ static int crb_cmd_ready(struct device *dev, struct crb_priv *priv)
return 0; return 0;
} }
static int crb_cmd_ready(struct tpm_chip *chip)
{
struct device *dev = &chip->dev;
struct crb_priv *priv = dev_get_drvdata(dev);
return __crb_cmd_ready(dev, priv);
}
static int __crb_request_locality(struct device *dev, static int __crb_request_locality(struct device *dev,
struct crb_priv *priv, int loc) struct crb_priv *priv, int loc)
{ {
...@@ -401,6 +418,8 @@ static const struct tpm_class_ops tpm_crb = { ...@@ -401,6 +418,8 @@ static const struct tpm_class_ops tpm_crb = {
.send = crb_send, .send = crb_send,
.cancel = crb_cancel, .cancel = crb_cancel,
.req_canceled = crb_req_canceled, .req_canceled = crb_req_canceled,
.go_idle = crb_go_idle,
.cmd_ready = crb_cmd_ready,
.request_locality = crb_request_locality, .request_locality = crb_request_locality,
.relinquish_locality = crb_relinquish_locality, .relinquish_locality = crb_relinquish_locality,
.req_complete_mask = CRB_DRV_STS_COMPLETE, .req_complete_mask = CRB_DRV_STS_COMPLETE,
...@@ -520,7 +539,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, ...@@ -520,7 +539,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
* PTT HW bug w/a: wake up the device to access * PTT HW bug w/a: wake up the device to access
* possibly not retained registers. * possibly not retained registers.
*/ */
ret = crb_cmd_ready(dev, priv); ret = __crb_cmd_ready(dev, priv);
if (ret) if (ret)
goto out_relinquish_locality; goto out_relinquish_locality;
...@@ -565,7 +584,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, ...@@ -565,7 +584,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv,
if (!ret) if (!ret)
priv->cmd_size = cmd_size; priv->cmd_size = cmd_size;
crb_go_idle(dev, priv); __crb_go_idle(dev, priv);
out_relinquish_locality: out_relinquish_locality:
...@@ -628,32 +647,7 @@ static int crb_acpi_add(struct acpi_device *device) ...@@ -628,32 +647,7 @@ static int crb_acpi_add(struct acpi_device *device)
chip->acpi_dev_handle = device->handle; chip->acpi_dev_handle = device->handle;
chip->flags = TPM_CHIP_FLAG_TPM2; chip->flags = TPM_CHIP_FLAG_TPM2;
rc = __crb_request_locality(dev, priv, 0); return tpm_chip_register(chip);
if (rc)
return rc;
rc = crb_cmd_ready(dev, priv);
if (rc)
goto out;
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
rc = tpm_chip_register(chip);
if (rc) {
crb_go_idle(dev, priv);
pm_runtime_put_noidle(dev);
pm_runtime_disable(dev);
goto out;
}
pm_runtime_put_sync(dev);
out:
__crb_relinquish_locality(dev, priv, 0);
return rc;
} }
static int crb_acpi_remove(struct acpi_device *device) static int crb_acpi_remove(struct acpi_device *device)
...@@ -663,52 +657,11 @@ static int crb_acpi_remove(struct acpi_device *device) ...@@ -663,52 +657,11 @@ static int crb_acpi_remove(struct acpi_device *device)
tpm_chip_unregister(chip); tpm_chip_unregister(chip);
pm_runtime_disable(dev);
return 0; return 0;
} }
static int __maybe_unused crb_pm_runtime_suspend(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
return crb_go_idle(dev, priv);
}
static int __maybe_unused crb_pm_runtime_resume(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
return crb_cmd_ready(dev, priv);
}
static int __maybe_unused crb_pm_suspend(struct device *dev)
{
int ret;
ret = tpm_pm_suspend(dev);
if (ret)
return ret;
return crb_pm_runtime_suspend(dev);
}
static int __maybe_unused crb_pm_resume(struct device *dev)
{
int ret;
ret = crb_pm_runtime_resume(dev);
if (ret)
return ret;
return tpm_pm_resume(dev);
}
static const struct dev_pm_ops crb_pm = { static const struct dev_pm_ops crb_pm = {
SET_SYSTEM_SLEEP_PM_OPS(crb_pm_suspend, crb_pm_resume) SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume)
SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL)
}; };
static const struct acpi_device_id crb_device_ids[] = { static const struct acpi_device_id crb_device_ids[] = {
......
...@@ -43,6 +43,8 @@ struct tpm_class_ops { ...@@ -43,6 +43,8 @@ struct tpm_class_ops {
u8 (*status) (struct tpm_chip *chip); u8 (*status) (struct tpm_chip *chip);
bool (*update_timeouts)(struct tpm_chip *chip, bool (*update_timeouts)(struct tpm_chip *chip,
unsigned long *timeout_cap); unsigned long *timeout_cap);
int (*go_idle)(struct tpm_chip *chip);
int (*cmd_ready)(struct tpm_chip *chip);
int (*request_locality)(struct tpm_chip *chip, int loc); int (*request_locality)(struct tpm_chip *chip, int loc);
int (*relinquish_locality)(struct tpm_chip *chip, int loc); int (*relinquish_locality)(struct tpm_chip *chip, int loc);
void (*clk_enable)(struct tpm_chip *chip, bool value); void (*clk_enable)(struct tpm_chip *chip, bool value);
......
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