Skip to content

Commit

Permalink
tpm: Fix cancellation of TPM commands (interrupt mode)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Stefan Berger authored and Kent Yoder committed Feb 5, 2013
1 parent 1f86605 commit 78f09cc
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 12 deletions.
29 changes: 24 additions & 5 deletions drivers/char/tpm/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1102,12 +1102,28 @@ ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
}
EXPORT_SYMBOL_GPL(tpm_store_cancel);

static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask, bool check_cancel,
bool *canceled)
{
u8 status = chip->vendor.status(chip);

*canceled = false;
if ((status & mask) == mask)
return true;
if (check_cancel && chip->vendor.req_canceled(chip, status)) {
*canceled = true;
return true;
}
return false;
}

int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
wait_queue_head_t *queue)
wait_queue_head_t *queue, bool check_cancel)
{
unsigned long stop;
long rc;
u8 status;
bool canceled = false;

/* check current status */
status = chip->vendor.status(chip);
Expand All @@ -1122,11 +1138,14 @@ int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
if ((long)timeout <= 0)
return -ETIME;
rc = wait_event_interruptible_timeout(*queue,
((chip->vendor.status(chip)
& mask) == mask),
timeout);
if (rc > 0)
wait_for_tpm_stat_cond(chip, mask, check_cancel,
&canceled),
timeout);
if (rc > 0) {
if (canceled)
return -ECANCELED;
return 0;
}
if (rc == -ERESTARTSYS && freezing(current)) {
clear_thread_flag(TIF_SIGPENDING);
goto again;
Expand Down
2 changes: 1 addition & 1 deletion drivers/char/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ extern void tpm_remove_hardware(struct device *);
extern int tpm_pm_suspend(struct device *);
extern int tpm_pm_resume(struct device *);
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
wait_queue_head_t *);
wait_queue_head_t *, bool);

#ifdef CONFIG_ACPI
extern int tpm_add_ppi(struct kobject *);
Expand Down
12 changes: 6 additions & 6 deletions drivers/char/tpm/tpm_tis.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
wait_for_tpm_stat(chip,
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
chip->vendor.timeout_c,
&chip->vendor.read_queue)
&chip->vendor.read_queue, true)
== 0) {
burstcnt = get_burstcount(chip);
for (; burstcnt > 0 && size < count; burstcnt--)
Expand Down Expand Up @@ -241,7 +241,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}

wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue);
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
dev_err(chip->dev, "Error left over data\n");
Expand Down Expand Up @@ -277,7 +277,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
tpm_tis_ready(chip);
if (wait_for_tpm_stat
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
&chip->vendor.int_queue) < 0) {
&chip->vendor.int_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
Expand All @@ -292,7 +292,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
}

wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue);
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) {
rc = -EIO;
Expand All @@ -304,7 +304,7 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len)
iowrite8(buf[count],
chip->vendor.iobase + TPM_DATA_FIFO(chip->vendor.locality));
wait_for_tpm_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c,
&chip->vendor.int_queue);
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if ((status & TPM_STS_DATA_EXPECT) != 0) {
rc = -EIO;
Expand Down Expand Up @@ -342,7 +342,7 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (wait_for_tpm_stat
(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
tpm_calc_ordinal_duration(chip, ordinal),
&chip->vendor.read_queue) < 0) {
&chip->vendor.read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
}
Expand Down

0 comments on commit 78f09cc

Please sign in to comment.