tpm: ibmvtpm: retry on H_CLOSED in tpm_ibmvtpm_send()
tpm_ibmvtpm_send() can fail during PowerVM Live Partition Mobility resume
with an H_CLOSED return from ibmvtpm_send_crq(). The PAPR says, 'The
"partner partition suspended" transport event disables the associated CRQ
such that any H_SEND_CRQ hcall() to the associated CRQ returns H_Closed
until the CRQ has been explicitly enabled using the H_ENABLE_CRQ hcall.'
This patch adds a check in tpm_ibmvtpm_send() for an H_CLOSED return from
ibmvtpm_send_crq() and in that case calls tpm_ibmvtpm_resume() and
retries the ibmvtpm_send_crq() once.
Cc: stable@vger.kernel.org # 3.7.x
Fixes: 132f762947
("drivers/char/tpm: Add new device driver to support IBM vTPM")
Reported-by: Linh Pham <phaml@us.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Signed-off-by: George Wilson <gcwilson@linux.ibm.com>
Tested-by: Linh Pham <phaml@us.ibm.com>
Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
This commit is contained in:
parent
684c6bd806
commit
eba5cf3dcb
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2012 IBM Corporation
|
||||
* Copyright (C) 2012-2020 IBM Corporation
|
||||
*
|
||||
* Author: Ashley Lai <ashleydlai@gmail.com>
|
||||
*
|
||||
@ -134,6 +134,64 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvtpm_crq_send_init - Send a CRQ initialize message
|
||||
* @ibmvtpm: vtpm device struct
|
||||
*
|
||||
* Return:
|
||||
* 0 on success.
|
||||
* Non-zero on failure.
|
||||
*/
|
||||
static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD);
|
||||
if (rc != H_SUCCESS)
|
||||
dev_err(ibmvtpm->dev,
|
||||
"%s failed rc=%d\n", __func__, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_ibmvtpm_resume - Resume from suspend
|
||||
*
|
||||
* @dev: device struct
|
||||
*
|
||||
* Return: Always 0.
|
||||
*/
|
||||
static int tpm_ibmvtpm_resume(struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
|
||||
int rc = 0;
|
||||
|
||||
do {
|
||||
if (rc)
|
||||
msleep(100);
|
||||
rc = plpar_hcall_norets(H_ENABLE_CRQ,
|
||||
ibmvtpm->vdev->unit_address);
|
||||
} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
|
||||
|
||||
if (rc) {
|
||||
dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = vio_enable_interrupts(ibmvtpm->vdev);
|
||||
if (rc) {
|
||||
dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ibmvtpm_crq_send_init(ibmvtpm);
|
||||
if (rc)
|
||||
dev_err(dev, "Error send_init rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_ibmvtpm_send() - Send a TPM command
|
||||
* @chip: tpm chip struct
|
||||
@ -147,6 +205,7 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
{
|
||||
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
|
||||
bool retry = true;
|
||||
int rc, sig;
|
||||
|
||||
if (!ibmvtpm->rtce_buf) {
|
||||
@ -180,18 +239,27 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||
*/
|
||||
ibmvtpm->tpm_processing_cmd = true;
|
||||
|
||||
again:
|
||||
rc = ibmvtpm_send_crq(ibmvtpm->vdev,
|
||||
IBMVTPM_VALID_CMD, VTPM_TPM_COMMAND,
|
||||
count, ibmvtpm->rtce_dma_handle);
|
||||
if (rc != H_SUCCESS) {
|
||||
/*
|
||||
* H_CLOSED can be returned after LPM resume. Call
|
||||
* tpm_ibmvtpm_resume() to re-enable the CRQ then retry
|
||||
* ibmvtpm_send_crq() once before failing.
|
||||
*/
|
||||
if (rc == H_CLOSED && retry) {
|
||||
tpm_ibmvtpm_resume(ibmvtpm->dev);
|
||||
retry = false;
|
||||
goto again;
|
||||
}
|
||||
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
|
||||
rc = 0;
|
||||
ibmvtpm->tpm_processing_cmd = false;
|
||||
} else
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
spin_unlock(&ibmvtpm->rtce_lock);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
|
||||
@ -269,26 +337,6 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* ibmvtpm_crq_send_init - Send a CRQ initialize message
|
||||
* @ibmvtpm: vtpm device struct
|
||||
*
|
||||
* Return:
|
||||
* 0 on success.
|
||||
* Non-zero on failure.
|
||||
*/
|
||||
static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ibmvtpm_send_crq_word(ibmvtpm->vdev, INIT_CRQ_CMD);
|
||||
if (rc != H_SUCCESS)
|
||||
dev_err(ibmvtpm->dev,
|
||||
"ibmvtpm_crq_send_init failed rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_ibmvtpm_remove - ibm vtpm remove entry point
|
||||
* @vdev: vio device struct
|
||||
@ -401,44 +449,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
|
||||
ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* tpm_ibmvtpm_resume - Resume from suspend
|
||||
*
|
||||
* @dev: device struct
|
||||
*
|
||||
* Return: Always 0.
|
||||
*/
|
||||
static int tpm_ibmvtpm_resume(struct device *dev)
|
||||
{
|
||||
struct tpm_chip *chip = dev_get_drvdata(dev);
|
||||
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
|
||||
int rc = 0;
|
||||
|
||||
do {
|
||||
if (rc)
|
||||
msleep(100);
|
||||
rc = plpar_hcall_norets(H_ENABLE_CRQ,
|
||||
ibmvtpm->vdev->unit_address);
|
||||
} while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc));
|
||||
|
||||
if (rc) {
|
||||
dev_err(dev, "Error enabling ibmvtpm rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = vio_enable_interrupts(ibmvtpm->vdev);
|
||||
if (rc) {
|
||||
dev_err(dev, "Error vio_enable_interrupts rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ibmvtpm_crq_send_init(ibmvtpm);
|
||||
if (rc)
|
||||
dev_err(dev, "Error send_init rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
|
||||
{
|
||||
return (status == 0);
|
||||
|
Loading…
Reference in New Issue
Block a user