LCOV - code coverage report
Current view: top level - dev/acpi - tpm.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 199 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* $OpenBSD: tpm.c,v 1.3 2018/07/01 19:40:49 mlarkin Exp $ */
       2             : 
       3             : /*
       4             :  * Minimal interface to Trusted Platform Module chips implementing the
       5             :  * TPM Interface Spec 1.2, just enough to tell the TPM to save state before
       6             :  * a system suspend.
       7             :  *
       8             :  * Copyright (c) 2008, 2009 Michael Shalayeff
       9             :  * Copyright (c) 2009, 2010 Hans-Joerg Hoexer
      10             :  * Copyright (c) 2016 joshua stein <jcs@openbsd.org>
      11             :  * All rights reserved.
      12             :  *
      13             :  * Permission to use, copy, modify, and distribute this software for any
      14             :  * purpose with or without fee is hereby granted, provided that the above
      15             :  * copyright notice and this permission notice appear in all copies.
      16             :  *
      17             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      18             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      19             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      20             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      21             :  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
      22             :  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
      23             :  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      24             :  */
      25             : 
      26             : #include <sys/param.h>
      27             : #include <sys/systm.h>
      28             : #include <sys/device.h>
      29             : #include <sys/malloc.h>
      30             : 
      31             : #include <machine/bus.h>
      32             : #include <machine/apmvar.h>
      33             : 
      34             : #include <dev/acpi/acpireg.h>
      35             : #include <dev/acpi/acpivar.h>
      36             : #include <dev/acpi/acpidev.h>
      37             : #include <dev/acpi/amltypes.h>
      38             : #include <dev/acpi/dsdt.h>
      39             : 
      40             : /* #define TPM_DEBUG */
      41             : 
      42             : #ifdef TPM_DEBUG
      43             : #define DPRINTF(x) printf x
      44             : #else
      45             : #define DPRINTF(x)
      46             : #endif
      47             : 
      48             : #define TPM_BUFSIZ                      1024
      49             : #define TPM_HDRSIZE                     10
      50             : #define TPM_PARAM_SIZE                  0x0001
      51             : 
      52             : #define TPM_ACCESS                      0x0000  /* access register */
      53             : #define TPM_ACCESS_ESTABLISHMENT        0x01    /* establishment */
      54             : #define TPM_ACCESS_REQUEST_USE          0x02    /* request using locality */
      55             : #define TPM_ACCESS_REQUEST_PENDING      0x04    /* pending request */
      56             : #define TPM_ACCESS_SEIZE                0x08    /* request locality seize */
      57             : #define TPM_ACCESS_SEIZED               0x10    /* locality has been seized */
      58             : #define TPM_ACCESS_ACTIVE_LOCALITY      0x20    /* locality is active */
      59             : #define TPM_ACCESS_VALID                0x80    /* bits are valid */
      60             : #define TPM_ACCESS_BITS \
      61             :     "\020\01EST\02REQ\03PEND\04SEIZE\05SEIZED\06ACT\010VALID"
      62             : 
      63             : #define TPM_INTERRUPT_ENABLE            0x0008
      64             : #define TPM_GLOBAL_INT_ENABLE           0x80000000 /* enable ints */
      65             : #define TPM_CMD_READY_INT               0x00000080 /* cmd ready enable */
      66             : #define TPM_INT_EDGE_FALLING            0x00000018
      67             : #define TPM_INT_EDGE_RISING             0x00000010
      68             : #define TPM_INT_LEVEL_LOW               0x00000008
      69             : #define TPM_INT_LEVEL_HIGH              0x00000000
      70             : #define TPM_LOCALITY_CHANGE_INT         0x00000004 /* locality change enable */
      71             : #define TPM_STS_VALID_INT               0x00000002 /* int on TPM_STS_VALID is set */
      72             : #define TPM_DATA_AVAIL_INT              0x00000001 /* int on TPM_STS_DATA_AVAIL is set */
      73             : #define TPM_INTERRUPT_ENABLE_BITS \
      74             :     "\020\040ENA\010RDY\03LOCH\02STSV\01DRDY"
      75             : 
      76             : #define TPM_INT_VECTOR                  0x000c  /* 8 bit reg for 4 bit irq vector */
      77             : #define TPM_INT_STATUS                  0x0010  /* bits are & 0x87 from TPM_INTERRUPT_ENABLE */
      78             : 
      79             : #define TPM_INTF_CAPABILITIES           0x0014  /* capability register */
      80             : #define TPM_INTF_BURST_COUNT_STATIC     0x0100  /* TPM_STS_BMASK static */
      81             : #define TPM_INTF_CMD_READY_INT          0x0080  /* int on ready supported */
      82             : #define TPM_INTF_INT_EDGE_FALLING       0x0040  /* falling edge ints supported */
      83             : #define TPM_INTF_INT_EDGE_RISING        0x0020  /* rising edge ints supported */
      84             : #define TPM_INTF_INT_LEVEL_LOW          0x0010  /* level-low ints supported */
      85             : #define TPM_INTF_INT_LEVEL_HIGH         0x0008  /* level-high ints supported */
      86             : #define TPM_INTF_LOCALITY_CHANGE_INT    0x0004  /* locality-change int (mb 1) */
      87             : #define TPM_INTF_STS_VALID_INT          0x0002  /* TPM_STS_VALID int supported */
      88             : #define TPM_INTF_DATA_AVAIL_INT         0x0001  /* TPM_STS_DATA_AVAIL int supported (mb 1) */
      89             : #define TPM_CAPSREQ \
      90             :   (TPM_INTF_DATA_AVAIL_INT|TPM_INTF_LOCALITY_CHANGE_INT|TPM_INTF_INT_LEVEL_LOW)
      91             : #define TPM_CAPBITS \
      92             :   "\020\01IDRDY\02ISTSV\03ILOCH\04IHIGH\05ILOW\06IEDGE\07IFALL\010IRDY\011BCST"
      93             : 
      94             : #define TPM_STS                         0x0018     /* status register */
      95             : #define TPM_STS_MASK                    0x000000ff /* status bits */
      96             : #define TPM_STS_BMASK                   0x00ffff00 /* ro io burst size */
      97             : #define TPM_STS_VALID                   0x00000080 /* ro other bits are valid */
      98             : #define TPM_STS_CMD_READY               0x00000040 /* rw chip/signal ready */
      99             : #define TPM_STS_GO                      0x00000020 /* wo start the command */
     100             : #define TPM_STS_DATA_AVAIL              0x00000010 /* ro data available */
     101             : #define TPM_STS_DATA_EXPECT             0x00000008 /* ro more data to be written */
     102             : #define TPM_STS_RESP_RETRY              0x00000002 /* wo resend the response */
     103             : #define TPM_STS_BITS    "\020\010VALID\07RDY\06GO\05DRDY\04EXPECT\02RETRY"
     104             : 
     105             : #define TPM_DATA                        0x0024
     106             : #define TPM_ID                          0x0f00
     107             : #define TPM_REV                         0x0f04
     108             : #define TPM_SIZE                        0x5000  /* five pages of the above */
     109             : 
     110             : #define TPM_ACCESS_TMO                  2000    /* 2sec */
     111             : #define TPM_READY_TMO                   2000    /* 2sec */
     112             : #define TPM_READ_TMO                    120000  /* 2 minutes */
     113             : #define TPM_BURST_TMO                   2000    /* 2sec */
     114             : 
     115             : struct tpm_softc {
     116             :         struct device           sc_dev;
     117             : 
     118             :         bus_space_tag_t         sc_bt;
     119             :         bus_space_handle_t      sc_bh;
     120             : 
     121             :         struct acpi_softc       *sc_acpi;
     122             :         struct aml_node         *sc_devnode;
     123             : 
     124             :         uint32_t                sc_devid;
     125             :         uint32_t                sc_rev;
     126             : 
     127             :         int                     sc_enabled;
     128             : };
     129             : 
     130             : struct tpm_crs {
     131             :         int irq_int;
     132             :         uint8_t irq_flags;
     133             :         uint32_t addr_min;
     134             :         uint32_t addr_bas;
     135             :         uint32_t addr_len;
     136             :         uint16_t i2c_addr;
     137             :         struct aml_node *devnode;
     138             :         struct aml_node *gpio_int_node;
     139             :         uint16_t gpio_int_pin;
     140             :         uint16_t gpio_int_flags;
     141             : };
     142             : 
     143             : const struct {
     144             :         uint32_t devid;
     145             :         char name[32];
     146             : } tpm_devs[] = {
     147             :         { 0x000615d1, "Infineon SLD9630 1.1" },
     148             :         { 0x000b15d1, "Infineon SLB9635 1.2" },
     149             :         { 0x100214e4, "Broadcom BCM0102" },
     150             :         { 0x00fe1050, "WEC WPCT200" },
     151             :         { 0x687119fa, "SNS SSX35" },
     152             :         { 0x2e4d5453, "STM ST19WP18" },
     153             :         { 0x32021114, "Atmel 97SC3203" },
     154             :         { 0x10408086, "Intel INTC0102" },
     155             :         { 0, "" },
     156             : };
     157             : 
     158             : int     tpm_match(struct device *, void *, void *);
     159             : void    tpm_attach(struct device *, struct device *, void *);
     160             : int     tpm_activate(struct device *, int);
     161             : int     tpm_parse_crs(int, union acpi_resource *, void *);
     162             : 
     163             : int     tpm_probe(bus_space_tag_t, bus_space_handle_t);
     164             : int     tpm_init(struct tpm_softc *);
     165             : int     tpm_read(struct tpm_softc *, void *, int, size_t *, int);
     166             : int     tpm_write(struct tpm_softc *, void *, int);
     167             : int     tpm_suspend(struct tpm_softc *);
     168             : int     tpm_resume(struct tpm_softc *);
     169             : 
     170             : int     tpm_waitfor(struct tpm_softc *, uint8_t, int);
     171             : int     tpm_request_locality(struct tpm_softc *, int);
     172             : void    tpm_release_locality(struct tpm_softc *);
     173             : int     tpm_getburst(struct tpm_softc *);
     174             : uint8_t tpm_status(struct tpm_softc *);
     175             : int     tpm_tmotohz(int);
     176             : 
     177             : struct cfattach tpm_ca = {
     178             :         sizeof(struct tpm_softc),
     179             :         tpm_match,
     180             :         tpm_attach,
     181             :         NULL,
     182             :         tpm_activate
     183             : };
     184             : 
     185             : struct cfdriver tpm_cd = {
     186             :         NULL, "tpm", DV_DULL
     187             : };
     188             : 
     189             : const char *tpm_hids[] = {
     190             :         "PNP0C31",
     191             :         "ATM1200",
     192             :         "IFX0102",
     193             :         "BCM0101",
     194             :         "BCM0102",
     195             :         "NSC1200",
     196             :         "ICO0102",
     197             :         NULL
     198             : };
     199             : 
     200             : int
     201           0 : tpm_match(struct device *parent, void *match, void *aux)
     202             : {
     203           0 :         struct acpi_attach_args *aa = aux;
     204           0 :         struct cfdata           *cf = match;
     205             : 
     206           0 :         return (acpi_matchhids(aa, tpm_hids, cf->cf_driver->cd_name));
     207             : }
     208             : 
     209             : void
     210           0 : tpm_attach(struct device *parent, struct device *self, void *aux)
     211             : {
     212           0 :         struct tpm_softc        *sc = (struct tpm_softc *)self;
     213           0 :         struct acpi_attach_args *aa = aux;
     214           0 :         struct tpm_crs  crs;
     215           0 :         struct aml_value        res;
     216           0 :         int64_t                 st;
     217             : 
     218           0 :         sc->sc_acpi = (struct acpi_softc *)parent;
     219           0 :         sc->sc_devnode = aa->aaa_node;
     220           0 :         sc->sc_enabled = 0;
     221             : 
     222           0 :         printf(": %s", sc->sc_devnode->name);
     223             : 
     224           0 :         if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &st))
     225           0 :                 st = STA_PRESENT | STA_ENABLED | STA_DEV_OK;
     226           0 :         if ((st & (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) !=
     227             :             (STA_PRESENT | STA_ENABLED | STA_DEV_OK)) {
     228           0 :                 printf(", not enabled\n");
     229           0 :                 return;
     230             :         }
     231             : 
     232           0 :         if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_CRS", 0, NULL, &res)) {
     233           0 :                 printf(", no _CRS method\n");
     234           0 :                 return;
     235             :         }
     236           0 :         if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
     237           0 :                 printf(", invalid _CRS object (type %d len %d)\n",
     238           0 :                     res.type, res.length);
     239           0 :                 aml_freevalue(&res);
     240           0 :                 return;
     241             :         }
     242           0 :         memset(&crs, 0, sizeof(crs));
     243           0 :         crs.devnode = sc->sc_devnode;
     244           0 :         aml_parse_resource(&res, tpm_parse_crs, &crs);
     245           0 :         aml_freevalue(&res);
     246             : 
     247           0 :         if (crs.addr_bas == 0) {
     248           0 :                 printf(", can't find address\n");
     249           0 :                 return;
     250             :         }
     251             : 
     252           0 :         printf(" addr 0x%x/0x%x", crs.addr_bas, crs.addr_len);
     253             : 
     254           0 :         sc->sc_bt = aa->aaa_memt;
     255           0 :         if (bus_space_map(sc->sc_bt, crs.addr_bas, crs.addr_len, 0,
     256           0 :             &sc->sc_bh)) {
     257           0 :                 printf(", failed mapping at 0x%x\n", crs.addr_bas);
     258           0 :                 return;
     259             :         }
     260             : 
     261           0 :         if (!tpm_probe(sc->sc_bt, sc->sc_bh)) {
     262           0 :                 printf(", probe failed\n");
     263           0 :                 return;
     264             :         }
     265             : 
     266           0 :         if (tpm_init(sc) != 0) {
     267           0 :                 printf(", init failed\n");
     268           0 :                 return;
     269             :         }
     270             : 
     271           0 :         sc->sc_enabled = 1;
     272           0 : }
     273             : 
     274             : int
     275           0 : tpm_parse_crs(int crsidx, union acpi_resource *crs, void *arg)
     276             : {
     277           0 :         struct tpm_crs *sc_crs = arg;
     278             : 
     279           0 :         switch (AML_CRSTYPE(crs)) {
     280             :         case LR_MEM32:
     281           0 :                 sc_crs->addr_min = letoh32(crs->lr_m32._min);
     282           0 :                 sc_crs->addr_len = letoh32(crs->lr_m32._len);
     283           0 :                 break;
     284             : 
     285             :         case LR_MEM32FIXED:
     286           0 :                 sc_crs->addr_bas = letoh32(crs->lr_m32fixed._bas);
     287           0 :                 sc_crs->addr_len = letoh32(crs->lr_m32fixed._len);
     288           0 :                 break;
     289             : 
     290             :         case SR_IOPORT:
     291             :         case SR_IRQ:
     292             :         case LR_EXTIRQ:
     293             :         case LR_GPIO:
     294             :                 break;
     295             : 
     296             :         default:
     297             :                 DPRINTF(("%s: unknown resource type %d\n", __func__,
     298             :                     AML_CRSTYPE(crs)));
     299             :         }
     300             : 
     301           0 :         return 0;
     302             : }
     303             : 
     304             : int
     305           0 : tpm_activate(struct device *self, int act)
     306             : {
     307           0 :         struct tpm_softc        *sc = (struct tpm_softc *)self;
     308             : 
     309           0 :         switch (act) {
     310             :         case DVACT_SUSPEND:
     311           0 :                 if (!sc->sc_enabled) {
     312             :                         DPRINTF(("%s: suspend, but not enabled\n",
     313             :                             sc->sc_dev.dv_xname));
     314           0 :                         return 0;
     315             :                 }
     316           0 :                 tpm_suspend(sc);
     317           0 :                 break;
     318             : 
     319             :         case DVACT_WAKEUP:
     320           0 :                 if (!sc->sc_enabled) {
     321             :                         DPRINTF(("%s: wakeup, but not enabled\n",
     322             :                             sc->sc_dev.dv_xname));
     323           0 :                         return 0;
     324             :                 }
     325           0 :                 tpm_resume(sc);
     326           0 :                 break;
     327             :         }
     328             : 
     329           0 :         return 0;
     330           0 : }
     331             : 
     332             : int
     333           0 : tpm_suspend(struct tpm_softc *sc)
     334             : {
     335           0 :         uint8_t command[] = {
     336             :             0, 0xc1,            /* TPM_TAG_RQU_COMMAND */
     337             :             0, 0, 0, 10,        /* Length in bytes */
     338             :             0, 0, 0, 0x98       /* TPM_ORD_SaveStates */
     339             :         };
     340             : 
     341             :         DPRINTF(("%s: saving state preparing for suspend\n",
     342             :             sc->sc_dev.dv_xname));
     343             : 
     344             :         /*
     345             :          * Tell the chip to save its state so the BIOS can then restore it upon
     346             :          * resume.
     347             :          */
     348           0 :         tpm_write(sc, &command, sizeof(command));
     349           0 :         tpm_read(sc, &command, sizeof(command), NULL, TPM_HDRSIZE);
     350             : 
     351           0 :         return 0;
     352           0 : }
     353             : 
     354             : int
     355           0 : tpm_resume(struct tpm_softc *sc)
     356             : {
     357             :         /*
     358             :          * TODO: The BIOS should have restored the chip's state for us already,
     359             :          * but we should tell the chip to do a self-test here (according to the
     360             :          * Linux driver).
     361             :          */
     362             : 
     363             :         DPRINTF(("%s: resume\n", sc->sc_dev.dv_xname));
     364           0 :         return 0;
     365             : }
     366             : 
     367             : int
     368           0 : tpm_probe(bus_space_tag_t bt, bus_space_handle_t bh)
     369             : {
     370             :         uint32_t r;
     371             :         int tries = 10000;
     372             : 
     373             :         /* wait for chip to settle */
     374           0 :         while (tries--) {
     375           0 :                 if (bus_space_read_1(bt, bh, TPM_ACCESS) & TPM_ACCESS_VALID)
     376             :                         break;
     377           0 :                 else if (!tries) {
     378           0 :                         printf(": timed out waiting for validity\n");
     379           0 :                         return 1;
     380             :                 }
     381             : 
     382           0 :                 DELAY(10);
     383             :         }
     384             : 
     385           0 :         r = bus_space_read_4(bt, bh, TPM_INTF_CAPABILITIES);
     386           0 :         if (r == 0xffffffff)
     387           0 :                 return 0;
     388             : 
     389           0 :         return 1;
     390           0 : }
     391             : 
     392             : int
     393           0 : tpm_init(struct tpm_softc *sc)
     394             : {
     395             :         uint32_t r, intmask;
     396             :         int i;
     397             : 
     398           0 :         r = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTF_CAPABILITIES);
     399           0 :         if ((r & TPM_CAPSREQ) != TPM_CAPSREQ ||
     400           0 :             !(r & (TPM_INTF_INT_EDGE_RISING | TPM_INTF_INT_LEVEL_LOW))) {
     401             :                 DPRINTF((": caps too low (caps=%b)\n", r, TPM_CAPBITS));
     402           0 :                 return 0;
     403             :         }
     404             : 
     405             :         /* ack and disable all interrupts, we'll be using polling only */
     406           0 :         intmask = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE);
     407           0 :         intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
     408             :             TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
     409           0 :         intmask &= ~TPM_GLOBAL_INT_ENABLE;
     410           0 :         bus_space_write_4(sc->sc_bt, sc->sc_bh, TPM_INTERRUPT_ENABLE, intmask);
     411             : 
     412           0 :         if (tpm_request_locality(sc, 0)) {
     413           0 :                 printf(", requesting locality failed\n");
     414           0 :                 return 1;
     415             :         }
     416             : 
     417           0 :         sc->sc_devid = bus_space_read_4(sc->sc_bt, sc->sc_bh, TPM_ID);
     418           0 :         sc->sc_rev = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_REV);
     419             : 
     420           0 :         for (i = 0; tpm_devs[i].devid; i++)
     421           0 :                 if (tpm_devs[i].devid == sc->sc_devid)
     422             :                         break;
     423             : 
     424           0 :         if (tpm_devs[i].devid)
     425           0 :                 printf(": %s rev 0x%x\n", tpm_devs[i].name, sc->sc_rev);
     426             :         else
     427           0 :                 printf(": device 0x%08x rev 0x%x\n", sc->sc_devid, sc->sc_rev);
     428             : 
     429           0 :         return 0;
     430           0 : }
     431             : 
     432             : int
     433           0 : tpm_request_locality(struct tpm_softc *sc, int l)
     434             : {
     435             :         uint32_t r;
     436             :         int to;
     437             : 
     438           0 :         if (l != 0)
     439           0 :                 return EINVAL;
     440             : 
     441           0 :         if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
     442           0 :             (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) ==
     443             :             (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY))
     444           0 :                 return 0;
     445             : 
     446           0 :         bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
     447             :             TPM_ACCESS_REQUEST_USE);
     448             : 
     449           0 :         to = tpm_tmotohz(TPM_ACCESS_TMO);
     450             : 
     451           0 :         while ((r = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
     452           0 :             (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
     453           0 :             (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY) && to--) {
     454           0 :                 DELAY(10);
     455             :         }
     456             : 
     457           0 :         if ((r & (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) !=
     458             :             (TPM_ACCESS_VALID | TPM_ACCESS_ACTIVE_LOCALITY)) {
     459             :                 DPRINTF(("%s: %s: access %b\n", sc->sc_dev.dv_xname, __func__,
     460             :                     r, TPM_ACCESS_BITS));
     461           0 :                 return EBUSY;
     462             :         }
     463             : 
     464           0 :         return 0;
     465           0 : }
     466             : 
     467             : void
     468           0 : tpm_release_locality(struct tpm_softc *sc)
     469             : {
     470           0 :         if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS) &
     471           0 :             (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) ==
     472             :             (TPM_ACCESS_REQUEST_PENDING|TPM_ACCESS_VALID)) {
     473             :                 DPRINTF(("%s: releasing locality\n", sc->sc_dev.dv_xname));
     474           0 :                 bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_ACCESS,
     475             :                     TPM_ACCESS_ACTIVE_LOCALITY);
     476           0 :         }
     477           0 : }
     478             : 
     479             : int
     480           0 : tpm_getburst(struct tpm_softc *sc)
     481             : {
     482             :         int burst, burst2, to;
     483             : 
     484           0 :         to = tpm_tmotohz(TPM_BURST_TMO);
     485             : 
     486             :         burst = 0;
     487           0 :         while (burst == 0 && to--) {
     488             :                 /*
     489             :                  * Burst count has to be read from bits 8 to 23 without
     490             :                  * touching any other bits, eg. the actual status bits 0 to 7.
     491             :                  */
     492           0 :                 burst = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 1);
     493             :                 DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
     494             :                     __func__, TPM_STS + 1, burst));
     495           0 :                 burst2 = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS + 2);
     496             :                 DPRINTF(("%s: %s: read1(0x%x): 0x%x\n", sc->sc_dev.dv_xname,
     497             :                     __func__, TPM_STS + 2, burst2));
     498           0 :                 burst |= burst2 << 8;
     499           0 :                 if (burst)
     500           0 :                         return burst;
     501             : 
     502           0 :                 DELAY(10);
     503             :         }
     504             : 
     505             :         DPRINTF(("%s: getburst timed out\n", sc->sc_dev.dv_xname));
     506             : 
     507           0 :         return 0;
     508           0 : }
     509             : 
     510             : uint8_t
     511           0 : tpm_status(struct tpm_softc *sc)
     512             : {
     513           0 :         return bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_STS) & TPM_STS_MASK;
     514             : }
     515             : 
     516             : int
     517           0 : tpm_tmotohz(int tmo)
     518             : {
     519           0 :         struct timeval tv;
     520             : 
     521           0 :         tv.tv_sec = tmo / 1000;
     522           0 :         tv.tv_usec = 1000 * (tmo % 1000);
     523             : 
     524           0 :         return tvtohz(&tv);
     525           0 : }
     526             : 
     527             : int
     528           0 : tpm_waitfor(struct tpm_softc *sc, uint8_t mask, int tries)
     529             : {
     530             :         uint8_t status;
     531             : 
     532           0 :         while (((status = tpm_status(sc)) & mask) != mask) {
     533           0 :                 if (tries == 0) {
     534             :                         DPRINTF(("%s: %s: timed out, status 0x%x != 0x%x\n",
     535             :                             sc->sc_dev.dv_xname, __func__, status, mask));
     536           0 :                         return status;
     537             :                 }
     538             : 
     539           0 :                 tries--;
     540           0 :                 DELAY(1);
     541             :         }
     542             : 
     543           0 :         return 0;
     544           0 : }
     545             : 
     546             : int
     547           0 : tpm_read(struct tpm_softc *sc, void *buf, int len, size_t *count,
     548             :     int flags)
     549             : {
     550             :         uint8_t *p = buf;
     551             :         uint8_t c;
     552             :         size_t cnt;
     553             :         int rv, n, bcnt;
     554             : 
     555             :         DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
     556             : 
     557             :         cnt = 0;
     558           0 :         while (len > 0) {
     559           0 :                 if ((rv = tpm_waitfor(sc, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
     560             :                     TPM_READ_TMO)))
     561           0 :                         return rv;
     562             : 
     563           0 :                 bcnt = tpm_getburst(sc);
     564           0 :                 n = MIN(len, bcnt);
     565             : 
     566           0 :                 for (; n--; len--) {
     567           0 :                         c = bus_space_read_1(sc->sc_bt, sc->sc_bh, TPM_DATA);
     568             :                         DPRINTF((" %02x", c));
     569           0 :                         *p++ = c;
     570           0 :                         cnt++;
     571             :                 }
     572             : 
     573           0 :                 if ((flags & TPM_PARAM_SIZE) == 0 && cnt >= 6)
     574             :                         break;
     575             :         }
     576             : 
     577             :         DPRINTF(("\n"));
     578             : 
     579           0 :         if (count)
     580           0 :                 *count = cnt;
     581             : 
     582           0 :         return 0;
     583           0 : }
     584             : 
     585             : int
     586           0 : tpm_write(struct tpm_softc *sc, void *buf, int len)
     587             : {
     588             :         uint8_t *p = buf;
     589             :         uint8_t status;
     590             :         size_t count = 0;
     591             :         int rv, r;
     592             : 
     593           0 :         if ((rv = tpm_request_locality(sc, 0)) != 0)
     594           0 :                 return rv;
     595             : 
     596             :         DPRINTF(("%s: %s %d:", sc->sc_dev.dv_xname, __func__, len));
     597           0 :         for (r = 0; r < len; r++)
     598             :                 DPRINTF((" %02x", (uint8_t)(*(p + r))));
     599             :         DPRINTF(("\n"));
     600             : 
     601             :         /* read status */
     602           0 :         status = tpm_status(sc);
     603           0 :         if ((status & TPM_STS_CMD_READY) == 0) {
     604             :                 /* abort! */
     605           0 :                 bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS,
     606             :                     TPM_STS_CMD_READY);
     607           0 :                 if ((rv = tpm_waitfor(sc, TPM_STS_CMD_READY, TPM_READ_TMO))) {
     608             :                         DPRINTF(("%s: failed waiting for ready after abort "
     609             :                             "(0x%x)\n", sc->sc_dev.dv_xname, rv));
     610           0 :                         return rv;
     611             :                 }
     612             :         }
     613             : 
     614           0 :         while (count < len - 1) {
     615           0 :                 for (r = tpm_getburst(sc); r > 0 && count < len - 1; r--) {
     616             :                         DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n",
     617             :                             sc->sc_dev.dv_xname, __func__, TPM_DATA, *p));
     618           0 :                         bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p++);
     619           0 :                         count++;
     620             :                 }
     621           0 :                 if ((rv = tpm_waitfor(sc, TPM_STS_VALID | TPM_STS_DATA_EXPECT,
     622             :                     TPM_READ_TMO))) {
     623             :                         DPRINTF(("%s: %s: failed waiting for next byte (%d)\n",
     624             :                             sc->sc_dev.dv_xname, __func__, rv));
     625           0 :                         return rv;
     626             :                 }
     627             :         }
     628             : 
     629             :         DPRINTF(("%s: %s: write1(0x%x, 0x%x)\n", sc->sc_dev.dv_xname, __func__,
     630             :             TPM_DATA, *p));
     631           0 :         bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_DATA, *p);
     632             :         count++;
     633             : 
     634           0 :         if ((rv = tpm_waitfor(sc, TPM_STS_VALID, TPM_READ_TMO))) {
     635             :                 DPRINTF(("%s: %s: failed after last byte (%d)\n",
     636             :                     sc->sc_dev.dv_xname, __func__, rv));
     637           0 :                 return rv;
     638             :         }
     639             : 
     640           0 :         if ((status = tpm_status(sc)) & TPM_STS_DATA_EXPECT) {
     641             :                 DPRINTF(("%s: %s: final status still expecting data: %b\n",
     642             :                     sc->sc_dev.dv_xname, __func__, status, TPM_STS_BITS));
     643           0 :                 return status;
     644             :         }
     645             : 
     646             :         DPRINTF(("%s: final status after write: %b\n", sc->sc_dev.dv_xname,
     647             :             status, TPM_STS_BITS));
     648             : 
     649             :         /* XXX: are we ever sending non-command data? */
     650           0 :         bus_space_write_1(sc->sc_bt, sc->sc_bh, TPM_STS, TPM_STS_GO);
     651             : 
     652           0 :         return 0;
     653           0 : }

Generated by: LCOV version 1.13