tpm, tpm: Implement usage counter for locality
authorLino Sanfilippo <l.sanfilippo@kunbus.com>
Thu, 24 Nov 2022 13:55:33 +0000 (14:55 +0100)
committerJarkko Sakkinen <jarkko@kernel.org>
Mon, 24 Apr 2023 13:15:53 +0000 (16:15 +0300)
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>
drivers/char/tpm/tpm_tis_core.c
drivers/char/tpm/tpm_tis_core.h

index 717b81435cbd050f6d041c25673bcf80f693435f..b05c1ed51dd3f33d48401a89f589c12ce67dc265 100644 (file)
@@ -165,16 +165,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;
@@ -215,6 +226,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);
@@ -682,7 +707,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);
@@ -703,7 +728,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;
 }
@@ -792,14 +817,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;
        }
 
@@ -838,7 +863,7 @@ restore_irqs:
                rc = -1;
        }
 
-       release_locality(chip, priv->locality);
+       tpm_tis_relinquish_locality(chip, priv->locality);
 
        return rc;
 }
@@ -954,8 +979,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,
 };
 
@@ -989,6 +1014,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);
 
@@ -1067,14 +1094,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
 
        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)
@@ -1108,13 +1135,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");
@@ -1134,11 +1161,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);
                }
        }
 
@@ -1205,13 +1232,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 19ef8c1a4142e38c9267a9b6b49d5e07a5940a51..e978f457fd4d4ce083a7a9f9689df5f2d7a8ed9d 100644 (file)
@@ -92,6 +92,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;
        unsigned int int_mask;