/* Finish transaction. */ int tpm_tis12_end(struct tpm_softc *sc, int flag, int err) { int rv = 0; if (flag == UIO_READ) { if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read))) return rv; /* Still more data? */ sc->sc_stat = tpm_status(sc); if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL) == TPM_STS_DATA_AVAIL)) { #ifdef TPM_DEBUG char buf[128]; snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); aprint_debug_dev(sc->sc_dev, "%s: read failed stat=%s\n", __func__, buf); #endif rv = EIO; } bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); /* Release our (0th) locality. */ bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS, TPM_ACCESS_ACTIVE_LOCALITY); } else { /* Hungry for more? */ sc->sc_stat = tpm_status(sc); if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) { #ifdef TPM_DEBUG char buf[128]; snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); aprint_debug_dev(sc->sc_dev, "%s: write failed stat=%s\n", __func__, buf); #endif rv = EIO; } bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, err ? TPM_STS_CMD_READY : TPM_STS_GO); } return rv; }
int tpm_tis12_write(struct tpm_softc *sc, void *buf, int len) { u_int8_t *p = buf; size_t cnt; int rv, r; #ifdef TPM_DEBUG printf("tpm_tis12_write: sc %p buf %p len %d\n", sc, buf, len); #endif if ((rv = tpm_request_locality(sc, 0)) != 0) return rv; cnt = 0; while (cnt < len - 1) { for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) { bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); cnt++; } if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { #ifdef TPM_DEBUG printf("tpm_tis12_write: failed burst rv %d\n", rv); #endif return rv; } sc->sc_stat = tpm_status(sc); if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) { #ifdef TPM_DEBUG printf("tpm_tis12_write: failed rv %d stat=%b\n", rv, sc->sc_stat, TPM_STS_BITS); #endif return EIO; } } bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); cnt++; if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { #ifdef TPM_DEBUG printf("tpm_tis12_write: failed last byte rv %d\n", rv); #endif return rv; } if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) { #ifdef TPM_DEBUG printf("tpm_tis12_write: failed rv %d stat=%b\n", rv, sc->sc_stat, TPM_STS_BITS); #endif return EIO; } #ifdef TPM_DEBUG printf("tpm_tis12_write: wrote %d byte\n", cnt); #endif return 0; }
/* Start transaction. */ int tpm_tis12_start(struct tpm_softc *sc, int flag) { int rv; if (flag == UIO_READ) { rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, TPM_READ_TMO, sc->sc_read); return rv; } /* Own our (0th) locality. */ if ((rv = tpm_request_locality(sc, 0)) != 0) return rv; sc->sc_stat = tpm_status(sc); if (sc->sc_stat & TPM_STS_CMD_READY) { #ifdef TPM_DEBUG char buf[128]; snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat); aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE status %s\n", __func__, buf); #endif return 0; } #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE readying chip\n", __func__); #endif /* Abort previous and restart. */ bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write))) { #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE readying failed %d\n", __func__, rv); #endif return rv; } #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE readying done\n", __func__); #endif return 0; }
/* Start transaction. */ int tpm_tis12_start(struct tpm_softc *sc, int flag) { int rv; if (flag == UIO_READ) { rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID, TPM_READ_TMO, sc->sc_read); return rv; } /* Own our (0th) locality. */ if ((rv = tpm_request_locality(sc, 0)) != 0) return rv; sc->sc_stat = tpm_status(sc); if (sc->sc_stat & TPM_STS_CMD_READY) { #ifdef TPM_DEBUG printf("tpm_tis12_start: UIO_WRITE status %b\n", sc->sc_stat, TPM_STS_BITS); #endif return 0; } #ifdef TPM_DEBUG printf("tpm_tis12_start: UIO_WRITE readying chip\n"); #endif /* Abort previous and restart. */ bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY); if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write))) { #ifdef TPM_DEBUG printf("tpm_tis12_start: UIO_WRITE readying failed %d\n", rv); #endif return rv; } #ifdef TPM_DEBUG printf("tpm_tis12_start: UIO_WRITE readying done\n"); #endif return 0; }
/* Wait for given status bits using polling. */ int tpm_waitfor_poll(struct tpm_softc *sc, u_int8_t mask, int tmo, void *c) { int rv; /* * Poll until either the requested condition or a time out is * met. */ while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) { rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1); if (rv && rv != EWOULDBLOCK) { #ifdef TPM_DEBUG printf("tpm_waitfor_poll: interrupted %d\n", rv); #endif return rv; } } return 0; }
/* Wait for given status bits using interrupts. */ int tpm_waitfor_int(struct tpm_softc *sc, u_int8_t mask, int tmo, void *c, int inttype) { int rv, to; /* Poll and return when condition is already met. */ sc->sc_stat = tpm_status(sc); if ((sc->sc_stat & mask) == mask) return 0; /* * Enable interrupt on tpm chip. Note that interrupts on our * level (SPL_TTY) are disabled (see tpm{read,write} et al) and * will not be delivered to the cpu until we call tsleep(9) below. */ 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) | inttype); 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); /* * Poll once more to remedy the race between previous polling * and enabling interrupts on the tpm chip. */ sc->sc_stat = tpm_status(sc); if ((sc->sc_stat & mask) == mask) { rv = 0; goto out; } to = tpm_tmotohz(tmo); #ifdef TPM_DEBUG printf("tpm_waitfor_int: sleeping for %d ticks on %p\n", to, c); #endif /* * tsleep(9) enables interrupts on the cpu and returns after * wake up with interrupts disabled again. Note that interrupts * generated by the tpm chip while being at SPL_TTY are not lost * but held and delivered as soon as the cpu goes below SPL_TTY. */ rv = tsleep(c, PRIBIO | PCATCH, "tpm_intr", to); sc->sc_stat = tpm_status(sc); #ifdef TPM_DEBUG printf("tpm_waitfor_int: woke up with rv %d stat %b\n", rv, sc->sc_stat, TPM_STS_BITS); #endif if ((sc->sc_stat & mask) == mask) rv = 0; /* Disable interrupts on tpm chip again. */ out: 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_INTERRUPT_ENABLE, bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) & ~inttype); return rv; }
int tpm_tis12_write(struct tpm_softc *sc, const void *buf, size_t len) { const uint8_t *p = buf; size_t cnt; int rv, r; #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: sc %p buf %p len %zu\n", __func__, sc, buf, len); #endif if (len == 0) return 0; if ((rv = tpm_request_locality(sc, 0)) != 0) return rv; cnt = 0; while (cnt < len - 1) { for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) { bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); cnt++; } if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: failed burst rv %d\n", __func__, rv); #endif return rv; } sc->sc_stat = tpm_status(sc); if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) { #ifdef TPM_DEBUG char sbuf[128]; snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat); aprint_debug_dev(sc->sc_dev, "%s: failed rv %d stat=%s\n", __func__, rv, sbuf); #endif return EIO; } } bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++); cnt++; if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) { #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: failed last byte rv %d\n", __func__, rv); #endif return rv; } if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) { #ifdef TPM_DEBUG char sbuf[128]; snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat); aprint_debug_dev(sc->sc_dev, "%s: failed rv %d stat=%s\n", __func__, rv, sbuf); #endif return EIO; } #ifdef TPM_DEBUG aprint_debug_dev(sc->sc_dev, "%s: wrote %zu byte\n", __func__, cnt); #endif return 0; }