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