Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
		return 0;
	}

	sig = wait_event_interruptible(ibmvtpm->wq, ibmvtpm->res_len != 0);
	sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd);
	if (sig)
		return -EINTR;

@@ -125,7 +125,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
	struct ibmvtpm_dev *ibmvtpm;
	struct ibmvtpm_crq crq;
	__be64 *word = (__be64 *)&crq;
	int rc;
	int rc, sig;

	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)
		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);
	ibmvtpm->res_len = 0;
	memcpy((void *)ibmvtpm->rtce_buf, (void *)buf, count);
	crq.valid = (u8)IBMVTPM_VALID_CMD;
	crq.msg = (u8)VTPM_TPM_COMMAND;
	crq.len = cpu_to_be16(count);
	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]),
			      be64_to_cpu(word[1]));
	if (rc != H_SUCCESS) {
		dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
		rc = 0;
		ibmvtpm->tpm_processing_cmd = false;
	} else
		rc = count;

@@ -515,6 +532,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
		case VTPM_TPM_COMMAND_RES:
			/* len of the data in rtce buffer */
			ibmvtpm->res_len = be16_to_cpu(crq->len);
			ibmvtpm->tpm_processing_cmd = false;
			wake_up_interruptible(&ibmvtpm->wq);
			return;
		default:
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct ibmvtpm_dev {
	wait_queue_head_t wq;
	u16 res_len;
	u32 vtpm_version;
	bool tpm_processing_cmd;
};

#define CRQ_RES_BUF_SIZE	PAGE_SIZE