Page MenuHomeFreeBSD

D59653.id187781.diff
No OneTemporary

D59653.id187781.diff

diff --git a/sys/dev/tpm/tpm.c b/sys/dev/tpm/tpm.c
--- a/sys/dev/tpm/tpm.c
+++ b/sys/dev/tpm/tpm.c
@@ -197,7 +197,10 @@
static int tpm_transmit_header(struct tpm_softc *, uint32_t, uint32_t *);
static void tpm_tis12_abort(struct tpm_softc *);
static int tpm_tis12_devid_index(uint32_t);
+static int tpm_tis12_quiesce(struct tpm_softc *);
+static void tpm_tis12_release_locality_hw(bus_space_tag_t, bus_space_handle_t);
static void tpm_tis12_relinquish_locality(struct tpm_softc *);
+static int tpm_tis12_request_locality(struct tpm_softc *, int);
static int tpm_tis12_resume(struct tpm_softc *);
@@ -217,6 +220,8 @@
{
struct make_dev_args args;
struct tpm_softc *sc;
+ rman_res_t irq_start;
+ void *intr_cookie;
int error, irq;
sc = device_get_softc(dev);
@@ -224,7 +229,10 @@
mtx_init(&sc->sc_intr_lock, "TPM interrupt lock", NULL, MTX_DEF);
cv_init(&sc->sc_intr_cv, "tpm_intr");
sc->intr_cookie = NULL;
+ sc->irq_res = NULL;
sc->sc_cdev = NULL;
+ sc->sc_vector = IRQUNK;
+ sc->sc_capabilities = 0;
sc->sc_flags = 0;
sc->sc_suspend = 0;
sc->sc_dying = false;
@@ -245,11 +253,6 @@
sc->irq_rid = 0;
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
RF_ACTIVE | RF_SHAREABLE);
- if (sc->irq_res != NULL)
- irq = rman_get_start(sc->irq_res);
- else
- irq = IRQUNK;
-
if (tpm_legacy_probe(sc->sc_bt, sc->sc_bh)) {
sc->sc_init = tpm_legacy_init;
sc->sc_start = tpm_legacy_start;
@@ -264,6 +267,24 @@
sc->sc_end = tpm_tis12_end;
}
+ irq = IRQUNK;
+ if (sc->irq_res != NULL) {
+ irq_start = rman_get_start(sc->irq_res);
+ /*
+ * The TIS path uses the resource IRQ as the LPC SIRQ selector.
+ * Parent IRQ numbers need not map directly to SIRQ channels.
+ * Validate the full resource value before narrowing and use
+ * polling for routes outside the supported range.
+ */
+ if (sc->sc_init == tpm_tis12_init &&
+ (irq_start == 0 || irq_start > 15))
+ device_printf(dev,
+ "cannot use IRQ %ju; using polling\n",
+ (uintmax_t)irq_start);
+ else
+ irq = irq_start;
+ }
+
printf("%s", device_get_name(dev));
sx_xlock(&sc->sc_lock);
error = sc->sc_init(sc, irq, "tpm");
@@ -273,12 +294,24 @@
goto fail;
}
- if (sc->sc_init == tpm_tis12_init && sc->irq_res != NULL &&
- bus_setup_intr(dev, sc->irq_res, INTR_TYPE_TTY | INTR_MPSAFE, NULL,
- tpm_intr, sc, &sc->intr_cookie) != 0) {
- printf(": cannot establish interrupt\n");
- error = ENXIO;
- goto fail;
+ if (sc->sc_init == tpm_tis12_init && sc->irq_res != NULL) {
+ if (sc->sc_vector == IRQUNK) {
+ if (bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
+ sc->irq_res) == 0)
+ sc->irq_res = NULL;
+ } else {
+ /* Failed setup may leave a stale output cookie. */
+ intr_cookie = NULL;
+ error = bus_setup_intr(dev, sc->irq_res,
+ INTR_TYPE_TTY | INTR_MPSAFE, NULL, tpm_intr, sc,
+ &intr_cookie);
+ if (error != 0) {
+ printf(": cannot establish interrupt\n");
+ error = ENXIO;
+ goto fail;
+ }
+ sc->intr_cookie = intr_cookie;
+ }
}
make_dev_args_init(&args);
@@ -318,8 +351,13 @@
sc->sc_cdev = NULL;
}
sx_xlock(&sc->sc_lock);
- if (sc->mem_res != NULL && sc->sc_init == tpm_tis12_init)
+ if (sc->mem_res != NULL && sc->sc_init == tpm_tis12_init) {
+ /* Identified TIS devices may enable delivery while polling. */
+ if (sc->sc_capabilities != 0 && tpm_tis12_quiesce(sc) != 0)
+ device_printf(dev,
+ "failed to quiesce TPM interrupts during detach\n");
tpm_tis12_abort(sc);
+ }
sx_xunlock(&sc->sc_lock);
if (sc->intr_cookie != NULL) {
bus_teardown_intr(dev, sc->irq_res, sc->intr_cookie);
@@ -348,7 +386,7 @@
{
u_int32_t r;
u_int8_t reg;
- bool acquired;
+ bool requested;
int to;
r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
@@ -367,20 +405,21 @@
}
reg = bus_space_read_1(bt, bh, TPM_ACCESS);
- acquired = false;
+ requested = false;
if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
+ requested = true;
bus_space_write_1(bt, bh, TPM_ACCESS,
TPM_ACCESS_REQUEST_USE);
+ bus_space_barrier(bt, bh, TPM_ACCESS, 1,
+ BUS_SPACE_BARRIER_WRITE);
to = TPM_ACCESS_TMO; /* Steps of one millisecond. */
do {
reg = bus_space_read_1(bt, bh, TPM_ACCESS);
if ((reg & (TPM_ACCESS_VALID |
TPM_ACCESS_ACTIVE_LOCALITY)) ==
- (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
- acquired = true;
+ (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
break;
- }
DELAY(1000);
} while (--to != 0);
}
@@ -390,12 +429,49 @@
r = bus_space_read_4(bt, bh, TPM_ID);
else
r = UINT32_MAX;
- if (acquired)
- bus_space_write_1(bt, bh, TPM_ACCESS,
- TPM_ACCESS_ACTIVE_LOCALITY);
+ if (requested)
+ tpm_tis12_release_locality_hw(bt, bh);
return (r != UINT32_MAX);
}
+/* Leave delivery disabled, preserving any locality owned by the caller. */
+static int
+tpm_tis12_quiesce(struct tpm_softc *sc)
+{
+ uint32_t reg;
+ bool release;
+ int error;
+
+ sx_assert(&sc->sc_lock, SA_XLOCKED);
+ release = !sc->sc_locality;
+ if (release) {
+ error = tpm_tis12_request_locality(sc, 0);
+ if (error != 0) {
+ /* This register can be read without owning locality. */
+ reg = bus_space_read_4(sc->sc_bt, sc->sc_bh,
+ TPM_INTERRUPT_ENABLE);
+ return ((reg & TPM_GLOBAL_INT_ENABLE) == 0 ? 0 : error);
+ }
+ }
+
+ mtx_lock(&sc->sc_intr_lock);
+ reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
+ reg & ~TPM_GLOBAL_INT_ENABLE);
+ bus_space_barrier(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, 4,
+ BUS_SPACE_BARRIER_WRITE);
+ reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
+ error = (reg & TPM_GLOBAL_INT_ENABLE) != 0 ? EIO : 0;
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
+ bus_space_barrier(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, 4,
+ BUS_SPACE_BARRIER_WRITE);
+ mtx_unlock(&sc->sc_intr_lock);
+ if (release)
+ tpm_tis12_relinquish_locality(sc);
+ return (error);
+}
+
/*
* Setup the interrupt vector if one is provided and interrupts are known
* to work on that particular chip. The caller must hold locality zero.
@@ -404,18 +480,16 @@
tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
{
u_int32_t r;
+ int error;
sx_assert(&sc->sc_lock, SA_XLOCKED);
- mtx_lock(&sc->sc_intr_lock);
-
- /* Ack and disable all interrupts. */
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
- ~TPM_GLOBAL_INT_ENABLE);
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
+ KASSERT(sc->sc_locality, ("%s: locality not owned", __func__));
+ error = tpm_tis12_quiesce(sc);
+ if (error != 0)
+ return (error);
- if ((irq == IRQUNK) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
+ mtx_lock(&sc->sc_intr_lock);
+ if (irq < 1 || irq > 15 || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
sc->sc_vector = IRQUNK;
mtx_unlock(&sc->sc_intr_lock);
return (0);
@@ -478,13 +552,16 @@
else
printf(": device 0x%08x rev 0x%x\n", sc->sc_devid, sc->sc_rev);
- error = tpm_request_locality(sc, 0);
+ error = tpm_tis12_request_locality(sc, 0);
if (error != 0)
return 1;
error = tpm_tis12_irqinit(sc, irq, i);
- if (error != 0)
+ if (error != 0) {
+ printf("%s: failed to quiesce interrupts during attach: %d\n",
+ name, error);
goto out;
+ }
/* Abort whatever it thought it was doing. */
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
@@ -517,7 +594,7 @@
sc->sc_capabilities = capabilities;
i = tpm_tis12_devid_index(devid);
irq = sc->sc_vector;
- error = tpm_request_locality(sc, 0);
+ error = tpm_tis12_request_locality(sc, 0);
if (error != 0)
return (error);
error = tpm_tis12_irqinit(sc, irq, i);
@@ -537,12 +614,21 @@
int
tpm_request_locality(struct tpm_softc *sc, int l)
{
- u_int32_t r;
- int to, rv;
sx_assert(&sc->sc_lock, SA_XLOCKED);
if (l != 0)
return EINVAL;
+ return (tpm_tis12_request_locality(sc, PCATCH));
+}
+
+/* Lifecycle callers wait through signals; command callers pass PCATCH. */
+static int
+tpm_tis12_request_locality(struct tpm_softc *sc, int flags)
+{
+ u_int32_t r;
+ int to, rv;
+
+ sx_assert(&sc->sc_lock, SA_XLOCKED);
KASSERT(!sc->sc_locality, ("%s: locality already owned", __func__));
if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
@@ -555,25 +641,21 @@
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
TPM_ACCESS_REQUEST_USE);
+ bus_space_barrier(sc->sc_bt, sc->sc_bh, TPM_ACCESS, 1,
+ BUS_SPACE_BARRIER_WRITE);
to = tpm_tmotohz(TPM_ACCESS_TMO);
while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
- rv = pause_sig("tpm_locality", 1);
+ rv = pause_sbt("tpm_locality", tick_sbt, 0,
+ C_HARDCLOCK | ((flags & PCATCH) != 0 ? C_CATCH : 0));
if (rv && rv != EWOULDBLOCK) {
#ifdef TPM_DEBUG
printf("tpm_request_locality: interrupted %d\n", rv);
#endif
- r = bus_space_read_1(sc->sc_bt, sc->sc_bh,
- TPM_ACCESS);
- if ((r & (TPM_ACCESS_VALID |
- TPM_ACCESS_ACTIVE_LOCALITY)) ==
- (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
- sc->sc_locality = true;
- tpm_tis12_relinquish_locality(sc);
- }
+ tpm_tis12_release_locality_hw(sc->sc_bt, sc->sc_bh);
return rv;
}
}
@@ -583,6 +665,7 @@
#ifdef TPM_DEBUG
printf("tpm_request_locality: access %b\n", r, TPM_ACCESS_BITS);
#endif
+ tpm_tis12_release_locality_hw(sc->sc_bt, sc->sc_bh);
return EBUSY;
}
@@ -590,6 +673,16 @@
return 0;
}
+/* Release an active locality or cancel a request that has not been granted. */
+static void
+tpm_tis12_release_locality_hw(bus_space_tag_t bt, bus_space_handle_t bh)
+{
+
+ bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_ACTIVE_LOCALITY);
+ bus_space_barrier(bt, bh, TPM_ACCESS, 1, BUS_SPACE_BARRIER_WRITE);
+}
+
+/* Release the driver's locality and clear its associated command state. */
static void
tpm_tis12_relinquish_locality(struct tpm_softc *sc)
{
@@ -598,8 +691,7 @@
sc->sc_command_pending = false;
if (!sc->sc_locality)
return;
- bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
- TPM_ACCESS_ACTIVE_LOCALITY);
+ tpm_tis12_release_locality_hw(sc->sc_bt, sc->sc_bh);
sc->sc_locality = false;
}
@@ -912,7 +1004,7 @@
* really long. The other TPM_STS* are not needed very often
* so we do not support them.
*/
- if (sc->sc_vector != IRQUNK) {
+ if (sc->sc_vector != IRQUNK && sc->intr_cookie != NULL) {
b = b0;
/*

File Metadata

Mime Type
text/plain
Expires
Sat, Oct 3, 8:37 PM (10 h, 36 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39767810
Default Alt Text
D59653.id187781.diff (10 KB)

Event Timeline