Skip to content

Commit e87fcf0

Browse files
linosanfilippo-kunbusjarkkojs
authored andcommitted
tpm, tpm_tis: Only handle supported interrupts
According to the TPM Interface Specification (TIS) support for "stsValid" and "commandReady" interrupts is only optional. This has to be taken into account when handling the interrupts in functions like wait_for_tpm_stat(). To determine the supported interrupts use the capability query. Also adjust wait_for_tpm_stat() to only wait for interrupt reported status changes. After that process all the remaining status changes by polling the status register. Signed-off-by: Lino Sanfilippo <[email protected]> Tested-by: Michael Niewöhner <[email protected]> Tested-by: Jarkko Sakkinen <[email protected]> Reviewed-by: Jarkko Sakkinen <[email protected]> Signed-off-by: Jarkko Sakkinen <[email protected]>
1 parent 15d7aa4 commit e87fcf0

File tree

2 files changed

+73
-48
lines changed

2 files changed

+73
-48
lines changed

drivers/char/tpm/tpm_tis_core.c

Lines changed: 72 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -53,41 +53,63 @@ static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
5353
long rc;
5454
u8 status;
5555
bool canceled = false;
56+
u8 sts_mask = 0;
57+
int ret = 0;
5658

5759
/* check current status */
5860
status = chip->ops->status(chip);
5961
if ((status & mask) == mask)
6062
return 0;
6163

62-
stop = jiffies + timeout;
64+
/* check what status changes can be handled by irqs */
65+
if (priv->int_mask & TPM_INTF_STS_VALID_INT)
66+
sts_mask |= TPM_STS_VALID;
6367

64-
if (chip->flags & TPM_CHIP_FLAG_IRQ) {
68+
if (priv->int_mask & TPM_INTF_DATA_AVAIL_INT)
69+
sts_mask |= TPM_STS_DATA_AVAIL;
70+
71+
if (priv->int_mask & TPM_INTF_CMD_READY_INT)
72+
sts_mask |= TPM_STS_COMMAND_READY;
73+
74+
sts_mask &= mask;
75+
76+
stop = jiffies + timeout;
77+
/* process status changes with irq support */
78+
if (sts_mask) {
79+
ret = -ETIME;
6580
again:
6681
timeout = stop - jiffies;
6782
if ((long)timeout <= 0)
6883
return -ETIME;
6984
rc = wait_event_interruptible_timeout(*queue,
70-
wait_for_tpm_stat_cond(chip, mask, check_cancel,
85+
wait_for_tpm_stat_cond(chip, sts_mask, check_cancel,
7186
&canceled),
7287
timeout);
7388
if (rc > 0) {
7489
if (canceled)
7590
return -ECANCELED;
76-
return 0;
91+
ret = 0;
7792
}
7893
if (rc == -ERESTARTSYS && freezing(current)) {
7994
clear_thread_flag(TIF_SIGPENDING);
8095
goto again;
8196
}
82-
} else {
83-
do {
84-
usleep_range(priv->timeout_min,
85-
priv->timeout_max);
86-
status = chip->ops->status(chip);
87-
if ((status & mask) == mask)
88-
return 0;
89-
} while (time_before(jiffies, stop));
9097
}
98+
99+
if (ret)
100+
return ret;
101+
102+
mask &= ~sts_mask;
103+
if (!mask) /* all done */
104+
return 0;
105+
/* process status changes without irq support */
106+
do {
107+
status = chip->ops->status(chip);
108+
if ((status & mask) == mask)
109+
return 0;
110+
usleep_range(priv->timeout_min,
111+
priv->timeout_max);
112+
} while (time_before(jiffies, stop));
91113
return -ETIME;
92114
}
93115

@@ -1005,8 +1027,40 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
10051027
if (rc < 0)
10061028
goto out_err;
10071029

1008-
intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
1009-
TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
1030+
/* Figure out the capabilities */
1031+
rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps);
1032+
if (rc < 0)
1033+
goto out_err;
1034+
1035+
dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
1036+
intfcaps);
1037+
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
1038+
dev_dbg(dev, "\tBurst Count Static\n");
1039+
if (intfcaps & TPM_INTF_CMD_READY_INT) {
1040+
intmask |= TPM_INTF_CMD_READY_INT;
1041+
dev_dbg(dev, "\tCommand Ready Int Support\n");
1042+
}
1043+
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
1044+
dev_dbg(dev, "\tInterrupt Edge Falling\n");
1045+
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
1046+
dev_dbg(dev, "\tInterrupt Edge Rising\n");
1047+
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
1048+
dev_dbg(dev, "\tInterrupt Level Low\n");
1049+
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
1050+
dev_dbg(dev, "\tInterrupt Level High\n");
1051+
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT) {
1052+
intmask |= TPM_INTF_LOCALITY_CHANGE_INT;
1053+
dev_dbg(dev, "\tLocality Change Int Support\n");
1054+
}
1055+
if (intfcaps & TPM_INTF_STS_VALID_INT) {
1056+
intmask |= TPM_INTF_STS_VALID_INT;
1057+
dev_dbg(dev, "\tSts Valid Int Support\n");
1058+
}
1059+
if (intfcaps & TPM_INTF_DATA_AVAIL_INT) {
1060+
intmask |= TPM_INTF_DATA_AVAIL_INT;
1061+
dev_dbg(dev, "\tData Avail Int Support\n");
1062+
}
1063+
10101064
intmask &= ~TPM_GLOBAL_INT_ENABLE;
10111065

