Module Name: src
Committed By: maxv
Date: Sat Jun 22 12:57:41 UTC 2019
Modified Files:
src/sys/dev/acpi: tpm_acpi.c
src/sys/dev/ic: tpm.c tpmreg.h tpmvar.h
src/sys/dev/isa: tpm_isa.c
Log Message:
Revamp the TPM driver
* Fix several bugs, and clean up.
* Drop the "legacy" interface, it relied on an undocumented global
variable that was never initialized. It likely had never been tested
either, so good riddance.
* Add support for TPM 2.0 chips via ACPI. For these we use the TIS1.2
interface, same as TPM 1.2.
* Provide an ioctl to fetch TPM information from the driver.
Tested on a Lenovo desktop with ACPI-TPM2.0, an HP laptop ACPI-TPM2.0, a
Dell laptop with ISA-TPM1.2.
To generate a diff of this commit:
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/acpi/tpm_acpi.c
cvs rdiff -u -r1.12 -r1.13 src/sys/dev/ic/tpm.c
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/ic/tpmreg.h src/sys/dev/ic/tpmvar.h
cvs rdiff -u -r1.3 -r1.4 src/sys/dev/isa/tpm_isa.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/acpi/tpm_acpi.c
diff -u src/sys/dev/acpi/tpm_acpi.c:1.7 src/sys/dev/acpi/tpm_acpi.c:1.8
--- src/sys/dev/acpi/tpm_acpi.c:1.7 Sun Dec 9 11:12:58 2018
+++ src/sys/dev/acpi/tpm_acpi.c Sat Jun 22 12:57:40 2019
@@ -1,11 +1,11 @@
-/* $NetBSD: tpm_acpi.c,v 1.7 2018/12/09 11:12:58 jdolecek Exp $ */
+/* $NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $ */
-/*-
- * Copyright (c) 2012 The NetBSD Foundation, Inc.
+/*
+ * Copyright (c) 2012, 2019 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
- * by Christos Zoulas.
+ * by Christos Zoulas and Maxime Villard.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,31 +28,9 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-/*
- * Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-J�rg H�xer
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-/*
- * ACPI attachment for the Infineon SLD 9630 TT 1.1 and SLB 9635 TT 1.2
- * trusted platform module. See www.trustedcomputinggroup.org
- */
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.7 2018/12/09 11:12:58 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v 1.8 2019/06/22 12:57:40 maxv Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -71,44 +49,48 @@ __KERNEL_RCSID(0, "$NetBSD: tpm_acpi.c,v
#include "ioconf.h"
-#define _COMPONENT ACPI_RESOURCE_COMPONENT
-ACPI_MODULE_NAME ("tpm_acpi")
+#define _COMPONENT ACPI_RESOURCE_COMPONENT
+ACPI_MODULE_NAME ("tpm_acpi")
static int tpm_acpi_match(device_t, cfdata_t, void *);
static void tpm_acpi_attach(device_t, device_t, void *);
-
CFATTACH_DECL_NEW(tpm_acpi, sizeof(struct tpm_softc), tpm_acpi_match,
tpm_acpi_attach, NULL, NULL);
/*
- * Supported device IDs
+ * Supported TPM 2.0 devices.
*/
-
-#ifdef notyet
-static const char * const tpm_acpi_ids[] = {
- "IFX0101",
- "IFX0102",
+static const char * const tpm2_acpi_ids[] = {
+ "MSFT0101",
NULL
};
-#endif
static int
tpm_acpi_match(device_t parent, cfdata_t match, void *aux)
{
struct acpi_attach_args *aa = aux;
+ ACPI_TABLE_TPM2 *tpm2;
+ ACPI_STATUS rv;
if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
return 0;
- /* There can be only one. */
+ /* We support only one TPM. */
if (tpm_cd.cd_devs && tpm_cd.cd_devs[0])
return 0;
-#ifdef notyet
- return acpi_match_hid(aa->aa_node->ad_devinfo, tpm_acpi_ids);
-#else
- return 0;
-#endif
+
+ if (!acpi_match_hid(aa->aa_node->ad_devinfo, tpm2_acpi_ids))
+ return 0;
+
+ /* Make sure it uses TIS, and not CRB. */
+ rv = AcpiGetTable(ACPI_SIG_TPM2, 1, (ACPI_TABLE_HEADER **)&tpm2);
+ if (ACPI_FAILURE(rv))
+ return 0;
+ if (tpm2->StartMethod != ACPI_TPM2_MEMORY_MAPPED)
+ return 0;
+
+ return 1;
}
static void
@@ -117,7 +99,6 @@ tpm_acpi_attach(device_t parent, device_
struct tpm_softc *sc = device_private(self);
struct acpi_attach_args *aa = aux;
struct acpi_resources res;
- struct acpi_io *io;
struct acpi_mem *mem;
struct acpi_irq *irq;
bus_addr_t base;
@@ -125,59 +106,43 @@ tpm_acpi_attach(device_t parent, device_
int rv, inum;
sc->sc_dev = self;
+ sc->sc_ver = TPM_2_0;
- /* Parse our resources */
- rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res,
- &acpi_resource_parse_ops_default);
-
- if (ACPI_FAILURE(rv)) {
+ rv = acpi_resource_parse(self, aa->aa_node->ad_handle, "_CRS", &res,
+ &acpi_resource_parse_ops_default);
+ if (ACPI_FAILURE(rv)) {
aprint_error_dev(sc->sc_dev, "cannot parse resources %d\n", rv);
- return;
+ return;
}
- io = acpi_res_io(&res, 0);
- if (io && tpm_legacy_probe(aa->aa_iot, io->ar_base)) {
- sc->sc_bt = aa->aa_iot;
- base = io->ar_base;
- size = io->ar_length;
- sc->sc_batm = aa->aa_iot;
- sc->sc_init = tpm_legacy_init;
- sc->sc_start = tpm_legacy_start;
- sc->sc_read = tpm_legacy_read;
- sc->sc_write = tpm_legacy_write;
- sc->sc_end = tpm_legacy_end;
- mem = NULL;
- } else {
- mem = acpi_res_mem(&res, 0);
- if (mem == NULL) {
- aprint_error_dev(sc->sc_dev, "cannot find mem\n");
- goto out;
- }
-
- if (mem->ar_length != TPM_SIZE) {
- aprint_error_dev(sc->sc_dev,
- "wrong size mem %"PRIu64" != %u\n",
- (uint64_t)mem->ar_length, TPM_SIZE);
- goto out;
- }
-
- base = mem->ar_base;
- size = mem->ar_length;
- sc->sc_bt = aa->aa_memt;
- sc->sc_init = tpm_tis12_init;
- sc->sc_start = tpm_tis12_start;
- sc->sc_read = tpm_tis12_read;
- sc->sc_write = tpm_tis12_write;
- sc->sc_end = tpm_tis12_end;
+ mem = acpi_res_mem(&res, 0);
+ if (mem == NULL) {
+ aprint_error_dev(sc->sc_dev, "cannot find mem\n");
+ goto out;
+ }
+ if (mem->ar_length != TPM_SPACE_SIZE) {
+ aprint_error_dev(sc->sc_dev,
+ "wrong size mem %"PRIu64" != %u\n",
+ (uint64_t)mem->ar_length, TPM_SPACE_SIZE);
+ goto out;
}
+ base = mem->ar_base;
+ size = mem->ar_length;
+ sc->sc_bt = aa->aa_memt;
+ sc->sc_init = tpm_tis12_init;
+ sc->sc_start = tpm_tis12_start;
+ sc->sc_read = tpm_tis12_read;
+ sc->sc_write = tpm_tis12_write;
+ sc->sc_end = tpm_tis12_end;
+
if (bus_space_map(sc->sc_bt, base, size, 0, &sc->sc_bh)) {
aprint_error_dev(sc->sc_dev, "cannot map registers\n");
goto out;
}
- if (mem && !tpm_tis12_probe(sc->sc_bt, sc->sc_bh)) {
- aprint_error_dev(sc->sc_dev, "1.2 probe failed\n");
+ if (!tpm_tis12_probe(sc->sc_bt, sc->sc_bh)) {
+ aprint_error_dev(sc->sc_dev, "TIS1.2 probe failed\n");
goto out1;
}
@@ -187,7 +152,7 @@ tpm_acpi_attach(device_t parent, device_
else
inum = irq->ar_irq;
- if ((rv = (*sc->sc_init)(sc, inum, device_xname(sc->sc_dev))) != 0) {
+ if ((rv = (*sc->sc_init)(sc, inum)) != 0) {
aprint_error_dev(sc->sc_dev, "cannot init device %d\n", rv);
goto out1;
}
@@ -199,9 +164,9 @@ tpm_acpi_attach(device_t parent, device_
goto out1;
}
- if (!pmf_device_register(sc->sc_dev, tpm_suspend, tpm_resume))
- aprint_error_dev(sc->sc_dev, "Cannot set power mgmt handler\n");
+ acpi_resource_cleanup(&res);
return;
+
out1:
bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
out:
Index: src/sys/dev/ic/tpm.c
diff -u src/sys/dev/ic/tpm.c:1.12 src/sys/dev/ic/tpm.c:1.13
--- src/sys/dev/ic/tpm.c:1.12 Sat Oct 28 04:53:55 2017
+++ src/sys/dev/ic/tpm.c Sat Jun 22 12:57:41 2019
@@ -1,7 +1,37 @@
-/* $NetBSD: tpm.c,v 1.12 2017/10/28 04:53:55 riastradh Exp $ */
+/* $NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $ */
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
/*
* Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-J�rg H�xer
+ * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -18,12 +48,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.12 2017/10/28 04:53:55 riastradh Exp $");
-
-#if 0
-#define TPM_DEBUG
-#define aprint_debug_dev aprint_error_dev
-#endif
+__KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.13 2019/06/22 12:57:41 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -40,12 +65,23 @@ __KERNEL_RCSID(0, "$NetBSD: tpm.c,v 1.12
#include "ioconf.h"
-/* Set when enabling legacy interface in host bridge. */
-int tpm_enabled;
+#define TPM_BUFSIZ 1024
+#define TPM_HDRSIZE 10
+#define TPM_PARAM_SIZE 0x0001 /* that's a flag */
+
+/* Timeouts. */
+#define TPM_ACCESS_TMO 2000 /* 2sec */
+#define TPM_READY_TMO 2000 /* 2sec */
+#define TPM_READ_TMO 2000 /* 2sec */
+#define TPM_BURST_TMO 2000 /* 2sec */
+
+#define TPM_CAPS_REQUIRED \
+ (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT| \
+ TPM_INTF_INT_LEVEL_LOW)
-const struct {
+static const struct {
uint32_t devid;
- char name[32];
+ const char *name;
int flags;
#define TPM_DEV_NOINTS 0x0001
} tpm_devs[] = {
@@ -60,177 +96,18 @@ const struct {
{ 0, "", TPM_DEV_NOINTS },
};
-int tpm_tis12_irqinit(struct tpm_softc *, int, int);
-
-int tpm_waitfor_poll(struct tpm_softc *, uint8_t, int, void *);
-int tpm_waitfor_int(struct tpm_softc *, uint8_t, int, void *, int);
-int tpm_waitfor(struct tpm_softc *, uint8_t, int, void *);
-int tpm_request_locality(struct tpm_softc *, int);
-int tpm_getburst(struct tpm_softc *);
-uint8_t tpm_status(struct tpm_softc *);
-int tpm_tmotohz(int);
-
-static dev_type_open(tpmopen);
-static dev_type_close(tpmclose);
-static dev_type_read(tpmread);
-static dev_type_read(tpmwrite);
-static dev_type_ioctl(tpmioctl);
-
-#define TPMUNIT(a) minor(a)
-
-const struct cdevsw tpm_cdevsw = {
- .d_open = tpmopen,
- .d_close = tpmclose,
- .d_read = tpmread,
- .d_write = tpmwrite,
- .d_ioctl = tpmioctl,
- .d_stop = nostop,
- .d_tty = notty,
- .d_poll = nopoll,
- .d_mmap = nommap,
- .d_kqfilter = nokqfilter,
- .d_discard = nodiscard,
- .d_flag = D_OTHER,
-};
-
-/* Probe TPM using TIS 1.2 interface. */
-int
-tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
-{
- uint32_t r;
- uint8_t save, reg;
-
- r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
- if (r == 0xffffffff)
- return 0;
-
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_CAPBITS, r);
- printf("%s: caps=%s\n", __func__, buf);
-#endif
- if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
- !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
-#ifdef TPM_DEBUG
- printf("%s: caps too low (caps=%s)\n", __func__, buf);
-#endif
- return 0;
- }
-
- save = bus_space_read_1(bt, bh, TPM_ACCESS);
- bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
- reg = bus_space_read_1(bt, bh, TPM_ACCESS);
- if ((reg & TPM_ACCESS_VALID) && (reg & TPM_ACCESS_ACTIVE_LOCALITY) &&
- bus_space_read_4(bt, bh, TPM_ID) != 0xffffffff)
- return 1;
-
- bus_space_write_1(bt, bh, TPM_ACCESS, save);
- return 0;
-}
-
-/*
- * Setup interrupt vector if one is provided and interrupts are know to
- * work on that particular chip.
- */
-int
-tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
-{
- uint32_t r;
-
- if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
- sc->sc_vector = -1;
- return 0;
- }
-
- /* Ack and disable all interrupts. */
- r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
- r & ~TPM_GLOBAL_INT_ENABLE);
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: before ien %s\n", __func__, buf);
-#endif
-
- /* Program interrupt vector. */
- bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
- sc->sc_vector = irq;
-
- /* Program interrupt type. */
- r &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH|
- TPM_INT_LEVEL_LOW);
- r |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT|
- TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT;
- if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
- r |= TPM_INT_EDGE_RISING;
- else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING)
- r |= TPM_INT_EDGE_FALLING;
- else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
- r |= TPM_INT_LEVEL_HIGH;
- else
- r |= TPM_INT_LEVEL_LOW;
-
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, r);
-#ifdef TPM_DEBUG
- snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: after ien %s\n", __func__, buf);
-#endif
-
- return 0;
-}
-
-/* Setup TPM using TIS 1.2 interface. */
-int
-tpm_tis12_init(struct tpm_softc *sc, int irq, const char *name)
+static inline int
+tpm_tmotohz(int tmo)
{
- uint32_t r;
- int i;
-
- r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
-#ifdef TPM_DEBUG
- char cbuf[128];
- snprintb(cbuf, sizeof(cbuf), TPM_CAPBITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: caps=%s ", __func__, cbuf);
-#endif
- if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
- !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_CAPBITS, r);
- aprint_error_dev(sc->sc_dev, "capabilities too low (caps=%s)\n",
- buf);
- return 1;
- }
- sc->sc_capabilities = r;
-
- sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
- sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
-
- for (i = 0; tpm_devs[i].devid; i++)
- if (tpm_devs[i].devid == sc->sc_devid)
- break;
-
- if (tpm_devs[i].devid)
- aprint_normal(": %s rev 0x%x\n",
- tpm_devs[i].name, sc->sc_rev);
- else
- aprint_normal(": device 0x%08x rev 0x%x\n",
- sc->sc_devid, sc->sc_rev);
-
- if (tpm_tis12_irqinit(sc, irq, i))
- return 1;
-
- if (tpm_request_locality(sc, 0))
- return 1;
+ struct timeval tv;
- /* Abort whatever it thought it was doing. */
- bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
+ tv.tv_sec = tmo / 1000;
+ tv.tv_usec = 1000 * (tmo % 1000);
- return 0;
+ return tvtohz(&tv);
}
-int
+static int
tpm_request_locality(struct tpm_softc *sc, int l)
{
uint32_t r;
@@ -253,48 +130,34 @@ tpm_request_locality(struct tpm_softc *s
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
rv = tsleep(sc->sc_init, PRIBIO | PCATCH, "tpm_locality", 1);
- if (rv && rv != EWOULDBLOCK) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: interrupted %d\n",
- __func__, rv);
-#endif
+ if (rv && rv != EWOULDBLOCK) {
return rv;
}
}
if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
(TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_ACCESS_BITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: access %s\n", __func__, buf);
-#endif
return EBUSY;
}
return 0;
}
-int
+static int
tpm_getburst(struct tpm_softc *sc)
{
int burst, to, rv;
to = tpm_tmotohz(TPM_BURST_TMO);
- burst = 0;
- while (burst == 0 && to--) {
+ while (to--) {
/*
- * Burst count has to be read from bits 8 to 23 without
- * touching any other bits, eg. the actual status bits 0
- * to 7.
+ * Burst count is in bits 23:8, so read the two higher bytes.
*/
burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
burst |= bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2)
<< 8;
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: read %d\n", __func__, burst);
-#endif
+
if (burst)
return burst;
@@ -307,77 +170,56 @@ tpm_getburst(struct tpm_softc *sc)
return 0;
}
-uint8_t
+static inline uint8_t
tpm_status(struct tpm_softc *sc)
{
- return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
+ return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) &
+ TPM_STS_STATUS_BITS;
}
-int
-tpm_tmotohz(int tmo)
-{
- struct timeval tv;
-
- tv.tv_sec = tmo / 1000;
- tv.tv_usec = 1000 * (tmo % 1000);
+/* -------------------------------------------------------------------------- */
- return tvtohz(&tv);
-}
+/*
+ * Save TPM state on suspend. On resume we don't do anything, since the BIOS
+ * is supposed to restore the previously saved state.
+ */
-/* Save TPM state on suspend. */
bool
-tpm_suspend(device_t dev, const pmf_qual_t *qual)
+tpm12_suspend(device_t dev, const pmf_qual_t *qual)
{
struct tpm_softc *sc = device_private(dev);
static const uint8_t command[] = {
- 0, 193, /* TPM_TAG_RQU_COMMAND */
- 0, 0, 0, 10, /* Length in bytes */
- 0, 0, 0, 156 /* TPM_ORD_SaveStates */
+ 0, 193, /* TPM_TAG_RQU_COMMAND */
+ 0, 0, 0, 10, /* Length in bytes */
+ 0, 0, 0, 156 /* TPM_ORD_SaveStates */
};
uint8_t scratch[sizeof(command)];
- /*
- * Power down: We have to issue the SaveStates command.
- */
(*sc->sc_write)(sc, &command, sizeof(command));
- (*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, TPM_HDRSIZE);
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: power down\n", __func__);
-#endif
+ (*sc->sc_read)(sc, &scratch, sizeof(scratch), NULL, 0);
+
return true;
}
-/*
- * Handle resume event. Actually nothing to do as the BIOS is supposed
- * to restore the previously saved state.
- */
bool
-tpm_resume(device_t dev, const pmf_qual_t *qual)
+tpm12_resume(device_t dev, const pmf_qual_t *qual)
{
-#ifdef TPM_DEBUG
- struct tpm_softc *sc = device_private(dev);
- aprint_debug_dev(sc->sc_dev, "%s: resume\n", __func__);
-#endif
return true;
}
-/* Wait for given status bits using polling. */
-int
-tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int tmo, void *c)
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Wait for given status bits using polling.
+ */
+static int
+tpm_waitfor_poll(struct tpm_softc *sc, uint8_t mask, int to, wchan_t chan)
{
int rv;
- /*
- * Poll until either the requested condition or a time out is
- * met.
- */
- while (((sc->sc_stat = tpm_status(sc)) & mask) != mask && tmo--) {
- rv = tsleep(c, PRIBIO | PCATCH, "tpm_poll", 1);
+ while (((sc->sc_status = tpm_status(sc)) & mask) != mask && to--) {
+ rv = tsleep(chan, PRIBIO | PCATCH, "tpm_poll", 1);
if (rv && rv != EWOULDBLOCK) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: interrupted %d\n", __func__, rv);
-#endif
return rv;
}
}
@@ -385,16 +227,17 @@ tpm_waitfor_poll(struct tpm_softc *sc, u
return 0;
}
-/* Wait for given status bits using interrupts. */
-int
-tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, void *c,
+/*
+ * Wait for given status bits using interrupts.
+ */
+static int
+tpm_waitfor_int(struct tpm_softc *sc, uint8_t mask, int tmo, wchan_t chan,
int inttype)
{
int rv, to;
- /* Poll and return when condition is already met. */
- sc->sc_stat = tpm_status(sc);
- if ((sc->sc_stat & mask) == mask)
+ sc->sc_status = tpm_status(sc);
+ if ((sc->sc_status & mask) == mask)
return 0;
/*
@@ -402,147 +245,120 @@ tpm_waitfor_int(struct tpm_softc *sc, ui
* level (SPL_TTY) are disabled (see tpm{read,write} et al) and
* will not be delivered to the cpu until we call tsleep(9) below.
*/
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) |
inttype);
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) |
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) |
TPM_GLOBAL_INT_ENABLE);
- /*
- * Poll once more to remedy the race between previous polling
- * and enabling interrupts on the tpm chip.
- */
- sc->sc_stat = tpm_status(sc);
- if ((sc->sc_stat & mask) == mask) {
+ sc->sc_status = tpm_status(sc);
+ if ((sc->sc_status & mask) == mask) {
rv = 0;
goto out;
}
to = tpm_tmotohz(tmo);
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: sleeping for %d ticks on %p\n", __func__, to, c);
-#endif
+
/*
* tsleep(9) enables interrupts on the cpu and returns after
* wake up with interrupts disabled again. Note that interrupts
* generated by the tpm chip while being at SPL_TTY are not lost
* but held and delivered as soon as the cpu goes below SPL_TTY.
*/
- rv = tsleep(c, PRIBIO | PCATCH, "tpm_wait", to);
+ rv = tsleep(chan, PRIBIO | PCATCH, "tpm_wait", to);
- sc->sc_stat = tpm_status(sc);
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev,
- "%s: woke up with rv %d stat %s\n", __func__, rv, buf);
-#endif
- if ((sc->sc_stat & mask) == mask)
+ sc->sc_status = tpm_status(sc);
+ if ((sc->sc_status & mask) == mask)
rv = 0;
+out:
/* Disable interrupts on tpm chip again. */
-out: bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) &
~TPM_GLOBAL_INT_ENABLE);
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE,
- bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE) &
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE) &
~inttype);
return rv;
}
/*
- * Wait on given status bits, uses interrupts where possible, otherwise polls.
+ * Wait on given status bits, use interrupts where possible, otherwise poll.
*/
-int
-tpm_waitfor(struct tpm_softc *sc, uint8_t b0, int tmo, void *c)
+static int
+tpm_waitfor(struct tpm_softc *sc, uint8_t bits, int tmo, wchan_t chan)
{
- uint8_t b;
- int re, to, rv;
-
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev, "%s: b0 %s\n", __func__, buf);
-#endif
+ int retry, to, rv;
+ uint8_t todo;
/*
- * If possible, use interrupts, otherwise poll.
- *
- * We use interrupts for TPM_STS_VALID and TPM_STS_DATA_AVAIL (if
- * the tpm chips supports them) as waiting for those can take
- * really long. The other TPM_STS* are not needed very often
- * so we do not support them.
+ * We use interrupts for TPM_STS_DATA_AVAIL and TPM_STS_VALID (if the
+ * TPM chip supports them) as waiting for those can take really long.
+ * The other TPM_STS* are not needed very often so we do not support
+ * them.
*/
if (sc->sc_vector != -1) {
- b = b0;
+ todo = bits;
/*
- * Wait for data ready. This interrupt only occures
- * when both TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted.
- * Thus we don't have to bother with TPM_STS_VALID
- * separately and can just return.
+ * Wait for data ready. This interrupt only occurs when both
+ * TPM_STS_VALID and TPM_STS_DATA_AVAIL are asserted. Thus we
+ * don't have to bother with TPM_STS_VALID separately and can
+ * just return.
*
- * This only holds for interrupts! When using polling
- * both flags have to be waited for, see below.
+ * This only holds for interrupts! When using polling both
+ * flags have to be waited for, see below.
*/
- if ((b & TPM_STS_DATA_AVAIL) && (sc->sc_capabilities &
- TPM_INTF_DATA_AVAIL_INT))
- return tpm_waitfor_int(sc, b, tmo, c,
+ if ((bits & TPM_STS_DATA_AVAIL) &&
+ (sc->sc_capabilities & TPM_INTF_DATA_AVAIL_INT))
+ return tpm_waitfor_int(sc, bits, tmo, chan,
TPM_DATA_AVAIL_INT);
/* Wait for status valid bit. */
- if ((b & TPM_STS_VALID) && (sc->sc_capabilities &
- TPM_INTF_STS_VALID_INT)) {
- rv = tpm_waitfor_int(sc, b, tmo, c, TPM_STS_VALID_INT);
- if (rv != 0)
+ if ((bits & TPM_STS_VALID) &&
+ (sc->sc_capabilities & TPM_INTF_STS_VALID_INT)) {
+ rv = tpm_waitfor_int(sc, bits, tmo, chan,
+ TPM_STS_VALID_INT);
+ if (rv)
return rv;
- else
- b = b0 & ~TPM_STS_VALID;
+ todo = bits & ~TPM_STS_VALID;
}
/*
- * When all flags are taken care of, return. Otherwise
- * use polling for eg. TPM_STS_CMD_READY.
+ * When all flags have been taken care of, return. Otherwise
+ * use polling for eg TPM_STS_CMD_READY.
*/
- if (b == 0)
+ if (todo == 0)
return 0;
}
- re = 3;
+ retry = 3;
+
restart:
/*
- * If requested wait for TPM_STS_VALID before dealing with
- * any other flag. Eg. when both TPM_STS_DATA_AVAIL and TPM_STS_VALID
- * are requested, wait for the latter first.
+ * If requested, wait for TPM_STS_VALID before dealing with any other
+ * flag. Eg when both TPM_STS_DATA_AVAIL and TPM_STS_VALID are
+ * requested, wait for the latter first.
*/
- b = b0;
- if (b0 & TPM_STS_VALID)
- b = TPM_STS_VALID;
-
+ todo = bits;
+ if (bits & TPM_STS_VALID)
+ todo = TPM_STS_VALID;
to = tpm_tmotohz(tmo);
again:
- if ((rv = tpm_waitfor_poll(sc, b, to, c)) != 0)
+ if ((rv = tpm_waitfor_poll(sc, todo, to, chan)) != 0)
return rv;
- if ((b & sc->sc_stat) == TPM_STS_VALID) {
+ if ((todo & sc->sc_status) == TPM_STS_VALID) {
/* Now wait for other flags. */
- b = b0 & ~TPM_STS_VALID;
+ todo = bits & ~TPM_STS_VALID;
to++;
goto again;
}
- if ((sc->sc_stat & b) != b) {
-#ifdef TPM_DEBUG
- char bbuf[128], cbuf[128];
- snprintb(bbuf, sizeof(bbuf), TPM_STS_BITS, b);
- snprintb(cbuf, sizeof(cbuf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev,
- "%s: timeout: stat=%s b=%s\n", __func__, cbuf, bbuf);
-#endif
- if (re-- && (b0 & TPM_STS_VALID)) {
+ if ((todo & sc->sc_status) != todo) {
+ if (retry-- && (bits & TPM_STS_VALID)) {
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
TPM_STS_RESP_RETRY);
goto restart;
@@ -553,7 +369,147 @@ again:
return 0;
}
-/* Start transaction. */
+int
+tpm_intr(void *v)
+{
+ struct tpm_softc *sc = v;
+ uint32_t reg;
+
+ reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
+ if (!(reg & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
+ TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
+ return 0;
+
+ if (reg & TPM_STS_VALID_INT)
+ wakeup(sc);
+ if (reg & TPM_CMD_READY_INT)
+ wakeup(sc->sc_write);
+ if (reg & TPM_DATA_AVAIL_INT)
+ wakeup(sc->sc_read);
+ if (reg & TPM_LOCALITY_CHANGE_INT)
+ wakeup(sc->sc_init);
+
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, reg);
+
+ return 1;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * TPM using TIS 1.2 interface.
+ */
+
+int
+tpm_tis12_probe(bus_space_tag_t bt, bus_space_handle_t bh)
+{
+ uint32_t cap;
+ uint8_t reg;
+ int tmo;
+
+ cap = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITY);
+ if (cap == 0xffffffff)
+ return 0;
+ if ((cap & TPM_CAPS_REQUIRED) != TPM_CAPS_REQUIRED)
+ return 0;
+ if (!(cap & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW)))
+ return 0;
+
+ /* Request locality 0. */
+ bus_space_write_1(bt, bh, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
+
+ /* Wait for it to become active. */
+ tmo = TPM_ACCESS_TMO; /* Milliseconds. */
+ while ((reg = bus_space_read_1(bt, bh, TPM_ACCESS) &
+ (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
+ (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && tmo--) {
+ DELAY(1000); /* 1 millisecond. */
+ }
+ if ((reg & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
+ (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
+ return 0;
+ }
+
+ if (bus_space_read_4(bt, bh, TPM_ID) == 0xffffffff)
+ return 0;
+
+ return 1;
+}
+
+static int
+tpm_tis12_irqinit(struct tpm_softc *sc, int irq, int idx)
+{
+ uint32_t reg;
+
+ if ((irq == -1) || (tpm_devs[idx].flags & TPM_DEV_NOINTS)) {
+ sc->sc_vector = -1;
+ return 0;
+ }
+
+ /* Ack and disable all interrupts. */
+ reg = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE);
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE,
+ reg & ~TPM_GLOBAL_INT_ENABLE);
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS,
+ bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS));
+
+ /* Program interrupt vector. */
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_INT_VECTOR, irq);
+ sc->sc_vector = irq;
+
+ /* Program interrupt type. */
+ reg &= ~(TPM_INT_EDGE_RISING|TPM_INT_EDGE_FALLING|TPM_INT_LEVEL_HIGH|
+ TPM_INT_LEVEL_LOW);
+ reg |= TPM_GLOBAL_INT_ENABLE|TPM_CMD_READY_INT|TPM_LOCALITY_CHANGE_INT|
+ TPM_STS_VALID_INT|TPM_DATA_AVAIL_INT;
+ if (sc->sc_capabilities & TPM_INTF_INT_EDGE_RISING)
+ reg |= TPM_INT_EDGE_RISING;
+ else if (sc->sc_capabilities & TPM_INTF_INT_EDGE_FALLING)
+ reg |= TPM_INT_EDGE_FALLING;
+ else if (sc->sc_capabilities & TPM_INTF_INT_LEVEL_HIGH)
+ reg |= TPM_INT_LEVEL_HIGH;
+ else
+ reg |= TPM_INT_LEVEL_LOW;
+
+ bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_ENABLE, reg);
+
+ return 0;
+}
+
+int
+tpm_tis12_init(struct tpm_softc *sc, int irq)
+{
+ int i;
+
+ sc->sc_capabilities = bus_space_read_4(sc->sc_bt, sc->sc_bh,
+ TPM_INTF_CAPABILITY);
+ sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
+ sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
+
+ for (i = 0; tpm_devs[i].devid; i++) {
+ if (tpm_devs[i].devid == sc->sc_devid)
+ break;
+ }
+
+ if (tpm_devs[i].devid)
+ aprint_normal_dev(sc->sc_dev, "%s rev 0x%x\n",
+ tpm_devs[i].name, sc->sc_rev);
+ else
+ aprint_normal_dev(sc->sc_dev, "device 0x%08x rev 0x%x\n",
+ sc->sc_devid, sc->sc_rev);
+
+ if (tpm_tis12_irqinit(sc, irq, i))
+ return 1;
+
+ if (tpm_request_locality(sc, 0))
+ return 1;
+
+ /* Abort whatever it thought it was doing. */
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
+
+ return 0;
+}
+
int
tpm_tis12_start(struct tpm_softc *sc, int flag)
{
@@ -565,41 +521,19 @@ tpm_tis12_start(struct tpm_softc *sc, in
return rv;
}
- /* Own our (0th) locality. */
+ /* Request the 0th locality. */
if ((rv = tpm_request_locality(sc, 0)) != 0)
return rv;
- sc->sc_stat = tpm_status(sc);
- if (sc->sc_stat & TPM_STS_CMD_READY) {
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev, "%s: UIO_WRITE status %s\n",
- __func__, buf);
-#endif
+ sc->sc_status = tpm_status(sc);
+ if (sc->sc_status & TPM_STS_CMD_READY)
return 0;
- }
-
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: UIO_WRITE readying chip\n", __func__);
-#endif
/* Abort previous and restart. */
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_CMD_READY);
- if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO,
- sc->sc_write))) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: UIO_WRITE readying failed %d\n", __func__, rv);
-#endif
+ rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READY_TMO, sc->sc_write);
+ if (rv)
return rv;
- }
-
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: UIO_WRITE readying done\n", __func__);
-#endif
return 0;
}
@@ -612,21 +546,16 @@ tpm_tis12_read(struct tpm_softc *sc, voi
size_t cnt;
int rv, n, bcnt;
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: len %zu\n", __func__, len);
-#endif
cnt = 0;
while (len > 0) {
- if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- TPM_READ_TMO, sc->sc_read)))
+ rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
+ TPM_READ_TMO, sc->sc_read);
+ if (rv)
return rv;
bcnt = tpm_getburst(sc);
n = MIN(len, bcnt);
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: fetching %d, burst is %d\n", __func__, n, bcnt);
-#endif
+
for (; n--; len--) {
*p++ = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
cnt++;
@@ -635,10 +564,6 @@ tpm_tis12_read(struct tpm_softc *sc, voi
if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
break;
}
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: read %zu bytes, len %zu\n", __func__, cnt, len);
-#endif
if (count)
*count = cnt;
@@ -653,13 +578,8 @@ tpm_tis12_write(struct tpm_softc *sc, co
size_t cnt;
int rv, r;
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: sc %p buf %p len %zu\n", __func__, sc, buf, len);
-#endif
if (len == 0)
return 0;
-
if ((rv = tpm_request_locality(sc, 0)) != 0)
return rv;
@@ -670,20 +590,10 @@ tpm_tis12_write(struct tpm_softc *sc, co
cnt++;
}
if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: failed burst rv %d\n", __func__, rv);
-#endif
return rv;
}
- sc->sc_stat = tpm_status(sc);
- if (!(sc->sc_stat & TPM_STS_DATA_EXPECT)) {
-#ifdef TPM_DEBUG
- char sbuf[128];
- snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev,
- "%s: failed rv %d stat=%s\n", __func__, rv, sbuf);
-#endif
+ sc->sc_status = tpm_status(sc);
+ if (!(sc->sc_status & TPM_STS_DATA_EXPECT)) {
return EIO;
}
}
@@ -692,69 +602,42 @@ tpm_tis12_write(struct tpm_softc *sc, co
cnt++;
if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc))) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: failed last byte rv %d\n",
- __func__, rv);
-#endif
return rv;
}
- if ((sc->sc_stat & TPM_STS_DATA_EXPECT) != 0) {
-#ifdef TPM_DEBUG
- char sbuf[128];
- snprintb(sbuf, sizeof(sbuf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev,
- "%s: failed rv %d stat=%s\n", __func__, rv, sbuf);
-#endif
+ if ((sc->sc_status & TPM_STS_DATA_EXPECT) != 0) {
return EIO;
}
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: wrote %zu byte\n", __func__, cnt);
-#endif
-
return 0;
}
-/* Finish transaction. */
int
tpm_tis12_end(struct tpm_softc *sc, int flag, int err)
{
int rv = 0;
if (flag == UIO_READ) {
- if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO,
- sc->sc_read)))
+ rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO, sc->sc_read);
+ if (rv)
return rv;
/* Still more data? */
- sc->sc_stat = tpm_status(sc);
- if (!err && ((sc->sc_stat & TPM_STS_DATA_AVAIL)
- == TPM_STS_DATA_AVAIL)) {
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev,
- "%s: read failed stat=%s\n", __func__, buf);
-#endif
+ sc->sc_status = tpm_status(sc);
+ if (!err && ((sc->sc_status & TPM_STS_DATA_AVAIL) ==
+ TPM_STS_DATA_AVAIL)) {
rv = EIO;
}
bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
TPM_STS_CMD_READY);
- /* Release our (0th) locality. */
- bus_space_write_1(sc->sc_bt, sc->sc_bh,TPM_ACCESS,
+ /* Release the 0th locality. */
+ bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
TPM_ACCESS_ACTIVE_LOCALITY);
} else {
/* Hungry for more? */
- sc->sc_stat = tpm_status(sc);
- if (!err && (sc->sc_stat & TPM_STS_DATA_EXPECT)) {
-#ifdef TPM_DEBUG
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_STS_BITS, sc->sc_stat);
- aprint_debug_dev(sc->sc_dev,
- "%s: write failed stat=%s\n", __func__, buf);
-#endif
+ sc->sc_status = tpm_status(sc);
+ if (!err && (sc->sc_status & TPM_STS_DATA_EXPECT)) {
rv = EIO;
}
@@ -765,247 +648,38 @@ tpm_tis12_end(struct tpm_softc *sc, int
return rv;
}
-int
-tpm_intr(void *v)
-{
- struct tpm_softc *sc = v;
- uint32_t r;
-#ifdef TPM_DEBUG
- static int cnt = 0;
-#endif
-
- r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS);
-#ifdef TPM_DEBUG
- if (r != 0) {
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_INTERRUPT_ENABLE_BITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: int=%s (%d)\n", __func__,
- buf, cnt);
- } else
- cnt++;
-#endif
- if (!(r & (TPM_CMD_READY_INT | TPM_LOCALITY_CHANGE_INT |
- TPM_STS_VALID_INT | TPM_DATA_AVAIL_INT)))
-#ifdef __FreeBSD__
- return;
-#else
- return 0;
-#endif
- if (r & TPM_STS_VALID_INT)
- wakeup(sc);
-
- if (r & TPM_CMD_READY_INT)
- wakeup(sc->sc_write);
-
- if (r & TPM_DATA_AVAIL_INT)
- wakeup(sc->sc_read);
-
- if (r & TPM_LOCALITY_CHANGE_INT)
- wakeup(sc->sc_init);
-
- bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INT_STATUS, r);
-
- return 1;
-}
-
-/* Read single byte using legacy interface. */
-static inline uint8_t
-tpm_legacy_in(bus_space_tag_t iot, bus_space_handle_t ioh, int reg)
-{
- bus_space_write_1(iot, ioh, 0, reg);
- return bus_space_read_1(iot, ioh, 1);
-}
-
-/* Probe for TPM using legacy interface. */
-int
-tpm_legacy_probe(bus_space_tag_t iot, bus_addr_t iobase)
-{
- bus_space_handle_t ioh;
- uint8_t r, v;
- int i, rv = 0;
- char id[8];
-
- if (!tpm_enabled || iobase == -1)
- return 0;
-
- if (bus_space_map(iot, iobase, 2, 0, &ioh))
- return 0;
-
- v = bus_space_read_1(iot, ioh, 0);
- if (v == 0xff) {
- bus_space_unmap(iot, ioh, 2);
- return 0;
- }
- r = bus_space_read_1(iot, ioh, 1);
-
- for (i = sizeof(id); i--; )
- id[i] = tpm_legacy_in(iot, ioh, TPM_ID + i);
-
-#ifdef TPM_DEBUG
- printf("tpm_legacy_probe %.4s %d.%d.%d.%d\n",
- &id[4], id[0], id[1], id[2], id[3]);
-#endif
- /*
- * The only chips using the legacy interface we are aware of are
- * by Atmel. For other chips more signature would have to be added.
- */
- if (!bcmp(&id[4], "ATML", 4))
- rv = 1;
-
- if (!rv) {
- bus_space_write_1(iot, ioh, r, 1);
- bus_space_write_1(iot, ioh, v, 0);
- }
- bus_space_unmap(iot, ioh, 2);
-
- return rv;
-}
-
-/* Setup TPM using legacy interface. */
-int
-tpm_legacy_init(struct tpm_softc *sc, int irq, const char *name)
-{
- char id[8];
- int i;
-
- if ((i = bus_space_map(sc->sc_batm, tpm_enabled, 2, 0, &sc->sc_bahm))) {
- aprint_debug_dev(sc->sc_dev, "cannot map tpm registers (%d)\n",
- i);
- tpm_enabled = 0;
- return 1;
- }
-
- for (i = sizeof(id); i--; )
- id[i] = tpm_legacy_in(sc->sc_bt, sc->sc_bh, TPM_ID + i);
-
- aprint_debug_dev(sc->sc_dev, "%.4s %d.%d @0x%x\n", &id[4], id[0],
- id[1], tpm_enabled);
- tpm_enabled = 0;
-
- return 0;
-}
-
-/* Start transaction. */
-int
-tpm_legacy_start(struct tpm_softc *sc, int flag)
-{
- struct timeval tv;
- uint8_t bits, r;
- int to, rv;
-
- bits = flag == UIO_READ ? TPM_LEGACY_DA : 0;
- tv.tv_sec = TPM_LEGACY_TMO;
- tv.tv_usec = 0;
- to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
- while (((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
- (TPM_LEGACY_BUSY|bits)) != bits && to--) {
- rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_start",
- TPM_LEGACY_SLEEP);
- if (rv && rv != EWOULDBLOCK)
- return rv;
- }
-
-#if defined(TPM_DEBUG) && !defined(__FreeBSD__)
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: bits %s\n", device_xname(sc->sc_dev),
- buf);
-#endif
- if ((r & (TPM_LEGACY_BUSY|bits)) != bits)
- return EIO;
-
- return 0;
-}
-
-int
-tpm_legacy_read(struct tpm_softc *sc, void *buf, size_t len, size_t *count,
- int flags)
-{
- uint8_t *p;
- size_t cnt;
- int to, rv;
-
- cnt = rv = 0;
- for (p = buf; !rv && len > 0; len--) {
- for (to = 1000;
- !(bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1) &
- TPM_LEGACY_DA); DELAY(1))
- if (!to--)
- return EIO;
-
- DELAY(TPM_LEGACY_DELAY);
- *p++ = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 0);
- cnt++;
- }
-
- *count = cnt;
- return 0;
-}
-
-int
-tpm_legacy_write(struct tpm_softc *sc, const void *buf, size_t len)
-{
- const uint8_t *p;
- size_t n;
-
- for (p = buf, n = len; n--; DELAY(TPM_LEGACY_DELAY)) {
- if (!n && len != TPM_BUFSIZ) {
- bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1,
- TPM_LEGACY_LAST);
- DELAY(TPM_LEGACY_DELAY);
- }
- bus_space_write_1(sc->sc_batm, sc->sc_bahm, 0, *p++);
- }
-
- return 0;
-}
-
-/* Finish transaction. */
-int
-tpm_legacy_end(struct tpm_softc *sc, int flag, int rv)
-{
- struct timeval tv;
- uint8_t r;
- int to;
-
- if (rv || flag == UIO_READ)
- bus_space_write_1(sc->sc_batm, sc->sc_bahm, 1, TPM_LEGACY_ABRT);
- else {
- tv.tv_sec = TPM_LEGACY_TMO;
- tv.tv_usec = 0;
- to = tvtohz(&tv) / TPM_LEGACY_SLEEP;
- while(((r = bus_space_read_1(sc->sc_batm, sc->sc_bahm, 1)) &
- TPM_LEGACY_BUSY) && to--) {
- rv = tsleep(sc, PRIBIO | PCATCH, "legacy_tpm_end",
- TPM_LEGACY_SLEEP);
- if (rv && rv != EWOULDBLOCK)
- return rv;
- }
+/* -------------------------------------------------------------------------- */
-#if defined(TPM_DEBUG) && !defined(__FreeBSD__)
- char buf[128];
- snprintb(buf, sizeof(buf), TPM_LEGACY_BITS, r);
- aprint_debug_dev(sc->sc_dev, "%s: bits %s\n",
- device_xname(sc->sc_dev), buf);
-#endif
- if (r & TPM_LEGACY_BUSY)
- return EIO;
+static dev_type_open(tpmopen);
+static dev_type_close(tpmclose);
+static dev_type_read(tpmread);
+static dev_type_write(tpmwrite);
+static dev_type_ioctl(tpmioctl);
- if (r & TPM_LEGACY_RE)
- return EIO; /* XXX Retry the loop? */
- }
+const struct cdevsw tpm_cdevsw = {
+ .d_open = tpmopen,
+ .d_close = tpmclose,
+ .d_read = tpmread,
+ .d_write = tpmwrite,
+ .d_ioctl = tpmioctl,
+ .d_stop = nostop,
+ .d_tty = notty,
+ .d_poll = nopoll,
+ .d_mmap = nommap,
+ .d_kqfilter = nokqfilter,
+ .d_discard = nodiscard,
+ .d_flag = D_OTHER,
+};
- return rv;
-}
+#define TPMUNIT(a) minor(a)
-int
+static int
tpmopen(dev_t dev, int flag, int mode, struct lwp *l)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
- if (!sc)
+ if (sc == NULL)
return ENXIO;
-
if (sc->sc_flags & TPM_OPEN)
return EBUSY;
@@ -1014,14 +688,13 @@ tpmopen(dev_t dev, int flag, int mode, s
return 0;
}
-int
+static int
tpmclose(dev_t dev, int flag, int mode, struct lwp *l)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
- if (!sc)
+ if (sc == NULL)
return ENXIO;
-
if (!(sc->sc_flags & TPM_OPEN))
return EINVAL;
@@ -1030,7 +703,7 @@ tpmclose(dev_t dev, int flag, int mode,
return 0;
}
-int
+static int
tpmread(dev_t dev, struct uio *uio, int flags)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
@@ -1038,43 +711,27 @@ tpmread(dev_t dev, struct uio *uio, int
size_t cnt, len, n;
int rv, s;
- if (!sc)
+ if (sc == NULL)
return ENXIO;
s = spltty();
if ((rv = (*sc->sc_start)(sc, UIO_READ)))
goto out;
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: getting header\n", __func__);
-#endif
if ((rv = (*sc->sc_read)(sc, buf, TPM_HDRSIZE, &cnt, 0))) {
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
len = (buf[2] << 24) | (buf[3] << 16) | (buf[4] << 8) | buf[5];
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: len %zu, io count %zu\n", __func__,
- len, uio->uio_resid);
-#endif
if (len > uio->uio_resid) {
rv = EIO;
(*sc->sc_end)(sc, UIO_READ, rv);
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: bad residual io count 0x%zx\n", __func__,
- uio->uio_resid);
-#endif
goto out;
}
/* Copy out header. */
if ((rv = uiomove(buf, cnt, uio))) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: uiomove failed %d\n", __func__, rv);
-#endif
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
@@ -1083,20 +740,12 @@ tpmread(dev_t dev, struct uio *uio, int
for (len -= cnt, p = buf, n = sizeof(buf); len > 0; p = buf, len -= n,
n = sizeof(buf)) {
n = MIN(n, len);
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: n %zu len %zu\n", __func__,
- n, len);
-#endif
if ((rv = (*sc->sc_read)(sc, p, n, NULL, TPM_PARAM_SIZE))) {
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
p += n;
if ((rv = uiomove(buf, p - buf, uio))) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: uiomove failed %d\n", __func__, rv);
-#endif
(*sc->sc_end)(sc, UIO_READ, rv);
goto out;
}
@@ -1108,50 +757,56 @@ out:
return rv;
}
-int
+static int
tpmwrite(dev_t dev, struct uio *uio, int flags)
{
struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
uint8_t buf[TPM_BUFSIZ];
int n, rv, s;
- if (!sc)
+ if (sc == NULL)
return ENXIO;
s = spltty();
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev, "%s: io count %zu\n", __func__,
- uio->uio_resid);
-#endif
-
n = MIN(sizeof(buf), uio->uio_resid);
if ((rv = uiomove(buf, n, uio))) {
-#ifdef TPM_DEBUG
- aprint_debug_dev(sc->sc_dev,
- "%s: uiomove failed %d\n", __func__, rv);
-#endif
- splx(s);
- return rv;
+ goto out;
}
-
if ((rv = (*sc->sc_start)(sc, UIO_WRITE))) {
- splx(s);
- return rv;
+ goto out;
}
-
if ((rv = (*sc->sc_write)(sc, buf, n))) {
- splx(s);
- return rv;
+ goto out;
}
rv = (*sc->sc_end)(sc, UIO_WRITE, rv);
+out:
splx(s);
return rv;
}
-int
-tpmioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
+static int
+tpmioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
{
+ struct tpm_softc *sc = device_lookup_private(&tpm_cd, TPMUNIT(dev));
+ struct tpm_ioc_getinfo *info;
+
+ if (sc == NULL)
+ return ENXIO;
+
+ switch (cmd) {
+ case TPM_IOC_GETINFO:
+ info = addr;
+ info->api_version = TPM_API_VERSION;
+ info->tpm_version = sc->sc_ver;
+ info->device_id = sc->sc_devid;
+ info->device_rev = sc->sc_rev;
+ info->device_caps = sc->sc_capabilities;
+ return 0;
+ default:
+ break;
+ }
+
return ENOTTY;
}
Index: src/sys/dev/ic/tpmreg.h
diff -u src/sys/dev/ic/tpmreg.h:1.3 src/sys/dev/ic/tpmreg.h:1.4
--- src/sys/dev/ic/tpmreg.h:1.3 Mon Jan 23 04:12:26 2012
+++ src/sys/dev/ic/tpmreg.h Sat Jun 22 12:57:41 2019
@@ -1,100 +1,90 @@
-/* $NetBSD: tpmreg.h,v 1.3 2012/01/23 04:12:26 christos Exp $ */
+/* $NetBSD: tpmreg.h,v 1.4 2019/06/22 12:57:41 maxv Exp $ */
/*
- * Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-J�rg H�xer
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
* All rights reserved.
*
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
*/
-#define TPM_BUFSIZ 1024
-
-#define TPM_HDRSIZE 10
+/*
+ * TPM Interface Specification 1.2 (TIS12).
+ */
-#define TPM_PARAM_SIZE 0x0001
+#define TPM_ACCESS 0x0000 /* 8bit register */
+#define TPM_ACCESS_VALID __BIT(7)
+#define TPM_ACCESS_ACTIVE_LOCALITY __BIT(5)
+#define TPM_ACCESS_BEEN_SEIZED __BIT(4)
+#define TPM_ACCESS_SEIZE __BIT(3)
+#define TPM_ACCESS_PENDING_REQUEST __BIT(2)
+#define TPM_ACCESS_REQUEST_USE __BIT(1)
+#define TPM_ACCESS_ESTABLISHMENT __BIT(0)
+
+#define TPM_INT_ENABLE 0x0008 /* 32bit register */
+#define TPM_GLOBAL_INT_ENABLE __BIT(31)
+#define TPM_CMD_READY_INT __BIT(7)
+#define TPM_TYPE_POLARITY __BITS(4,3)
+#define TPM_INT_LEVEL_HIGH __SHIFTIN(0, TPM_TYPE_POLARITY)
+#define TPM_INT_LEVEL_LOW __SHIFTIN(1, TPM_TYPE_POLARITY)
+#define TPM_INT_EDGE_RISING __SHIFTIN(2, TPM_TYPE_POLARITY)
+#define TPM_INT_EDGE_FALLING __SHIFTIN(3, TPM_TYPE_POLARITY)
+#define TPM_LOCALITY_CHANGE_INT __BIT(2)
+#define TPM_STS_VALID_INT __BIT(1)
+#define TPM_DATA_AVAIL_INT __BIT(0)
+
+#define TPM_INT_VECTOR 0x000c /* 8bit register */
+#define TPM_INT_STATUS 0x0010 /* 32bit register */
+
+#define TPM_INTF_CAPABILITY 0x0014 /* 32bit register */
+#define TPM_INTF_BURST_COUNT_STATIC __BIT(8)
+#define TPM_INTF_CMD_READY_INT __BIT(7)
+#define TPM_INTF_INT_EDGE_FALLING __BIT(6)
+#define TPM_INTF_INT_EDGE_RISING __BIT(5)
+#define TPM_INTF_INT_LEVEL_LOW __BIT(4)
+#define TPM_INTF_INT_LEVEL_HIGH __BIT(3)
+#define TPM_INTF_LOCALITY_CHANGE_INT __BIT(2)
+#define TPM_INTF_STS_VALID_INT __BIT(1)
+#define TPM_INTF_DATA_AVAIL_INT __BIT(0)
+#define TPM_INTF_CAPABILITY_BITS \
+ "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IRISE\07IFALL\010IRDY\011BCST"
+
+#define TPM_STS 0x0018 /* 24bit register */
+#define TPM_STS_BURST_COUNT __BITS(23,8)
+#define TPM_STS_STATUS_BITS __BITS(7,0)
+#define TPM_STS_VALID __BIT(7)
+#define TPM_STS_CMD_READY __BIT(6)
+#define TPM_STS_GO __BIT(5)
+#define TPM_STS_DATA_AVAIL __BIT(4)
+#define TPM_STS_DATA_EXPECT __BIT(3)
+#define TPM_STS_RESP_RETRY __BIT(1)
+
+#define TPM_DATA 0x0024 /* 32bit register */
+#define TPM_ID 0x0f00 /* 32bit register */
+#define TPM_REV 0x0f04 /* 8bit register */
-#define TPM_ACCESS 0x0000 /* access register */
-#define TPM_ACCESS_ESTABLISHMENT 0x01 /* establishment */
-#define TPM_ACCESS_REQUEST_USE 0x02 /* request using locality */
-#define TPM_ACCESS_REQUEST_PENDING 0x04 /* pending request */
-#define TPM_ACCESS_SEIZE 0x08 /* request locality seize */
-#define TPM_ACCESS_SEIZED 0x10 /* locality has been seized */
-#define TPM_ACCESS_ACTIVE_LOCALITY 0x20 /* locality is active */
-#define TPM_ACCESS_VALID 0x80 /* bits are valid */
-#define TPM_ACCESS_BITS \
- "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
-
-#define TPM_INTERRUPT_ENABLE 0x0008
-#define TPM_GLOBAL_INT_ENABLE 0x80000000 /* enable ints */
-#define TPM_CMD_READY_INT 0x00000080 /* cmd ready enable */
-#define TPM_INT_EDGE_FALLING 0x00000018
-#define TPM_INT_EDGE_RISING 0x00000010
-#define TPM_INT_LEVEL_LOW 0x00000008
-#define TPM_INT_LEVEL_HIGH 0x00000000
-#define TPM_LOCALITY_CHANGE_INT 0x00000004 /* locality change enable */
-#define TPM_STS_VALID_INT 0x00000002 /* int on TPM_STS_VALID is set */
-#define TPM_DATA_AVAIL_INT 0x00000001 /* int on TPM_STS_DATA_AVAIL is set */
-#define TPM_INTERRUPT_ENABLE_BITS \
- "\177\020b\0DRDY\0b\1STSVALID\0b\2LOCCHG\0" \
- "F\3\2:\0HIGH\0:\1LOW\0:\2RISE\0:\3FALL\0" \
- "b\7IRDY\0b\x1fGIENABLE\0"
-
-#define TPM_INT_VECTOR 0x000c /* 8 bit reg for 4 bit irq vector */
-#define TPM_INT_STATUS 0x0010 /* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
-
-#define TPM_INTF_CAPABILITIES 0x0014 /* capability register */
-#define TPM_INTF_BURST_COUNT_STATIC 0x0100 /* TPM_STS_BMASK static */
-#define TPM_INTF_CMD_READY_INT 0x0080 /* int on ready supported */
-#define TPM_INTF_INT_EDGE_FALLING 0x0040 /* falling edge ints supported */
-#define TPM_INTF_INT_EDGE_RISING 0x0020 /* rising edge ints supported */
-#define TPM_INTF_INT_LEVEL_LOW 0x0010 /* level-low ints supported */
-#define TPM_INTF_INT_LEVEL_HIGH 0x0008 /* level-high ints supported */
-#define TPM_INTF_LOCALITY_CHANGE_INT 0x0004 /* locality-change int (mb 1) */
-#define TPM_INTF_STS_VALID_INT 0x0002 /* TPM_STS_VALID int supported */
-#define TPM_INTF_DATA_AVAIL_INT 0x0001 /* TPM_STS_DATA_AVAIL int supported (mb 1) */
-#define TPM_CAPSREQ \
- (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
-#define TPM_CAPBITS \
- "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IRISE\07IFALL\010IRDY\011BCST"
-
-#define TPM_STS 0x0018 /* status register */
-#define TPM_STS_MASK 0x000000ff /* status bits */
-#define TPM_STS_BMASK 0x00ffff00 /* ro io burst size */
-#define TPM_STS_VALID 0x00000080 /* ro other bits are valid */
-#define TPM_STS_CMD_READY 0x00000040 /* rw chip/signal ready */
-#define TPM_STS_GO 0x00000020 /* wo start the command */
-#define TPM_STS_DATA_AVAIL 0x00000010 /* ro data available */
-#define TPM_STS_DATA_EXPECT 0x00000008 /* ro more data to be written */
-#define TPM_STS_RESP_RETRY 0x00000002 /* wo resend the response */
-#define TPM_STS_BITS "\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
-
-#define TPM_DATA 0x0024
-#define TPM_ID 0x0f00
-#define TPM_REV 0x0f04
-#define TPM_SIZE 0x5000 /* five pages of the above */
-
-#define TPM_ACCESS_TMO 2000 /* 2sec */
-#define TPM_READY_TMO 2000 /* 2sec */
-#define TPM_READ_TMO 2000 /* 2sec */
-#define TPM_BURST_TMO 2000 /* 2sec */
-
-#define TPM_LEGACY_BUSY 0x01
-#define TPM_LEGACY_ABRT 0x01
-#define TPM_LEGACY_DA 0x02
-#define TPM_LEGACY_RE 0x04
-#define TPM_LEGACY_LAST 0x04
-#define TPM_LEGACY_BITS "\020\01BUSY\2DA\3RE\4LAST"
-#define TPM_LEGACY_TMO (2*60) /* sec */
-#define TPM_LEGACY_SLEEP 5 /* ticks */
-#define TPM_LEGACY_DELAY 100
+/*
+ * Five localities, 4K per locality.
+ */
+#define TPM_SPACE_SIZE 0x5000
Index: src/sys/dev/ic/tpmvar.h
diff -u src/sys/dev/ic/tpmvar.h:1.3 src/sys/dev/ic/tpmvar.h:1.4
--- src/sys/dev/ic/tpmvar.h:1.3 Sat Oct 27 17:18:23 2012
+++ src/sys/dev/ic/tpmvar.h Sat Jun 22 12:57:41 2019
@@ -1,7 +1,37 @@
-/* $NetBSD: tpmvar.h,v 1.3 2012/10/27 17:18:23 chs Exp $ */
+/* $NetBSD: tpmvar.h,v 1.4 2019/06/22 12:57:41 maxv Exp $ */
+
+/*
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
/*
* Copyright (c) 2008, 2009 Michael Shalayeff
- * Copyright (c) 2009, 2010 Hans-J�rg H�xer
+ * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
@@ -17,45 +47,61 @@
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#define TPM_API_VERSION 1
+
+enum tpm_version {
+ TPM_1_2,
+ TPM_2_0
+};
+
+struct tpm_ioc_getinfo {
+ uint32_t api_version;
+
+ uint32_t tpm_version;
+ uint32_t device_id;
+ uint32_t device_rev;
+ uint32_t device_caps;
+};
+
+#define TPM_IOC_GETINFO _IOR ('N', 0, struct tpm_ioc_getinfo)
+
+#ifdef _KERNEL
+
struct tpm_softc {
device_t sc_dev;
+ enum tpm_version sc_ver;
void *sc_ih;
- int (*sc_init)(struct tpm_softc *, int, const char *);
- int (*sc_start)(struct tpm_softc *, int);
- int (*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int);
- int (*sc_write)(struct tpm_softc *, const void *, size_t);
- int (*sc_end)(struct tpm_softc *, int, int);
+ int (*sc_init)(struct tpm_softc *, int);
+ int (*sc_start)(struct tpm_softc *, int);
+ int (*sc_read)(struct tpm_softc *, void *, size_t, size_t *, int);
+ int (*sc_write)(struct tpm_softc *, const void *, size_t);
+ int (*sc_end)(struct tpm_softc *, int, int);
bus_space_tag_t sc_bt, sc_batm;
bus_space_handle_t sc_bh, sc_bahm;
- u_int32_t sc_devid;
- u_int32_t sc_rev;
- u_int32_t sc_stat;
- u_int32_t sc_capabilities;
+ uint32_t sc_devid;
+ uint32_t sc_rev;
+ uint32_t sc_status;
+ uint32_t sc_capabilities;
int sc_flags;
#define TPM_OPEN 0x0001
- int sc_vector;
+ int sc_vector;
};
int tpm_intr(void *);
-bool tpm_suspend(device_t, const pmf_qual_t *);
-bool tpm_resume(device_t, const pmf_qual_t *);
+bool tpm12_suspend(device_t, const pmf_qual_t *);
+bool tpm12_resume(device_t, const pmf_qual_t *);
int tpm_tis12_probe(bus_space_tag_t, bus_space_handle_t);
-int tpm_tis12_init(struct tpm_softc *, int, const char *);
+int tpm_tis12_init(struct tpm_softc *, int);
int tpm_tis12_start(struct tpm_softc *, int);
int tpm_tis12_read(struct tpm_softc *, void *, size_t, size_t *, int);
int tpm_tis12_write(struct tpm_softc *, const void *, size_t);
int tpm_tis12_end(struct tpm_softc *, int, int);
-int tpm_legacy_probe(bus_space_tag_t, bus_addr_t);
-int tpm_legacy_init(struct tpm_softc *, int, const char *);
-int tpm_legacy_start(struct tpm_softc *, int);
-int tpm_legacy_read(struct tpm_softc *, void *, size_t, size_t *, int);
-int tpm_legacy_write(struct tpm_softc *, const void *, size_t);
-int tpm_legacy_end(struct tpm_softc *, int, int);
+#endif
Index: src/sys/dev/isa/tpm_isa.c
diff -u src/sys/dev/isa/tpm_isa.c:1.3 src/sys/dev/isa/tpm_isa.c:1.4
--- src/sys/dev/isa/tpm_isa.c:1.3 Thu Apr 27 10:01:53 2017
+++ src/sys/dev/isa/tpm_isa.c Sat Jun 22 12:57:41 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: tpm_isa.c,v 1.3 2017/04/27 10:01:53 msaitoh Exp $ */
+/* $NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $ */
/*
* Copyright (c) 2008, 2009 Michael Shalayeff
@@ -19,7 +19,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.3 2017/04/27 10:01:53 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tpm_isa.c,v 1.4 2019/06/22 12:57:41 maxv Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -56,27 +56,22 @@ tpm_isa_match(device_t parent, cfdata_t
if (tpm_cd.cd_devs && tpm_cd.cd_devs[0])
return 0;
- if (tpm_legacy_probe(ia->ia_iot, ia->ia_io[0].ir_addr)) {
- ia->ia_io[0].ir_size = 2;
- return 1;
- }
-
if (ia->ia_iomem[0].ir_addr == ISA_UNKNOWN_IOMEM)
return 0;
/* XXX: integer locator sign extension */
- if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SIZE,
+ if (bus_space_map(bt, (unsigned int)ia->ia_iomem[0].ir_addr, TPM_SPACE_SIZE,
0, &bh))
return 0;
if ((rv = tpm_tis12_probe(bt, bh))) {
ia->ia_nio = 0;
ia->ia_io[0].ir_size = 0;
- ia->ia_iomem[0].ir_size = TPM_SIZE;
+ ia->ia_iomem[0].ir_size = TPM_SPACE_SIZE;
}
ia->ia_ndrq = 0;
- bus_space_unmap(bt, bh, TPM_SIZE);
+ bus_space_unmap(bt, bh, TPM_SPACE_SIZE);
return rv;
}
@@ -90,35 +85,23 @@ tpm_isa_attach(device_t parent, device_t
int rv;
sc->sc_dev = self;
+ sc->sc_ver = TPM_1_2;
- if (tpm_legacy_probe(ia->ia_iot, ia->ia_io[0].ir_addr)) {
- sc->sc_bt = ia->ia_iot;
- iobase = (unsigned int)ia->ia_io[0].ir_addr;
- size = ia->ia_io[0].ir_size;
- sc->sc_batm = ia->ia_iot;
- sc->sc_init = tpm_legacy_init;
- sc->sc_start = tpm_legacy_start;
- sc->sc_read = tpm_legacy_read;
- sc->sc_write = tpm_legacy_write;
- sc->sc_end = tpm_legacy_end;
- } else {
- sc->sc_bt = ia->ia_memt;
- iobase = (unsigned int)ia->ia_iomem[0].ir_addr;
- size = TPM_SIZE;
- sc->sc_init = tpm_tis12_init;
- sc->sc_start = tpm_tis12_start;
- sc->sc_read = tpm_tis12_read;
- sc->sc_write = tpm_tis12_write;
- sc->sc_end = tpm_tis12_end;
- }
+ sc->sc_bt = ia->ia_memt;
+ iobase = (unsigned int)ia->ia_iomem[0].ir_addr;
+ size = TPM_SPACE_SIZE;
+ sc->sc_init = tpm_tis12_init;
+ sc->sc_start = tpm_tis12_start;
+ sc->sc_read = tpm_tis12_read;
+ sc->sc_write = tpm_tis12_write;
+ sc->sc_end = tpm_tis12_end;
if (bus_space_map(sc->sc_bt, iobase, size, 0, &sc->sc_bh)) {
aprint_error_dev(sc->sc_dev, "cannot map registers\n");
return;
}
- if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq,
- device_xname(sc->sc_dev))) != 0) {
+ if ((rv = (*sc->sc_init)(sc, ia->ia_irq[0].ir_irq)) != 0) {
bus_space_unmap(sc->sc_bt, sc->sc_bh, size);
return;
}
@@ -132,11 +115,11 @@ tpm_isa_attach(device_t parent, device_t
(sc->sc_ih = isa_intr_establish_xname(ia->ia_ic,
ia->ia_irq[0].ir_irq, IST_EDGE, IPL_TTY, tpm_intr, sc,
device_xname(sc->sc_dev))) == NULL) {
- bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SIZE);
+ bus_space_unmap(sc->sc_bt, sc->sc_bh, TPM_SPACE_SIZE);
aprint_error_dev(sc->sc_dev, "cannot establish interrupt\n");
return;
}
- if (!pmf_device_register(sc->sc_dev, tpm_suspend, tpm_resume))
- aprint_error_dev(sc->sc_dev, "Cannot set power mgmt handler\n");
+ if (!pmf_device_register(sc->sc_dev, tpm12_suspend, tpm12_resume))
+ aprint_error_dev(sc->sc_dev, "cannot set power mgmt handler\n");
}