aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
authorStefan Berger <stefanb@linux.vnet.ibm.com>2011-03-30 12:13:31 -0400
committerRajiv Andrade <srajiv@linux.vnet.ibm.com>2011-07-12 17:53:08 -0400
commit20b87bbfada971ae917cc2ff9dbc9dae05b94d25 (patch)
treedeacbb011383a6a95922b8c49cd3c8e77c34afd2 /drivers/char/tpm
parent45baa1d1fa3926510ead93c96e6b0baa5ad79bd3 (diff)
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/tpm')
-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 @@
26#include <linux/interrupt.h> 26#include <linux/interrupt.h>
27#include <linux/wait.h> 27#include <linux/wait.h>
28#include <linux/acpi.h> 28#include <linux/acpi.h>
29#include <linux/freezer.h>
29#include "tpm.h" 30#include "tpm.h"
30 31
31#define TPM_HEADER_SIZE 10 32#define TPM_HEADER_SIZE 10
@@ -120,7 +121,7 @@ static void release_locality(struct tpm_chip *chip, int l, int force)
120 121
121static int request_locality(struct tpm_chip *chip, int l) 122static int request_locality(struct tpm_chip *chip, int l)
122{ 123{
123 unsigned long stop; 124 unsigned long stop, timeout;
124 long rc; 125 long rc;
125 126
126 if (check_locality(chip, l) >= 0) 127 if (check_locality(chip, l) >= 0)
@@ -129,17 +130,25 @@ static int request_locality(struct tpm_chip *chip, int l)
129 iowrite8(TPM_ACCESS_REQUEST_USE, 130 iowrite8(TPM_ACCESS_REQUEST_USE,
130 chip->vendor.iobase + TPM_ACCESS(l)); 131 chip->vendor.iobase + TPM_ACCESS(l));
131 132
133 stop = jiffies + chip->vendor.timeout_a;
134
132 if (chip->vendor.irq) { 135 if (chip->vendor.irq) {
136again:
137 timeout = stop - jiffies;
138 if ((long)timeout <= 0)
139 return -1;
133 rc = wait_event_interruptible_timeout(chip->vendor.int_queue, 140 rc = wait_event_interruptible_timeout(chip->vendor.int_queue,
134 (check_locality 141 (check_locality
135 (chip, l) >= 0), 142 (chip, l) >= 0),
136 chip->vendor.timeout_a); 143 timeout);
137 if (rc > 0) 144 if (rc > 0)
138 return l; 145 return l;
139 146 if (rc == -ERESTARTSYS && freezing(current)) {
147 clear_thread_flag(TIF_SIGPENDING);
148 goto again;
149 }
140 } else { 150 } else {
141 /* wait for burstcount */ 151 /* wait for burstcount */
142 stop = jiffies + chip->vendor.timeout_a;
143 do { 152 do {
144 if (check_locality(chip, l) >= 0) 153 if (check_locality(chip, l) >= 0)
145 return l; 154 return l;
@@ -196,15 +205,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
196 if ((status & mask) == mask) 205 if ((status & mask) == mask)
197 return 0; 206 return 0;
198 207
208 stop = jiffies + timeout;
209
199 if (chip->vendor.irq) { 210 if (chip->vendor.irq) {
211again:
212 timeout = stop - jiffies;
213 if ((long)timeout <= 0)
214 return -ETIME;
200 rc = wait_event_interruptible_timeout(*queue, 215 rc = wait_event_interruptible_timeout(*queue,
201 ((tpm_tis_status 216 ((tpm_tis_status
202 (chip) & mask) == 217 (chip) & mask) ==
203 mask), timeout); 218 mask), timeout);
204 if (rc > 0) 219 if (rc > 0)
205 return 0; 220 return 0;
221 if (rc == -ERESTARTSYS && freezing(current)) {
222 clear_thread_flag(TIF_SIGPENDING);
223 goto again;
224 }
206 } else { 225 } else {
207 stop = jiffies + timeout;
208 do { 226 do {
209 msleep(TPM_TIMEOUT); 227 msleep(TPM_TIMEOUT);
210 status = tpm_tis_status(chip); 228 status = tpm_tis_status(chip);