10121066
rc = request_locality(chip, 0);
@@ -1040,32 +1094,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
10401094
goto out_err;
10411095
}
10421096

1043-
/* Figure out the capabilities */
1044-
rc = tpm_tis_read32(priv, TPM_INTF_CAPS(priv->locality), &intfcaps);
1045-
if (rc < 0)
1046-
goto out_err;
1047-
1048-
dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
1049-
intfcaps);
1050-
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
1051-
dev_dbg(dev, "\tBurst Count Static\n");
1052-
if (intfcaps & TPM_INTF_CMD_READY_INT)
1053-
dev_dbg(dev, "\tCommand Ready Int Support\n");
1054-
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
1055-
dev_dbg(dev, "\tInterrupt Edge Falling\n");
1056-
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
1057-
dev_dbg(dev, "\tInterrupt Edge Rising\n");
1058-
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
1059-
dev_dbg(dev, "\tInterrupt Level Low\n");
1060-
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
1061-
dev_dbg(dev, "\tInterrupt Level High\n");
1062-
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
1063-
dev_dbg(dev, "\tLocality Change Int Support\n");
1064-
if (intfcaps & TPM_INTF_STS_VALID_INT)
1065-
dev_dbg(dev, "\tSts Valid Int Support\n");
1066-
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
1067-
dev_dbg(dev, "\tData Avail Int Support\n");
1068-
10691097
/* INTERRUPT Setup */
10701098
init_waitqueue_head(&priv->read_queue);
10711099
init_waitqueue_head(&priv->int_queue);
@@ -1096,7 +1124,9 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
10961124
else
10971125
tpm_tis_probe_irq(chip, intmask);
10981126

1099-
if (!(chip->flags & TPM_CHIP_FLAG_IRQ)) {
1127+
if (chip->flags & TPM_CHIP_FLAG_IRQ) {
1128+
priv->int_mask = intmask;
1129+
} else {
11001130
dev_err(&chip->dev, FW_BUG
11011131
"TPM interrupt not working, polling instead\n");
11021132

@@ -1143,13 +1173,7 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
11431173
if (rc < 0)
11441174
goto out;
11451175

1146-
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
1147-
if (rc < 0)
1148-
goto out;
1149-
1150-
intmask |= TPM_INTF_CMD_READY_INT
1151-
| TPM_INTF_LOCALITY_CHANGE_INT | TPM_INTF_DATA_AVAIL_INT
1152-
| TPM_INTF_STS_VALID_INT | TPM_GLOBAL_INT_ENABLE;
1176+
intmask = priv->int_mask | TPM_GLOBAL_INT_ENABLE;
11531177

11541178
tpm_tis_write32(priv, TPM_INT_ENABLE(priv->locality), intmask);
11551179

drivers/char/tpm/tpm_tis_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct tpm_tis_data {
9494
u16 manufacturer_id;
9595
int locality;
9696
int irq;
97+
unsigned int int_mask;
9798
unsigned long flags;
9899
void __iomem *ilb_base_addr;
99100
u16 clkrun_enabled;

0 commit comments

Comments
 (0)