From patchwork Wed Jun 29 23:26:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Lino Sanfilippo X-Patchwork-Id: 12900799 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1ECAC43334 for ; Wed, 29 Jun 2022 23:27:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229821AbiF2X1m (ORCPT ); Wed, 29 Jun 2022 19:27:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33332 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231231AbiF2X1j (ORCPT ); Wed, 29 Jun 2022 19:27:39 -0400 Received: from mout.gmx.net (mout.gmx.net [212.227.15.15]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BDB91255B9; Wed, 29 Jun 2022 16:27:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1656545245; bh=OxT6orG/M1ZoEPE31KTuTtlu7fY3J7clKbTWUReYR3E=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=AICp0kL+UNCRRslzxDIC3IorVL/hk2Xh8wm7n1fgMMoxrgcsjhk0gm7vq2uMMKDqz LDuC2oDDfi3P0sTQCfxAv1c+/QkSsNGIfvmfMdysMCNa80UfE/dZNn3qD2llIxdW2Q bxUc8zCIe7bgYMCI+mwSNAOZol/komn/tfudTlXo= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from localhost.localdomain ([46.223.3.23]) by mail.gmx.net (mrgmx004 [212.227.17.190]) with ESMTPSA (Nemesis) id 1MK3Rs-1oLSWB0XFe-00LXS5; Thu, 30 Jun 2022 01:27:25 +0200 From: Lino Sanfilippo To: peterhuewe@gmx.de, jarkko@kernel.org, jgg@ziepe.ca Cc: stefanb@linux.vnet.ibm.com, linux@mniewoehner.de, linux-integrity@vger.kernel.org, linux-kernel@vger.kernel.org, l.sanfilippo@kunbus.com, LinoSanfilippo@gmx.de, lukas@wunner.de, p.rosenberger@kunbus.com Subject: [PATCH v7 05/10] tpm, tpm_tis: Only handle supported interrupts Date: Thu, 30 Jun 2022 01:26:48 +0200 Message-Id: <20220629232653.1306735-6-LinoSanfilippo@gmx.de> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220629232653.1306735-1-LinoSanfilippo@gmx.de> References: <20220629232653.1306735-1-LinoSanfilippo@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:YG934ZGUnKJQRghRcLKlPcTHwIXbpcVYxg/nNlYt0aycyfeLYjB Vzxm4atoO4qDUKm7TuVHx22Xs8LeLk8vg64+VxXv1aR85pXqbx5oLYi+jxUvavBg/7TnUXi FW9GReqDrfJX3+n7td4MFD29MShLW1RiV9NqEFPRNgzymA0jBghcJK879Y6KbaR1KRBjVaX lF4jrrcrIbBl23980FYYA== X-UI-Out-Filterresults: notjunk:1;V03:K0:l95XRWW19XU=:bsoR4jlGol1mxZubUDJvdO tfiuzWkcdAZZ/0PZZcWGi4QQDZQBQlM2CHfm+mLTb5HN7qWziVEOCGlfbd3SmVAdu9GtwVOGU 0HMDzPNt5Ehl8peIJJGFMDd5CNIVvgSX05LqQPVdqI8w9f1B8/E1FxBsx2daaQWQut8IWPYJN YscYBOTRtR2TJEasuFRgzA7nI0ZMnjAVMAgWfcqPkjXCuH4iFl8M6Clw+nasqU9bl3a6HdwW5 kXydEN71S/fS3lTyEv7n70JF94wb6KUm3tnUCfgwgAo9O+9/S3V5CCwPXd3nsibxODVOGc0HP xFnNoKDuMvZFq4gHr0oURpZoZT3YBcLQyu/8yCQmS3pF1Oervf0Pll3wo+6G8i4KwdDpQFjna TwdWyn4skEhofhyZEhfFAHf4koCyjyte0WPaE18MacKcqMRLkKkFYFh0ZHDWu5iOLTs02N9VB tbyHWcrdnvvL6usmXS0I67zfV47t+1TQNA5fREwPCJOdXXMDeMD5fN0JIPAhxbbUNq5ZfXfE5 AhV1UTZWbusE6kfg7dN7yuR0P27qTn8E5yVZB53HHaCsnzNeoGnkEg/gvZ4A0cnBBTVaOJ+E6 8ln707k1Ti76PZRmKJGqJ9T0yrZEtLeGuXCwR3jfP7x8W7pZXtgF315YZwhnxiD5KLI50zF6p 7EpQPnaLVbDPF1Vp78OFGIP60/U4i06t9oPf/LiXZVgmvxCt4Y6HehaeO45kLnEUBfQPCiYYa TC1A7TRbHuYIF3gWwZPCJJ4gd3UaRLiCIbGnk99FvwTeEgDcb986C7NYE4RtXhMMXrjRo++zs SGYtvupu/6IpWW1ruoc5rIOy0Qnb9ApKBMCWRFEg77GEm6L47P8OiPmVkjr6+BCMDJcbaEZFJ XfytOLy3V1dpC7f+eh9+SjdXmCH1oxn2Rtfh0XIrk9sL0y1/2/OALbSB+pdffyAd3ifJ5hpso z6FU/+UqGBcQPRzqbkJ7ifT+qQ5JgT++pMnv/wm8RjwplzJuQKCg1yfH9tEyM/4J4EsWiBcX4 rn5p+usSdKqPGCHZ4oyVnTW8vp56N7NFzRzQJowgf2OZbUZm3GGSkOSZ0QaFi5ahe0SheUvjh kT7gNrfSOOEZZpz4nRCTiYva4BzgVwj4cw6W703FUWYJp0UE75D3qAygg== Precedence: bulk List-ID: X-Mailing-List: linux-integrity@vger.kernel.org From: Lino Sanfilippo According to the TPM Interface Specification (TIS) support for "stsValid" and "commandReady" interrupts is only optional. This has to be taken into account when handling the interrupts in functions like wait_for_tpm_stat(). To determine the supported interrupts use the capability query. Also adjust wait_for_tpm_stat() to only wait for interrupt reported status changes. After that process all the remaining status changes by polling the status register. Signed-off-by: Lino Sanfilippo Tested-by: Michael Niewöhner Reviewed-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 119 +++++++++++++++++++------------- drivers/char/tpm/tpm_tis_core.h | 1 + 2 files changed, 72 insertions(+), 48 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 09d8f04cbc81..c13599e94ab6 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -53,41 +53,63 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, long rc; u8 status; bool canceled = false; + u8 sts_mask = 0; + int ret = 0; /* check current status */ status = chip->ops->status(chip); if ((status & mask) == mask) return 0; - stop = jiffies + timeout; + /* check which status changes can be handled by irqs */ + if (priv->int_mask & TPM_INTF_STS_VALID_INT) + sts_mask |= TPM_STS_VALID; - if (chip->flags & TPM_CHIP_FLAG_IRQ) { + if (priv->int_mask & TPM_INTF_DATA_AVAIL_INT) + sts_mask |= TPM_STS_DATA_AVAIL; + + if (priv->int_mask & TPM_INTF_CMD_READY_INT) + sts_mask |= TPM_STS_COMMAND_READY; + + sts_mask &= mask; + + stop = jiffies + timeout; + /* process status changes with irq support */ + if (sts_mask) { + ret = -ETIME; again: timeout = stop - jiffies; if ((long)timeout <= 0) return -ETIME; rc = wait_event_interruptible_timeout(*queue, - wait_for_tpm_stat_cond(chip, mask, check_cancel, + wait_for_tpm_stat_cond(chip, sts_mask, check_cancel, &canceled), timeout); if (rc > 0) { if (canceled) return -ECANCELED; - return 0; + ret = 0; } if (rc == -ERESTARTSYS && freezing(current)) { clear_thread_flag(TIF_SIGPENDING); goto again; } - } else { - do { - usleep_range(priv->timeout_min, - priv->timeout_max); - status = chip->ops->status(chip); - if ((status & mask) == mask) - return 0; - } while (time_before(jiffies, stop)); } + + if (ret) + return ret; + + mask &= ~sts_mask; + if (!mask) /* all done */ + return 0; + /* process status changes without irq support */ + do { + status = chip->ops->status(chip); + if ((status & mask) == mask) + return 0; + usleep_range(priv->timeout_min, + priv->timeout_max); + } while (time_before(jiffies, stop)); return -ETIME; } @@ -1007,8 +1029,39 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, if (rc < 0) goto out_err; - intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT | - TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT; + /* Figure out the capabilities */ + rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps); + if (rc < 0) + goto out_err; + + dev_dbg(dev, "TPM interface capabilities (0x%x):\n", + intfcaps); + if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) + dev_dbg(dev, "\tBurst Count Static\n"); + if (intfcaps & TPM_INTF_CMD_READY_INT) { + intmask |= TPM_INTF_CMD_READY_INT; + dev_dbg(dev, "\tCommand Ready Int Support\n"); + } + if (intfcaps & TPM_INTF_INT_EDGE_FALLING) + dev_dbg(dev, "\tInterrupt Edge Falling\n"); + if (intfcaps & TPM_INTF_INT_EDGE_RISING) + dev_dbg(dev, "\tInterrupt Edge Rising\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_LOW) + dev_dbg(dev, "\tInterrupt Level Low\n"); + if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) + dev_dbg(dev, "\tInterrupt Level High\n"); + if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) + intmask |= TPM_INTF_LOCALITY_CHANGE_INT; + dev_dbg(dev, "\tLocality Change Int Support\n"); + if (intfcaps & TPM_INTF_STS_VALID_INT) { + intmask |= TPM_INTF_STS_VALID_INT; + dev_dbg(dev, "\tSts Valid Int Support\n"); + } + if (intfcaps & TPM_INTF_DATA_AVAIL_INT) { + intmask |= TPM_INTF_DATA_AVAIL_INT; + dev_dbg(dev, "\tData Avail Int Support\n"); + } + intmask &= ~TPM_GLOBAL_INT_ENABLE; rc = request_locality(chip, 0); @@ -1042,32 +1095,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, goto out_err; } - /* Figure out the capabilities */ - rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps); - if (rc < 0) - goto out_err; - - dev_dbg(dev, "TPM interface capabilities (0x%x):\n", - intfcaps); - if (intfcaps & TPM_INTF_BURST_COUNT_STATIC) - dev_dbg(dev, "\tBurst Count Static\n"); - if (intfcaps & TPM_INTF_CMD_READY_INT) - dev_dbg(dev, "\tCommand Ready Int Support\n"); - if (intfcaps & TPM_INTF_INT_EDGE_FALLING) - dev_dbg(dev, "\tInterrupt Edge Falling\n"); - if (intfcaps & TPM_INTF_INT_EDGE_RISING) - dev_dbg(dev, "\tInterrupt Edge Rising\n"); - if (intfcaps & TPM_INTF_INT_LEVEL_LOW) - dev_dbg(dev, "\tInterrupt Level Low\n"); - if (intfcaps & TPM_INTF_INT_LEVEL_HIGH) - dev_dbg(dev, "\tInterrupt Level High\n"); - if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) - dev_dbg(dev, "\tLocality Change Int Support\n"); - if (intfcaps & TPM_INTF_STS_VALID_INT) - dev_dbg(dev, "\tSts Valid Int Support\n"); - if (intfcaps & TPM_INTF_DATA_AVAIL_INT) - dev_dbg(dev, "\tData Avail Int Support\n"); - /* INTERRUPT Setup */ init_waitqueue_head(&priv->read_queue); init_waitqueue_head(&priv->int_queue); @@ -1098,7 +1125,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, else tpm_tis_probe_irq(chip, intmask); - if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) { + if (chip->flags & TPM_CHIP_FLAG_IRQ) { + priv->int_mask = intmask; + } else { dev_err(&chip->dev, FW_BUG "TPM interrupt not working, polling instead\n"); @@ -1145,13 +1174,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) if (rc < 0) goto out; - rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask); - if (rc < 0) - 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; + intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE; tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index bf07379dea42..e005eb99480e 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -93,6 +93,7 @@ struct tpm_tis_data { u16 manufacturer_id; int locality; int irq; + unsigned int int_mask; unsigned long flags; void __iomem *ilb_base_addr; u16 clkrun_enabled;