Commit cd07db5f authored by James Morris's avatar James Morris
parents 1fa185eb eb71f8a5
...@@ -901,8 +901,10 @@ int tpm_pm_suspend(struct device *dev) ...@@ -901,8 +901,10 @@ int tpm_pm_suspend(struct device *dev)
if (chip == NULL) if (chip == NULL)
return -ENODEV; return -ENODEV;
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2) {
return tpm2_shutdown(chip, TPM2_SU_CLEAR); tpm2_shutdown(chip, TPM2_SU_STATE);
return 0;
}
/* for buggy tpm, flush pcrs with extend to selected dummy */ /* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr) { if (tpm_suspend_pcr) {
......
...@@ -432,7 +432,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, ...@@ -432,7 +432,8 @@ ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
u32 *value, const char *desc); u32 *value, const char *desc);
extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
extern int tpm2_do_selftest(struct tpm_chip *chip); extern int tpm2_do_selftest(struct tpm_chip *chip);
extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet); extern int tpm2_gen_interrupt(struct tpm_chip *chip);
extern int tpm2_probe(struct tpm_chip *chip);
...@@ -456,20 +456,23 @@ static const struct tpm_input_header tpm2_shutdown_header = { ...@@ -456,20 +456,23 @@ static const struct tpm_input_header tpm2_shutdown_header = {
* @chip: TPM chip to use. * @chip: TPM chip to use.
* @shutdown_type shutdown type. The value is either * @shutdown_type shutdown type. The value is either
* TPM_SU_CLEAR or TPM_SU_STATE. * TPM_SU_CLEAR or TPM_SU_STATE.
*
* 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error.
*/ */
int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type) void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
{ {
struct tpm2_cmd cmd; struct tpm2_cmd cmd;
int rc;
cmd.header.in = tpm2_shutdown_header; cmd.header.in = tpm2_shutdown_header;
cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type); cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
"stopping the TPM"); rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM");
/* In places where shutdown command is sent there's no much we can do
* except print the error code on a system failure.
*/
if (rc < 0)
dev_warn(chip->pdev, "transmit returned %d while stopping the TPM",
rc);
} }
EXPORT_SYMBOL_GPL(tpm2_shutdown); EXPORT_SYMBOL_GPL(tpm2_shutdown);
...@@ -598,20 +601,46 @@ EXPORT_SYMBOL_GPL(tpm2_do_selftest); ...@@ -598,20 +601,46 @@ EXPORT_SYMBOL_GPL(tpm2_do_selftest);
/** /**
* tpm2_gen_interrupt() - generate an interrupt * tpm2_gen_interrupt() - generate an interrupt
* @chip: TPM chip to use * @chip: TPM chip to use
* @quiet: surpress the error message
* *
* 0 is returned when the operation is successful. If a negative number is * 0 is returned when the operation is successful. If a negative number is
* returned it remarks a POSIX error code. If a positive number is returned * returned it remarks a POSIX error code. If a positive number is returned
* it remarks a TPM error. * it remarks a TPM error.
*/ */
int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet) int tpm2_gen_interrupt(struct tpm_chip *chip)
{ {
const char *desc = NULL;
u32 dummy; u32 dummy;
if (!quiet) return tpm2_get_tpm_pt(chip, 0x100, &dummy,
desc = "attempting to generate an interrupt"; "attempting to generate an interrupt");
return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc);
} }
EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);
/**
* tpm2_probe() - probe TPM 2.0
* @chip: TPM chip to use
*
* Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on
* the reply tag.
*/
int tpm2_probe(struct tpm_chip *chip)
{
struct tpm2_cmd cmd;
int rc;
cmd.header.in = tpm2_get_tpm_pt_header;
cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd));
if (rc < 0)
return rc;
else if (rc < TPM_HEADER_SIZE)
return -EFAULT;
if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS)
chip->flags |= TPM_CHIP_FLAG_TPM2;
return 0;
}
EXPORT_SYMBOL_GPL(tpm2_probe);
...@@ -95,21 +95,7 @@ struct crb_priv { ...@@ -95,21 +95,7 @@ struct crb_priv {
u8 __iomem *rsp; u8 __iomem *rsp;
}; };
#ifdef CONFIG_PM_SLEEP static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume);
static int crb_resume(struct device *dev)
{
int rc;
struct tpm_chip *chip = dev_get_drvdata(dev);
rc = tpm2_shutdown(chip, TPM2_SU_STATE);
if (!rc)
rc = tpm2_do_selftest(chip);
return rc;
}
#endif
static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, crb_resume);
static u8 crb_status(struct tpm_chip *chip) static u8 crb_status(struct tpm_chip *chip)
{ {
...@@ -326,6 +312,10 @@ static int crb_acpi_remove(struct acpi_device *device) ...@@ -326,6 +312,10 @@ static int crb_acpi_remove(struct acpi_device *device)
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
tpm_chip_unregister(chip); tpm_chip_unregister(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_CLEAR);
return 0; return 0;
} }
......
...@@ -148,7 +148,8 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) ...@@ -148,7 +148,8 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
crq.len = (u16)count; crq.len = (u16)count;
crq.data = ibmvtpm->rtce_dma_handle; crq.data = ibmvtpm->rtce_dma_handle;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]); rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]),
cpu_to_be64(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;
...@@ -186,7 +187,8 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm) ...@@ -186,7 +187,8 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
crq.valid = (u8)IBMVTPM_VALID_CMD; crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE; crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
cpu_to_be64(buf[1]));
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc); "ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
...@@ -212,7 +214,8 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm) ...@@ -212,7 +214,8 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
crq.valid = (u8)IBMVTPM_VALID_CMD; crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_GET_VERSION; crq.msg = (u8)VTPM_GET_VERSION;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
cpu_to_be64(buf[1]));
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"ibmvtpm_crq_get_version failed rc=%d\n", rc); "ibmvtpm_crq_get_version failed rc=%d\n", rc);
...@@ -336,7 +339,8 @@ static int tpm_ibmvtpm_suspend(struct device *dev) ...@@ -336,7 +339,8 @@ static int tpm_ibmvtpm_suspend(struct device *dev)
crq.valid = (u8)IBMVTPM_VALID_CMD; crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND; crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]); rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
cpu_to_be64(buf[1]));
if (rc != H_SUCCESS) if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev, dev_err(ibmvtpm->dev,
"tpm_ibmvtpm_suspend failed rc=%d\n", rc); "tpm_ibmvtpm_suspend failed rc=%d\n", rc);
...@@ -481,11 +485,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, ...@@ -481,11 +485,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
case IBMVTPM_VALID_CMD: case IBMVTPM_VALID_CMD:
switch (crq->msg) { switch (crq->msg) {
case VTPM_GET_RTCE_BUFFER_SIZE_RES: case VTPM_GET_RTCE_BUFFER_SIZE_RES:
if (crq->len <= 0) { if (be16_to_cpu(crq->len) <= 0) {
dev_err(ibmvtpm->dev, "Invalid rtce size\n"); dev_err(ibmvtpm->dev, "Invalid rtce size\n");
return; return;
} }
ibmvtpm->rtce_size = crq->len; ibmvtpm->rtce_size = be16_to_cpu(crq->len);
ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size, ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
GFP_KERNEL); GFP_KERNEL);
if (!ibmvtpm->rtce_buf) { if (!ibmvtpm->rtce_buf) {
...@@ -506,11 +510,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, ...@@ -506,11 +510,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
return; return;
case VTPM_GET_VERSION_RES: case VTPM_GET_VERSION_RES:
ibmvtpm->vtpm_version = crq->data; ibmvtpm->vtpm_version = be32_to_cpu(crq->data);
return; return;
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 = crq->len; ibmvtpm->res_len = be16_to_cpu(crq->len);
wake_up_interruptible(&ibmvtpm->wq); wake_up_interruptible(&ibmvtpm->wq);
return; return;
default: default:
......
...@@ -588,6 +588,9 @@ MODULE_PARM_DESC(interrupts, "Enable interrupts"); ...@@ -588,6 +588,9 @@ MODULE_PARM_DESC(interrupts, "Enable interrupts");
static void tpm_tis_remove(struct tpm_chip *chip) static void tpm_tis_remove(struct tpm_chip *chip)
{ {
if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_shutdown(chip, TPM2_SU_CLEAR);
iowrite32(~TPM_GLOBAL_INT_ENABLE & iowrite32(~TPM_GLOBAL_INT_ENABLE &
ioread32(chip->vendor.iobase + ioread32(chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor. TPM_INT_ENABLE(chip->vendor.
...@@ -639,12 +642,9 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, ...@@ -639,12 +642,9 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
goto out_err; goto out_err;
} }
/* Every TPM 2.x command has a higher ordinal than TPM 1.x commands. rc = tpm2_probe(chip);
* Therefore, we can use an idempotent TPM 2.x command to probe TPM 2.x. if (rc)
*/ goto out_err;
rc = tpm2_gen_interrupt(chip, true);
if (rc == 0 || rc == TPM2_RC_INITIALIZE)
chip->flags |= TPM_CHIP_FLAG_TPM2;
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
chip->vendor.manufacturer_id = vendor; chip->vendor.manufacturer_id = vendor;
...@@ -747,7 +747,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle, ...@@ -747,7 +747,7 @@ static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
/* Generate Interrupts */ /* Generate Interrupts */
if (chip->flags & TPM_CHIP_FLAG_TPM2) if (chip->flags & TPM_CHIP_FLAG_TPM2)
tpm2_gen_interrupt(chip, false); tpm2_gen_interrupt(chip);
else else
tpm_gen_interrupt(chip); tpm_gen_interrupt(chip);
...@@ -865,25 +865,22 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip) ...@@ -865,25 +865,22 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
static int tpm_tis_resume(struct device *dev) static int tpm_tis_resume(struct device *dev)
{ {
struct tpm_chip *chip = dev_get_drvdata(dev); struct tpm_chip *chip = dev_get_drvdata(dev);
int ret = 0; int ret;
if (chip->vendor.irq) if (chip->vendor.irq)
tpm_tis_reenable_interrupts(chip); tpm_tis_reenable_interrupts(chip);
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
/* NOP if firmware properly does this. */
tpm2_startup(chip, TPM2_SU_STATE);
ret = tpm2_shutdown(chip, TPM2_SU_STATE);
if (!ret)
ret = tpm2_do_selftest(chip);
} else {
ret = tpm_pm_resume(dev); ret = tpm_pm_resume(dev);
if (!ret) if (ret)
return ret;
/* TPM 1.2 requires self-test on resume. This function actually returns
* an error code but for unknown reason it isn't handled.
*/
if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
tpm_do_selftest(chip); tpm_do_selftest(chip);
}
return ret; return 0;
} }
#endif #endif
......
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