summaryrefslogtreecommitdiffstats
path: root/drivers/char/tpm
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2017-03-24 11:45:49 +0200
committerJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2017-04-03 22:46:02 +0300
commit877c57d0d0cac2c8fc661f708d8ee3fa7aa8d28b (patch)
tree36fcb0bf566df51a40ce092141394426800e02d0 /drivers/char/tpm
parent84d25940678b7f93665d0964c9729680fa4a97e9 (diff)
downloadop-kernel-dev-877c57d0d0cac2c8fc661f708d8ee3fa7aa8d28b.zip
op-kernel-dev-877c57d0d0cac2c8fc661f708d8ee3fa7aa8d28b.tar.gz
tpm_crb: request and relinquish locality 0
This commit adds support for requesting and relinquishing locality 0 in tpm_crb for the course of command transmission. In order to achieve this, two new callbacks are added to struct tpm_class_ops: - request_locality - relinquish_locality With CRB interface you first set either requestAccess or relinquish bit from TPM_LOC_CTRL_x register and then wait for locAssigned and tpmRegValidSts bits to be set in the TPM_LOC_STATE_x register. The reason why were are doing this is to make sure that the driver will work properly with Intel TXT that uses locality 2. There's no explicit guarantee that it would relinquish this locality. In more general sense this commit enables tpm_crb to be a well behaving citizen in a multi locality environment. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Reviewed-by: Jerry Snitselaar <jsnitsel@redhat.com> Tested-by: Jerry Snitselaar <jsnitsel@redhat.com>
Diffstat (limited to 'drivers/char/tpm')
-rw-r--r--drivers/char/tpm/tpm-chip.c1
-rw-r--r--drivers/char/tpm/tpm-interface.c16
-rw-r--r--drivers/char/tpm/tpm.h3
-rw-r--r--drivers/char/tpm/tpm_crb.c41
4 files changed, 61 insertions, 0 deletions
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index aade699..a321bd5 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -231,6 +231,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
goto out;
}
+ chip->locality = -1;
return chip;
out:
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 16abbf9..158c1db 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -389,6 +389,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
ssize_t len = 0;
u32 count, ordinal;
unsigned long stop;
+ bool need_locality;
if (!tpm_validate_command(chip, space, buf, bufsiz))
return -EINVAL;
@@ -412,6 +413,16 @@ ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
if (chip->dev.parent)
pm_runtime_get_sync(chip->dev.parent);
+ /* Store the decision as chip->locality will be changed. */
+ need_locality = chip->locality == -1;
+
+ if (need_locality && chip->ops->request_locality) {
+ rc = chip->ops->request_locality(chip, 0);
+ if (rc < 0)
+ goto out_no_locality;
+ chip->locality = rc;
+ }
+
rc = tpm2_prepare_space(chip, space, ordinal, buf);
if (rc)
goto out;
@@ -471,6 +482,11 @@ out_recv:
rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
out:
+ if (need_locality && chip->ops->relinquish_locality) {
+ chip->ops->relinquish_locality(chip, chip->locality);
+ chip->locality = -1;
+ }
+out_no_locality:
if (chip->dev.parent)
pm_runtime_put_sync(chip->dev.parent);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 5eacb3f..4b4c8de 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -228,6 +228,9 @@ struct tpm_chip {
struct tpm_space work_space;
u32 nr_commands;
u32 *cc_attrs_tbl;
+
+ /* active locality */
+ int locality;
};
#define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
index 9f31609..d91e47d 100644
--- a/drivers/char/tpm/tpm_crb.c
+++ b/drivers/char/tpm/tpm_crb.c
@@ -34,6 +34,16 @@ enum crb_defaults {
CRB_ACPI_START_INDEX = 1,
};
+enum crb_loc_ctrl {
+ CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0),
+ CRB_LOC_CTRL_RELINQUISH = BIT(1),
+};
+
+enum crb_loc_state {
+ CRB_LOC_STATE_LOC_ASSIGNED = BIT(1),
+ CRB_LOC_STATE_TPM_REG_VALID_STS = BIT(7),
+};
+
enum crb_ctrl_req {
CRB_CTRL_REQ_CMD_READY = BIT(0),
CRB_CTRL_REQ_GO_IDLE = BIT(1),
@@ -172,6 +182,35 @@ static int __maybe_unused crb_cmd_ready(struct device *dev,
return 0;
}
+static int crb_request_locality(struct tpm_chip *chip, int loc)
+{
+ struct crb_priv *priv = dev_get_drvdata(&chip->dev);
+ u32 value = CRB_LOC_STATE_LOC_ASSIGNED |
+ CRB_LOC_STATE_TPM_REG_VALID_STS;
+
+ if (!priv->regs_h)
+ return 0;
+
+ iowrite32(CRB_LOC_CTRL_REQUEST_ACCESS, &priv->regs_h->loc_ctrl);
+ if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, value, value,
+ TPM2_TIMEOUT_C)) {
+ dev_warn(&chip->dev, "TPM_LOC_STATE_x.requestAccess timed out\n");
+ return -ETIME;
+ }
+
+ return 0;
+}
+
+static void crb_relinquish_locality(struct tpm_chip *chip, int loc)
+{
+ struct crb_priv *priv = dev_get_drvdata(&chip->dev);
+
+ if (!priv->regs_h)
+ return;
+
+ iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl);
+}
+
static u8 crb_status(struct tpm_chip *chip)
{
struct crb_priv *priv = dev_get_drvdata(&chip->dev);
@@ -278,6 +317,8 @@ static const struct tpm_class_ops tpm_crb = {
.send = crb_send,
.cancel = crb_cancel,
.req_canceled = crb_req_canceled,
+ .request_locality = crb_request_locality,
+ .relinquish_locality = crb_relinquish_locality,
.req_complete_mask = CRB_DRV_STS_COMPLETE,
.req_complete_val = CRB_DRV_STS_COMPLETE,
};
OpenPOWER on IntegriCloud