aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOlivier Cochard <olivier@FreeBSD.org>2026-11-04 21:05:22 +0000
committerOlivier Cochard <olivier@FreeBSD.org>2026-11-05 19:51:20 +0000
commitbfe4be85a9354b92135e105028f2e1b3e0307ada (patch)
treebe840cbb1e5bf5161cab5a62655d45ee62d62c30
parent843cb77850d991c349fd384fee6402b6af5d7f74 (diff)
tpm_crb: wait for idle and locality release after each command
transmit only requested GO_IDLE and the locality release, so a back-to-back command could see stale state and fail with EIO. A post-send idle timeout no longer discards a completed response. Reviewed by: kbowling Approved by: kbowling Differential Revision: https://ron-dev.freebsd.org/FreeBSD/src/pulls/93
-rw-r--r--sys/dev/tpm/tpm_crb.c39
1 files changed, 32 insertions, 7 deletions
diff --git a/sys/dev/tpm/tpm_crb.c b/sys/dev/tpm/tpm_crb.c
index df47f88f79fd..4e6f550e473c 100644
--- a/sys/dev/tpm/tpm_crb.c
+++ b/sys/dev/tpm/tpm_crb.c
@@ -552,10 +552,33 @@ tpmcrb_request_locality(struct tpmcrb_sc *crb_sc, int locality)
static void
tpmcrb_relinquish_locality(struct tpmcrb_sc *crb_sc)
{
+ struct resource *res = crb_sc->base.mem_res;
+ uint32_t mask;
+ int timeout;
- if (crb_sc->has_locality)
- bus_write_4(crb_sc->base.mem_res, TPM_LOC_CTRL,
- TPM_LOC_CTRL_RELINQUISH);
+ if (!crb_sc->has_locality)
+ return;
+
+ /* PTP 1.07, Table 37: the other fields mean something only if valid. */
+ mask = TPM_LOC_STATE_VALID | TPM_LOC_STATE_ASSIGNED;
+
+ bus_write_4(res, TPM_LOC_CTRL, TPM_LOC_CTRL_RELINQUISH);
+
+ /*
+ * Wait for the TPM to act on the request. Otherwise a following
+ * tpmcrb_request_locality() can see the stale assignment and proceed
+ * just before the locality goes away. Read once more after the last
+ * pause so a release during it is not reported as a failure.
+ */
+ for (timeout = TPM_TIMEOUT_C;; timeout -= tick) {
+ if ((bus_read_4(res, TPM_LOC_STATE) & mask) ==
+ TPM_LOC_STATE_VALID)
+ return;
+ if (timeout <= 0)
+ break;
+ pause("TPM locality", 1);
+ }
+ device_printf(crb_sc->base.dev, "Failed to relinquish locality\n");
}
static bool
@@ -783,12 +806,14 @@ out:
(tpmcrb_ctrl_read_4(crb_sc, TPM_CRB_CTRL_START) &
TPM_CRB_CTRL_START_CMD) != 0)
(void)tpmcrb_cancel_cmd(crb_sc);
- if (!tpmcrb_state_idle(crb_sc, false)) {
+ /*
+ * Let the TPM finish going idle before giving up the locality.
+ * The next transmit requests idle again if needed, so a timeout
+ * here must not discard the response of a completed command.
+ */
+ if (!tpmcrb_state_idle(crb_sc, true))
device_printf(dev,
"Failed to transition to idle state post-send\n");
- if (error == 0)
- error = EIO;
- }
tpmcrb_relinquish_locality(crb_sc);
}