lkml.org 
[lkml]   [2018]   [Sep]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 020/126] tpm: separate cmd_ready/go_idle from runtime_pm
    Date
    4.14-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Tomas Winkler <tomas.winkler@intel.com>

    commit 627448e85c766587f6fdde1ea3886d6615081c77 upstream.

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

    Cc: stable@vger.kernel.org
    Fixes: 888d867df441 (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>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/char/tpm/tpm-interface.c | 50 +++++++++++++++----
    drivers/char/tpm/tpm.h | 12 +++-
    drivers/char/tpm/tpm2-space.c | 16 +++---
    drivers/char/tpm/tpm_crb.c | 101 ++++++++++-----------------------------
    include/linux/tpm.h | 2
    5 files changed, 90 insertions(+), 91 deletions(-)

    --- a/drivers/char/tpm/tpm-interface.c
    +++ b/drivers/char/tpm/tpm-interface.c
    @@ -369,10 +369,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 +388,13 @@ static int tpm_request_locality(struct t
    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 +405,28 @@ static void tpm_relinquish_locality(stru
    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 +477,15 @@ static ssize_t tpm_try_transmit(struct t
    /* 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 +545,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)
    --- a/drivers/char/tpm/tpm.h
    +++ b/drivers/char/tpm/tpm.h
    @@ -511,9 +511,17 @@ extern const struct file_operations tpm_
    extern const struct file_operations tpmrm_fops;
    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 {
    - TPM_TRANSMIT_UNLOCKED = BIT(0),
    - TPM_TRANSMIT_RAW = BIT(1),
    + TPM_TRANSMIT_UNLOCKED = BIT(0),
    + TPM_TRANSMIT_RAW = BIT(1),
    };

    ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
    --- a/drivers/char/tpm/tpm2-space.c
    +++ b/drivers/char/tpm/tpm2-space.c
    @@ -39,7 +39,8 @@ static void tpm2_flush_sessions(struct t
    for (i = 0; i < ARRAY_SIZE(space->session_tbl); i++) {
    if (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_
    tpm_buf_append(&tbuf, &buf[*offset], body_size);

    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) {
    dev_warn(&chip->dev, "%s: failed with a system error %d\n",
    __func__, rc);
    @@ -133,7 +134,7 @@ static int tpm2_save_context(struct tpm_
    tpm_buf_append_u32(&tbuf, handle);

    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) {
    dev_warn(&chip->dev, "%s: failed with a system error %d\n",
    __func__, rc);
    @@ -170,7 +171,8 @@ static void tpm2_flush_space(struct tpm_
    for (i = 0; i < ARRAY_SIZE(space->context_tbl); i++)
    if (space->context_tbl[i] && ~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);
    }
    @@ -377,7 +379,8 @@ static int tpm2_map_response_header(stru

    return 0;
    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__,
    phandle);
    return -ENOMEM;
    @@ -465,7 +468,8 @@ static int tpm2_save_space(struct tpm_ch
    return rc;

    tpm2_flush_context_cmd(chip, space->context_tbl[i],
    - TPM_TRANSMIT_UNLOCKED);
    + TPM_TRANSMIT_UNLOCKED |
    + TPM_TRANSMIT_RAW);
    space->context_tbl[i] = ~0;
    }

    --- a/drivers/char/tpm/tpm_crb.c
    +++ b/drivers/char/tpm/tpm_crb.c
    @@ -137,7 +137,7 @@ static bool crb_wait_for_reg_32(u32 __io
    }

    /**
    - * 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
    * @priv: crb private data
    @@ -151,7 +151,7 @@ static bool crb_wait_for_reg_32(u32 __io
    *
    * 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->flags & CRB_FL_ACPI_START) ||
    (priv->flags & CRB_FL_CRB_SMC_START))
    @@ -166,11 +166,20 @@ static int crb_go_idle(struct device *de
    dev_warn(dev, "goIdle timed out\n");
    return -ETIME;
    }
    +
    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
    * @priv: crb private data
    @@ -183,7 +192,7 @@ static int crb_go_idle(struct device *de
    *
    * 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->flags & CRB_FL_ACPI_START) ||
    (priv->flags & CRB_FL_CRB_SMC_START))
    @@ -201,6 +210,14 @@ static int crb_cmd_ready(struct device *
    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,
    struct crb_priv *priv, int loc)
    {
    @@ -393,6 +410,8 @@ static const struct tpm_class_ops tpm_cr
    .send = crb_send,
    .cancel = crb_cancel,
    .req_canceled = crb_req_canceled,
    + .go_idle = crb_go_idle,
    + .cmd_ready = crb_cmd_ready,
    .request_locality = crb_request_locality,
    .relinquish_locality = crb_relinquish_locality,
    .req_complete_mask = CRB_DRV_STS_COMPLETE,
    @@ -508,7 +527,7 @@ static int crb_map_io(struct acpi_device
    * PTT HW bug w/a: wake up the device to access
    * possibly not retained registers.
    */
    - ret = crb_cmd_ready(dev, priv);
    + ret = __crb_cmd_ready(dev, priv);
    if (ret)
    return ret;

    @@ -553,7 +572,7 @@ out:
    if (!ret)
    priv->cmd_size = cmd_size;

    - crb_go_idle(dev, priv);
    + __crb_go_idle(dev, priv);

    __crb_relinquish_locality(dev, priv, 0);

    @@ -624,32 +643,7 @@ static int crb_acpi_add(struct acpi_devi
    chip->acpi_dev_handle = device->handle;
    chip->flags = TPM_CHIP_FLAG_TPM2;

    - rc = __crb_request_locality(dev, priv, 0);
    - 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;
    + return tpm_chip_register(chip);
    }

    static int crb_acpi_remove(struct acpi_device *device)
    @@ -659,52 +653,11 @@ static int crb_acpi_remove(struct acpi_d

    tpm_chip_unregister(chip);

    - pm_runtime_disable(dev);
    -
    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 = {
    - SET_SYSTEM_SLEEP_PM_OPS(crb_pm_suspend, crb_pm_resume)
    - SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL)
    + SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume)
    };

    static const struct acpi_device_id crb_device_ids[] = {
    --- a/include/linux/tpm.h
    +++ b/include/linux/tpm.h
    @@ -48,6 +48,8 @@ struct tpm_class_ops {
    u8 (*status) (struct tpm_chip *chip);
    bool (*update_timeouts)(struct tpm_chip *chip,
    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 (*relinquish_locality)(struct tpm_chip *chip, int loc);
    void (*clk_enable)(struct tpm_chip *chip, bool value);

    \
     
     \ /
      Last update: 2018-09-18 01:31    [W:5.407 / U:0.340 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site