Page MenuHomeFreeBSD

D59241.1794381715.diff
No OneTemporary

Authored By
Unknown
Size
8 KB
Referenced Files
None
Subscribers
None

D59241.1794381715.diff

Index: sys/dev/tpm/tpm20.h
===================================================================
--- sys/dev/tpm/tpm20.h
+++ sys/dev/tpm/tpm20.h
@@ -40,8 +40,10 @@
#include <sys/bus.h>
#include <sys/callout.h>
#include <sys/conf.h>
+#include <sys/condvar.h>
#include <sys/lock.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/rman.h>
#include <sys/sx.h>
#include <sys/taskqueue.h>
@@ -121,10 +123,14 @@
struct cdev *sc_cdev;
+ /* Serialize commands and lifecycle; intr_lock nests inside. */
struct sx dev_lock;
+ struct mtx intr_lock;
+ struct cv intr_cv;
void *intr_cookie;
int intr_type; /* Current event type */
+ uint32_t intr_generation;
uint32_t intr_mask; /* Saved TIS interrupt configuration */
bool interrupts;
bool common_initialized;
Index: sys/dev/tpm/tpm_tis_core.c
===================================================================
--- sys/dev/tpm/tpm_tis_core.c
+++ sys/dev/tpm/tpm_tis_core.c
@@ -89,8 +89,9 @@
static void tpmtis_relinquish_locality(struct tpm_sc *sc);
static bool tpmtis_go_ready(struct tpm_sc *sc);
-static bool tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off,
- uint32_t mask, uint32_t val, int32_t timeout);
+static bool tpm_wait_for_reg(struct tpm_sc *sc, bus_size_t off,
+ uint32_t mask, uint32_t val, int32_t timeout, int intr_type,
+ bool reg32);
static uint16_t tpmtis_wait_for_burst(struct tpm_sc *sc);
@@ -104,8 +105,11 @@
sc = device_get_softc(dev);
sc->dev = dev;
sc->intr_type = -1;
+ sc->intr_generation = 0;
sx_init(&sc->dev_lock, "TPM driver lock");
+ mtx_init(&sc->intr_lock, "TPM interrupt lock", NULL, MTX_DEF);
+ cv_init(&sc->intr_cv, "tpmtis_intr");
resource_int_value("tpm", device_get_unit(dev), "use_polling", &poll);
if (poll != 0) {
@@ -148,6 +152,8 @@
if (sc->intr_cookie != NULL)
bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
+ cv_destroy(&sc->intr_cv);
+ mtx_destroy(&sc->intr_lock);
if (sc->irq_res != NULL)
bus_release_resource(dev, SYS_RES_IRQ,
@@ -240,7 +246,10 @@
{
bool configured, enable;
+ mtx_lock(&sc->intr_lock);
sc->interrupts = false;
+ sc->intr_type = -1;
+ mtx_unlock(&sc->intr_lock);
enable = sc->intr_cookie != NULL;
sx_xlock(&sc->dev_lock);
configured = tpmtis_program_intr(sc, enable);
@@ -258,6 +267,7 @@
sc = device_get_softc(dev);
sx_xlock(&sc->dev_lock);
+ mtx_lock(&sc->intr_lock);
restore_intr = sc->interrupts;
/*
@@ -266,6 +276,8 @@
* observed by the handler.
*/
sc->interrupts = false;
+ sc->intr_type = -1;
+ mtx_unlock(&sc->intr_lock);
if (!tpmtis_program_intr(sc, restore_intr))
device_printf(dev,
"failed to %s interrupts; using polling\n",
@@ -286,40 +298,74 @@
TPM_WRITE_4(sc->dev, TPM_INT_STS, status);
+ mtx_lock(&sc->intr_lock);
/* Check for stray interrupts. */
- if (sc->intr_type == -1 || (sc->intr_type & status) == 0)
- return;
+ if (sc->intr_type != -1 && (sc->intr_type & status) != 0) {
+ sc->interrupts = true;
+ sc->intr_generation++;
+ cv_broadcast(&sc->intr_cv);
+ }
+ mtx_unlock(&sc->intr_lock);
+}
+
+static uint32_t
+tpmtis_read_wait_reg(struct tpm_sc *sc, bus_size_t off, bool reg32)
+{
- sc->interrupts = true;
- wakeup(sc);
+ if (reg32)
+ return (TPM_READ_4(sc->dev, off));
+ return (TPM_READ_1(sc->dev, off));
}
static bool
-tpm_wait_for_u32(struct tpm_sc *sc, bus_size_t off, uint32_t mask, uint32_t val,
- int32_t timeout)
+tpm_wait_for_reg(struct tpm_sc *sc, bus_size_t off, uint32_t mask,
+ uint32_t val, int32_t timeout, int intr_type, bool reg32)
{
+ sbintime_t deadline;
+ uint32_t generation;
+ bool interrupts, result;
- /* Check for condition */
- if ((TPM_READ_4(sc->dev, off) & mask) == val)
- return (true);
-
- /* If interrupts are enabled sleep for timeout duration */
- if(sc->interrupts && sc->intr_type != -1) {
- tsleep(sc, PWAIT, "TPM WITH INTERRUPTS", timeout / tick);
+ sx_assert(&sc->dev_lock, SA_XLOCKED);
+ deadline = sbinuptime() + ustosbt(timeout);
+ mtx_lock(&sc->intr_lock);
+ sc->intr_type = intr_type;
+ generation = sc->intr_generation;
+ interrupts = sc->interrupts;
+ mtx_unlock(&sc->intr_lock);
+
+ for (;;) {
+ result = (tpmtis_read_wait_reg(sc, off, reg32) & mask) == val;
+ if (result)
+ break;
+ if (sbinuptime() >= deadline)
+ break;
+ if (!interrupts) {
+ pause("TPM POLLING", 1);
+ mtx_lock(&sc->intr_lock);
+ generation = sc->intr_generation;
+ interrupts = sc->interrupts;
+ mtx_unlock(&sc->intr_lock);
+ continue;
+ }
- sc->intr_type = -1;
- return ((TPM_READ_4(sc->dev, off) & mask) == val);
+ /*
+ * Register access may sleep for a SPI TPM, so evaluate the
+ * predicate without intr_lock. The generation check closes the
+ * resulting window before cv_timedwait_sbt() atomically sleeps.
+ */
+ mtx_lock(&sc->intr_lock);
+ if (generation == sc->intr_generation)
+ (void)cv_timedwait_sbt(&sc->intr_cv, &sc->intr_lock,
+ deadline, 0, C_ABSOLUTE | C_HARDCLOCK);
+ generation = sc->intr_generation;
+ interrupts = sc->interrupts;
+ mtx_unlock(&sc->intr_lock);
}
- /* If we don't have interrupts poll the device every tick */
- while (timeout > 0) {
- if ((TPM_READ_4(sc->dev, off) & mask) == val)
- return (true);
-
- pause("TPM POLLING", 1);
- timeout -= tick;
- }
- return (false);
+ mtx_lock(&sc->intr_lock);
+ sc->intr_type = -1;
+ mtx_unlock(&sc->intr_lock);
+ return (result);
}
static uint16_t
@@ -385,44 +431,36 @@
tpmtis_request_locality(struct tpm_sc *sc, int locality)
{
uint8_t mask;
- int timeout;
+ sx_assert(&sc->dev_lock, SA_XLOCKED);
/* Currently we only support Locality 0 */
if (locality != 0)
return (false);
mask = TPM_ACCESS_LOC_ACTIVE | TPM_ACCESS_VALID;
- timeout = TPM_TIMEOUT_A;
- sc->intr_type = TPM_INT_STS_LOC_CHANGE;
TPM_WRITE_1(sc->dev, TPM_ACCESS, TPM_ACCESS_LOC_REQ);
TPM_WRITE_BARRIER(sc->dev, TPM_ACCESS, 1);
- if(sc->interrupts) {
- tsleep(sc, PWAIT, "TPMLOCREQUEST with INTR", timeout / tick);
- return ((TPM_READ_1(sc->dev, TPM_ACCESS) & mask) == mask);
- } else {
- while(timeout > 0) {
- if ((TPM_READ_1(sc->dev, TPM_ACCESS) & mask) == mask)
- return (true);
-
- pause("TPMLOCREQUEST POLLING", 1);
- timeout -= tick;
- }
- }
-
- return (false);
+ return (tpm_wait_for_reg(sc, TPM_ACCESS, mask, mask, TPM_TIMEOUT_A,
+ TPM_INT_STS_LOC_CHANGE, false));
}
static void
tpmtis_relinquish_locality(struct tpm_sc *sc)
{
+ bool interrupts;
+ sx_assert(&sc->dev_lock, SA_XLOCKED);
/*
* Interrupts can only be cleared when a locality is active.
* Clear them now in case interrupt handler didn't make it in time.
*/
- if(sc->interrupts)
- AND4(sc, TPM_INT_STS, TPM_READ_4(sc->dev, TPM_INT_STS));
+ mtx_lock(&sc->intr_lock);
+ interrupts = sc->interrupts;
+ mtx_unlock(&sc->intr_lock);
+ if (interrupts)
+ TPM_WRITE_4(sc->dev, TPM_INT_STS,
+ TPM_READ_4(sc->dev, TPM_INT_STS));
OR1(sc, TPM_ACCESS, TPM_ACCESS_LOC_RELINQUISH);
}
@@ -433,11 +471,11 @@
uint32_t mask;
mask = TPM_STS_CMD_RDY;
- sc->intr_type = TPM_INT_STS_CMD_RDY;
TPM_WRITE_4(sc->dev, TPM_STS, TPM_STS_CMD_RDY);
TPM_WRITE_BARRIER(sc->dev, TPM_STS, 4);
- if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_B))
+ if (!tpm_wait_for_reg(sc, TPM_STS, mask, mask, TPM_TIMEOUT_B,
+ TPM_INT_STS_CMD_RDY, true))
return (false);
return (true);
@@ -471,8 +509,8 @@
}
mask = TPM_STS_VALID;
- sc->intr_type = TPM_INT_STS_VALID;
- if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C)) {
+ if (!tpm_wait_for_reg(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C,
+ TPM_INT_STS_VALID, true)) {
device_printf(dev,
"Timeout while waiting for valid bit\n");
return (EIO);
@@ -495,8 +533,8 @@
TPM_WRITE_BARRIER(dev, TPM_STS, 4);
mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID;
- sc->intr_type = TPM_INT_STS_DATA_AVAIL;
- if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, timeout)) {
+ if (!tpm_wait_for_reg(sc, TPM_STS, mask, mask, timeout,
+ TPM_INT_STS_DATA_AVAIL, true)) {
device_printf(dev,
"Timeout while waiting for device to process cmd\n");
/*
@@ -510,8 +548,8 @@
* After canceling a command we should get a response,
* check if there is one.
*/
- sc->intr_type = TPM_INT_STS_DATA_AVAIL;
- if (!tpm_wait_for_u32(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C))
+ if (!tpm_wait_for_reg(sc, TPM_STS, mask, mask, TPM_TIMEOUT_C,
+ TPM_INT_STS_DATA_AVAIL, true))
return (EIO);
}
/* Read response header. Length is passed in bytes 2 - 6. */

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 11, 7:21 AM (16 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41656000
Default Alt Text
D59241.1794381715.diff (8 KB)

Event Timeline