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

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
...@@ -165,16 +165,27 @@ static bool check_locality(struct tpm_chip *chip, int l) ...@@ -165,16 +165,27 @@ static bool check_locality(struct tpm_chip *chip, int l)
return false; 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); 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; 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); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
unsigned long stop, timeout; unsigned long stop, timeout;
...@@ -215,6 +226,20 @@ static int request_locality(struct tpm_chip *chip, int l) ...@@ -215,6 +226,20 @@ static int request_locality(struct tpm_chip *chip, int l)
return -1; 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) static u8 tpm_tis_status(struct tpm_chip *chip)
{ {
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
...@@ -682,7 +707,7 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -682,7 +707,7 @@ static int probe_itpm(struct tpm_chip *chip)
if (vendor != TPM_VID_INTEL) if (vendor != TPM_VID_INTEL)
return 0; return 0;
if (request_locality(chip, 0) != 0) if (tpm_tis_request_locality(chip, 0) != 0)
return -EBUSY; return -EBUSY;
rc = tpm_tis_send_data(chip, cmd_getticks, len); rc = tpm_tis_send_data(chip, cmd_getticks, len);
...@@ -703,7 +728,7 @@ static int probe_itpm(struct tpm_chip *chip) ...@@ -703,7 +728,7 @@ static int probe_itpm(struct tpm_chip *chip)
out: out:
tpm_tis_ready(chip); tpm_tis_ready(chip);
release_locality(chip, priv->locality); tpm_tis_relinquish_locality(chip, priv->locality);
return rc; return rc;
} }
...@@ -792,14 +817,14 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, ...@@ -792,14 +817,14 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
} }
priv->irq = irq; priv->irq = irq;
rc = request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) if (rc < 0)
return rc; return rc;
rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality), rc = tpm_tis_read8(priv, TPM_INT_VECTOR(priv->locality),
&original_int_vec); &original_int_vec);
if (rc < 0) { if (rc < 0) {
release_locality(chip, priv->locality); tpm_tis_relinquish_locality(chip, priv->locality);
return rc; return rc;
} }
...@@ -838,7 +863,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask, ...@@ -838,7 +863,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
rc = -1; rc = -1;
} }
release_locality(chip, priv->locality); tpm_tis_relinquish_locality(chip, priv->locality);
return rc; return rc;
} }
...@@ -954,8 +979,8 @@ static const struct tpm_class_ops tpm_tis = { ...@@ -954,8 +979,8 @@ static const struct tpm_class_ops tpm_tis = {
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_canceled = tpm_tis_req_canceled, .req_canceled = tpm_tis_req_canceled,
.request_locality = request_locality, .request_locality = tpm_tis_request_locality,
.relinquish_locality = release_locality, .relinquish_locality = tpm_tis_relinquish_locality,
.clk_enable = tpm_tis_clkrun_enable, .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, ...@@ -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_min = TPM_TIMEOUT_USECS_MIN;
priv->timeout_max = TPM_TIMEOUT_USECS_MAX; priv->timeout_max = TPM_TIMEOUT_USECS_MAX;
priv->phy_ops = phy_ops; priv->phy_ops = phy_ops;
priv->locality_count = 0;
mutex_init(&priv->locality_count_mutex);
dev_set_drvdata(&chip->dev, priv); 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, ...@@ -1067,14 +1094,14 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
intmask &= ~TPM_GLOBAL_INT_ENABLE; intmask &= ~TPM_GLOBAL_INT_ENABLE;
rc = request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) { if (rc < 0) {
rc = -ENODEV; rc = -ENODEV;
goto out_err; goto out_err;
} }
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask); 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); rc = tpm_chip_start(chip);
if (rc) if (rc)
...@@ -1108,13 +1135,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, ...@@ -1108,13 +1135,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
* proper timeouts for the driver. * proper timeouts for the driver.
*/ */
rc = request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) if (rc < 0)
goto out_err; goto out_err;
rc = tpm_get_timeouts(chip); rc = tpm_get_timeouts(chip);
release_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
if (rc) { if (rc) {
dev_err(dev, "Could not get TPM timeouts and durations\n"); 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, ...@@ -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 dev_err(&chip->dev, FW_BUG
"TPM interrupt not working, polling instead\n"); "TPM interrupt not working, polling instead\n");
rc = request_locality(chip, 0); rc = tpm_tis_request_locality(chip, 0);
if (rc < 0) if (rc < 0)
goto out_err; goto out_err;
disable_interrupts(chip); disable_interrupts(chip);
release_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
} }
} }
...@@ -1205,13 +1232,13 @@ int tpm_tis_resume(struct device *dev) ...@@ -1205,13 +1232,13 @@ int tpm_tis_resume(struct device *dev)
* an error code but for unknown reason it isn't handled. * an error code but for unknown reason it isn't handled.
*/ */
if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) { if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
ret = request_locality(chip, 0); ret = tpm_tis_request_locality(chip, 0);
if (ret < 0) if (ret < 0)
return ret; return ret;
tpm1_do_selftest(chip); tpm1_do_selftest(chip);
release_locality(chip, 0); tpm_tis_relinquish_locality(chip, 0);
} }
return 0; return 0;
......
...@@ -92,6 +92,8 @@ enum tpm_tis_flags { ...@@ -92,6 +92,8 @@ enum tpm_tis_flags {
struct tpm_tis_data { struct tpm_tis_data {
u16 manufacturer_id; u16 manufacturer_id;
struct mutex locality_count_mutex;
unsigned int locality_count;
int locality; int locality;
int irq; int irq;
unsigned int int_mask; unsigned int int_mask;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment