diff options
author | Stefan Berger <stefanb@linux.vnet.ibm.com> | 2013-01-22 14:57:53 -0500 |
---|---|---|
committer | Kent Yoder <key@linux.vnet.ibm.com> | 2013-02-05 10:38:24 -0500 |
commit | 78f09cc248731716633c0ef219613e762a9c4f2e (patch) | |
tree | e0c1f2197bff7a5ad3f566cdd6ca2389c8e7cb31 /drivers/char | |
parent | 1f866057291fc00f14e4962473bd7724ffa8f578 (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')
-rw-r--r-- | drivers/char/tpm/tpm.c | 29 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_tis.c | 12 |
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 | } |
1103 | EXPORT_SYMBOL_GPL(tpm_store_cancel); | 1103 | EXPORT_SYMBOL_GPL(tpm_store_cancel); |
1104 | 1104 | ||
1105 | static 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 | |||
1105 | int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, | 1120 | int 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 *); | |||
338 | extern int tpm_pm_suspend(struct device *); | 338 | extern int tpm_pm_suspend(struct device *); |
339 | extern int tpm_pm_resume(struct device *); | 339 | extern int tpm_pm_resume(struct device *); |
340 | extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long, | 340 | extern 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 |
344 | extern int tpm_add_ppi(struct kobject *); | 344 | extern 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 | } |