From patchwork Wed Sep 7 10:25:48 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Winkler, Tomas" X-Patchwork-Id: 9326913 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id A5DC16077F for ; Mon, 12 Sep 2016 15:53:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9862A28CC7 for ; Mon, 12 Sep 2016 15:53:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8D0FC28E00; Mon, 12 Sep 2016 15:53:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 393B028DFF for ; Mon, 12 Sep 2016 15:53:17 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1bjTXn-0004Zg-8Z; Mon, 12 Sep 2016 15:53:15 +0000 Received: from sog-mx-1.v43.ch3.sourceforge.com ([172.29.43.191] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1bha5a-0001Vd-88 for tpmdd-devel@lists.sourceforge.net; Wed, 07 Sep 2016 10:28:18 +0000 Received-SPF: fail (sog-mx-1.v43.ch3.sourceforge.com: domain of intel.com does not designate 192.55.52.88 as permitted sender) client-ip=192.55.52.88; envelope-from=tomas.winkler@intel.com; helo=mga01.intel.com; Received: from mga01.intel.com ([192.55.52.88]) by sog-mx-1.v43.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.76) id 1bha5Z-0006jg-8L for tpmdd-devel@lists.sourceforge.net; Wed, 07 Sep 2016 10:28:18 +0000 Received: from orsmga004.jf.intel.com ([10.7.209.38]) by fmsmga101.fm.intel.com with ESMTP; 07 Sep 2016 03:28:14 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.30,296,1470726000"; d="scan'208";a="5910504" Received: from twinkler-lnx.jer.intel.com ([10.12.87.167]) by orsmga004.jf.intel.com with ESMTP; 07 Sep 2016 03:28:13 -0700 From: Tomas Winkler To: tpmdd-devel@lists.sourceforge.net, Jarkko Sakkinen Date: Wed, 7 Sep 2016 13:25:48 +0300 Message-Id: <1473243950-23579-2-git-send-email-tomas.winkler@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1473243950-23579-1-git-send-email-tomas.winkler@intel.com> References: <1473243950-23579-1-git-send-email-tomas.winkler@intel.com> X-Headers-End: 1bha5Z-0006jg-8L X-Mailman-Approved-At: Mon, 12 Sep 2016 15:53:12 +0000 Subject: [tpmdd-devel] [PATCH 1/3] tpm/tpm_crb: implement tpm crb idle state X-BeenThere: tpmdd-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Tpm Device Driver maintainance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: tpmdd-devel-bounces@lists.sourceforge.net X-Virus-Scanned: ClamAV using ClamSMTP The register TPM_CRB_CTRL_REQ_x contains bits goIdle and cmdReady for SW to indicate that the device can enter or should exit the idle state. The legacy ACPI-start (SMI + DMA) based devices do not support these bits and the idle state management is not exposed to the host SW. Thus, this functionality only is enabled only for a CRB start (MMIO) based devices. We introduce two new callbacks for command ready and go idle for TPM CRB device which are called across TPM transactions. Based on Jarkko Sakkinen oringal patch 'tpm_crb: implement power tpm crb power management' Signed-off-by: Tomas Winkler --- drivers/char/tpm/tpm-interface.c | 21 +++++++++++ drivers/char/tpm/tpm_crb.c | 77 ++++++++++++++++++++++++++++++++++++++++ include/linux/tpm.h | 3 +- 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index fd863ff30f79..c78dca5ce7a6 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -327,6 +327,20 @@ unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); +static inline int tpm_go_idle(struct tpm_chip *chip) +{ + if (!chip->ops->idle) + return 0; + return chip->ops->idle(chip); +} + +static inline int tpm_cmd_ready(struct tpm_chip *chip) +{ + if (!chip->ops->ready) + return 0; + return chip->ops->ready(chip); +} + /* * Internal kernel interface to transmit TPM commands */ @@ -353,6 +367,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); + rc = tpm_cmd_ready(chip); + if (rc) + goto out; + rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(&chip->dev, @@ -394,8 +412,11 @@ out_recv: dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: + tpm_go_idle(chip); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); + return rc; } diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 82a3ccd52a3a..98a7fdfe9936 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -83,6 +83,81 @@ struct crb_priv { u8 __iomem *rsp; }; +/** + * __crb_go_idle - write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ + * The device should respond within TIMEOUT_C by clearing the bit. + * Anyhow, we do not wait here as a consequent CMD_READY request + * will be handled correctly even if idle was not completed. + * + * @dev: tpm device + * @priv: crb private context + * + * Return: 0 always + */ +static int __crb_go_idle(struct device *dev, struct crb_priv *priv) +{ + if (priv->flags & CRB_FL_ACPI_START) + return 0; + iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req); + /* we don't really care when this settles */ + + return 0; +} + +static int crb_go_idle(struct tpm_chip *chip) +{ + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return __crb_go_idle(&chip->dev, priv); +} + +/** + * __crb_cmd_ready - write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ + * and poll till the device acknowledge it by clearing the bit. + * The device should respond within TIMEOUT_C. + * + * The function does nothing for devices with ACPI-start method + * + * @dev: tpm device + * @priv: crb private context + * + * Return: 0 on success -ETIME on timeout; + */ +static int __crb_cmd_ready(struct device *dev, struct crb_priv *priv) +{ + ktime_t stop, start; + + if (priv->flags & CRB_FL_ACPI_START) + return 0; + + iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req); + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C)); + do { + if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) { + dev_dbg(dev, "cmdReady in %lld usecs\n", + ktime_to_us(ktime_sub(ktime_get(), start))); + return 0; + } + usleep_range(500, 1000); + } while (ktime_before(ktime_get(), stop)); + + if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) { + dev_warn(dev, "cmdReady timed out\n"); + return -ETIME; + } + + return 0; +} + +static int crb_cmd_ready(struct tpm_chip *chip) +{ + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return __crb_cmd_ready(&chip->dev, priv); +} + static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); static u8 crb_status(struct tpm_chip *chip) @@ -193,6 +268,8 @@ static const struct tpm_class_ops tpm_crb = { .recv = crb_recv, .send = crb_send, .cancel = crb_cancel, + .ready = crb_cmd_ready, + .idle = crb_go_idle, .req_canceled = crb_req_canceled, .req_complete_mask = CRB_DRV_STS_COMPLETE, .req_complete_val = CRB_DRV_STS_COMPLETE, diff --git a/include/linux/tpm.h b/include/linux/tpm.h index da158f06e0b2..1ed9ff6a5d48 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -48,7 +48,8 @@ struct tpm_class_ops { u8 (*status) (struct tpm_chip *chip); bool (*update_timeouts)(struct tpm_chip *chip, unsigned long *timeout_cap); - + int (*idle)(struct tpm_chip *chip); + int (*ready)(struct tpm_chip *chip); }; #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)