tpm, tpm: Implement usage counter for locality
authorLino Sanfilippo <l.sanfilippo@kunbus.com>
Thu, 24 Nov 2022 13:55:33 +0000 (14:55 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 May 2023 14:03:06 +0000 (23:03 +0900)
[ Upstream commit 7a2f55d0be296c4e81fd782f3d6c43ed4ec7e265 ]

Implement a usage counter for the (default) locality used by the TPM TIS
driver:
Request the locality from the TPM if it has not been claimed yet, otherwise
only increment the counter. Also release the locality if the counter is 0
otherwise only decrement the counter. Since in case of SPI the register
accesses are locked by means of the SPI bus mutex use a sleepable lock
(i.e. also a mutex) to ensure thread-safety of the counter which may be
accessed by both a userspace thread and the interrupt handler.

By doing this refactor the names of the amended functions to use a more
appropriate prefix.

Signed-off-by: Lino Sanfilippo <l.sanfilippo@kunbus.com>
Tested-by: Michael Niewöhner <linux@mniewoehner.de>
Tested-by: Jarkko Sakkinen <jarkko@kernel.org>
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
Stable-dep-of: 955df4f87760 ("tpm, tpm_tis: Claim locality when interrupts are reenabled on resume")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h

index 39f27ed..c5fef63 100644 (file)
@@ -136,16 +136,27 @@ static bool check_locality(struct tpm_chip *chip, int l)
        return false;
 }
 
-static int release_locality(struct tpm_chip *chip, int l)
+static int __tpm_tis_relinquish_locality(struct tpm_tis_data *priv, int l)
+{
+       tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
+
+       return 0;
+}
+
+static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
 
-       tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
+       mutex_lock(&priv->locality_count_mutex);
+       priv->locality_count--;
+       if (priv->locality_count == 0)
+               __tpm_tis_relinquish_locality(priv, l);
+       mutex_unlock(&priv->locality_count_mutex);
 
        return 0;
 }
 
-static int request_locality(struct tpm_chip *chip, int l)
+static int __tpm_tis_request_locality(struct tpm_chip *chip, int l)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        unsigned long stop, timeout;
@@ -186,6 +197,20 @@ again:
        return -1;
 }
 
+static int tpm_tis_request_locality(struct tpm_chip *chip, int l)
+{
+       struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
+       int ret = 0;
+
+       mutex_lock(&priv->locality_count_mutex);
+       if (priv->locality_count == 0)
+               ret = __tpm_tis_request_locality(chip, l);
+       if (!ret)
+               priv->locality_count++;
+       mutex_unlock(&priv->locality_count_mutex);
+       return ret;
+}
+
 static u8 tpm_tis_status(struct tpm_chip *chip)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
@@ -652,7 +677,7 @@ static int probe_itpm(struct tpm_chip *chip)
        if (vendor != TPM_VID_INTEL)
                return 0;
 
-       if (request_locality(chip, 0) != 0)
+       if (tpm_tis_request_locality(chip, 0) != 0)
                return -EBUSY;
 
        rc = tpm_tis_send_data(chip, cmd_getticks, len);
@@ -673,7 +698,7 @@ static int probe_itpm(struct tpm_chip *chip)
 
 out:
        tpm_tis_ready(chip);
-       release_locality(chip, priv->locality);
+       tpm_tis_relinquish_locality(chip, priv->locality);
 
        return rc;
 }
@@ -765,14 +790,14 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
        }
        priv->irq = irq;
 
-       rc = request_locality(chip, 0);
+       rc = tpm_tis_request_locality(chip, 0);
        if (rc < 0)
                return rc;
 
        rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality),
                           &original_int_vec);
        if (rc < 0) {
-               release_locality(chip, priv->locality);
+               tpm_tis_relinquish_locality(chip, priv->locality);
                return rc;
        }
 
@@ -811,7 +836,7 @@ restore_irqs:
                rc = -1;
        }
 
-       release_locality(chip, priv->locality);
+       tpm_tis_relinquish_locality(chip, priv->locality);
 
        return rc;
 }
@@ -927,8 +952,8 @@ static const struct tpm_class_ops tpm_tis = {
        .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
        .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
        .req_canceled = tpm_tis_req_canceled,
-       .request_locality = request_locality,
-       .relinquish_locality = release_locality,
+       .request_locality = tpm_tis_request_locality,
+       .relinquish_locality = tpm_tis_relinquish_locality,
        .clk_enable = tpm_tis_clkrun_enable,
 };
 
@@ -962,6 +987,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
        priv->timeout_min = TPM_TIMEOUT_USECS_MIN;
        priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
        priv->phy_ops = phy_ops;
+       priv->locality_count = 0;
+       mutex_init(&priv->locality_count_mutex);
 
        dev_set_drvdata(&chip->dev, priv);
 
@@ -1008,14 +1035,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                   TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
        intmask &= ~TPM_GLOBAL_INT_ENABLE;
 
-       rc = request_locality(chip, 0);
+       rc = tpm_tis_request_locality(chip, 0);
        if (rc < 0) {
                rc = -ENODEV;
                goto out_err;
        }
 
        tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
-       release_locality(chip, 0);
+       tpm_tis_relinquish_locality(chip, 0);
 
        rc = tpm_chip_start(chip);
        if (rc)
@@ -1075,13 +1102,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                 * proper timeouts for the driver.
                 */
 
-               rc = request_locality(chip, 0);
+               rc = tpm_tis_request_locality(chip, 0);
                if (rc < 0)
                        goto out_err;
 
                rc = tpm_get_timeouts(chip);
 
-               release_locality(chip, 0);
+               tpm_tis_relinquish_locality(chip, 0);
 
                if (rc) {
                        dev_err(dev, "Could not get TPM timeouts and durations\n");
@@ -1099,11 +1126,11 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
                        dev_err(&chip->dev, FW_BUG
                                        "TPM interrupt not working, polling instead\n");
 
-                       rc = request_locality(chip, 0);
+                       rc = tpm_tis_request_locality(chip, 0);
                        if (rc < 0)
                                goto out_err;
                        disable_interrupts(chip);
-                       release_locality(chip, 0);
+                       tpm_tis_relinquish_locality(chip, 0);
                }
        }
 
@@ -1176,13 +1203,13 @@ int tpm_tis_resume(struct device *dev)
         * an error code but for unknown reason it isn't handled.
         */
        if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
-               ret = request_locality(chip, 0);
+               ret = tpm_tis_request_locality(chip, 0);
                if (ret < 0)
                        return ret;
 
                tpm1_do_selftest(chip);
 
-               release_locality(chip, 0);
+               tpm_tis_relinquish_locality(chip, 0);
        }
 
        return 0;
index b68479e..1d51d51 100644 (file)
@@ -91,6 +91,8 @@ enum tpm_tis_flags {
 
 struct tpm_tis_data {
        u16 manufacturer_id;
+       struct mutex locality_count_mutex;
+       unsigned int locality_count;
        int locality;
        int irq;
        bool irq_tested;