Received: by 10.223.164.202 with SMTP id h10csp2357719wrb; Mon, 27 Nov 2017 16:05:48 -0800 (PST) X-Google-Smtp-Source: AGs4zMaJVqD6uANilQOaiy9AMDdg9wILOClclAmKbj5diBJbvkFc0p7NoEq0CpKwpf+GjK4VcrAz X-Received: by 10.84.248.68 with SMTP id e4mr3170418pln.0.1511827548447; Mon, 27 Nov 2017 16:05:48 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511827548; cv=none; d=google.com; s=arc-20160816; b=Tkli2VfPxclWoke+YARyv1H3WrJgfuhtGUjJm8OpyOFYWSUzU7GCyD+XrfubxH8G63 b6PAdXGCR1FWW747cY+ytuae4xBDaNzwA3PHpDgZyyuaOZV9BnRFHHYKusXRSpoJ42aP aFdhpF3Igry285ErDKjDFJjDTqEv4uSvp4yQ7RrywKlCfcEBVhWJ7Qn/DI6f8U9VHfB3 rgKJ6Ax63MN2ti11xhRI7oPoePJSgItvTyHcgMUrocb1kwVvdv317U+uPDIvZ34b7F0d y4o1kfHeegIuVPuL0ytaFNEmnz2BJo5FaHVygU2UR994bpa/3iu1afVpfN411lU1DJJZ c5ww== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:arc-authentication-results; bh=HXOgxKeJG+jc3F4EFwz+nndnSeefrvQQtkqnL7E31O8=; b=hb3mNfOcgJ+FgJjaUVuIFHohigZP4NHNc/fZSz55tKcMTv4ieMftDuFLpwzi2W0FFX xK0oDAoUbMkq/5n6sflKNeH9hsNxc3/Dg+MpzDjOHiUQOa3/dItFYLK0Y3Egqfpmqx8B qEYWGdqmL4Kpmh5CrEaNQMd5bvEk518MIo3Htz7uqdYWXq5XReawmRelykb5aWL2Em2u RQEZRDYZx1VJWyofpqFXgTh+aAxYf8ao2fmGvrht759x4isFI/nXhg7fiisnNs2MrzYY Ex/ZieZfqEBO5HqxCzViNOwHBUxBj7hb0+D9dJv2LGTjzc3lVXJH7ssT6tPKKVXTYNiJ BP7A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id p21si26173377pfi.396.2017.11.27.16.05.36; Mon, 27 Nov 2017 16:05:48 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753423AbdK1AEg (ORCPT + 78 others); Mon, 27 Nov 2017 19:04:36 -0500 Received: from mga09.intel.com ([134.134.136.24]:56889 "EHLO mga09.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752681AbdK1AEX (ORCPT ); Mon, 27 Nov 2017 19:04:23 -0500 Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 27 Nov 2017 16:04:21 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.44,466,1505804400"; d="scan'208";a="6831428" Received: from otc-chromeosbuild-1.jf.intel.com ([10.54.30.35]) by fmsmga004.fm.intel.com with ESMTP; 27 Nov 2017 16:04:21 -0800 From: Azhar Shaikh To: jarkko.sakkinen@linux.intel.com, jgunthorpe@obsidianresearch.com, peterhuewe@gmx.de Cc: linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, tpmdd-devel@lists.sourceforge.net, azhar.shaikh@intel.com Subject: [PATCH v5 2/2] tpm: Keep CLKRUN enabled throughout the duration of transmit_cmd() Date: Mon, 27 Nov 2017 16:04:20 -0800 Message-Id: <1511827460-29941-3-git-send-email-azhar.shaikh@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1511827460-29941-1-git-send-email-azhar.shaikh@intel.com> References: <1511827460-29941-1-git-send-email-azhar.shaikh@intel.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Commit 5e572cab92f0bb5 ("tpm: Enable CLKRUN protocol for Braswell systems") disabled CLKRUN protocol during TPM transactions and re-enabled once the transaction is completed. But there were still some corner cases observed where, reading of TPM header failed for savestate command while going to suspend, which resulted in suspend failure. To fix this issue keep the CLKRUN protocol disabled for the entire duration of a single TPM command and not disabling and re-enabling again for every TPM transaction. For the other TPM accesses outside the flow of TPM command processing, disable and re-enable CLKRUN protocol for every TPM access. Fixes: 5e572cab92f0bb5 ("tpm: Enable CLKRUN protocol for Braswell systems") Signed-off-by: Azhar Shaikh --- drivers/char/tpm/tpm-interface.c | 6 +++ drivers/char/tpm/tpm_tis.c | 86 +++++------------------------------- drivers/char/tpm/tpm_tis_core.c | 95 +++++++++++++++++++++++++++++++++++++--- drivers/char/tpm/tpm_tis_core.h | 4 ++ include/linux/tpm.h | 1 + 5 files changed, 111 insertions(+), 81 deletions(-) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index ebe0a1d36d8c..6e19e3dd98e4 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -413,6 +413,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, if (chip->dev.parent) pm_runtime_get_sync(chip->dev.parent); + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + /* Store the decision as chip->locality will be changed. */ need_locality = chip->locality == -1; @@ -489,6 +492,9 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space, chip->locality = -1; } out_no_locality: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + if (chip->dev.parent) pm_runtime_put_sync(chip->dev.parent); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 923f8f2cbaca..d29add49b033 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -133,79 +133,17 @@ static int check_acpi_tpm2(struct device *dev) } #endif -#ifdef CONFIG_X86 -#define LPC_CNTRL_OFFSET 0x84 -#define LPC_CLKRUN_EN (1 << 2) - -/** - * tpm_platform_begin_xfer() - clear LPC CLKRUN_EN i.e. clocks will be running - */ -static void tpm_platform_begin_xfer(struct tpm_tis_data *data) -{ - u32 clkrun_val; - - if (!is_bsw()) - return; - - clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET); - - /* Disable LPC CLKRUN# */ - clkrun_val &= ~LPC_CLKRUN_EN; - iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); - - /* - * Write any random value on port 0x80 which is on LPC, to make - * sure LPC clock is running before sending any TPM command. - */ - outb(0xCC, 0x80); - -} - -/** - * tpm_platform_end_xfer() - set LPC CLKRUN_EN i.e. clocks can be turned off - */ -static void tpm_platform_end_xfer(struct tpm_tis_data *data) -{ - u32 clkrun_val; - - if (!is_bsw()) - return; - - clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET); - - /* Enable LPC CLKRUN# */ - clkrun_val |= LPC_CLKRUN_EN; - iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); - - /* - * Write any random value on port 0x80 which is on LPC, to make - * sure LPC clock is running before sending any TPM command. - */ - outb(0xCC, 0x80); - -} -#else -static void tpm_platform_begin_xfer(struct tpm_tis_data *data) -{ -} - -static void tpm_platform_end_xfer(struct tpm_tis_data *data) -{ -} -#endif - static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, u8 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(data); + if (is_bsw() && !(data->flags & TPM_TIS_CLK_ENABLE)) + WARN(1, "CLKRUN not enabled!\n"); while (len--) *result++ = ioread8(phy->iobase + addr); - tpm_platform_end_xfer(data); - return 0; } @@ -214,13 +152,12 @@ static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(data); + if (is_bsw() && !(data->flags & TPM_TIS_CLK_ENABLE)) + WARN(1, "CLKRUN not enabled!\n"); while (len--) iowrite8(*value++, phy->iobase + addr); - tpm_platform_end_xfer(data); - return 0; } @@ -228,12 +165,11 @@ static int tpm_tcg_read16(struct tpm_tis_data *data, u32 addr, u16 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(data); + if (is_bsw() && !(data->flags & TPM_TIS_CLK_ENABLE)) + WARN(1, "CLKRUN not enabled!\n"); *result = ioread16(phy->iobase + addr); - tpm_platform_end_xfer(data); - return 0; } @@ -241,12 +177,11 @@ static int tpm_tcg_read32(struct tpm_tis_data *data, u32 addr, u32 *result) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(data); + if (is_bsw() && !(data->flags & TPM_TIS_CLK_ENABLE)) + WARN(1, "CLKRUN not enabled!\n"); *result = ioread32(phy->iobase + addr); - tpm_platform_end_xfer(data); - return 0; } @@ -254,12 +189,11 @@ static int tpm_tcg_write32(struct tpm_tis_data *data, u32 addr, u32 value) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); - tpm_platform_begin_xfer(data); + if (is_bsw() && !(data->flags & TPM_TIS_CLK_ENABLE)) + WARN(1, "CLKRUN not enabled!\n"); iowrite32(value, phy->iobase + addr); - tpm_platform_end_xfer(data); - return 0; } diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index bea151844692..c2227983ed88 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -475,19 +475,28 @@ static bool tpm_tis_update_timeouts(struct tpm_chip *chip, int i, rc; u32 did_vid; + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + rc = tpm_tis_read32(priv, TPM_DID_VID(0), &did_vid); if (rc < 0) - return rc; + goto out; for (i = 0; i != ARRAY_SIZE(vendor_timeout_overrides); i++) { if (vendor_timeout_overrides[i].did_vid != did_vid) continue; memcpy(timeout_cap, vendor_timeout_overrides[i].timeout_us, sizeof(vendor_timeout_overrides[i].timeout_us)); - return true; + rc = true; } - return false; + rc = false; + +out: + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + + return rc; } /* @@ -707,14 +716,71 @@ void tpm_tis_remove(struct tpm_chip *chip) u32 interrupt; int rc; + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + rc = tpm_tis_read32(priv, reg, &interrupt); if (rc < 0) interrupt = 0; tpm_tis_write32(priv, reg, ~TPM_GLOBAL_INT_ENABLE & interrupt); + + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); } EXPORT_SYMBOL_GPL(tpm_tis_remove); +/** + * tpm_tis_clkrun_enable() - Keep clkrun protocol disabled for entire duration + * of a single TPM command + * @chip: TPM chip to use + * @value: 1 - Disable CLKRUN protocol, so that clocks are free running + * 0 - Enable CLKRUN protocol + */ +static void tpm_tis_clkrun_enable(struct tpm_chip *chip, bool value) +{ + struct tpm_tis_data *data = dev_get_drvdata(&chip->dev); + u32 clkrun_val; + + if (!IS_ENABLED(CONFIG_X86) || !is_bsw()) + return; + + if (value) { + data->flags |= TPM_TIS_CLK_ENABLE; + data->clkrun_enabled++; + if (data->clkrun_enabled > 1) + return; + clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* Disable LPC CLKRUN# */ + clkrun_val &= ~LPC_CLKRUN_EN; + iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* + * Write any random value on port 0x80 which is on LPC, to make + * sure LPC clock is running before sending any TPM command. + */ + outb(0xCC, 0x80); + } else { + data->clkrun_enabled--; + if (data->clkrun_enabled) + return; + + clkrun_val = ioread32(data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* Enable LPC CLKRUN# */ + clkrun_val |= LPC_CLKRUN_EN; + iowrite32(clkrun_val, data->ilb_base_addr + LPC_CNTRL_OFFSET); + + /* + * Write any random value on port 0x80 which is on LPC, to make + * sure LPC clock is running before sending any TPM command. + */ + outb(0xCC, 0x80); + data->flags &= ~TPM_TIS_CLK_ENABLE; + } +} + static const struct tpm_class_ops tpm_tis = { .flags = TPM_OPS_AUTO_STARTUP, .status = tpm_tis_status, @@ -727,6 +793,7 @@ void tpm_tis_remove(struct tpm_chip *chip) .req_canceled = tpm_tis_req_canceled, .request_locality = request_locality, .relinquish_locality = release_locality, + .clk_enable = tpm_tis_clkrun_enable, }; int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, @@ -761,6 +828,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, return -ENOMEM; } + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, true); + if (wait_startup(chip, 0) != 0) { rc = -ENODEV; goto out_err; @@ -855,12 +925,18 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, if (rc && is_bsw()) iounmap(priv->ilb_base_addr); + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + return rc; out_err: tpm_tis_remove(chip); if (is_bsw()) iounmap(priv->ilb_base_addr); + if (chip->ops->clk_enable != NULL) + chip->ops->clk_enable(chip, false); + return rc; } EXPORT_SYMBOL_GPL(tpm_tis_core_init); @@ -872,22 +948,31 @@ 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 */ rc = tpm_tis_write8(priv, TPM_INT_VECTOR(priv->locality), priv->irq); if (rc < 0) - return; + goto out; rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); if (rc < 0) - return; + goto out; intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT | 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; } int tpm_tis_resume(struct device *dev) diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 458847f72758..afc50cde1ba6 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -79,11 +79,14 @@ enum tis_defaults { #define TPM_DID_VID(l) (0x0F00 | ((l) << 12)) #define TPM_RID(l) (0x0F04 | ((l) << 12)) +#define LPC_CNTRL_OFFSET 0x84 +#define LPC_CLKRUN_EN (1 << 2) #define INTEL_LEGACY_BLK_BASE_ADDR 0xFED08000 #define ILB_REMAP_SIZE 0x100 enum tpm_tis_flags { TPM_TIS_ITPM_WORKAROUND = BIT(0), + TPM_TIS_CLK_ENABLE = BIT(1), }; struct tpm_tis_data { @@ -93,6 +96,7 @@ struct tpm_tis_data { bool irq_tested; unsigned int flags; void __iomem *ilb_base_addr; + u16 clkrun_enabled; wait_queue_head_t int_queue; wait_queue_head_t read_queue; const struct tpm_tis_phy_ops *phy_ops; diff --git a/include/linux/tpm.h b/include/linux/tpm.h index 5a090f5ab335..881312d85574 100644 --- a/include/linux/tpm.h +++ b/include/linux/tpm.h @@ -50,6 +50,7 @@ struct tpm_class_ops { unsigned long *timeout_cap); int (*request_locality)(struct tpm_chip *chip, int loc); void (*relinquish_locality)(struct tpm_chip *chip, int loc); + void (*clk_enable)(struct tpm_chip *chip, bool value); }; #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE) -- 1.9.1 From 1585306566593690080@xxx Tue Nov 28 10:49:16 +0000 2017 X-GM-THRID: 1585306566593690080 X-Gmail-Labels: Inbox,Category Promotions,HistoricalUnread