In tpm_tis_core_init(), tpm2_probe() will be called first, this function will eventually call tpm_tis_send(), and then tpm_tis_probe_irq_single() will detect whether the interrupt is normal, mainly the installation interrupted, set `priv->irq_tested` to false. The logic will eventually be executed to tpm_tis_send() to trigger an interrupt. There is currently such a scenario, which will cause the IRQ probe code to never be executed, so that the TPM device is in polling mode: after setting irq_tested to false, an interrupt occurs between entering the ttpm_tis_send() function, and the interrupt will be first set irq_tested to true will cause the IRQ probe code to never be executed. It seems that this interrupt comes from tpm2_probe(). Although the interrupt has not been installed when tpm2_probe() is called, the interrupt of tpm2_probe() is only received after IRQ detection. This patch solves this issue by introducing a new variable, which is only used in interrupts, and irq_tested only marks whether the interrupt test has been completed. Signed-off-by: Tianjia Zhang <tianjia.zhang@xxxxxxxxxxxxxxxxx> --- drivers/char/tpm/tpm_tis_core.c | 8 ++++---- drivers/char/tpm/tpm_tis_core.h | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 92c51c6cfd1b..d7589b0b3e56 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -502,7 +502,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) int rc, irq; struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); - if (!(chip->flags & TPM_CHIP_FLAG_IRQ) || priv->irq_tested) + if (priv->irq_tested) return tpm_tis_send_main(chip, buf, len); /* Verify receipt of the expected IRQ */ @@ -512,9 +512,9 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len) rc = tpm_tis_send_main(chip, buf, len); priv->irq = irq; chip->flags |= TPM_CHIP_FLAG_IRQ; - if (!priv->irq_tested) + if (!priv->int_count) tpm_msleep(1); - if (!priv->irq_tested) + if (!priv->int_count) disable_interrupts(chip); priv->irq_tested = true; return rc; @@ -725,7 +725,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id) if (interrupt == 0) return IRQ_NONE; - priv->irq_tested = true; + priv->int_count += 1; if (interrupt & TPM_INTF_DATA_AVAIL_INT) wake_up_interruptible(&priv->read_queue); if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT) diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 9b2d32a59f67..c6845672f6f7 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -90,6 +90,7 @@ struct tpm_tis_data { int locality; int irq; bool irq_tested; + unsigned int int_count; unsigned int flags; void __iomem *ilb_base_addr; u16 clkrun_enabled; -- 2.19.1.3.ge56e4f7