Commit 7a2f55d0 authored by Lino Sanfilippo's avatar Lino Sanfilippo Committed by Jarkko Sakkinen
Browse files

tpm, tpm: Implement usage counter for locality



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: default avatarLino Sanfilippo <l.sanfilippo@kunbus.com>
Tested-by: default avatarMichael Niewöhner <linux@mniewoehner.de>
Tested-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
Reviewed-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
Signed-off-by: default avatarJarkko Sakkinen <jarkko@kernel.org>
parent 35f62128
Loading
Loading
Loading
Loading
+45 −18
Original line number Diff line number Diff line
@@ -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 @@ static int request_locality(struct tpm_chip *chip, int l)
	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 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
		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;
+2 −0
Original line number Diff line number Diff line
@@ -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;