예제 #1
0
파일: tpm.c 프로젝트: ele7enxxh/dtrace-pf
int
tpm_getburst(struct tpm_softc *sc)
{
	int burst, to, rv;

	to = tpm_tmotohz(TPM_BURST_TMO);

	burst = 0;
	while (burst == 0 && to--) {
		/*
		 * Burst count has to be read from bits 8 to 23 without
		 * touching any other bits, eg. the actual status bits 0
		 * to 7.
		 */
		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
		burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2)
		    << 8;
#ifdef TPM_DEBUG
		printf("tpm_getburst: read %d\n", burst);
#endif
		if (burst)
			return burst;

		rv = tsleep(sc, PRIBIO | PCATCH, "tpm_getburst", 1);
		if (rv && rv != EWOULDBLOCK) {
			return 0;
		}
	}

	return 0;
}
예제 #2
0
int
tpm_request_locality(struct tpm_softc *sc, int l)
{
	uint32_t r;
	int to, rv;

	if (l != 0)
		return EINVAL;

	if ((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))
		return 0;

	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
	    TPM_ACCESS_REQUEST_USE);

	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 = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
		if (rv &&  rv != EWOULDBLOCK) {
#ifdef TPM_DEBUG
			aprint_debug_dev(sc->sc_dev, "%s: interrupted %d\n",
			    __func__, rv);
#endif
			return rv;
		}
	}

	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
#ifdef TPM_DEBUG
		char buf[128];
		snprintb(buf, sizeof(buf), TPM_ACCESS_BITS, r);
		aprint_debug_dev(sc->sc_dev, "%s: access %s\n", __func__, buf);
#endif
		return EBUSY;
	}

	return 0;
}
예제 #3
0
파일: tpm.c 프로젝트: ele7enxxh/dtrace-pf
int
tpm_request_locality(struct tpm_softc *sc, int l)
{
	u_int32_t r;
	int to, rv;

	if (l != 0)
		return EINVAL;

	if ((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))
		return 0;

	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
	    TPM_ACCESS_REQUEST_USE);

	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 = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
		if (rv &&  rv != EWOULDBLOCK) {
#ifdef TPM_DEBUG
			printf("tpm_request_locality: interrupted %d\n", rv);
#endif
			return rv;
		}
	}

	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
#ifdef TPM_DEBUG
		printf("tpm_request_locality: access %b\n", r, TPM_ACCESS_BITS);
#endif
		return EBUSY;
	}

	return 0;
}
예제 #4
0
파일: tpm.c 프로젝트: ele7enxxh/dtrace-pf
/*
 * Wait on given status bits, uses interrupts where possible, otherwise polls.
 */
int
tpm_waitfor(struct tpm_softc *sc, u_int8_t b0, int tmo, void *c)
{
	u_int8_t b;
	int re, to, rv;

#ifdef TPM_DEBUG
	printf("tpm_waitfor: b0 %b\n", b0, TPM_STS_BITS);
#endif

	/*
	 * If possible, use interrupts, otherwise poll.
	 *
	 * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if
	 * the tpm chips supports them) as waiting for those can take
	 * really long.  The other TPM_STS* are not needed very often
	 * so we do not support them.
	 */
	if (sc->sc_vector != IRQUNK) {
		b = b0;

		/*
		 * Wait for data ready.  This interrupt only occures
		 * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted.
		 * Thus we don't have to bother with TPM_STS_VALID
		 * separately and can just return.
		 *
		 * This only holds for interrupts!  When using polling
		 * both flags have to be waited for, see below.
		 */
		if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities &
		    TPM_INTF_DATA_AVAIL_INT))
			return tpm_waitfor_int(sc, b, tmo, c,
			    TPM_DATA_AVAIL_INT);

		/* Wait for status valid bit. */
		if ((b & TPM_STS_VALID) && (sc->sc_capabilities &
		    TPM_INTF_STS_VALID_INT)) {
			rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT);
			if (rv != 0)
				return rv;
			else
				b = b0 & ~TPM_STS_VALID;
		}

		/*
		 * When all flags are taken care of, return.  Otherwise
		 * use polling for eg. TPM_STS_CMD_READY.
		 */
		if (b == 0)
			return 0;
	}

	re = 3;
restart:
	/*
	 * If requested wait for TPM_STS_VALID before dealing with
	 * any other flag.  Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID
	 * are requested, wait for the latter first.
	 */
	b = b0;
	if (b0 & TPM_STS_VALID)
		b = TPM_STS_VALID;

	to = tpm_tmotohz(tmo);
again:
	if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0)
		return rv;

	if ((b & sc->sc_stat) == TPM_STS_VALID) {
		/* Now wait for other flags. */
		b = b0 & ~TPM_STS_VALID;
		to++;
		goto again;
	}

	if ((sc->sc_stat & b) != b) {
#ifdef TPM_DEBUG
		printf("tpm_waitfor: timeout: stat=%b b=%b\n",
		    sc->sc_stat, TPM_STS_BITS, b, TPM_STS_BITS);
#endif
		if (re-- && (b0 & TPM_STS_VALID)) {
			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
			    TPM_STS_RESP_RETRY);
			goto restart;
		}
		return EIO;
	}

	return 0;
}
예제 #5
0
파일: tpm.c 프로젝트: ele7enxxh/dtrace-pf
/* 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;
}