aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
authorStefan Berger <stefanb@linux.vnet.ibm.com>2013-01-22 14:57:53 -0500
committerKent Yoder <key@linux.vnet.ibm.com>2013-02-05 10:38:24 -0500
commit78f09cc248731716633c0ef219613e762a9c4f2e (patch)
treee0c1f2197bff7a5ad3f566cdd6ca2389c8e7cb31 /drivers/char/tpm
parent1f866057291fc00f14e4962473bd7724ffa8f578 (diff)
tpm: Fix cancellation of TPM commands (interrupt mode)
Support cancellation of TPM commands when driver is used in interrupt mode. Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com> Signed-off-by: Kent Yoder <key@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r--drivers/char/tpm/tpm.c29
-rw-r--r--drivers/char/tpm/tpm.h2
-rw-r--r--drivers/char/tpm/tpm_tis.c12
3 files changed, 31 insertions, 12 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index a244cd3e7dbc..0d2e82f95577 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1102,12 +1102,28 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
1102} 1102}
1103EXPORT_SYMBOL_GPL(tpm_store_cancel); 1103EXPORT_SYMBOL_GPL(tpm_store_cancel);
1104 1104
1105static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel,
1106 bool *canceled)
1107{
1108 u8 status = chip->vendor.status(chip);
1109
1110 *canceled = false;
1111 if ((status & mask) == mask)
1112 return true;
1113 if (check_cancel && chip->vendor.req_canceled(chip, status)) {
1114 *canceled = true;
1115 return true;
1116 }
1117 return false;
1118}
1119
1105int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, 1120int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
1106 wait_queue_head_t *queue) 1121 wait_queue_head_t *queue, bool check_cancel)
1107{ 1122{
1108 unsigned long stop; 1123 unsigned long stop;
1109 long rc; 1124 long rc;
1110 u8 status; 1125 u8 status;
1126 bool canceled = false;
1111 1127
1112 /* check current status */ 1128 /* check current status */
1113 status = chip->vendor.status(chip); 1129 status = chip->vendor.status(chip);
@@ -1122,11 +1138,14 @@ again:
1122 if ((long)timeout <= 0) 1138 if ((long)timeout <= 0)
1123 return -ETIME; 1139 return -ETIME;
1124 rc = wait_event_interruptible_timeout(*queue, 1140 rc = wait_event_interruptible_timeout(*queue,
1125 ((chip->vendor.status(chip) 1141 wait_for_tpm_stat_cond(chip, mask, check_cancel,
1126 & mask) == mask), 1142 &canceled),
1127 timeout); 1143 timeout);
1128 if (rc > 0) 1144 if (rc > 0) {
1145 if (canceled)
1146 return -ECANCELED;
1129 return 0; 1147 return 0;
1148 }
1130 if (rc == -ERESTARTSYS && freezing(current)) { 1149 if (rc == -ERESTARTSYS && freezing(current)) {
1131 clear_thread_flag(TIF_SIGPENDING); 1150 clear_thread_flag(TIF_SIGPENDING);
1132 goto again; 1151 goto again;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 725cb9b657dd..81b52015f669 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -338,7 +338,7 @@ extern void tpm_remove_hardware(struct device *);
338extern int tpm_pm_suspend(struct device *); 338extern int tpm_pm_suspend(struct device *);
339extern int tpm_pm_resume(struct device *); 339extern int tpm_pm_resume(struct device *);
340extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, 340extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
341 wait_queue_head_t *); 341 wait_queue_head_t *, bool);
342 342
343#ifdef CONFIG_ACPI 343#ifdef CONFIG_ACPI
344extern int tpm_add_ppi(struct kobject *); 344extern int tpm_add_ppi(struct kobject *);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index e4e0c65df768..ae91c115c438 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -198,7 +198,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
198 wait_for_tpm_stat(chip, 198 wait_for_tpm_stat(chip,
199 TPM_STS_DATA_AVAIL | TPM_STS_VALID, 199 TPM_STS_DATA_AVAIL | TPM_STS_VALID,
200 chip->vendor.timeout_c, 200 chip->vendor.timeout_c,
201 &chip->vendor.read_queue) 201 &chip->vendor.read_queue, true)
202 == 0) { 202 == 0) {
203 burstcnt = get_burstcount(chip); 203 burstcnt = get_burstcount(chip);
204 for (; burstcnt > 0 && size < count; burstcnt--) 204 for (; burstcnt > 0 && size < count; burstcnt--)
@@ -241,7 +241,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
241 } 241 }
242 242
243 wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, 243 wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
244 &chip->vendor.int_queue); 244 &chip->vendor.int_queue, false);
245 status = tpm_tis_status(chip); 245 status = tpm_tis_status(chip);
246 if (status & TPM_STS_DATA_AVAIL) { /* retry? */ 246 if (status & TPM_STS_DATA_AVAIL) { /* retry? */
247 dev_err(chip->dev, "Error left over data\n"); 247 dev_err(chip->dev, "Error left over data\n");
@@ -277,7 +277,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
277 tpm_tis_ready(chip); 277 tpm_tis_ready(chip);
278 if (wait_for_tpm_stat 278 if (wait_for_tpm_stat
279 (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b, 279 (chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
280 &chip->vendor.int_queue) < 0) { 280 &chip->vendor.int_queue, false) < 0) {
281 rc = -ETIME; 281 rc = -ETIME;
282 goto out_err; 282 goto out_err;
283 } 283 }
@@ -292,7 +292,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
292 } 292 }
293 293
294 wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, 294 wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
295 &chip->vendor.int_queue); 295 &chip->vendor.int_queue, false);
296 status = tpm_tis_status(chip); 296 status = tpm_tis_status(chip);
297 if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { 297 if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
298 rc = -EIO; 298 rc = -EIO;
@@ -304,7 +304,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
304 iowrite8(buf[count], 304 iowrite8(buf[count],
305 chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality)); 305 chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
306 wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, 306 wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
307 &chip->vendor.int_queue); 307 &chip->vendor.int_queue, false);
308 status = tpm_tis_status(chip); 308 status = tpm_tis_status(chip);
309 if ((status & TPM_STS_DATA_EXPECT) != 0) { 309 if ((status & TPM_STS_DATA_EXPECT) != 0) {
310 rc = -EIO; 310 rc = -EIO;
@@ -342,7 +342,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
342 if (wait_for_tpm_stat 342 if (wait_for_tpm_stat
343 (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, 343 (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
344 tpm_calc_ordinal_duration(chip, ordinal), 344 tpm_calc_ordinal_duration(chip, ordinal),
345 &chip->vendor.read_queue) < 0) { 345 &chip->vendor.read_queue, false) < 0) {
346 rc = -ETIME; 346 rc = -ETIME;
347 goto out_err; 347 goto out_err;
348 } 348 }