From patchwork Sun Nov 20 13:31:26 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Lino Sanfilippo X-Patchwork-Id: 13050043 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 81702C4332F for ; Sun, 20 Nov 2022 13:32:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229554AbiKTNcw (ORCPT ); Sun, 20 Nov 2022 08:32:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46920 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229721AbiKTNcj (ORCPT ); Sun, 20 Nov 2022 08:32:39 -0500 Received: from mout.gmx.net (mout.gmx.net [212.227.15.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8AD67E82; Sun, 20 Nov 2022 05:32:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.de; s=s31663417; t=1668951126; bh=S+hhbmGWDO0VTuSnSrMDyNR5O/r2XEHMgIEZ7ffd/3o=; h=X-UI-Sender-Class:From:To:Cc:Subject:Date:In-Reply-To:References; b=N8Pr9BhFF3SCxSv1LBebt52RsBq77SoQGxRDE0yI9UTR0SGoSZe3Mv1WFfV8qzIih iAvCJQiyEeLK49eqi7neJWSEIY+xXgGNmKsAlE2mZQ9NJGhYlOEBeIKOEUZhbP0jSI RB3fh/iKG4C4YsVQoqffXEqqQBaQdGKM9147eNYzYHFiweffHrUZuTwBJBQUtFg8WF aTNTJKEISHBS3NEZfezhdZOWrBbt4lTz36QaLu3/ZFU2rQYKOZeIYDhmJFlHdxrKQE 8+N9xJzYHv2gLpnTwmbrgLo/KFFBbT2wNiC9jTZps373eoHVz46ck+gdn7BoUcboYG PmIsPiQZb6FWw== X-UI-Sender-Class: 724b4f7f-cbec-4199-ad4e-598c01a50d3a Received: from Venus.speedport.ip ([84.162.7.17]) by mail.gmx.net (mrgmx004 [212.227.17.190]) with ESMTPSA (Nemesis) id 1MhD2O-1pR9Yi2qFm-00eOCL; Sun, 20 Nov 2022 14:32:06 +0100 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, jandryuk@gmail.com, pmenzel@molgen.mpg.de, l.sanfilippo@kunbus.com, LinoSanfilippo@gmx.de, lukas@wunner.de, p.rosenberger@kunbus.com Subject: [PATCH v10 06/14] tpm, tpm_tis: Only handle supported interrupts Date: Sun, 20 Nov 2022 14:31:26 +0100 Message-Id: <20221120133134.28926-7-LinoSanfilippo@gmx.de> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20221120133134.28926-1-LinoSanfilippo@gmx.de> References: <20221120133134.28926-1-LinoSanfilippo@gmx.de> MIME-Version: 1.0 X-Provags-ID: V03:K1:pj9FekuflmRkmp8yKItK+S15WfK+mvG73cJI33XbaCDKiXdEYhH RMuk+wI0Bzde5PWEpNMdaJFim3D4B0DSVlWxvSdBjLAEIfFQgYzTqn2bOhnHWRNCIta3ttB E84mMOrbYZRVnU63L6wUOiBGhqcKmc9jnxHuvhZjerzkmai88MzxxHM1oT0Aapi1k8hKRbq BKxr0kxEdOkXMfunZ+JOA== UI-OutboundReport: notjunk:1;M01:P0:6AjY/MVFtng=;jLWczQZvTXNacP1t7vpKs+IaCFW yObG/QcyeDJVIMIkwolW6f77oIMVYXe5kag/9tri6fzZPF521H95EfpN6UdPgrtLNQGYJSHn+ XsEP4tdFIPxqX/oBuE7cuUBaQbQtDsFMMUAJfI0Ze/Y5QYnfOPrmPUTkwY72zj1RBg3DUNTei Nu1IwA/bak6DviOczNz4Dq7x5KiesoJawOCWfRQTM6EnQFT2F5286ILrbLf8X8PX/tNJTK4rn ainZNGgFFqsuxIHvg0jMr4VbMpKw84ANLLWtCnPPJoUKfpoo4BKU7j9C2NvmhPC3neOQPqFNy P2d1hfdErCy7yV3PlpdjHWh/5Dc/lwv0SnvrvWJyYcUuAbtdqS9BxxNtcmlfqqcghmcjwc944 sUQ3uc6a+FeWypDfyYewLQaVmJtpgQdrZUYbVQDs7ddTiZECydGc93tMSu+z2g3//kxaGtgI3 oTmXAO18QOfh7yPv3T2HsWoxu1pu7Ly8dITe2GqHoGZXhThCSty68H+AXoP8m98O4mVPF7Fg+ lzyWwLdQK+XrQ2AboUrPWdviG+wHputox4SVd2FEm5Uuj82DZUtQvyI4JBLYfyvBDOa/a8WZr +5fvqhkNFUq7GXCgEUPW/YKcJuBvRB176Bugkgp3X0pD70bzTfgsJcvNKtjJlq9vzXzfuQTEc FjJ4ZjnHDEwnetV38tmkaPqP/LsCVVJc+AzwzQp9U8Ig4asIXavPsVdWoXxMPzPbcOWhzFL36 0w26YtkMtnC2m8G5Y2dnRPZR7g4ndwigmzndzmB35xY2vvuZoMt+IEuKfAAXR/JKo4Mmklke+ PTVeQlkGjXIfpMOy9qc3Fl6BU+BEv7fq+AHNDEYAH+e13tIiMl/nFa6u/chUjiXCjL5pXVF6o 0Yh3R4IuvObdAdgbqE2jU9SaxNQLu3DV3XTXd9m8Rjn2oI/9De+k536XvNmW68ntEyKGNOnF3 IB5ySa6fjJgYME90gQt52ev7UEk= 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 | 120 +++++++++++++++++++------------- drivers/char/tpm/tpm_tis_core.h | 1 + 2 files changed, 73 insertions(+), 48 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 58a53ec534aa..fbad92b18788 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 what 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; } @@ -1000,8 +1022,40 @@ 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); @@ -1035,32 +1089,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); @@ -1091,7 +1119,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"); @@ -1138,13 +1168,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 695a2516dce0..2deef11c88db 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;