Skip to content

Commit 858e8b7

Browse files
linosanfilippo-kunbusjarkkojs
authored andcommitted
tpm, tpm_tis: Avoid cache incoherency in test for interrupts
The interrupt handler that sets the boolean variable irq_tested may run on another CPU as the thread that checks irq_tested as part of the irq test in tpm_tis_send(). Since nothing guarantees cache coherency between CPUs for unsynchronized accesses to boolean variables the testing thread might not perceive the value change done in the interrupt handler. Avoid this issue by setting the bit TPM_TIS_IRQ_TESTED in the flags field of the tpm_tis_data struct and by accessing this field with the bit manipulating functions that provide cache coherency. Also convert all other existing sites to use the proper macros when accessing this bitfield. 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>
1 parent 099f26f commit 858e8b7

File tree

3 files changed

+13
-12
lines changed

3 files changed

+13
-12
lines changed

drivers/char/tpm/tpm_tis.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
227227
irq = tpm_info->irq;
228228

229229
if (itpm || is_itpm(ACPI_COMPANION(dev)))
230-
phy->priv.flags |= TPM_TIS_ITPM_WORKAROUND;
230+
set_bit(TPM_TIS_ITPM_WORKAROUND, &phy->priv.flags);
231231

232232
return tpm_tis_core_init(dev, &phy->priv, irq, &tpm_tcg,
233233
ACPI_HANDLE(dev));

drivers/char/tpm/tpm_tis_core.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
351351
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
352352
int rc, status, burstcnt;
353353
size_t count = 0;
354-
bool itpm = priv->flags & TPM_TIS_ITPM_WORKAROUND;
354+
bool itpm = test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
355355

356356
status = tpm_tis_status(chip);
357357
if ((status & TPM_STS_COMMAND_READY) == 0) {
@@ -484,7 +484,8 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
484484
int rc, irq;
485485
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
486486

487-
if (!(chip->flags & TPM_CHIP_FLAG_IRQ) || priv->irq_tested)
487+
if (!(chip->flags & TPM_CHIP_FLAG_IRQ) ||
488+
test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
488489
return tpm_tis_send_main(chip, buf, len);
489490

490491
/* Verify receipt of the expected IRQ */
@@ -494,11 +495,11 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
494495
rc = tpm_tis_send_main(chip, buf, len);
495496
priv->irq = irq;
496497
chip->flags |= TPM_CHIP_FLAG_IRQ;
497-
if (!priv->irq_tested)
498+
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
498499
tpm_msleep(1);
499-
if (!priv->irq_tested)
500+
if (!test_bit(TPM_TIS_IRQ_TESTED, &priv->flags))
500501
disable_interrupts(chip);
501-
priv->irq_tested = true;
502+
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
502503
return rc;
503504
}
504505

@@ -641,7 +642,7 @@ static int probe_itpm(struct tpm_chip *chip)
641642
size_t len = sizeof(cmd_getticks);
642643
u16 vendor;
643644

644-
if (priv->flags & TPM_TIS_ITPM_WORKAROUND)
645+
if (test_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags))
645646
return 0;
646647

647648
rc = tpm_tis_read16(priv, TPM_DID_VID(0), &vendor);
@@ -661,13 +662,13 @@ static int probe_itpm(struct tpm_chip *chip)
661662

662663
tpm_tis_ready(chip);
663664

664-
priv->flags |= TPM_TIS_ITPM_WORKAROUND;
665+
set_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
665666

666667
rc = tpm_tis_send_data(chip, cmd_getticks, len);
667668
if (rc == 0)
668669
dev_info(&chip->dev, "Detected an iTPM.\n");
669670
else {
670-
priv->flags &= ~TPM_TIS_ITPM_WORKAROUND;
671+
clear_bit(TPM_TIS_ITPM_WORKAROUND, &priv->flags);
671672
rc = -EFAULT;
672673
}
673674

@@ -711,7 +712,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
711712
if (interrupt == 0)
712713
return IRQ_NONE;
713714

714-
priv->irq_tested = true;
715+
set_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
715716
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
716717
wake_up_interruptible(&priv->read_queue);
717718
if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
@@ -797,7 +798,7 @@ static int tpm_tis_probe_irq_single(struct tpm_chip *chip, u32 intmask,
797798
if (rc < 0)
798799
return rc;
799800

800-
priv->irq_tested = false;
801+
clear_bit(TPM_TIS_IRQ_TESTED, &priv->flags);
801802

802803
/* Generate an interrupt by having the core call through to
803804
* tpm_tis_send

drivers/char/tpm/tpm_tis_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ enum tpm_tis_flags {
8787
TPM_TIS_ITPM_WORKAROUND = BIT(0),
8888
TPM_TIS_INVALID_STATUS = BIT(1),
8989
TPM_TIS_DEFAULT_CANCELLATION = BIT(2),
90+
TPM_TIS_IRQ_TESTED = BIT(3),
9091
};
9192

9293
struct tpm_tis_data {
9394
u16 manufacturer_id;
9495
int locality;
9596
int irq;
96-
bool irq_tested;
9797
unsigned long flags;
9898
void __iomem *ilb_base_addr;
9999
u16 clkrun_enabled;

0 commit comments

Comments
 (0)