Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+63 -1
+1
drivers/char/tpm/tpm-chip.c
··· 231 231 goto out; 232 232 } 233 233 234 + chip->locality = -1; 234 235 return chip; 235 236 236 237 out:
+16
drivers/char/tpm/tpm-interface.c
··· 389 389 ssize_t len = 0; 390 390 u32 count, ordinal; 391 391 unsigned long stop; 392 + bool need_locality; 392 393 393 394 if (!tpm_validate_command(chip, space, buf, bufsiz)) 394 395 return -EINVAL; ··· 412 411 413 412 if (chip->dev.parent) 414 413 pm_runtime_get_sync(chip->dev.parent); 414 + 415 + /* Store the decision as chip->locality will be changed. */ 416 + need_locality = chip->locality == -1; 417 + 418 + if (need_locality && chip->ops->request_locality) { 419 + rc = chip->ops->request_locality(chip, 0); 420 + if (rc < 0) 421 + goto out_no_locality; 422 + chip->locality = rc; 423 + } 415 424 416 425 rc = tpm2_prepare_space(chip, space, ordinal, buf); 417 426 if (rc) ··· 482 471 rc = tpm2_commit_space(chip, space, ordinal, buf, &len); 483 472 484 473 out: 474 + if (need_locality && chip->ops->relinquish_locality) { 475 + chip->ops->relinquish_locality(chip, chip->locality); 476 + chip->locality = -1; 477 + } 478 + out_no_locality: 485 479 if (chip->dev.parent) 486 480 pm_runtime_put_sync(chip->dev.parent); 487 481
+3
drivers/char/tpm/tpm.h
··· 228 228 struct tpm_space work_space; 229 229 u32 nr_commands; 230 230 u32 *cc_attrs_tbl; 231 + 232 + /* active locality */ 233 + int locality; 231 234 }; 232 235 233 236 #define to_tpm_chip(d) container_of(d, struct tpm_chip, dev)
+41
drivers/char/tpm/tpm_crb.c
··· 34 34 CRB_ACPI_START_INDEX = 1, 35 35 }; 36 36 37 + enum crb_loc_ctrl { 38 + CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0), 39 + CRB_LOC_CTRL_RELINQUISH = BIT(1), 40 + }; 41 + 42 + enum crb_loc_state { 43 + CRB_LOC_STATE_LOC_ASSIGNED = BIT(1), 44 + CRB_LOC_STATE_TPM_REG_VALID_STS = BIT(7), 45 + }; 46 + 37 47 enum crb_ctrl_req { 38 48 CRB_CTRL_REQ_CMD_READY = BIT(0), 39 49 CRB_CTRL_REQ_GO_IDLE = BIT(1), ··· 182 172 return 0; 183 173 } 184 174 175 + static int crb_request_locality(struct tpm_chip *chip, int loc) 176 + { 177 + struct crb_priv *priv = dev_get_drvdata(&chip->dev); 178 + u32 value = CRB_LOC_STATE_LOC_ASSIGNED | 179 + CRB_LOC_STATE_TPM_REG_VALID_STS; 180 + 181 + if (!priv->regs_h) 182 + return 0; 183 + 184 + iowrite32(CRB_LOC_CTRL_REQUEST_ACCESS, &priv->regs_h->loc_ctrl); 185 + if (!crb_wait_for_reg_32(&priv->regs_h->loc_state, value, value, 186 + TPM2_TIMEOUT_C)) { 187 + dev_warn(&chip->dev, "TPM_LOC_STATE_x.requestAccess timed out\n"); 188 + return -ETIME; 189 + } 190 + 191 + return 0; 192 + } 193 + 194 + static void crb_relinquish_locality(struct tpm_chip *chip, int loc) 195 + { 196 + struct crb_priv *priv = dev_get_drvdata(&chip->dev); 197 + 198 + if (!priv->regs_h) 199 + return; 200 + 201 + iowrite32(CRB_LOC_CTRL_RELINQUISH, &priv->regs_h->loc_ctrl); 202 + } 203 + 185 204 static u8 crb_status(struct tpm_chip *chip) 186 205 { 187 206 struct crb_priv *priv = dev_get_drvdata(&chip->dev); ··· 317 278 .send = crb_send, 318 279 .cancel = crb_cancel, 319 280 .req_canceled = crb_req_canceled, 281 + .request_locality = crb_request_locality, 282 + .relinquish_locality = crb_relinquish_locality, 320 283 .req_complete_mask = CRB_DRV_STS_COMPLETE, 321 284 .req_complete_val = CRB_DRV_STS_COMPLETE, 322 285 };
+2 -1
include/linux/tpm.h
··· 48 48 u8 (*status) (struct tpm_chip *chip); 49 49 bool (*update_timeouts)(struct tpm_chip *chip, 50 50 unsigned long *timeout_cap); 51 - 51 + int (*request_locality)(struct tpm_chip *chip, int loc); 52 + void (*relinquish_locality)(struct tpm_chip *chip, int loc); 52 53 }; 53 54 54 55 #if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)