Commit 6674ff14 authored by Stefan Berger's avatar Stefan Berger Committed by Jarkko Sakkinen

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: default avatarStefan Berger <stefanb@linux.vnet.ibm.com>
Tested-by: default avatarHon Ching(Vicky) Lo <honclo@linux.vnet.ibm.com>
Reviewed-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Reviewed-by: default avatarAshley Lai <ashley@ashleylai.com>
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Acked-by: default avatarPeter Huewe <peterhuewe@gmx.de>
parent b8ba1e74
...@@ -90,7 +90,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -90,7 +90,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return 0; return 0;
} }
sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0); sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
if (sig) if (sig)
return -EINTR; return -EINTR;
...@@ -125,7 +125,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -125,7 +125,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
struct ibmvtpm_dev *ibmvtpm; struct ibmvtpm_dev *ibmvtpm;
struct ibmvtpm_crq crq; struct ibmvtpm_crq crq;
__be64 *word = (__be64 *)&crq; __be64 *word = (__be64 *)&crq;
int rc; int rc, sig;
ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip); ibmvtpm = (struct ibmvtpm_dev *)TPM_VPRIV(chip);
...@@ -141,18 +141,35 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -141,18 +141,35 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
return -EIO; return -EIO;
} }
if (ibmvtpm->tpm_processing_cmd) {
dev_info(ibmvtpm->dev,
"Need to wait for TPM to finish\n");
/* wait for previous command to finish */
sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
if (sig)
return -EINTR;
}
spin_lock(&ibmvtpm->rtce_lock); spin_lock(&ibmvtpm->rtce_lock);
ibmvtpm->res_len = 0;
memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count); memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
crq.valid = (u8)IBMVTPM_VALID_CMD; crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_TPM_COMMAND; crq.msg = (u8)VTPM_TPM_COMMAND;
crq.len = cpu_to_be16(count); crq.len = cpu_to_be16(count);
crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle); crq.data = cpu_to_be32(ibmvtpm->rtce_dma_handle);
/*
* set the processing flag before the Hcall, since we may get the
* result (interrupt) before even being able to check rc.
*/
ibmvtpm->tpm_processing_cmd = true;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]), rc = ibmvtpm_send_crq(ibmvtpm->vdev, be64_to_cpu(word[0]),
be64_to_cpu(word[1])); be64_to_cpu(word[1]));
if (rc != H_SUCCESS) { if (rc != H_SUCCESS) {
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
rc = 0; rc = 0;
ibmvtpm->tpm_processing_cmd = false;
} else } else
rc = count; rc = count;
...@@ -515,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, ...@@ -515,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
case VTPM_TPM_COMMAND_RES: case VTPM_TPM_COMMAND_RES:
/* len of the data in rtce buffer */ /* len of the data in rtce buffer */
ibmvtpm->res_len = be16_to_cpu(crq->len); ibmvtpm->res_len = be16_to_cpu(crq->len);
ibmvtpm->tpm_processing_cmd = false;
wake_up_interruptible(&ibmvtpm->wq); wake_up_interruptible(&ibmvtpm->wq);
return; return;
default: default:
......
...@@ -45,6 +45,7 @@ struct ibmvtpm_dev { ...@@ -45,6 +45,7 @@ struct ibmvtpm_dev {
wait_queue_head_t wq; wait_queue_head_t wq;
u16 res_len; u16 res_len;
u32 vtpm_version; u32 vtpm_version;
bool tpm_processing_cmd;
}; };
#define CRQ_RES_BUF_SIZE PAGE_SIZE #define CRQ_RES_BUF_SIZE PAGE_SIZE
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment