mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 18:09:56 +00:00
tpm: ibmvtpm: retry on H_CLOSED in tpm_ibmvtpm_send()
commiteba5cf3dcbupstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
74a6b8631b
commit
456245a1b3
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012 IBM Corporation
|
* Copyright (C) 2012-2020 IBM Corporation
|
||||||
*
|
*
|
||||||
* Author: Ashley Lai <ashleydlai@gmail.com>
|
* Author: Ashley Lai <ashleydlai@gmail.com>
|
||||||
*
|
*
|
||||||
@@ -133,6 +133,64 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||||||
return len;
|
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
|
* tpm_ibmvtpm_send() - Send a TPM command
|
||||||
* @chip: tpm chip struct
|
* @chip: tpm chip struct
|
||||||
@@ -146,6 +204,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)
|
static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
|
struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev);
|
||||||
|
bool retry = true;
|
||||||
int rc, sig;
|
int rc, sig;
|
||||||
|
|
||||||
if (!ibmvtpm->rtce_buf) {
|
if (!ibmvtpm->rtce_buf) {
|
||||||
@@ -179,18 +238,27 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
|
|||||||
*/
|
*/
|
||||||
ibmvtpm->tpm_processing_cmd = true;
|
ibmvtpm->tpm_processing_cmd = true;
|
||||||
|
|
||||||
|
again:
|
||||||
rc = ibmvtpm_send_crq(ibmvtpm->vdev,
|
rc = ibmvtpm_send_crq(ibmvtpm->vdev,
|
||||||
IBMVTPM_VALID_CMD, VTPM_TPM_COMMAND,
|
IBMVTPM_VALID_CMD, VTPM_TPM_COMMAND,
|
||||||
count, ibmvtpm->rtce_dma_handle);
|
count, ibmvtpm->rtce_dma_handle);
|
||||||
if (rc != H_SUCCESS) {
|
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);
|
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
|
||||||
rc = 0;
|
|
||||||
ibmvtpm->tpm_processing_cmd = false;
|
ibmvtpm->tpm_processing_cmd = false;
|
||||||
} else
|
}
|
||||||
rc = 0;
|
|
||||||
|
|
||||||
spin_unlock(&ibmvtpm->rtce_lock);
|
spin_unlock(&ibmvtpm->rtce_lock);
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
|
static void tpm_ibmvtpm_cancel(struct tpm_chip *chip)
|
||||||
@@ -268,26 +336,6 @@ static int ibmvtpm_crq_send_init_complete(struct ibmvtpm_dev *ibmvtpm)
|
|||||||
return rc;
|
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
|
* tpm_ibmvtpm_remove - ibm vtpm remove entry point
|
||||||
* @vdev: vio device struct
|
* @vdev: vio device struct
|
||||||
@@ -400,44 +448,6 @@ static int ibmvtpm_reset_crq(struct ibmvtpm_dev *ibmvtpm)
|
|||||||
ibmvtpm->crq_dma_handle, CRQ_RES_BUF_SIZE);
|
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)
|
static bool tpm_ibmvtpm_req_canceled(struct tpm_chip *chip, u8 status)
|
||||||
{
|
{
|
||||||
return (status == 0);
|
return (status == 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user