summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorStefan Berger <stefanb@linux.vnet.ibm.com>2011-03-30 18:13:31 +0200
committerRajiv Andrade <srajiv@linux.vnet.ibm.com>2011-07-12 23:53:08 +0200
commit20b87bbfada971ae917cc2ff9dbc9dae05b94d25 (patch)
treedeacbb011383a6a95922b8c49cd3c8e77c34afd2 /drivers/char
parenttpm_tis: Re-enable interrupts upon (S3) resume (diff)
downloadlinux-20b87bbfada971ae917cc2ff9dbc9dae05b94d25.tar.xz
linux-20b87bbfada971ae917cc2ff9dbc9dae05b94d25.zip
tpm_tis: Delay ACPI S3 suspend while the TPM is busy
This patch delays the (ACPI S3) suspend while the TPM is busy processing a command and the TPM TIS driver is run in interrupt mode. This is the same behavior as we already have it for the TPM TIS driver in polling mode. Reasoning: Some of the TPM's commands advance the internal state of the TPM. An example would be the extending of one of its PCR registers. Upper layers, such as IMA or TSS (TrouSerS), would certainly want to be sure that the command succeeded rather than getting an error code (-62 = -ETIME) that may not give a conclusive answer as for what reason the command failed. Reissuing such a command would put the TPM into the wrong state, so waiting for it to finish is really the only option. The downside is that some commands (key creation) can take a long time and actually prevent the machine from entering S3 at all before the 20 second timeout of the power management subsystem arrives. Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com> Signed-off-by: Rajiv Andrade <srajiv@linux.vnet.ibm.com>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/tpm/tpm_tis.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 88de8fc41586..b97ce2b205d7 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -26,6 +26,7 @@
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/acpi.h>
+#include <linux/freezer.h>
#include "tpm.h"
#define TPM_HEADER_SIZE 10
@@ -120,7 +121,7 @@ static void release_locality(struct tpm_chip *chip, int l, int force)
static int request_locality(struct tpm_chip *chip, int l)
{
- unsigned long stop;
+ unsigned long stop, timeout;
long rc;
if (check_locality(chip, l) >= 0)
@@ -129,17 +130,25 @@ static int request_locality(struct tpm_chip *chip, int l)
iowrite8(TPM_ACCESS_REQUEST_USE,
chip->vendor.iobase + TPM_ACCESS(l));
+ stop = jiffies + chip->vendor.timeout_a;
+
if (chip->vendor.irq) {
+again:
+ timeout = stop - jiffies;
+ if ((long)timeout <= 0)
+ return -1;
rc = wait_event_interruptible_timeout(chip->vendor.int_queue,
(check_locality
(chip, l) >= 0),
- chip->vendor.timeout_a);
+ timeout);
if (rc > 0)
return l;
-
+ if (rc == -ERESTARTSYS && freezing(current)) {
+ clear_thread_flag(TIF_SIGPENDING);
+ goto again;
+ }
} else {
/* wait for burstcount */
- stop = jiffies + chip->vendor.timeout_a;
do {
if (check_locality(chip, l) >= 0)
return l;
@@ -196,15 +205,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
if ((status & mask) == mask)
return 0;
+ stop = jiffies + timeout;
+
if (chip->vendor.irq) {
+again:
+ timeout = stop - jiffies;
+ if ((long)timeout <= 0)
+ return -ETIME;
rc = wait_event_interruptible_timeout(*queue,
((tpm_tis_status
(chip) & mask) ==
mask), timeout);
if (rc > 0)
return 0;
+ if (rc == -ERESTARTSYS && freezing(current)) {
+ clear_thread_flag(TIF_SIGPENDING);
+ goto again;
+ }
} else {
- stop = jiffies + timeout;
do {
msleep(TPM_TIMEOUT);
status = tpm_tis_status(chip);