tpm, tpm: Implement usage counter for locality
[ 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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
140735c46d
commit
933bfc5ad2
@@ -136,16 +136,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)
|
||||||
{
|
{
|
||||||
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
|
||||||
|
|
||||||
tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
|
tpm_tis_write8(priv, TPM_ACCESS(l), TPM_ACCESS_ACTIVE_LOCALITY);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int request_locality(struct tpm_chip *chip, int l)
|
static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
|
||||||
|
{
|
||||||
|
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
|
||||||
|
|
||||||
|
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 __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;
|
||||||
@@ -186,6 +197,20 @@ again:
|
|||||||
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);
|
||||||
@@ -638,7 +663,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);
|
||||||
@@ -659,7 +684,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;
|
||||||
}
|
}
|
||||||
@@ -747,14 +772,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -793,7 +818,7 @@ restore_irqs:
|
|||||||
rc = -1;
|
rc = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
release_locality(chip, priv->locality);
|
tpm_tis_relinquish_locality(chip, priv->locality);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -909,8 +934,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,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -944,6 +969,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);
|
||||||
|
|
||||||
@@ -990,14 +1017,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;
|
TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
|
||||||
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)
|
||||||
@@ -1057,13 +1084,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");
|
||||||
@@ -1081,11 +1108,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1158,13 +1185,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;
|
||||||
|
|||||||
@@ -90,6 +90,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;
|
||||||
bool irq_tested;
|
bool irq_tested;
|
||||||
|
|||||||
Reference in New Issue
Block a user