diff options
author | Stefan Berger <stefanb@linux.vnet.ibm.com> | 2015-12-09 08:52:01 -0500 |
---|---|---|
committer | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | 2015-12-20 08:27:12 -0500 |
commit | 6674ff145eef1f158e3d1d065cb1e19f315d909b (patch) | |
tree | 82eb29e89966d0638edb5edbd0991a7ff5a2320e | |
parent | b8ba1e744445d65dad7dd61db909e7f2b89df35e (diff) |
tpm_ibmvtpm: properly handle interrupted packet receptions
When the TPM response reception is interrupted in the wait_event_interruptable
call, the TPM is still busy processing the command and will only deliver the
response later. So we have to wait for an outstanding response before sending
a new request to avoid trying to put a 2nd request into the CRQ. Also reset
the res_len before sending a command so we will end up in that
wait_event_interruptable() waiting for the response rather than reading the
command packet as a response.
The easiest way to trigger the problem is to run the following
cd /sys/device/vio/71000004
while :; cat pcrs >/dev/null; done
And press Ctrl-C. This will then display an error
tpm_ibmvtpm 71000004: tpm_transmit: tpm_recv: error -4
followed by several other errors once interaction with the TPM resumes.
tpm_ibmvtpm 71000004: A TPM error (101) occurred attempting to determine the number of PCRS.
Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Tested-by: Hon Ching(Vicky) Lo <honclo@linux.vnet.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: Ashley Lai <ashley@ashleylai.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Acked-by: Peter Huewe <peterhuewe@gmx.de>
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.c | 22 | ||||
-rw-r--r-- | drivers/char/tpm/tpm_ibmvtpm.h | 1 |
2 files changed, 21 insertions, 2 deletions
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 3e6a22658b63..b0a9a9e34241 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c | |||
@@ -90,7 +90,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) | |||
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0); | 93 | sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd); |
94 | if (sig) | 94 | if (sig) |
95 | return -EINTR; | 95 | return -EINTR; |
96 | 96 | ||
@@ -125,7 +125,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) | |||
125 | struct ibmvtpm_dev *ibmvtpm; | 125 | struct ibmvtpm_dev *ibmvtpm; |
126 | struct ibmvtpm_crq crq; | 126 | struct ibmvtpm_crq crq; |
127 | __be64 *word = (__be64 *)&crq; | 127 | __be64 *word = (__be64 *)&crq; |
128 | int rc; | 128 | int rc, sig; |
129 | 129 | ||
130 | ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); | 130 | ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); |
131 | 131 | ||
@@ -141,18 +141,35 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) | |||
141 | return -EIO; | 141 | return -EIO; |
142 | } | 142 | } |
143 | 143 | ||
144 | if (ibmvtpm->tpm_processing_cmd) { | ||
145 | dev_info(ibmvtpm->dev, | ||
146 | "Need to wait for TPM to finish\n"); | ||
147 | /* wait for previous command to finish */ | ||
148 | sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd); | ||
149 | if (sig) | ||
150 | return -EINTR; | ||
151 | } | ||
152 | |||
144 | spin_lock(&ibmvtpm->rtce_lock); | 153 | spin_lock(&ibmvtpm->rtce_lock); |
154 | ibmvtpm->res_len = 0; | ||
145 | memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); | 155 | memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); |
146 | crq.valid = (u8)IBMVTPM_VALID_CMD; | 156 | crq.valid = (u8)IBMVTPM_VALID_CMD; |
147 | crq.msg = (u8)VTPM_TPM_COMMAND; | 157 | crq.msg = (u8)VTPM_TPM_COMMAND; |
148 | crq.len = cpu_to_be16(count); | 158 | crq.len = cpu_to_be16(count); |
149 | crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); | 159 | crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); |
150 | 160 | ||
161 | /* | ||
162 | * set the processing flag before the Hcall, since we may get the | ||
163 | * result (interrupt) before even being able to check rc. | ||
164 | */ | ||
165 | ibmvtpm->tpm_processing_cmd = true; | ||
166 | |||
151 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), | 167 | rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), |
152 | be64_to_cpu(word[1])); | 168 | be64_to_cpu(word[1])); |
153 | if (rc != H_SUCCESS) { | 169 | if (rc != H_SUCCESS) { |
154 | dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); | 170 | dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); |
155 | rc = 0; | 171 | rc = 0; |
172 | ibmvtpm->tpm_processing_cmd = false; | ||
156 | } else | 173 | } else |
157 | rc = count; | 174 | rc = count; |
158 | 175 | ||
@@ -515,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, | |||
515 | case VTPM_TPM_COMMAND_RES: | 532 | case VTPM_TPM_COMMAND_RES: |
516 | /* len of the data in rtce buffer */ | 533 | /* len of the data in rtce buffer */ |
517 | ibmvtpm->res_len = be16_to_cpu(crq->len); | 534 | ibmvtpm->res_len = be16_to_cpu(crq->len); |
535 | ibmvtpm->tpm_processing_cmd = false; | ||
518 | wake_up_interruptible(&ibmvtpm->wq); | 536 | wake_up_interruptible(&ibmvtpm->wq); |
519 | return; | 537 | return; |
520 | default: | 538 | default: |
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index 6af92890518f..91dfe766d080 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h | |||
@@ -45,6 +45,7 @@ struct ibmvtpm_dev { | |||
45 | wait_queue_head_t wq; | 45 | wait_queue_head_t wq; |
46 | u16 res_len; | 46 | u16 res_len; |
47 | u32 vtpm_version; | 47 | u32 vtpm_version; |
48 | bool tpm_processing_cmd; | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | #define CRQ_RES_BUF_SIZE PAGE_SIZE | 51 | #define CRQ_RES_BUF_SIZE PAGE_SIZE |