Home | History | Annotate | Line # | Download | only in ic
tpm.c revision 1.11
      1  1.11  dholland /*	$NetBSD: tpm.c,v 1.11 2014/07/25 08:10:37 dholland Exp $	*/
      2   1.1  christos /*
      3   1.1  christos  * Copyright (c) 2008, 2009 Michael Shalayeff
      4   1.1  christos  * Copyright (c) 2009, 2010 Hans-Jrg Hxer
      5   1.1  christos  * All rights reserved.
      6   1.1  christos  *
      7   1.1  christos  * Permission to use, copy, modify, and distribute this software for any
      8   1.1  christos  * purpose with or without fee is hereby granted, provided that the above
      9   1.1  christos  * copyright notice and this permission notice appear in all copies.
     10   1.1  christos  *
     11   1.1  christos  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12   1.1  christos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13   1.1  christos  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14   1.1  christos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15   1.1  christos  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
     16   1.1  christos  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     17   1.1  christos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18   1.1  christos  */
     19   1.1  christos 
     20   1.1  christos #include <sys/cdefs.h>
     21  1.11  dholland __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.11 2014/07/25 08:10:37 dholland Exp $");
     22   1.1  christos 
     23   1.6  christos #if 0
     24   1.3  christos #define	TPM_DEBUG
     25   1.3  christos #define aprint_debug_dev aprint_error_dev
     26   1.3  christos #endif
     27   1.1  christos 
     28   1.1  christos #include <sys/param.h>
     29   1.1  christos #include <sys/systm.h>
     30   1.1  christos #include <sys/kernel.h>
     31   1.1  christos #include <sys/malloc.h>
     32   1.1  christos #include <sys/proc.h>
     33   1.1  christos #include <sys/device.h>
     34   1.1  christos #include <sys/conf.h>
     35   1.1  christos #include <sys/bus.h>
     36   1.1  christos #include <sys/pmf.h>
     37   1.1  christos 
     38   1.1  christos #include <dev/ic/tpmreg.h>
     39   1.1  christos #include <dev/ic/tpmvar.h>
     40   1.1  christos 
     41   1.1  christos /* Set when enabling legacy interface in host bridge. */
     42   1.1  christos int tpm_enabled;
     43   1.1  christos 
     44   1.1  christos const struct {
     45   1.1  christos 	uint32_t devid;
     46   1.1  christos 	char name[32];
     47   1.1  christos 	int flags;
     48   1.1  christos #define TPM_DEV_NOINTS	0x0001
     49   1.1  christos } tpm_devs[] = {
     50   1.1  christos 	{ 0x000615d1, "IFX SLD 9630 TT 1.1", 0 },
     51   1.1  christos 	{ 0x000b15d1, "IFX SLB 9635 TT 1.2", 0 },
     52   1.1  christos 	{ 0x100214e4, "Broadcom BCM0102", TPM_DEV_NOINTS },
     53   1.1  christos 	{ 0x00fe1050, "WEC WPCT200", 0 },
     54   1.1  christos 	{ 0x687119fa, "SNS SSX35", 0 },
     55   1.1  christos 	{ 0x2e4d5453, "STM ST19WP18", 0 },
     56   1.1  christos 	{ 0x32021114, "ATML 97SC3203", TPM_DEV_NOINTS },
     57   1.1  christos 	{ 0x10408086, "INTEL INTC0102", 0 },
     58   1.1  christos 	{ 0, "", TPM_DEV_NOINTS },
     59   1.1  christos };
     60   1.1  christos 
     61   1.1  christos int tpm_tis12_irqinit(struct tpm_softc *, int, int);
     62   1.1  christos 
     63   1.1  christos int tpm_waitfor_poll(struct tpm_softc *, uint8_t, int, void *);
     64   1.1  christos int tpm_waitfor_int(struct tpm_softc *, uint8_t, int, void *, int);
     65   1.1  christos int tpm_waitfor(struct tpm_softc *, uint8_t, int, void *);
     66   1.1  christos int tpm_request_locality(struct tpm_softc *, int);
     67   1.1  christos int tpm_getburst(struct tpm_softc *);
     68   1.1  christos uint8_t tpm_status(struct tpm_softc *);
     69   1.1  christos int tpm_tmotohz(int);
     70   1.1  christos 
     71   1.1  christos static dev_type_open(tpmopen);
     72   1.1  christos static dev_type_close(tpmclose);
     73   1.1  christos static dev_type_read(tpmread);
     74   1.1  christos static dev_type_read(tpmwrite);
     75   1.1  christos static dev_type_ioctl(tpmioctl);
     76   1.1  christos 
     77   1.1  christos extern struct cfdriver	tpm_cd;
     78   1.1  christos #define TPMUNIT(a)	minor(a)
     79   1.1  christos 
     80   1.1  christos const struct cdevsw tpm_cdevsw = {
     81  1.10  dholland 	.d_open = tpmopen,
     82  1.10  dholland 	.d_close = tpmclose,
     83  1.10  dholland 	.d_read = tpmread,
     84  1.10  dholland 	.d_write = tpmwrite,
     85  1.10  dholland 	.d_ioctl = tpmioctl,
     86  1.10  dholland 	.d_stop = nostop,
     87  1.10  dholland 	.d_tty = notty,
     88  1.10  dholland 	.d_poll = nopoll,
     89  1.10  dholland 	.d_mmap = nommap,
     90  1.10  dholland 	.d_kqfilter = nokqfilter,
     91  1.11  dholland 	.d_discard = nodiscard,
     92  1.10  dholland 	.d_flag = D_OTHER,
     93   1.1  christos };
     94   1.1  christos 
     95   1.1  christos /* Probe TPM using TIS 1.2 interface. */
     96   1.1  christos int
     97   1.1  christos tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
     98   1.1  christos {
     99   1.1  christos 	uint32_t r;
    100   1.1  christos 	uint8_t save, reg;
    101   1.1  christos 
    102   1.1  christos 	r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
    103   1.1  christos 	if (r == 0xffffffff)
    104   1.1  christos 		return 0;
    105   1.1  christos 
    106   1.1  christos #ifdef TPM_DEBUG
    107   1.1  christos 	char buf[128];
    108   1.1  christos 	snprintb(buf, sizeof(buf), TPM_CAPBITS, r);
    109   1.3  christos 	printf("%s: caps=%s\n", __func__, buf);
    110   1.1  christos #endif
    111   1.1  christos 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
    112   1.1  christos 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
    113   1.1  christos #ifdef TPM_DEBUG
    114   1.3  christos 		printf("%s: caps too low (caps=%s)\n", __func__, buf);
    115   1.1  christos #endif
    116   1.1  christos 		return 0;
    117   1.1  christos 	}
    118   1.1  christos 
    119   1.1  christos 	save = bus_space_read_1(bt, bh, TPM_ACCESS);
    120   1.1  christos 	bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
    121   1.1  christos 	reg = bus_space_read_1(bt, bh, TPM_ACCESS);
    122   1.1  christos 	if ((reg & TPM_ACCESS_VALID) && (reg & TPM_ACCESS_ACTIVE_LOCALITY) &&
    123   1.1  christos 	    bus_space_read_4(bt, bh, TPM_ID) != 0xffffffff)
    124   1.1  christos 		return 1;
    125   1.1  christos 
    126   1.1  christos 	bus_space_write_1(bt, bh, TPM_ACCESS, save);
    127   1.1  christos 	return 0;
    128   1.1  christos }
    129   1.1  christos 
    130   1.1  christos /*
    131   1.1  christos  * Setup interrupt vector if one is provided and interrupts are know to
    132   1.1  christos  * work on that particular chip.
    133   1.1  christos  */
    134   1.1  christos int
    135   1.1  christos tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
    136   1.1  christos {
    137   1.1  christos 	uint32_t r;
    138   1.1  christos 
    139   1.1  christos 	if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
    140   1.1  christos 		sc->sc_vector = -1;
    141   1.1  christos 		return 0;
    142   1.1  christos 	}
    143   1.1  christos 
    144   1.1  christos 	/* Ack and disable all interrupts. */
    145   1.4  christos 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
    146   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
    147   1.4  christos 	    r & ~TPM_GLOBAL_INT_ENABLE);
    148   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
    149   1.1  christos 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
    150   1.4  christos #ifdef TPM_DEBUG
    151   1.4  christos 	char buf[128];
    152   1.4  christos 	snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
    153   1.4  christos 	aprint_debug_dev(sc->sc_dev, "%s: before ien %s\n", __func__, buf);
    154   1.4  christos #endif
    155   1.1  christos 
    156   1.1  christos 	/* Program interrupt vector. */
    157   1.1  christos 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
    158   1.1  christos 	sc->sc_vector = irq;
    159   1.1  christos 
    160   1.1  christos 	/* Program interrupt type. */
    161   1.4  christos 	r &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH|
    162   1.4  christos 	    TPM_INT_LEVEL_LOW);
    163   1.4  christos 	r |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT|
    164   1.4  christos 	    TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT;
    165   1.1  christos 	if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
    166   1.4  christos 		r |= TPM_INT_EDGE_RISING;
    167   1.4  christos 	else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING)
    168   1.4  christos 		r |= TPM_INT_EDGE_FALLING;
    169   1.1  christos 	else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
    170   1.4  christos 		r |= TPM_INT_LEVEL_HIGH;
    171   1.1  christos 	else
    172   1.4  christos 		r |= TPM_INT_LEVEL_LOW;
    173   1.4  christos 
    174   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, r);
    175   1.4  christos #ifdef TPM_DEBUG
    176   1.4  christos 	snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
    177   1.4  christos 	aprint_debug_dev(sc->sc_dev, "%s: after ien %s\n", __func__, buf);
    178   1.4  christos #endif
    179   1.1  christos 
    180   1.1  christos 	return 0;
    181   1.1  christos }
    182   1.1  christos 
    183   1.1  christos /* Setup TPM using TIS 1.2 interface. */
    184   1.1  christos int
    185   1.1  christos tpm_tis12_init(struct tpm_softc *sc, int irq, const char *name)
    186   1.1  christos {
    187   1.1  christos 	uint32_t r;
    188   1.1  christos 	int i;
    189   1.1  christos 
    190   1.1  christos 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
    191   1.1  christos #ifdef TPM_DEBUG
    192   1.1  christos 	char cbuf[128];
    193   1.1  christos 	snprintb(cbuf, sizeof(cbuf), TPM_CAPBITS, r);
    194   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: caps=%s ", __func__, cbuf);
    195   1.1  christos #endif
    196   1.1  christos 	if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
    197   1.1  christos 	    !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
    198   1.1  christos 		char buf[128];
    199   1.1  christos 		snprintb(buf, sizeof(buf), TPM_CAPBITS, r);
    200   1.1  christos 		aprint_error_dev(sc->sc_dev, "capabilities too low (caps=%s)\n",
    201   1.1  christos 		    buf);
    202   1.1  christos 		return 1;
    203   1.1  christos 	}
    204   1.1  christos 	sc->sc_capabilities = r;
    205   1.1  christos 
    206   1.1  christos 	sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
    207   1.1  christos 	sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
    208   1.1  christos 
    209   1.1  christos 	for (i = 0; tpm_devs[i].devid; i++)
    210   1.1  christos 		if (tpm_devs[i].devid == sc->sc_devid)
    211   1.1  christos 			break;
    212   1.1  christos 
    213   1.1  christos 	if (tpm_devs[i].devid)
    214   1.1  christos 		aprint_normal(": %s rev 0x%x\n",
    215   1.1  christos 		    tpm_devs[i].name, sc->sc_rev);
    216   1.1  christos 	else
    217   1.1  christos 		aprint_normal(": device 0x%08x rev 0x%x\n",
    218   1.1  christos 		    sc->sc_devid, sc->sc_rev);
    219   1.1  christos 
    220   1.1  christos 	if (tpm_tis12_irqinit(sc, irq, i))
    221   1.1  christos 		return 1;
    222   1.1  christos 
    223   1.1  christos 	if (tpm_request_locality(sc, 0))
    224   1.1  christos 		return 1;
    225   1.1  christos 
    226   1.1  christos 	/* Abort whatever it thought it was doing. */
    227   1.1  christos 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
    228   1.1  christos 
    229   1.1  christos 	return 0;
    230   1.1  christos }
    231   1.1  christos 
    232   1.1  christos int
    233   1.1  christos tpm_request_locality(struct tpm_softc *sc, int l)
    234   1.1  christos {
    235   1.1  christos 	uint32_t r;
    236   1.1  christos 	int to, rv;
    237   1.1  christos 
    238   1.1  christos 	if (l != 0)
    239   1.1  christos 		return EINVAL;
    240   1.1  christos 
    241   1.1  christos 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
    242   1.1  christos 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
    243   1.1  christos 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
    244   1.1  christos 		return 0;
    245   1.1  christos 
    246   1.1  christos 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
    247   1.1  christos 	    TPM_ACCESS_REQUEST_USE);
    248   1.1  christos 
    249   1.1  christos 	to = tpm_tmotohz(TPM_ACCESS_TMO);
    250   1.1  christos 
    251   1.1  christos 	while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
    252   1.1  christos 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
    253   1.1  christos 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
    254   1.1  christos 		rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
    255   1.1  christos 		if (rv &&  rv != EWOULDBLOCK) {
    256   1.1  christos #ifdef TPM_DEBUG
    257   1.3  christos 			aprint_debug_dev(sc->sc_dev, "%s: interrupted %d\n",
    258   1.3  christos 			    __func__, rv);
    259   1.1  christos #endif
    260   1.1  christos 			return rv;
    261   1.1  christos 		}
    262   1.1  christos 	}
    263   1.1  christos 
    264   1.1  christos 	if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
    265   1.1  christos 	    (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
    266   1.1  christos #ifdef TPM_DEBUG
    267   1.1  christos 		char buf[128];
    268   1.3  christos 		snprintb(buf, sizeof(buf), TPM_ACCESS_BITS, r);
    269   1.3  christos 		aprint_debug_dev(sc->sc_dev, "%s: access %s\n", __func__, buf);
    270   1.1  christos #endif
    271   1.1  christos 		return EBUSY;
    272   1.1  christos 	}
    273   1.1  christos 
    274   1.1  christos 	return 0;
    275   1.1  christos }
    276   1.1  christos 
    277   1.1  christos int
    278   1.1  christos tpm_getburst(struct tpm_softc *sc)
    279   1.1  christos {
    280   1.1  christos 	int burst, to, rv;
    281   1.1  christos 
    282   1.1  christos 	to = tpm_tmotohz(TPM_BURST_TMO);
    283   1.1  christos 
    284   1.1  christos 	burst = 0;
    285   1.1  christos 	while (burst == 0 && to--) {
    286   1.1  christos 		/*
    287   1.1  christos 		 * Burst count has to be read from bits 8 to 23 without
    288   1.1  christos 		 * touching any other bits, eg. the actual status bits 0
    289   1.1  christos 		 * to 7.
    290   1.1  christos 		 */
    291   1.1  christos 		burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
    292   1.1  christos 		burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2)
    293   1.1  christos 		    << 8;
    294   1.1  christos #ifdef TPM_DEBUG
    295   1.3  christos 		aprint_debug_dev(sc->sc_dev, "%s: read %d\n", __func__, burst);
    296   1.1  christos #endif
    297   1.1  christos 		if (burst)
    298   1.1  christos 			return burst;
    299   1.1  christos 
    300   1.1  christos 		rv = tsleep(sc, PRIBIO | PCATCH, "tpm_getburst", 1);
    301   1.1  christos 		if (rv && rv != EWOULDBLOCK) {
    302   1.1  christos 			return 0;
    303   1.1  christos 		}
    304   1.1  christos 	}
    305   1.1  christos 
    306   1.1  christos 	return 0;
    307   1.1  christos }
    308   1.1  christos 
    309   1.1  christos uint8_t
    310   1.1  christos tpm_status(struct tpm_softc *sc)
    311   1.1  christos {
    312   1.3  christos 	return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
    313   1.1  christos }
    314   1.1  christos 
    315   1.1  christos int
    316   1.1  christos tpm_tmotohz(int tmo)
    317   1.1  christos {
    318   1.1  christos 	struct timeval tv;
    319   1.1  christos 
    320   1.1  christos 	tv.tv_sec = tmo / 1000;
    321   1.1  christos 	tv.tv_usec = 1000 * (tmo % 1000);
    322   1.1  christos 
    323   1.1  christos 	return tvtohz(&tv);
    324   1.1  christos }
    325   1.1  christos 
    326   1.1  christos /* Save TPM state on suspend. */
    327   1.1  christos bool
    328   1.1  christos tpm_suspend(device_t dev, const pmf_qual_t *qual)
    329   1.1  christos {
    330   1.1  christos 	struct tpm_softc *sc = device_private(dev);
    331   1.3  christos 	static const uint8_t command[] = {
    332   1.1  christos 	    0, 193,		/* TPM_TAG_RQU_COMMAND */
    333   1.1  christos 	    0, 0, 0, 10,	/* Length in bytes */
    334   1.1  christos 	    0, 0, 0, 156	/* TPM_ORD_SaveStates */
    335   1.1  christos 	};
    336   1.5  christos 	uint8_t scratch[sizeof(command)];
    337   1.1  christos 
    338   1.1  christos 	/*
    339   1.1  christos 	 * Power down:  We have to issue the SaveStates command.
    340   1.1  christos 	 */
    341   1.3  christos 	(*sc->sc_write)(sc, &command, sizeof(command));
    342   1.5  christos 	(*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, TPM_HDRSIZE);
    343   1.1  christos #ifdef TPM_DEBUG
    344   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: power down\n", __func__);
    345   1.1  christos #endif
    346   1.7  christos 	return true;
    347   1.1  christos }
    348   1.1  christos 
    349   1.1  christos /*
    350   1.1  christos  * Handle resume event.  Actually nothing to do as the BIOS is supposed
    351   1.1  christos  * to restore the previously saved state.
    352   1.1  christos  */
    353   1.1  christos bool
    354   1.1  christos tpm_resume(device_t dev, const pmf_qual_t *qual)
    355   1.1  christos {
    356   1.1  christos #ifdef TPM_DEBUG
    357   1.1  christos 	struct tpm_softc *sc = device_private(dev);
    358   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: resume\n", __func__);
    359   1.1  christos #endif
    360   1.7  christos 	return true;
    361   1.1  christos }
    362   1.1  christos 
    363   1.1  christos /* Wait for given status bits using polling. */
    364   1.1  christos int
    365   1.1  christos tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int tmo, void *c)
    366   1.1  christos {
    367   1.1  christos 	int rv;
    368   1.1  christos 
    369   1.1  christos 	/*
    370   1.1  christos 	 * Poll until either the requested condition or a time out is
    371   1.1  christos 	 * met.
    372   1.1  christos 	 */
    373   1.1  christos 	while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) {
    374   1.1  christos 		rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1);
    375   1.1  christos 		if (rv && rv != EWOULDBLOCK) {
    376   1.1  christos #ifdef TPM_DEBUG
    377   1.1  christos 			aprint_debug_dev(sc->sc_dev,
    378   1.3  christos 			    "%s: interrupted %d\n", __func__, rv);
    379   1.1  christos #endif
    380   1.1  christos 			return rv;
    381   1.1  christos 		}
    382   1.1  christos 	}
    383   1.1  christos 
    384   1.1  christos 	return 0;
    385   1.1  christos }
    386   1.1  christos 
    387   1.1  christos /* Wait for given status bits using interrupts. */
    388   1.1  christos int
    389   1.1  christos tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, void *c,
    390   1.1  christos     int inttype)
    391   1.1  christos {
    392   1.1  christos 	int rv, to;
    393   1.1  christos 
    394   1.1  christos 	/* Poll and return when condition is already met. */
    395   1.1  christos 	sc->sc_stat = tpm_status(sc);
    396   1.1  christos 	if ((sc->sc_stat & mask) == mask)
    397   1.1  christos 		return 0;
    398   1.1  christos 
    399   1.1  christos 	/*
    400   1.1  christos 	 * Enable interrupt on tpm chip.  Note that interrupts on our
    401   1.1  christos 	 * level (SPL_TTY) are disabled (see tpm{read,write} et al) and
    402   1.1  christos 	 * will not be delivered to the cpu until we call tsleep(9) below.
    403   1.1  christos 	 */
    404   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
    405   1.1  christos 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
    406   1.1  christos 	    inttype);
    407   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
    408   1.1  christos 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
    409   1.1  christos 	    TPM_GLOBAL_INT_ENABLE);
    410   1.1  christos 
    411   1.1  christos 	/*
    412   1.1  christos 	 * Poll once more to remedy the race between previous polling
    413   1.1  christos 	 * and enabling interrupts on the tpm chip.
    414   1.1  christos 	 */
    415   1.1  christos 	sc->sc_stat = tpm_status(sc);
    416   1.1  christos 	if ((sc->sc_stat & mask) == mask) {
    417   1.1  christos 		rv = 0;
    418   1.1  christos 		goto out;
    419   1.1  christos 	}
    420   1.1  christos 
    421   1.1  christos 	to = tpm_tmotohz(tmo);
    422   1.1  christos #ifdef TPM_DEBUG
    423   1.1  christos 	aprint_debug_dev(sc->sc_dev,
    424   1.3  christos 	    "%s: sleeping for %d ticks on %p\n", __func__, to, c);
    425   1.1  christos #endif
    426   1.1  christos 	/*
    427   1.1  christos 	 * tsleep(9) enables interrupts on the cpu and returns after
    428   1.1  christos 	 * wake up with interrupts disabled again.  Note that interrupts
    429   1.1  christos 	 * generated by the tpm chip while being at SPL_TTY are not lost
    430   1.1  christos 	 * but held and delivered as soon as the cpu goes below SPL_TTY.
    431   1.1  christos 	 */
    432   1.3  christos 	rv = tsleep(c, PRIBIO | PCATCH, "tpm_wait", to);
    433   1.1  christos 
    434   1.1  christos 	sc->sc_stat = tpm_status(sc);
    435   1.1  christos #ifdef TPM_DEBUG
    436   1.1  christos 	char buf[128];
    437   1.1  christos 	snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
    438   1.1  christos 	aprint_debug_dev(sc->sc_dev,
    439   1.3  christos 	    "%s: woke up with rv %d stat %s\n", __func__, rv, buf);
    440   1.1  christos #endif
    441   1.1  christos 	if ((sc->sc_stat & mask) == mask)
    442   1.1  christos 		rv = 0;
    443   1.1  christos 
    444   1.1  christos 	/* Disable interrupts on tpm chip again. */
    445   1.1  christos out:	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
    446   1.1  christos 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
    447   1.1  christos 	    ~TPM_GLOBAL_INT_ENABLE);
    448   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
    449   1.1  christos 	    bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
    450   1.1  christos 	    ~inttype);
    451   1.1  christos 
    452   1.1  christos 	return rv;
    453   1.1  christos }
    454   1.1  christos 
    455   1.1  christos /*
    456   1.1  christos  * Wait on given status bits, uses interrupts where possible, otherwise polls.
    457   1.1  christos  */
    458   1.1  christos int
    459   1.1  christos tpm_waitfor(struct tpm_softc *sc, uint8_t b0, int tmo, void *c)
    460   1.1  christos {
    461   1.1  christos 	uint8_t b;
    462   1.1  christos 	int re, to, rv;
    463   1.1  christos 
    464   1.1  christos #ifdef TPM_DEBUG
    465   1.1  christos 	char buf[128];
    466   1.1  christos 	snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
    467   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: b0 %s\n", __func__, buf);
    468   1.1  christos #endif
    469   1.1  christos 
    470   1.1  christos 	/*
    471   1.1  christos 	 * If possible, use interrupts, otherwise poll.
    472   1.1  christos 	 *
    473   1.1  christos 	 * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if
    474   1.1  christos 	 * the tpm chips supports them) as waiting for those can take
    475   1.1  christos 	 * really long.  The other TPM_STS* are not needed very often
    476   1.1  christos 	 * so we do not support them.
    477   1.1  christos 	 */
    478   1.1  christos 	if (sc->sc_vector != -1) {
    479   1.1  christos 		b = b0;
    480   1.1  christos 
    481   1.1  christos 		/*
    482   1.1  christos 		 * Wait for data ready.  This interrupt only occures
    483   1.1  christos 		 * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted.
    484   1.1  christos 		 * Thus we don't have to bother with TPM_STS_VALID
    485   1.1  christos 		 * separately and can just return.
    486   1.1  christos 		 *
    487   1.1  christos 		 * This only holds for interrupts!  When using polling
    488   1.1  christos 		 * both flags have to be waited for, see below.
    489   1.1  christos 		 */
    490   1.1  christos 		if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities &
    491   1.1  christos 		    TPM_INTF_DATA_AVAIL_INT))
    492   1.1  christos 			return tpm_waitfor_int(sc, b, tmo, c,
    493   1.1  christos 			    TPM_DATA_AVAIL_INT);
    494   1.1  christos 
    495   1.1  christos 		/* Wait for status valid bit. */
    496   1.1  christos 		if ((b & TPM_STS_VALID) && (sc->sc_capabilities &
    497   1.1  christos 		    TPM_INTF_STS_VALID_INT)) {
    498   1.1  christos 			rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT);
    499   1.1  christos 			if (rv != 0)
    500   1.1  christos 				return rv;
    501   1.1  christos 			else
    502   1.1  christos 				b = b0 & ~TPM_STS_VALID;
    503   1.1  christos 		}
    504   1.1  christos 
    505   1.1  christos 		/*
    506   1.1  christos 		 * When all flags are taken care of, return.  Otherwise
    507   1.1  christos 		 * use polling for eg. TPM_STS_CMD_READY.
    508   1.1  christos 		 */
    509   1.1  christos 		if (b == 0)
    510   1.1  christos 			return 0;
    511   1.1  christos 	}
    512   1.1  christos 
    513   1.1  christos 	re = 3;
    514   1.1  christos restart:
    515   1.1  christos 	/*
    516   1.1  christos 	 * If requested wait for TPM_STS_VALID before dealing with
    517   1.1  christos 	 * any other flag.  Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID
    518   1.1  christos 	 * are requested, wait for the latter first.
    519   1.1  christos 	 */
    520   1.1  christos 	b = b0;
    521   1.1  christos 	if (b0 & TPM_STS_VALID)
    522   1.1  christos 		b = TPM_STS_VALID;
    523   1.1  christos 
    524   1.1  christos 	to = tpm_tmotohz(tmo);
    525   1.1  christos again:
    526   1.1  christos 	if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0)
    527   1.1  christos 		return rv;
    528   1.1  christos 
    529   1.1  christos 	if ((b & sc->sc_stat) == TPM_STS_VALID) {
    530   1.1  christos 		/* Now wait for other flags. */
    531   1.1  christos 		b = b0 & ~TPM_STS_VALID;
    532   1.1  christos 		to++;
    533   1.1  christos 		goto again;
    534   1.1  christos 	}
    535   1.1  christos 
    536   1.1  christos 	if ((sc->sc_stat & b) != b) {
    537   1.1  christos #ifdef TPM_DEBUG
    538   1.1  christos 		char bbuf[128], cbuf[128];
    539   1.1  christos 		snprintb(bbuf, sizeof(bbuf), TPM_STS_BITS, b);
    540   1.1  christos 		snprintb(cbuf, sizeof(cbuf), TPM_STS_BITS, sc->sc_stat);
    541   1.1  christos 		aprint_debug_dev(sc->sc_dev,
    542   1.3  christos 		    "%s: timeout: stat=%s b=%s\n", __func__, cbuf, bbuf);
    543   1.1  christos #endif
    544   1.1  christos 		if (re-- && (b0 & TPM_STS_VALID)) {
    545   1.1  christos 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
    546   1.1  christos 			    TPM_STS_RESP_RETRY);
    547   1.1  christos 			goto restart;
    548   1.1  christos 		}
    549   1.1  christos 		return EIO;
    550   1.1  christos 	}
    551   1.1  christos 
    552   1.1  christos 	return 0;
    553   1.1  christos }
    554   1.1  christos 
    555   1.1  christos /* Start transaction. */
    556   1.1  christos int
    557   1.1  christos tpm_tis12_start(struct tpm_softc *sc, int flag)
    558   1.1  christos {
    559   1.1  christos 	int rv;
    560   1.1  christos 
    561   1.1  christos 	if (flag == UIO_READ) {
    562   1.1  christos 		rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
    563   1.1  christos 		    TPM_READ_TMO, sc->sc_read);
    564   1.1  christos 		return rv;
    565   1.1  christos 	}
    566   1.1  christos 
    567   1.1  christos 	/* Own our (0th) locality. */
    568   1.1  christos 	if ((rv = tpm_request_locality(sc, 0)) != 0)
    569   1.1  christos 		return rv;
    570   1.1  christos 
    571   1.1  christos 	sc->sc_stat = tpm_status(sc);
    572   1.1  christos 	if (sc->sc_stat & TPM_STS_CMD_READY) {
    573   1.1  christos #ifdef TPM_DEBUG
    574   1.1  christos 		char buf[128];
    575   1.1  christos 		snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
    576   1.3  christos 		aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE status %s\n",
    577   1.3  christos 		    __func__, buf);
    578   1.1  christos #endif
    579   1.1  christos 		return 0;
    580   1.1  christos 	}
    581   1.1  christos 
    582   1.1  christos #ifdef TPM_DEBUG
    583   1.1  christos 	aprint_debug_dev(sc->sc_dev,
    584   1.3  christos 	    "%s: UIO_WRITE readying chip\n", __func__);
    585   1.1  christos #endif
    586   1.1  christos 
    587   1.1  christos 	/* Abort previous and restart. */
    588   1.1  christos 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
    589   1.1  christos 	if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO,
    590   1.1  christos 	    sc->sc_write))) {
    591   1.1  christos #ifdef TPM_DEBUG
    592   1.1  christos 		aprint_debug_dev(sc->sc_dev,
    593   1.3  christos 		    "%s: UIO_WRITE readying failed %d\n", __func__, rv);
    594   1.1  christos #endif
    595   1.1  christos 		return rv;
    596   1.1  christos 	}
    597   1.1  christos 
    598   1.1  christos #ifdef TPM_DEBUG
    599   1.1  christos 	aprint_debug_dev(sc->sc_dev,
    600   1.3  christos 	    "%s: UIO_WRITE readying done\n", __func__);
    601   1.1  christos #endif
    602   1.1  christos 
    603   1.1  christos 	return 0;
    604   1.1  christos }
    605   1.1  christos 
    606   1.1  christos int
    607   1.3  christos tpm_tis12_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count,
    608   1.1  christos     int flags)
    609   1.1  christos {
    610   1.1  christos 	uint8_t *p = buf;
    611   1.1  christos 	size_t cnt;
    612   1.1  christos 	int rv, n, bcnt;
    613   1.1  christos 
    614   1.1  christos #ifdef TPM_DEBUG
    615   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: len %zu\n", __func__, len);
    616   1.1  christos #endif
    617   1.1  christos 	cnt = 0;
    618   1.1  christos 	while (len > 0) {
    619   1.1  christos 		if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
    620   1.1  christos 		    TPM_READ_TMO, sc->sc_read)))
    621   1.1  christos 			return rv;
    622   1.1  christos 
    623   1.1  christos 		bcnt = tpm_getburst(sc);
    624   1.1  christos 		n = MIN(len, bcnt);
    625   1.1  christos #ifdef TPM_DEBUG
    626   1.1  christos 		aprint_debug_dev(sc->sc_dev,
    627   1.3  christos 		    "%s: fetching %d, burst is %d\n", __func__, n, bcnt);
    628   1.1  christos #endif
    629   1.1  christos 		for (; n--; len--) {
    630   1.1  christos 			*p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
    631   1.1  christos 			cnt++;
    632   1.1  christos 		}
    633   1.1  christos 
    634   1.1  christos 		if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
    635   1.1  christos 			break;
    636   1.1  christos 	}
    637   1.1  christos #ifdef TPM_DEBUG
    638   1.1  christos 	aprint_debug_dev(sc->sc_dev,
    639   1.3  christos 	    "%s: read %zu bytes, len %zu\n", __func__, cnt, len);
    640   1.1  christos #endif
    641   1.1  christos 
    642   1.1  christos 	if (count)
    643   1.1  christos 		*count = cnt;
    644   1.1  christos 
    645   1.1  christos 	return 0;
    646   1.1  christos }
    647   1.1  christos 
    648   1.1  christos int
    649   1.3  christos tpm_tis12_write(struct tpm_softc *sc, const void *buf, size_t len)
    650   1.1  christos {
    651   1.3  christos 	const uint8_t *p = buf;
    652   1.1  christos 	size_t cnt;
    653   1.1  christos 	int rv, r;
    654   1.1  christos 
    655   1.1  christos #ifdef TPM_DEBUG
    656   1.1  christos 	aprint_debug_dev(sc->sc_dev,
    657   1.3  christos 	    "%s: sc %p buf %p len %zu\n", __func__, sc, buf, len);
    658   1.1  christos #endif
    659   1.3  christos 	if (len == 0)
    660   1.3  christos 		return 0;
    661   1.1  christos 
    662   1.1  christos 	if ((rv = tpm_request_locality(sc, 0)) != 0)
    663   1.1  christos 		return rv;
    664   1.1  christos 
    665   1.1  christos 	cnt = 0;
    666   1.1  christos 	while (cnt < len - 1) {
    667   1.1  christos 		for (r = tpm_getburst(sc); r > 0 && cnt < len - 1; r--) {
    668   1.1  christos 			bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
    669   1.1  christos 			cnt++;
    670   1.1  christos 		}
    671   1.1  christos 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
    672   1.1  christos #ifdef TPM_DEBUG
    673   1.1  christos 			aprint_debug_dev(sc->sc_dev,
    674   1.3  christos 			    "%s: failed burst rv %d\n", __func__, rv);
    675   1.1  christos #endif
    676   1.1  christos 			return rv;
    677   1.1  christos 		}
    678   1.1  christos 		sc->sc_stat = tpm_status(sc);
    679   1.1  christos 		if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) {
    680   1.1  christos #ifdef TPM_DEBUG
    681   1.1  christos 			char sbuf[128];
    682   1.1  christos 			snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat);
    683   1.1  christos 			aprint_debug_dev(sc->sc_dev,
    684   1.3  christos 			    "%s: failed rv %d stat=%s\n", __func__, rv, sbuf);
    685   1.1  christos #endif
    686   1.1  christos 			return EIO;
    687   1.1  christos 		}
    688   1.1  christos 	}
    689   1.1  christos 
    690   1.1  christos 	bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
    691   1.1  christos 	cnt++;
    692   1.1  christos 
    693   1.1  christos 	if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
    694   1.1  christos #ifdef TPM_DEBUG
    695   1.3  christos 		aprint_debug_dev(sc->sc_dev, "%s: failed last byte rv %d\n",
    696   1.3  christos 		    __func__, rv);
    697   1.1  christos #endif
    698   1.1  christos 		return rv;
    699   1.1  christos 	}
    700   1.1  christos 	if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) {
    701   1.1  christos #ifdef TPM_DEBUG
    702   1.1  christos 		char sbuf[128];
    703   1.1  christos 		snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat);
    704   1.1  christos 		aprint_debug_dev(sc->sc_dev,
    705   1.3  christos 		    "%s: failed rv %d stat=%s\n", __func__, rv, sbuf);
    706   1.1  christos #endif
    707   1.1  christos 		return EIO;
    708   1.1  christos 	}
    709   1.1  christos 
    710   1.1  christos #ifdef TPM_DEBUG
    711   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: wrote %zu byte\n", __func__, cnt);
    712   1.1  christos #endif
    713   1.1  christos 
    714   1.1  christos 	return 0;
    715   1.1  christos }
    716   1.1  christos 
    717   1.1  christos /* Finish transaction. */
    718   1.1  christos int
    719   1.1  christos tpm_tis12_end(struct tpm_softc *sc, int flag, int err)
    720   1.1  christos {
    721   1.1  christos 	int rv = 0;
    722   1.1  christos 
    723   1.1  christos 	if (flag == UIO_READ) {
    724   1.1  christos 		if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO,
    725   1.1  christos 		    sc->sc_read)))
    726   1.1  christos 			return rv;
    727   1.1  christos 
    728   1.1  christos 		/* Still more data? */
    729   1.1  christos 		sc->sc_stat = tpm_status(sc);
    730   1.3  christos 		if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL)
    731   1.3  christos 		    == TPM_STS_DATA_AVAIL)) {
    732   1.1  christos #ifdef TPM_DEBUG
    733   1.1  christos 			char buf[128];
    734   1.1  christos 			snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
    735   1.1  christos 			aprint_debug_dev(sc->sc_dev,
    736   1.3  christos 			    "%s: read failed stat=%s\n", __func__, buf);
    737   1.1  christos #endif
    738   1.1  christos 			rv = EIO;
    739   1.1  christos 		}
    740   1.1  christos 
    741   1.1  christos 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
    742   1.1  christos 		    TPM_STS_CMD_READY);
    743   1.1  christos 
    744   1.1  christos 		/* Release our (0th) locality. */
    745   1.1  christos 		bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS,
    746   1.1  christos 		    TPM_ACCESS_ACTIVE_LOCALITY);
    747   1.1  christos 	} else {
    748   1.1  christos 		/* Hungry for more? */
    749   1.1  christos 		sc->sc_stat = tpm_status(sc);
    750   1.1  christos 		if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) {
    751   1.1  christos #ifdef TPM_DEBUG
    752   1.1  christos 			char buf[128];
    753   1.1  christos 			snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
    754   1.1  christos 			aprint_debug_dev(sc->sc_dev,
    755   1.3  christos 			    "%s: write failed stat=%s\n", __func__, buf);
    756   1.1  christos #endif
    757   1.1  christos 			rv = EIO;
    758   1.1  christos 		}
    759   1.1  christos 
    760   1.1  christos 		bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
    761   1.1  christos 		    err ? TPM_STS_CMD_READY : TPM_STS_GO);
    762   1.1  christos 	}
    763   1.1  christos 
    764   1.1  christos 	return rv;
    765   1.1  christos }
    766   1.1  christos 
    767   1.1  christos int
    768   1.1  christos tpm_intr(void *v)
    769   1.1  christos {
    770   1.1  christos 	struct tpm_softc *sc = v;
    771   1.1  christos 	uint32_t r;
    772   1.1  christos #ifdef TPM_DEBUG
    773   1.1  christos 	static int cnt = 0;
    774   1.1  christos #endif
    775   1.1  christos 
    776   1.1  christos 	r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
    777   1.1  christos #ifdef TPM_DEBUG
    778   1.1  christos 	if (r != 0) {
    779   1.1  christos 		char buf[128];
    780   1.1  christos 		snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
    781   1.3  christos 		aprint_debug_dev(sc->sc_dev, "%s: int=%s (%d)\n", __func__,
    782   1.3  christos 		    buf, cnt);
    783   1.1  christos 	} else
    784   1.1  christos 		cnt++;
    785   1.1  christos #endif
    786   1.1  christos 	if (!(r & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
    787   1.1  christos 	    TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
    788   1.1  christos #ifdef __FreeBSD__
    789   1.1  christos 		return;
    790   1.1  christos #else
    791   1.1  christos 		return 0;
    792   1.1  christos #endif
    793   1.1  christos 	if (r & TPM_STS_VALID_INT)
    794   1.1  christos 		wakeup(sc);
    795   1.1  christos 
    796   1.1  christos 	if (r & TPM_CMD_READY_INT)
    797   1.1  christos 		wakeup(sc->sc_write);
    798   1.1  christos 
    799   1.1  christos 	if (r & TPM_DATA_AVAIL_INT)
    800   1.1  christos 		wakeup(sc->sc_read);
    801   1.1  christos 
    802   1.1  christos 	if (r & TPM_LOCALITY_CHANGE_INT)
    803   1.1  christos 		wakeup(sc->sc_init);
    804   1.1  christos 
    805   1.1  christos 	bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, r);
    806   1.1  christos 
    807   1.1  christos 	return 1;
    808   1.1  christos }
    809   1.1  christos 
    810   1.1  christos /* Read single byte using legacy interface. */
    811   1.1  christos static inline uint8_t
    812   1.1  christos tpm_legacy_in(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
    813   1.1  christos {
    814   1.1  christos 	bus_space_write_1(iot, ioh, 0, reg);
    815   1.1  christos 	return bus_space_read_1(iot, ioh, 1);
    816   1.1  christos }
    817   1.1  christos 
    818   1.1  christos /* Probe for TPM using legacy interface. */
    819   1.1  christos int
    820   1.1  christos tpm_legacy_probe(bus_space_tag_t iot, bus_addr_t iobase)
    821   1.1  christos {
    822   1.1  christos 	bus_space_handle_t ioh;
    823   1.1  christos 	uint8_t r, v;
    824   1.1  christos 	int i, rv = 0;
    825   1.1  christos 	char id[8];
    826   1.1  christos 
    827   1.1  christos 	if (!tpm_enabled || iobase == -1)
    828   1.1  christos 		return 0;
    829   1.1  christos 
    830   1.1  christos 	if (bus_space_map(iot, iobase, 2, 0, &ioh))
    831   1.1  christos 		return 0;
    832   1.1  christos 
    833   1.1  christos 	v = bus_space_read_1(iot, ioh, 0);
    834   1.1  christos 	if (v == 0xff) {
    835   1.1  christos 		bus_space_unmap(iot, ioh, 2);
    836   1.1  christos 		return 0;
    837   1.1  christos 	}
    838   1.1  christos 	r = bus_space_read_1(iot, ioh, 1);
    839   1.1  christos 
    840   1.1  christos 	for (i = sizeof(id); i--; )
    841   1.1  christos 		id[i] = tpm_legacy_in(iot, ioh, TPM_ID + i);
    842   1.1  christos 
    843   1.1  christos #ifdef TPM_DEBUG
    844   1.1  christos 	printf("tpm_legacy_probe %.4s %d.%d.%d.%d\n",
    845   1.1  christos 	    &id[4], id[0], id[1], id[2], id[3]);
    846   1.1  christos #endif
    847   1.1  christos 	/*
    848   1.1  christos 	 * The only chips using the legacy interface we are aware of are
    849   1.1  christos 	 * by Atmel.  For other chips more signature would have to be added.
    850   1.1  christos 	 */
    851   1.1  christos 	if (!bcmp(&id[4], "ATML", 4))
    852   1.1  christos 		rv = 1;
    853   1.1  christos 
    854   1.1  christos 	if (!rv) {
    855   1.1  christos 		bus_space_write_1(iot, ioh, r, 1);
    856   1.1  christos 		bus_space_write_1(iot, ioh, v, 0);
    857   1.1  christos 	}
    858   1.1  christos 	bus_space_unmap(iot, ioh, 2);
    859   1.1  christos 
    860   1.1  christos 	return rv;
    861   1.1  christos }
    862   1.1  christos 
    863   1.1  christos /* Setup TPM using legacy interface. */
    864   1.1  christos int
    865   1.1  christos tpm_legacy_init(struct tpm_softc *sc, int irq, const char *name)
    866   1.1  christos {
    867   1.1  christos 	char id[8];
    868   1.1  christos 	int i;
    869   1.1  christos 
    870   1.1  christos 	if ((i = bus_space_map(sc->sc_batm, tpm_enabled, 2, 0, &sc->sc_bahm))) {
    871   1.1  christos 		aprint_debug_dev(sc->sc_dev, "cannot map tpm registers (%d)\n",
    872   1.1  christos 		    i);
    873   1.1  christos 		tpm_enabled = 0;
    874   1.1  christos 		return 1;
    875   1.1  christos 	}
    876   1.1  christos 
    877   1.1  christos 	for (i = sizeof(id); i--; )
    878   1.1  christos 		id[i] = tpm_legacy_in(sc->sc_bt, sc->sc_bh, TPM_ID + i);
    879   1.1  christos 
    880   1.1  christos 	aprint_debug_dev(sc->sc_dev, "%.4s %d.%d @0x%x\n", &id[4], id[0],
    881   1.1  christos 	    id[1], tpm_enabled);
    882   1.1  christos 	tpm_enabled = 0;
    883   1.1  christos 
    884   1.1  christos 	return 0;
    885   1.1  christos }
    886   1.1  christos 
    887   1.1  christos /* Start transaction. */
    888   1.1  christos int
    889   1.1  christos tpm_legacy_start(struct tpm_softc *sc, int flag)
    890   1.1  christos {
    891   1.1  christos 	struct timeval tv;
    892   1.1  christos 	uint8_t bits, r;
    893   1.1  christos 	int to, rv;
    894   1.1  christos 
    895   1.1  christos 	bits = flag == UIO_READ ? TPM_LEGACY_DA : 0;
    896   1.1  christos 	tv.tv_sec = TPM_LEGACY_TMO;
    897   1.1  christos 	tv.tv_usec = 0;
    898   1.1  christos 	to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
    899   1.1  christos 	while (((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
    900   1.1  christos 	    (TPM_LEGACY_BUSY|bits)) != bits && to--) {
    901   1.1  christos 		rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_start",
    902   1.1  christos 		    TPM_LEGACY_SLEEP);
    903   1.1  christos 		if (rv && rv != EWOULDBLOCK)
    904   1.1  christos 			return rv;
    905   1.1  christos 	}
    906   1.1  christos 
    907   1.1  christos #if defined(TPM_DEBUG) && !defined(__FreeBSD__)
    908   1.1  christos 	char buf[128];
    909   1.1  christos 	snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r);
    910   1.1  christos 	aprint_debug_dev(sc->sc_dev, "%s: bits %s\n", device_xname(sc->sc_dev),
    911   1.1  christos 	    buf);
    912   1.1  christos #endif
    913   1.1  christos 	if ((r & (TPM_LEGACY_BUSY|bits)) != bits)
    914   1.1  christos 		return EIO;
    915   1.1  christos 
    916   1.1  christos 	return 0;
    917   1.1  christos }
    918   1.1  christos 
    919   1.1  christos int
    920   1.3  christos tpm_legacy_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count,
    921   1.1  christos     int flags)
    922   1.1  christos {
    923   1.1  christos 	uint8_t *p;
    924   1.1  christos 	size_t cnt;
    925   1.1  christos 	int to, rv;
    926   1.1  christos 
    927   1.1  christos 	cnt = rv = 0;
    928   1.1  christos 	for (p = buf; !rv && len > 0; len--) {
    929   1.1  christos 		for (to = 1000;
    930   1.1  christos 		    !(bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1) &
    931   1.1  christos 		    TPM_LEGACY_DA); DELAY(1))
    932   1.1  christos 			if (!to--)
    933   1.1  christos 				return EIO;
    934   1.1  christos 
    935   1.1  christos 		DELAY(TPM_LEGACY_DELAY);
    936   1.1  christos 		*p++ = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 0);
    937   1.1  christos 		cnt++;
    938   1.1  christos 	}
    939   1.1  christos 
    940   1.1  christos 	*count = cnt;
    941   1.1  christos 	return 0;
    942   1.1  christos }
    943   1.1  christos 
    944   1.1  christos int
    945   1.3  christos tpm_legacy_write(struct tpm_softc *sc, const void *buf, size_t len)
    946   1.1  christos {
    947   1.3  christos 	const uint8_t *p;
    948   1.3  christos 	size_t n;
    949   1.1  christos 
    950   1.1  christos 	for (p = buf, n = len; n--; DELAY(TPM_LEGACY_DELAY)) {
    951   1.1  christos 		if (!n && len != TPM_BUFSIZ) {
    952   1.1  christos 			bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1,
    953   1.1  christos 			    TPM_LEGACY_LAST);
    954   1.1  christos 			DELAY(TPM_LEGACY_DELAY);
    955   1.1  christos 		}
    956   1.1  christos 		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 0, *p++);
    957   1.1  christos 	}
    958   1.1  christos 
    959   1.1  christos 	return 0;
    960   1.1  christos }
    961   1.1  christos 
    962   1.1  christos /* Finish transaction. */
    963   1.1  christos int
    964   1.1  christos tpm_legacy_end(struct tpm_softc *sc, int flag, int rv)
    965   1.1  christos {
    966   1.1  christos 	struct timeval tv;
    967   1.1  christos 	uint8_t r;
    968   1.1  christos 	int to;
    969   1.1  christos 
    970   1.1  christos 	if (rv || flag == UIO_READ)
    971   1.1  christos 		bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, TPM_LEGACY_ABRT);
    972   1.1  christos 	else {
    973   1.1  christos 		tv.tv_sec = TPM_LEGACY_TMO;
    974   1.1  christos 		tv.tv_usec = 0;
    975   1.1  christos 		to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
    976   1.1  christos 		while(((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
    977   1.1  christos 		    TPM_LEGACY_BUSY) && to--) {
    978   1.1  christos 			rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_end",
    979   1.1  christos 			    TPM_LEGACY_SLEEP);
    980   1.1  christos 			if (rv && rv != EWOULDBLOCK)
    981   1.1  christos 				return rv;
    982   1.1  christos 		}
    983   1.1  christos 
    984   1.1  christos #if defined(TPM_DEBUG) && !defined(__FreeBSD__)
    985   1.1  christos 		char buf[128];
    986   1.1  christos 		snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r);
    987   1.1  christos 		aprint_debug_dev(sc->sc_dev, "%s: bits %s\n",
    988   1.1  christos 		    device_xname(sc->sc_dev), buf);
    989   1.1  christos #endif
    990   1.1  christos 		if (r & TPM_LEGACY_BUSY)
    991   1.1  christos 			return EIO;
    992   1.1  christos 
    993   1.1  christos 		if (r & TPM_LEGACY_RE)
    994   1.1  christos 			return EIO;	/* XXX Retry the loop? */
    995   1.1  christos 	}
    996   1.1  christos 
    997   1.1  christos 	return rv;
    998   1.1  christos }
    999   1.1  christos 
   1000   1.1  christos int
   1001   1.1  christos tpmopen(dev_t dev, int flag, int mode, struct lwp *l)
   1002   1.1  christos {
   1003   1.1  christos 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
   1004   1.1  christos 
   1005   1.1  christos 	if (!sc)
   1006   1.1  christos 		return ENXIO;
   1007   1.1  christos 
   1008   1.1  christos 	if (sc->sc_flags & TPM_OPEN)
   1009   1.1  christos 		return EBUSY;
   1010   1.1  christos 
   1011   1.1  christos 	sc->sc_flags |= TPM_OPEN;
   1012   1.1  christos 
   1013   1.1  christos 	return 0;
   1014   1.1  christos }
   1015   1.1  christos 
   1016   1.1  christos int
   1017   1.1  christos tpmclose(dev_t dev, int flag, int mode, struct lwp *l)
   1018   1.1  christos {
   1019   1.1  christos 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
   1020   1.1  christos 
   1021   1.1  christos 	if (!sc)
   1022   1.1  christos 		return ENXIO;
   1023   1.1  christos 
   1024   1.1  christos 	if (!(sc->sc_flags & TPM_OPEN))
   1025   1.1  christos 		return EINVAL;
   1026   1.1  christos 
   1027   1.1  christos 	sc->sc_flags &= ~TPM_OPEN;
   1028   1.1  christos 
   1029   1.1  christos 	return 0;
   1030   1.1  christos }
   1031   1.1  christos 
   1032   1.1  christos int
   1033   1.1  christos tpmread(dev_t dev, struct uio *uio, int flags)
   1034   1.1  christos {
   1035   1.1  christos 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
   1036   1.1  christos 	uint8_t buf[TPM_BUFSIZ], *p;
   1037   1.1  christos 	size_t cnt, len, n;
   1038   1.1  christos 	int  rv, s;
   1039   1.1  christos 
   1040   1.1  christos 	if (!sc)
   1041   1.1  christos 		return ENXIO;
   1042   1.1  christos 
   1043   1.1  christos 	s = spltty();
   1044   1.3  christos 	if ((rv = (*sc->sc_start)(sc, UIO_READ)))
   1045   1.3  christos 		goto out;
   1046   1.1  christos 
   1047   1.1  christos #ifdef TPM_DEBUG
   1048   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: getting header\n", __func__);
   1049   1.1  christos #endif
   1050   1.3  christos 	if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
   1051   1.3  christos 		(*sc->sc_end)(sc, UIO_READ, rv);
   1052   1.3  christos 		goto out;
   1053   1.1  christos 	}
   1054   1.1  christos 
   1055   1.1  christos 	len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
   1056   1.1  christos #ifdef TPM_DEBUG
   1057   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: len %zu, io count %zu\n", __func__,
   1058   1.1  christos 	    len, uio->uio_resid);
   1059   1.1  christos #endif
   1060   1.1  christos 	if (len > uio->uio_resid) {
   1061   1.1  christos 		rv = EIO;
   1062   1.3  christos 		(*sc->sc_end)(sc, UIO_READ, rv);
   1063   1.1  christos #ifdef TPM_DEBUG
   1064   1.1  christos 		aprint_debug_dev(sc->sc_dev,
   1065   1.3  christos 		    "%s: bad residual io count 0x%zx\n", __func__,
   1066   1.1  christos 		    uio->uio_resid);
   1067   1.1  christos #endif
   1068   1.3  christos 		goto out;
   1069   1.1  christos 	}
   1070   1.1  christos 
   1071   1.1  christos 	/* Copy out header. */
   1072   1.1  christos 	if ((rv = uiomove(buf, cnt, uio))) {
   1073   1.3  christos #ifdef TPM_DEBUG
   1074   1.3  christos 		aprint_debug_dev(sc->sc_dev,
   1075   1.3  christos 		    "%s: uiomove failed %d\n", __func__, rv);
   1076   1.3  christos #endif
   1077   1.3  christos 		(*sc->sc_end)(sc, UIO_READ, rv);
   1078   1.3  christos 		goto out;
   1079   1.1  christos 	}
   1080   1.1  christos 
   1081   1.1  christos 	/* Get remaining part of the answer (if anything is left). */
   1082   1.1  christos 	for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n,
   1083   1.1  christos 	    n = sizeof(buf)) {
   1084   1.1  christos 		n = MIN(n, len);
   1085   1.1  christos #ifdef TPM_DEBUG
   1086   1.3  christos 		aprint_debug_dev(sc->sc_dev, "%s: n %zu len %zu\n", __func__,
   1087   1.1  christos 		    n, len);
   1088   1.1  christos #endif
   1089   1.3  christos 		if ((rv = (*sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) {
   1090   1.3  christos 			(*sc->sc_end)(sc, UIO_READ, rv);
   1091   1.3  christos 			goto out;
   1092   1.1  christos 		}
   1093   1.1  christos 		p += n;
   1094   1.1  christos 		if ((rv = uiomove(buf, p - buf, uio))) {
   1095   1.3  christos #ifdef TPM_DEBUG
   1096   1.3  christos 			aprint_debug_dev(sc->sc_dev,
   1097   1.3  christos 			    "%s: uiomove failed %d\n", __func__, rv);
   1098   1.3  christos #endif
   1099   1.3  christos 			(*sc->sc_end)(sc, UIO_READ, rv);
   1100   1.3  christos 			goto out;
   1101   1.1  christos 		}
   1102   1.1  christos 	}
   1103   1.1  christos 
   1104   1.3  christos 	rv = (*sc->sc_end)(sc, UIO_READ, rv);
   1105   1.3  christos out:
   1106   1.1  christos 	splx(s);
   1107   1.1  christos 	return rv;
   1108   1.1  christos }
   1109   1.1  christos 
   1110   1.1  christos int
   1111   1.1  christos tpmwrite(dev_t dev, struct uio *uio, int flags)
   1112   1.1  christos {
   1113   1.1  christos 	struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
   1114   1.1  christos 	uint8_t buf[TPM_BUFSIZ];
   1115   1.1  christos 	int n, rv, s;
   1116   1.1  christos 
   1117   1.1  christos 	if (!sc)
   1118   1.1  christos 		return ENXIO;
   1119   1.1  christos 
   1120   1.1  christos 	s = spltty();
   1121   1.1  christos 
   1122   1.1  christos #ifdef TPM_DEBUG
   1123   1.3  christos 	aprint_debug_dev(sc->sc_dev, "%s: io count %zu\n", __func__,
   1124   1.1  christos 	    uio->uio_resid);
   1125   1.1  christos #endif
   1126   1.1  christos 
   1127   1.1  christos 	n = MIN(sizeof(buf), uio->uio_resid);
   1128   1.1  christos 	if ((rv = uiomove(buf, n, uio))) {
   1129   1.3  christos #ifdef TPM_DEBUG
   1130   1.3  christos 		aprint_debug_dev(sc->sc_dev,
   1131   1.3  christos 		    "%s: uiomove failed %d\n", __func__, rv);
   1132   1.3  christos #endif
   1133   1.1  christos 		splx(s);
   1134   1.1  christos 		return rv;
   1135   1.1  christos 	}
   1136   1.1  christos 
   1137   1.3  christos 	if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) {
   1138   1.1  christos 		splx(s);
   1139   1.1  christos 		return rv;
   1140   1.1  christos 	}
   1141   1.1  christos 
   1142   1.3  christos 	if ((rv = (*sc->sc_write)(sc, buf, n))) {
   1143   1.1  christos 		splx(s);
   1144   1.1  christos 		return rv;
   1145   1.1  christos 	}
   1146   1.1  christos 
   1147   1.3  christos 	rv = (*sc->sc_end)(sc, UIO_WRITE, rv);
   1148   1.1  christos 	splx(s);
   1149   1.1  christos 	return rv;
   1150   1.1  christos }
   1151   1.1  christos 
   1152   1.1  christos int
   1153   1.1  christos tpmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
   1154   1.1  christos {
   1155   1.1  christos 	return ENOTTY;
   1156   1.1  christos }
   1157